Files
illogical-impulse/.config/ags/widgets/sideleft/apis/waifu.js
T
2024-01-01 16:15:05 +07:00

279 lines
9.5 KiB
JavaScript

const { Gdk, Gio, GLib, Gtk, Pango } = imports.gi;
import { App, Utils, Widget } from '../../../imports.js';
const { Box, Button, Entry, EventBox, Icon, Label, Revealer, Scrollable, Stack } = Widget;
const { execAsync, exec } = Utils;
import { MaterialIcon } from "../../../lib/materialicon.js";
import { MarginRevealer } from '../../../lib/advancedrevealers.js';
import { setupCursorHover, setupCursorHoverInfo } from "../../../lib/cursorhover.js";
import WaifuService from '../../../services/waifus.js';
// Create cache folder and clear pics from previous session
Utils.exec(`bash -c 'mkdir -p ${GLib.get_user_cache_dir()}/ags/media/waifus'`);
Utils.exec(`bash -c 'rm ${GLib.get_user_cache_dir()}/ags/media/waifus/*'`);
const CommandButton = (command) => Button({
className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
onClicked: () => sendMessage(command),
setup: setupCursorHover,
label: command,
});
export const waifuTabIcon = Box({
hpack: 'center',
className: 'sidebar-chat-apiswitcher-icon',
homogeneous: true,
children: [
MaterialIcon('photo_library', 'norm'),
]
});
const WaifuImage = (taglist) => {
var imagePath = '';
var blockImageData = {};
const ImageState = (icon, name) => Box({
className: 'spacing-h-5',
children: [
Box({ hexpand: true }),
Label({
className: 'sidebar-waifu-txt txt-smallie txt',
xalign: 0,
label: name,
}),
MaterialIcon(icon, 'norm'),
]
})
const ImageAction = ({ name, icon, action }) => Button({
className: 'sidebar-waifu-image-action txt-norm icon-material',
tooltipText: name,
label: icon,
onClicked: action,
setup: setupCursorHover,
})
const colorIndicator = Box({
className: `sidebar-chat-indicator`,
});
const downloadState = Stack({
homogeneous: false,
transition: 'slide_up_down',
transitionDuration: 150,
items: [
['api', ImageState('api', 'Calling API')],
['download', ImageState('downloading', 'Downloading image')],
['done', ImageState('done', 'Finished!')],
['error', ImageState('error', 'Error')],
]
});
const downloadIndicator = MarginRevealer({
vpack: 'center',
transition: 'slide_left',
revealChild: true,
child: downloadState,
});
const blockHeading = Box({
hpack: 'fill',
className: 'sidebar-waifu-content spacing-h-5',
children: [
...taglist.map((tag) => CommandButton(tag)),
Box({ hexpand: true }),
downloadIndicator,
]
});
const blockImageActions = Box({
className: 'sidebar-waifu-image-actions spacing-h-3',
children: [
Box({ hexpand: true }),
ImageAction({
name: 'Go to source',
icon: 'link',
action: () => execAsync(['xdg-open', `${blockImageData.source}`]).catch(print),
}),
ImageAction({
name: 'Hoard',
icon: 'save',
action: () => execAsync(['bash', '-c', `mkdir -p ~/Pictures/waifus && cp ${imagePath} ~/Pictures/waifus`]).catch(print),
}),
ImageAction({
name: 'Open externally',
icon: 'open_in_new',
action: () => execAsync(['xdg-open', `${imagePath}`]).catch(print),
}),
]
})
const blockImage = Box({
className: 'test',
hpack: 'start',
vertical: true,
className: 'sidebar-waifu-image',
homogeneous: true,
children: [
Revealer({
transition: 'crossfade',
revealChild: false,
child: Box({
vertical: true,
children: [blockImageActions],
})
})
]
})
const blockImageRevealer = Revealer({
transition: 'slide_down',
transitionDuration: 150,
revealChild: false,
child: blockImage,
});
const thisBlock = Box({
className: 'sidebar-chat-message',
properties: [
['update', (imageData) => {
blockImageData = imageData;
const { status, signature, url, source, dominant_color, is_nsfw, width, height, tags } = blockImageData;
if (status != 200) {
downloadState.shown = 'error';
return;
}
imagePath = `${GLib.get_user_cache_dir()}/ags/media/waifus/${signature}`;
downloadState.shown = 'download';
// Width allocation
const widgetWidth = Math.min(Math.floor(waifuContent.get_allocated_width() * 0.75), width);
blockImage.set_size_request(widgetWidth, Math.ceil(widgetWidth * height / width));
// Start download
const showImage = () => {
downloadState.shown = 'done';
blockImage.css = `background-image:url('${imagePath}');`;
blockImageRevealer.revealChild = true;
Utils.timeout(blockImageRevealer.transitionDuration,
() => blockImage.get_children()[0].revealChild = true
);
downloadIndicator._hide(downloadIndicator);
}
if (Gio.File.new_for_path(imagePath).query_exists(null)) showImage();
else Utils.execAsync(['bash', '-c', `wget -O '${imagePath}' '${url}'`])
.then(showImage)
.catch(print);
colorIndicator.css = `background-color: ${dominant_color};`;
}],
],
children: [
colorIndicator,
Box({
vertical: true,
className: 'spacing-v-5',
children: [
blockHeading,
Box({
vertical: true,
children: [blockImageRevealer],
})
]
})
],
});
return thisBlock;
}
const waifuContent = Box({
className: 'spacing-v-15',
vertical: true,
vexpand: true,
properties: [
['map', new Map()],
],
connections: [
[WaifuService, (box, id) => {
if (id === undefined) return;
const newImageBlock = WaifuImage(WaifuService.queries[id]);
box.add(newImageBlock);
box.show_all();
box._map.set(id, newImageBlock);
}, 'newResponse'],
[WaifuService, (box, id) => {
if (id === undefined) return;
const data = WaifuService.responses[id];
if (!data) return;
const imageBlock = box._map.get(id);
imageBlock._update(data);
}, 'updateResponse'],
]
});
export const waifuView = Scrollable({
className: 'sidebar-chat-viewport',
vexpand: true,
child: Box({
vertical: true,
children: [
waifuContent,
]
}),
setup: (scrolledWindow) => {
// Show scrollbar
scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
const vScrollbar = scrolledWindow.get_vscrollbar();
vScrollbar.get_style_context().add_class('sidebar-scrollbar');
// Avoid click-to-scroll-widget-to-view behavior
Utils.timeout(1, () => {
const viewport = scrolledWindow.child;
viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
})
// Always scroll to bottom with new content
const adjustment = scrolledWindow.get_vadjustment();
adjustment.connect("changed", () => {
adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
})
}
});
// const waifuTags = Box({
// className: 'spacing-h-5',
// children: [
// Box({ hexpand: true }),
// CommandButton('waifu'),
// CommandButton('maid'),
// CommandButton('uniform'),
// CommandButton('oppai'),
// CommandButton('selfies'),
// CommandButton('marin-kitagawa'),
// CommandButton('raiden-shogun'),
// CommandButton('mori-calliope'),
// ]
// });
export const waifuCommands = Box({
className: 'spacing-h-5',
children: [
Box({ hexpand: true }),
CommandButton('/clear'),
]
});
export const sendMessage = (text) => {
// Do something on send
// Commands
if (text.startsWith('/')) {
if (text.startsWith('/clear')) {
const kids = waifuContent.get_children();
for (let i = 0; i < kids.length; i++) {
const child = kids[i];
child.destroy();
}
}
else if (text.startsWith('/test')) {
const newImage = WaifuImage(['/test']);
waifuContent.add(newImage);
Utils.timeout(13, () => newImage._update({ // Needs timeout or inits won't make it
// This is an image uploaded to my github repo
status: 200,
url: 'https://picsum.photos/400/600',
signature: 0,
source: 'https://picsum.photos/400/600',
dominant_color: '#9392A6',
is_nsfw: false,
width: 300,
height: 200,
tags: ['/test'],
}));
}
}
else WaifuService.fetch(text);
}