waifu widget: added actions

This commit is contained in:
end-4
2024-01-01 16:09:14 +07:00
parent ff377a5826
commit cc408501df
7 changed files with 309 additions and 114 deletions
@@ -201,6 +201,11 @@ export const chatGPTView = Scrollable({
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());
})
}
});
@@ -10,7 +10,6 @@ const CUSTOM_SOURCEVIEW_SCHEME_PATH = `${App.configDir}/data/sourceviewtheme.xml
const CUSTOM_SCHEME_ID = 'custom';
const USERNAME = GLib.get_user_name();
const CHATGPT_CURSOR = ' (o) ';
const MESSAGE_SCROLL_DELAY = 13; // In milliseconds, the time before an updated message scrolls to bottom
/////////////////////// Custom source view colorscheme /////////////////////////
@@ -125,7 +124,11 @@ const CodeBlock = (content = '', lang = 'txt') => {
Box({
className: 'sidebar-chat-codeblock-code',
homogeneous: true,
children: [sourceView,],
children: [Scrollable({
vscroll: 'never',
hscroll: 'automatic',
child: sourceView,
})],
})
]
})
@@ -246,11 +249,6 @@ export const ChatMessage = (message, scrolledWindow) => {
}, 'notify::thinking'],
[message, (self) => { // Message update
messageContentBox._fullUpdate(messageContentBox, message.content, message.role != 'user');
Utils.timeout(MESSAGE_SCROLL_DELAY, () => {
if (!scrolledWindow) return;
var adjustment = scrolledWindow.get_vadjustment();
adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
});
}, 'notify::content'],
[message, (label, isDone) => { // Remove the cursor
messageContentBox._fullUpdate(messageContentBox, message.content, false);
@@ -285,11 +283,6 @@ export const SystemMessage = (content, commandName, scrolledWindow) => {
],
})
],
setup: (self) => Utils.timeout(MESSAGE_SCROLL_DELAY, () => {
if (!scrolledWindow) return;
var adjustment = scrolledWindow.get_vadjustment();
adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
})
});
return thisMessage;
}
+150 -32
View File
@@ -1,13 +1,12 @@
const { Gdk, GLib, Gtk, Pango } = imports.gi;
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';
const MESSAGE_SCROLL_DELAY = 13; // In milliseconds, the time before an updated message scrolls to bottom
// 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/*'`);
@@ -29,62 +28,146 @@ export const waifuTabIcon = Box({
});
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 downloadIndicator = Label({
className: 'sidebar-waifu-txt txt-smallie txt',
xalign: 0,
label: 'Downloading image...',
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({
className: 'sidebar-waifu-content',
vertical: true,
hpack: 'fill',
className: 'sidebar-waifu-content spacing-h-5',
children: [
Box({
children: taglist.map((tag) => CommandButton(tag))
}),
...taglist.map((tag) => CommandButton(tag)),
Box({ hexpand: true }),
downloadIndicator,
]
});
const blockImage = Box({
hpack: 'start',
className: 'sidebar-waifu-image',
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) => {
const { signature, url, source, dominant_color, is_nsfw, width, height, tags } = imageData;
const imagePath = `${GLib.get_user_cache_dir()}/ags/media/waifus/${signature}`;
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
Utils.execAsync(['bash', '-c', `wget -O '${imagePath}' '${url}'`])
.then(() => {
blockImage.css = `background-image:url('${imagePath}');`;
downloadIndicator.destroy();
})
const showImage = () => {
downloadState.shown = 'done';
blockImage.css = `background-image:url('${imagePath}');`;
blockImage.get_children()[0].revealChild = true;
Utils.timeout(blockImageRevealer.transitionDuration,
() => blockImageRevealer.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};`;
// Width allocation
const widgetWidth = Math.floor(waifuContent.get_allocated_width() * 0.75); // idk tbh
blockImage.set_size_request(widgetWidth, Math.ceil(widgetWidth * height / width));
}],
],
children: [
colorIndicator,
Box({
vertical: true,
className: 'spacing-v-10',
className: 'spacing-v-5',
children: [
blockHeading,
blockImage,
Box({
vertical: true,
children: [blockImageRevealer],
})
]
})
],
setup: (self) => Utils.timeout(MESSAGE_SCROLL_DELAY, () => {
var adjustment = waifuView.get_vadjustment();
adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
})
});
return thisBlock;
}
@@ -99,7 +182,6 @@ const waifuContent = Box({
connections: [
[WaifuService, (box, id) => {
if (id === undefined) return;
console.log('new', WaifuService.queries[id]);
const newImageBlock = WaifuImage(WaifuService.queries[id]);
box.add(newImageBlock);
box.show_all();
@@ -134,9 +216,29 @@ export const waifuView = Scrollable({
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: [
@@ -156,6 +258,22 @@ export const sendMessage = (text) => {
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);
}