forked from Shinonome/dots-hyprland
waifu widget: added actions
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user