feat(agsV2): add clipboard
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-10-30 01:42:20 -04:00
parent cd8384a556
commit 171ff9629c
6 changed files with 213 additions and 0 deletions

View file

@ -8,6 +8,7 @@ import AppLauncher from './widgets/applauncher/main';
import Bar from './widgets/bar/wim'; import Bar from './widgets/bar/wim';
import BgFade from './widgets/bg-fade/main'; import BgFade from './widgets/bg-fade/main';
import Calendar from './widgets/date/main'; import Calendar from './widgets/date/main';
import Clipboard from './widgets/clipboard/main';
import Corners from './widgets/corners/main'; import Corners from './widgets/corners/main';
import IconBrowser from './widgets/icon-browser/main'; import IconBrowser from './widgets/icon-browser/main';
import { NotifPopups, NotifCenter } from './widgets/notifs/main'; import { NotifPopups, NotifCenter } from './widgets/notifs/main';
@ -59,6 +60,7 @@ switch (CONF) {
Bar(); Bar();
BgFade(); BgFade();
Calendar(); Calendar();
Clipboard();
Corners(); Corners();
IconBrowser(); IconBrowser();
NotifPopups(); NotifPopups();

View file

@ -40,6 +40,7 @@ progressbar {
@import 'widgets/applauncher/style.scss'; @import 'widgets/applauncher/style.scss';
@import 'widgets/bar/style.scss'; @import 'widgets/bar/style.scss';
@import 'widgets/clipboard/style.scss';
@import 'widgets/date/style.scss'; @import 'widgets/date/style.scss';
@import 'widgets/icon-browser/style.scss'; @import 'widgets/icon-browser/style.scss';
@import 'widgets/lockscreen/style.scss'; @import 'widgets/lockscreen/style.scss';

View file

@ -0,0 +1,96 @@
import { execAsync } from 'astal';
import { register } from 'astal/gobject';
import { Gtk, Widget } from 'astal/gtk3';
export interface EntryObject {
id: number
content: string
entry: string
}
const SCALE = 150;
const BINARY_DATA = /\[\[ binary data (\d+) (KiB|MiB) (\w+) (\d+)x(\d+) \]\]/;
export const CLIP_SCRIPT = `${SRC}/widgets/clipboard/cliphist.sh`;
@register()
export class ClipItem extends Widget.Box {
declare id: number;
declare content: string;
public show_image(file: string, width: string | number, height: string | number) {
this.children[2].destroy();
const initCss = () => {
const _widthPx = Number(width);
const heightPx = Number(height);
const maxWidth = 400;
const widthPx = (_widthPx / heightPx) * SCALE;
let css = `background-image: url("${file}");`;
if (widthPx > maxWidth) {
const newHeightPx = (SCALE / widthPx) * maxWidth;
css += `min-height: ${newHeightPx}px; min-width: ${maxWidth}px;`;
}
else {
css += `min-height: 150px; min-width: ${widthPx}px;`;
}
return css;
};
const icon = (
<box
valign={Gtk.Align.CENTER}
css={initCss()}
/>
);
this.children = [...this.children, icon];
};
constructor({ item }: { item: EntryObject }) {
super({
children: [
<label
label={item.id.toString()}
xalign={0}
valign={Gtk.Align.CENTER}
/>,
<label
label="・"
xalign={0}
valign={Gtk.Align.CENTER}
/>,
<label
label={item.content}
xalign={0}
valign={Gtk.Align.CENTER}
truncate
/>,
],
});
this.id = item.id;
this.content = item.content;
const matches = this.content.match(BINARY_DATA);
if (matches) {
// const size = matches[1];
const format = matches[3];
const width = matches[4];
const height = matches[5];
if (format === 'png') {
execAsync(`${CLIP_SCRIPT} --save-by-id ${this.id}`)
.then((file) => {
this.show_image(file, width, height);
})
.catch(print);
}
}
}
}

View file

@ -0,0 +1,44 @@
#!/usr/bin/env bash
# https://github.com/koeqaife/hyprland-material-you/blob/d23cf9d524522c8c215664c2c3334c2b51609cae/ags/scripts/cliphist.sh
get() {
cliphist list | iconv -f "$(locale charmap)" -t UTF-8 -c
}
copy_by_id() {
id=$1
cliphist decode "$id" | wl-copy
}
clear() {
cliphist wipe
}
save_cache_file() {
id=$1
output_file="/tmp/ags/cliphist/$id.png"
if [[ ! -f "$output_file" ]]; then
mkdir -p "/tmp/ags/cliphist/"
cliphist decode "$id" >"$output_file"
fi
echo "$output_file"
}
clear_tmp() {
rm "/tmp/ags/cliphist/*"
}
if [[ "$1" == "--get" ]]; then
get
elif [[ "$1" == "--copy-by-id" ]]; then
{ copy_by_id "$2"; }
elif [[ "$1" == "--save-by-id" ]]; then
{ save_cache_file "$2"; }
elif [[ "$1" == "--clear-cache" ]]; then
clear_tmp
elif [[ "$1" == "--clear" ]]; then
clear
fi

View file

@ -0,0 +1,66 @@
import { execAsync } from 'astal';
import { App } from 'astal/gtk3';
import SortedList from '../misc/sorted-list';
import { CLIP_SCRIPT, ClipItem, EntryObject } from './clip-item';
export default () => SortedList<EntryObject>({
name: 'clipboard',
create_list: async() => {
const output = await execAsync(`${CLIP_SCRIPT} --get`)
.then((str) => str)
.catch((err) => {
print(err);
return '';
});
return output
.split('\n')
.filter((line) => line.trim() !== '')
.map((entry) => {
const [id, ...content] = entry.split('\t');
return { id: parseInt(id.trim()), content: content.join(' ').trim(), entry };
});
},
create_row: (item) => new ClipItem({ item }),
fzf_options: {
selector: (item) => item.content,
},
compare_props: ['id'],
on_row_activated: (row) => {
const clip = row.get_children()[0] as ClipItem;
execAsync(`${CLIP_SCRIPT} --copy-by-id ${clip.id}`);
App.get_window('win-clipboard')?.set_visible(false);
},
sort_func: (a, b, entry, fzfResults) => {
const row1 = a.get_children()[0] as ClipItem;
const row2 = b.get_children()[0] as ClipItem;
if (entry.text === '' || entry.text === '-') {
a.set_visible(true);
b.set_visible(true);
return row2.id - row1.id;
}
else {
const s1 = fzfResults.find((r) => r.item.id === row1.id)?.score ?? 0;
const s2 = fzfResults.find((r) => r.item.id === row2.id)?.score ?? 0;
a.set_visible(s1 !== 0);
b.set_visible(s2 !== 0);
return s2 - s1;
}
},
});

View file

@ -0,0 +1,4 @@
.clipboard .list row box {
margin: 20px;
font-size: 16px;
}