feat(ags clipboard): hide long clips past 5 lines
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
1928a74e90
commit
59675a6d1f
5 changed files with 137 additions and 66 deletions
|
@ -46,15 +46,17 @@
|
||||||
all: unset;
|
all: unset;
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
|
padding: 10px;
|
||||||
box {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*:selected .item,
|
*:selected .item,
|
||||||
.item:hover,
|
*:hover .item,
|
||||||
.item:focus {
|
*:focus .item {
|
||||||
background-color: #363449;
|
background-color: #363449;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.down-arrow {
|
||||||
|
transition: all 500ms;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,15 +47,17 @@
|
||||||
all: unset;
|
all: unset;
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
|
padding: 10px;
|
||||||
box {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*:selected .item,
|
*:selected .item,
|
||||||
.item:hover,
|
*:hover .item,
|
||||||
.item:focus {
|
*:focus .item {
|
||||||
background-color: #363449;
|
background-color: #363449;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.down-arrow {
|
||||||
|
transition: all 500ms;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ class Clipboard extends Service {
|
||||||
// Public Class Methods
|
// Public Class Methods
|
||||||
public copyOldItem(key: string | number): void {
|
public copyOldItem(key: string | number): void {
|
||||||
execAsync([
|
execAsync([
|
||||||
'bash', '-c', `cliphist list | grep ${key} | cliphist decode | wl-copy`,
|
'bash', '-c', `cliphist list | grep '^${key}' | cliphist decode | wl-copy`,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +63,28 @@ class Clipboard extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getHistory(n = Clipboard._MAX_CLIPS) {
|
private _addClip(newClip: [number, { clip: string, isImage: boolean }]) {
|
||||||
this._clips = new Map();
|
if (
|
||||||
|
![...this.clips.values()]
|
||||||
|
.map((c) => c.clip)
|
||||||
|
.includes(newClip[1].clip)
|
||||||
|
) {
|
||||||
|
this._clips.set(...newClip);
|
||||||
|
this.emit('clip-added', newClip);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const oldClip = [...this.clips.entries()]
|
||||||
|
.find(([_, { clip }]) => clip === newClip[1].clip);
|
||||||
|
|
||||||
|
if (oldClip && oldClip[0] < newClip[0]) {
|
||||||
|
this.clips.delete(oldClip[0]);
|
||||||
|
this._clips.set(...newClip);
|
||||||
|
this.emit('clip-added', newClip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getHistory(n = Clipboard._MAX_CLIPS) {
|
||||||
// FIXME: this is necessary when not putting a cap on clip amount
|
// FIXME: this is necessary when not putting a cap on clip amount
|
||||||
// exec(`prlimit --pid ${exec('pgrep ags')} --nofile=10024:`);
|
// exec(`prlimit --pid ${exec('pgrep ags')} --nofile=10024:`);
|
||||||
|
|
||||||
|
@ -91,8 +110,7 @@ class Clipboard extends Service {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
this._clips.set(...newClip);
|
this._addClip(newClip);
|
||||||
this.emit('clip-added', newClip);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const decodedClip = await this._decodeItem(clip);
|
const decodedClip = await this._decodeItem(clip);
|
||||||
|
@ -106,8 +124,7 @@ class Clipboard extends Service {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
this._clips.set(...newClip);
|
this._addClip(newClip);
|
||||||
this.emit('clip-added', newClip);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
80
modules/ags/config/ts/clipboard/clip.ts
Normal file
80
modules/ags/config/ts/clipboard/clip.ts
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
const { Box, Button, Icon, Label, Revealer } = Widget;
|
||||||
|
|
||||||
|
|
||||||
|
const ImageClip = (key: number, val: string) => Box({
|
||||||
|
class_name: 'item',
|
||||||
|
name: key.toString(),
|
||||||
|
|
||||||
|
child: Icon({
|
||||||
|
icon: val.replace('img:', ''),
|
||||||
|
size: 100 * 2,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const TextClip = (key: number, val: string) => {
|
||||||
|
const lines = val.split('\n');
|
||||||
|
|
||||||
|
if (lines.length <= 5) {
|
||||||
|
return Box({
|
||||||
|
class_name: 'item',
|
||||||
|
name: key.toString(),
|
||||||
|
|
||||||
|
child: Label({
|
||||||
|
label: val,
|
||||||
|
truncate: 'end',
|
||||||
|
max_width_chars: 100,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const revText = Revealer({
|
||||||
|
hpack: 'start',
|
||||||
|
child: Label({
|
||||||
|
label: lines.slice(2, lines.length).join('\n'),
|
||||||
|
truncate: 'end',
|
||||||
|
max_width_chars: 100,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return Box({
|
||||||
|
class_name: 'item',
|
||||||
|
name: key.toString(),
|
||||||
|
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Label({
|
||||||
|
label: lines.slice(0, 2).join('\n'),
|
||||||
|
truncate: 'end',
|
||||||
|
max_width_chars: 100,
|
||||||
|
hpack: 'start',
|
||||||
|
}),
|
||||||
|
|
||||||
|
revText,
|
||||||
|
|
||||||
|
Button({
|
||||||
|
child: Icon({
|
||||||
|
class_name: 'down-arrow',
|
||||||
|
icon: 'down-large-symbolic',
|
||||||
|
size: 24,
|
||||||
|
}),
|
||||||
|
|
||||||
|
on_primary_click_release: (self) => {
|
||||||
|
const state = !revText.reveal_child;
|
||||||
|
|
||||||
|
revText.reveal_child = state;
|
||||||
|
|
||||||
|
self.child.setCss(`
|
||||||
|
-gtk-icon-transform: rotate(${state ? '180' : '0'}deg);
|
||||||
|
`);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ({
|
||||||
|
key = 0,
|
||||||
|
isImage = false,
|
||||||
|
val = '',
|
||||||
|
}) => isImage ? ImageClip(key, val) : TextClip(key, val);
|
|
@ -1,55 +1,17 @@
|
||||||
const { Box, Icon, Label } = Widget;
|
|
||||||
|
|
||||||
import { Fzf, FzfResultItem } from 'fzf';
|
import { Fzf, FzfResultItem } from 'fzf';
|
||||||
import Gtk from 'gi://Gtk?version=3.0';
|
import Gtk from 'gi://Gtk?version=3.0';
|
||||||
import Clipboard from '../../services/clipboard.ts';
|
import Clipboard from '../../services/clipboard.ts';
|
||||||
|
|
||||||
import CursorBox from '../misc/cursorbox.ts';
|
|
||||||
import SortedList from '../misc/sorted-list.ts';
|
import SortedList from '../misc/sorted-list.ts';
|
||||||
|
|
||||||
|
import ClipWidget from './clip.ts';
|
||||||
|
|
||||||
|
|
||||||
|
const getKey = (r: Gtk.ListBoxRow): number => parseInt(r.get_child()?.name ?? '0');
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const makeItem = (
|
|
||||||
list: Gtk.ListBox,
|
|
||||||
key: number,
|
|
||||||
val: string,
|
|
||||||
isImage: boolean,
|
|
||||||
): void => {
|
|
||||||
const widget = CursorBox({
|
|
||||||
class_name: 'item',
|
|
||||||
name: key.toString(),
|
|
||||||
|
|
||||||
on_primary_click_release: () => {
|
|
||||||
Clipboard.copyOldItem(key);
|
|
||||||
App.closeWindow('win-clipboard');
|
|
||||||
},
|
|
||||||
|
|
||||||
child: Box({
|
|
||||||
children: [
|
|
||||||
isImage ?
|
|
||||||
Icon({
|
|
||||||
icon: val.replace('img:', ''),
|
|
||||||
size: 100 * 2,
|
|
||||||
}) :
|
|
||||||
|
|
||||||
Label({
|
|
||||||
label: val,
|
|
||||||
truncate: 'end',
|
|
||||||
max_width_chars: 100,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
list.add(widget);
|
|
||||||
widget.show_all();
|
|
||||||
};
|
|
||||||
|
|
||||||
let fzfResults = [] as FzfResultItem<[number, { clip: string, isImage: boolean }]>[];
|
let fzfResults = [] as FzfResultItem<[number, { clip: string, isImage: boolean }]>[];
|
||||||
|
|
||||||
const getKey = (r: Gtk.ListBoxRow): number => parseInt(r.get_child()?.name ?? '0');
|
|
||||||
|
|
||||||
|
|
||||||
return SortedList({
|
return SortedList({
|
||||||
name: 'clipboard',
|
name: 'clipboard',
|
||||||
class_name: 'clipboard',
|
class_name: 'clipboard',
|
||||||
|
@ -61,18 +23,23 @@ export default () => {
|
||||||
},
|
},
|
||||||
|
|
||||||
setup_list: (list, entry) => {
|
setup_list: (list, entry) => {
|
||||||
|
list.cursor = 'pointer';
|
||||||
|
|
||||||
const CONNECT_ID = Clipboard.connect('history-searched', () => {
|
const CONNECT_ID = Clipboard.connect('history-searched', () => {
|
||||||
// Do every clip that existed before this widget
|
// Do every clip that existed before this widget
|
||||||
list.get_children().forEach((row) => {
|
|
||||||
row.destroy();
|
|
||||||
});
|
|
||||||
Clipboard.clips.forEach((clip, key) => {
|
Clipboard.clips.forEach((clip, key) => {
|
||||||
makeItem(list, key, clip.clip, clip.isImage);
|
const widget = ClipWidget({ key, isImage: clip.isImage, val: clip.clip });
|
||||||
|
|
||||||
|
list.add(widget);
|
||||||
|
widget.show_all();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup connection for new clips
|
// Setup connection for new clips
|
||||||
Clipboard.connect('clip-added', (_, [key, clip]) => {
|
Clipboard.connect('clip-added', (_, [key, clip]) => {
|
||||||
makeItem(list, key, clip.clip, clip.isImage);
|
const widget = ClipWidget({ key, isImage: clip.isImage, val: clip.clip });
|
||||||
|
|
||||||
|
list.add(widget);
|
||||||
|
widget.show_all();
|
||||||
});
|
});
|
||||||
|
|
||||||
list.set_sort_func((a, b) => {
|
list.set_sort_func((a, b) => {
|
||||||
|
@ -93,6 +60,9 @@ export default () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Trigger on_text_change after init
|
||||||
|
entry.text = '-';
|
||||||
|
|
||||||
Clipboard.disconnect(CONNECT_ID);
|
Clipboard.disconnect(CONNECT_ID);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue