✨ feat(runner/plugins/wallpapers): subdirectory exploration support
it's also recursivegit add .
This commit is contained in:
+1
-1
@@ -281,7 +281,7 @@ you should use the socket in the XDG_RUNTIME_DIR/colorshell.sock for a faster re
|
||||
Wallpaper.getDefault();
|
||||
Stylesheet.getDefault();
|
||||
|
||||
console.log("Adding runner plugins");
|
||||
console.log("Runner: Adding plugins");
|
||||
runnerPlugins.forEach(plugin => Runner.addPlugin(plugin));
|
||||
|
||||
createSubscription(
|
||||
|
||||
@@ -1,62 +1,156 @@
|
||||
import Fuse from "fuse.js";
|
||||
import Fuse, { IFuseOptions } from "fuse.js";
|
||||
import { Wallpaper } from "../../modules/wallpaper";
|
||||
import { Runner } from "../Runner";
|
||||
|
||||
import Gio from "gi://Gio?version=2.0";
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
|
||||
|
||||
class _PluginWallpapers implements Runner.Plugin {
|
||||
prefix = "#";
|
||||
prioritize = true;
|
||||
#fuse!: Fuse<string>;
|
||||
#files!: Array<string>;
|
||||
#files!: Array<Gio.FileInfo>;
|
||||
#dir: string = Wallpaper.getDefault().wallpapersPath;
|
||||
#subdir: string|undefined = undefined;
|
||||
readonly #options = {
|
||||
useExtendedSearch: false,
|
||||
shouldSort: true,
|
||||
isCaseSensitive: false
|
||||
} satisfies IFuseOptions<string>;
|
||||
|
||||
init() {
|
||||
this.#files = [];
|
||||
const dir = Gio.File.new_for_path(Wallpaper.getDefault().wallpapersPath);
|
||||
this.#subdir = undefined;
|
||||
|
||||
const dir = Gio.File.new_for_path(this.#dir);
|
||||
if(dir.query_file_type(null, null) === Gio.FileType.DIRECTORY) {
|
||||
for(const file of dir.enumerate_children(
|
||||
"standard::*",
|
||||
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
|
||||
Gio.FileQueryInfoFlags.NONE,
|
||||
null
|
||||
)) {
|
||||
this.#files.push(`${dir.get_path()}/${file.get_name()}`);
|
||||
this.#files.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
this.#fuse = new Fuse<string>(
|
||||
this.#files as ReadonlyArray<string>,
|
||||
{
|
||||
useExtendedSearch: false,
|
||||
shouldSort: true,
|
||||
isCaseSensitive: false
|
||||
}
|
||||
this.#files.map(inf => inf.get_name()) as ReadonlyArray<string>,
|
||||
this.#options
|
||||
);
|
||||
}
|
||||
|
||||
private wallpaperResult(path: string): Runner.Result {
|
||||
private result(info: Gio.FileInfo): Runner.Result {
|
||||
return {
|
||||
title: path.split('/')[path.split('/').length-1].replace(/\..*$/, ""),
|
||||
actionClick: () => Wallpaper.getDefault().setWallpaper(path)
|
||||
title: `${info.get_display_name()}${info.get_file_type() === Gio.FileType.DIRECTORY ? "/" : ""}`,
|
||||
icon: info.get_file_type() === Gio.FileType.DIRECTORY ?
|
||||
"inode-directory-symbolic"
|
||||
: undefined,
|
||||
closeOnClick: info.get_file_type() !== Gio.FileType.DIRECTORY,
|
||||
actionClick: () => {
|
||||
if(info.get_file_type() === Gio.FileType.DIRECTORY) {
|
||||
Runner.setEntryText(
|
||||
this.#subdir !== undefined ?
|
||||
`#${this.#subdir.startsWith('/') ?
|
||||
this.#subdir
|
||||
: `/${this.#subdir}`}/${info.get_name()}/`
|
||||
: `#/${info.get_name()}/`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Wallpaper.getDefault().setWallpaper(
|
||||
`${Wallpaper.getDefault().wallpapersPath}/${
|
||||
this.#subdir ? `${this.#subdir}/` : ""
|
||||
}${info.get_name()}`
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
handle(search: string, limit?: number) {
|
||||
if(search.trim().length === 0)
|
||||
return this.#files.map(path =>
|
||||
this.wallpaperResult(path)
|
||||
);
|
||||
async handle(search: string, limit?: number) {
|
||||
if(!GLib.file_test(this.#dir, GLib.FileTest.IS_DIR))
|
||||
return {
|
||||
title: "No wallpapers found!",
|
||||
description: "Define the WALLPAPERS variable in Hyprland or create ~/wallpapers",
|
||||
icon: "image-missing-symbolic"
|
||||
};
|
||||
|
||||
if(this.#files.length > 0)
|
||||
return this.#fuse.search(search, {
|
||||
limit: limit ?? Infinity
|
||||
}).map(result => this.wallpaperResult(result.item));
|
||||
this.#subdir = undefined;
|
||||
|
||||
return {
|
||||
title: "No wallpapers found!",
|
||||
description: "Define the $WALLPAPERS variable on Hyprland or create a ~/wallpapers directory",
|
||||
icon: "image-missing-symbolic"
|
||||
};
|
||||
if(search.startsWith('/')) {
|
||||
let split = search.split('/').filter(s => s.trim() !== "");
|
||||
|
||||
search = split.length > 1 && !search.endsWith('/') ?
|
||||
split[split.length - 1]
|
||||
: "";
|
||||
split = split.filter(s => s !== search);
|
||||
this.#subdir = split.join('/');
|
||||
|
||||
if(this.#subdir === undefined) {
|
||||
this.#fuse = new Fuse<string>(
|
||||
this.#files.filter(inf =>
|
||||
inf.get_file_type() === Gio.FileType.DIRECTORY
|
||||
).map(inf => inf.get_name()) as ReadonlyArray<string>,
|
||||
this.#options
|
||||
);
|
||||
|
||||
return this.#fuse.search(search.replace(/^\//, "")).map(r => {
|
||||
const info = this.#files.filter(inf =>
|
||||
inf.get_name() === r.item
|
||||
)[0];
|
||||
|
||||
return this.result(info);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: recursive search for subdirectories
|
||||
|
||||
if(GLib.file_test(`${this.#dir}/${this.#subdir}`, GLib.FileTest.IS_DIR)) {
|
||||
const dir = Gio.File.new_for_path(`${this.#dir}/${this.#subdir}`);
|
||||
this.#files = [];
|
||||
|
||||
for(const file of dir.enumerate_children(
|
||||
"standard::*",
|
||||
Gio.FileQueryInfoFlags.NONE,
|
||||
null
|
||||
)) {
|
||||
this.#files.push(file);
|
||||
}
|
||||
|
||||
this.#fuse = new Fuse<string>(
|
||||
this.#files.map(n => n.get_name()) as ReadonlyArray<string>,
|
||||
this.#options
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(search.length < 1)
|
||||
return this.#files.sort(s =>
|
||||
s.get_file_type() === Gio.FileType.DIRECTORY ? 1 : -1
|
||||
).map(info => this.result(info));
|
||||
|
||||
|
||||
const results: Array<Runner.Result> = [];
|
||||
|
||||
this.#fuse.search(search, {
|
||||
limit: limit ?? Infinity
|
||||
}).map(result => {
|
||||
const info = this.#files.filter(inf =>
|
||||
inf.get_name() === result.item
|
||||
)[0];
|
||||
|
||||
results.push(this.result(info));
|
||||
});
|
||||
|
||||
|
||||
if(results.length < 1)
|
||||
return {
|
||||
title: "No results found",
|
||||
description: "Wallpaper with provided name was not found :("
|
||||
} satisfies Runner.Result;
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ import AstalBluetooth from "gi://AstalBluetooth";
|
||||
import AstalNetwork from "gi://AstalNetwork";
|
||||
import AstalWp from "gi://AstalWp";
|
||||
|
||||
|
||||
export const Status = () =>
|
||||
(
|
||||
<Gtk.Button
|
||||
class={createBinding(Windows.getDefault(), "openWindows").as((openWins) =>
|
||||
openWins.includes("control-center") ? "open status" : "status"
|
||||
)}
|
||||
onClicked={() => Windows.getDefault().toggle("control-center")}
|
||||
>
|
||||
<Gtk.Button class={createBinding(Windows.getDefault(), "openWindows").as((openWins) =>
|
||||
openWins.includes("control-center") ?
|
||||
"open status"
|
||||
: "status"
|
||||
)} onClicked={() => Windows.getDefault().toggle("control-center")}>
|
||||
|
||||
<Gtk.Box>
|
||||
<Gtk.Box class={"volume-indicators"} spacing={5}>
|
||||
<BatteryStatus
|
||||
@@ -57,28 +57,21 @@ export const Status = () =>
|
||||
)}
|
||||
/>
|
||||
</Gtk.Box>
|
||||
<Gtk.Revealer
|
||||
revealChild={createBinding(Recording.getDefault(), "recording")}
|
||||
transitionDuration={500}
|
||||
transitionType={Gtk.RevealerTransitionType.SLIDE_LEFT}
|
||||
>
|
||||
<Gtk.Box>
|
||||
<Gtk.Image
|
||||
class={"recording state"}
|
||||
iconName={"media-record-symbolic"}
|
||||
css={"margin-right: 6px;"}
|
||||
/>
|
||||
<Gtk.Revealer revealChild={createBinding(Recording.getDefault(), "recording")}
|
||||
transitionDuration={500} transitionType={Gtk.RevealerTransitionType.SLIDE_LEFT}>
|
||||
|
||||
<Gtk.Label
|
||||
class={"rec-time"}
|
||||
label={createBinding(Recording.getDefault(), "recordingTime")}
|
||||
/>
|
||||
</Gtk.Box>
|
||||
<Gtk.Box>
|
||||
<Gtk.Image class={"recording state"} iconName={"media-record-symbolic"}
|
||||
css={"margin-right: 6px;"}
|
||||
/>
|
||||
<Gtk.Label label={createBinding(Recording.getDefault(), "recordingTime")}
|
||||
class={"rec-time"}
|
||||
/>
|
||||
</Gtk.Box>
|
||||
</Gtk.Revealer>
|
||||
<StatusIcons />
|
||||
</Gtk.Box>
|
||||
</Gtk.Button>
|
||||
) as Gtk.Button;
|
||||
</Gtk.Box>
|
||||
</Gtk.Button> as Gtk.Button;
|
||||
|
||||
function VolumeStatus(props: {
|
||||
class?: string;
|
||||
|
||||
Reference in New Issue
Block a user