✨ 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();
|
Wallpaper.getDefault();
|
||||||
Stylesheet.getDefault();
|
Stylesheet.getDefault();
|
||||||
|
|
||||||
console.log("Adding runner plugins");
|
console.log("Runner: Adding plugins");
|
||||||
runnerPlugins.forEach(plugin => Runner.addPlugin(plugin));
|
runnerPlugins.forEach(plugin => Runner.addPlugin(plugin));
|
||||||
|
|
||||||
createSubscription(
|
createSubscription(
|
||||||
|
|||||||
@@ -1,62 +1,156 @@
|
|||||||
import Fuse from "fuse.js";
|
import Fuse, { IFuseOptions } from "fuse.js";
|
||||||
import { Wallpaper } from "../../modules/wallpaper";
|
import { Wallpaper } from "../../modules/wallpaper";
|
||||||
import { Runner } from "../Runner";
|
import { Runner } from "../Runner";
|
||||||
|
|
||||||
import Gio from "gi://Gio?version=2.0";
|
import Gio from "gi://Gio?version=2.0";
|
||||||
|
import GLib from "gi://GLib?version=2.0";
|
||||||
|
|
||||||
|
|
||||||
class _PluginWallpapers implements Runner.Plugin {
|
class _PluginWallpapers implements Runner.Plugin {
|
||||||
prefix = "#";
|
prefix = "#";
|
||||||
prioritize = true;
|
prioritize = true;
|
||||||
#fuse!: Fuse<string>;
|
#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() {
|
init() {
|
||||||
this.#files = [];
|
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) {
|
if(dir.query_file_type(null, null) === Gio.FileType.DIRECTORY) {
|
||||||
for(const file of dir.enumerate_children(
|
for(const file of dir.enumerate_children(
|
||||||
"standard::*",
|
"standard::*",
|
||||||
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
|
Gio.FileQueryInfoFlags.NONE,
|
||||||
null
|
null
|
||||||
)) {
|
)) {
|
||||||
this.#files.push(`${dir.get_path()}/${file.get_name()}`);
|
this.#files.push(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#fuse = new Fuse<string>(
|
this.#fuse = new Fuse<string>(
|
||||||
this.#files as ReadonlyArray<string>,
|
this.#files.map(inf => inf.get_name()) as ReadonlyArray<string>,
|
||||||
{
|
this.#options
|
||||||
useExtendedSearch: false,
|
|
||||||
shouldSort: true,
|
|
||||||
isCaseSensitive: false
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private wallpaperResult(path: string): Runner.Result {
|
private result(info: Gio.FileInfo): Runner.Result {
|
||||||
return {
|
return {
|
||||||
title: path.split('/')[path.split('/').length-1].replace(/\..*$/, ""),
|
title: `${info.get_display_name()}${info.get_file_type() === Gio.FileType.DIRECTORY ? "/" : ""}`,
|
||||||
actionClick: () => Wallpaper.getDefault().setWallpaper(path)
|
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) {
|
async handle(search: string, limit?: number) {
|
||||||
if(search.trim().length === 0)
|
if(!GLib.file_test(this.#dir, GLib.FileTest.IS_DIR))
|
||||||
return this.#files.map(path =>
|
|
||||||
this.wallpaperResult(path)
|
|
||||||
);
|
|
||||||
|
|
||||||
if(this.#files.length > 0)
|
|
||||||
return this.#fuse.search(search, {
|
|
||||||
limit: limit ?? Infinity
|
|
||||||
}).map(result => this.wallpaperResult(result.item));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: "No wallpapers found!",
|
title: "No wallpapers found!",
|
||||||
description: "Define the $WALLPAPERS variable on Hyprland or create a ~/wallpapers directory",
|
description: "Define the WALLPAPERS variable in Hyprland or create ~/wallpapers",
|
||||||
icon: "image-missing-symbolic"
|
icon: "image-missing-symbolic"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.#subdir = undefined;
|
||||||
|
|
||||||
|
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 AstalNetwork from "gi://AstalNetwork";
|
||||||
import AstalWp from "gi://AstalWp";
|
import AstalWp from "gi://AstalWp";
|
||||||
|
|
||||||
|
|
||||||
export const Status = () =>
|
export const Status = () =>
|
||||||
(
|
<Gtk.Button class={createBinding(Windows.getDefault(), "openWindows").as((openWins) =>
|
||||||
<Gtk.Button
|
openWins.includes("control-center") ?
|
||||||
class={createBinding(Windows.getDefault(), "openWindows").as((openWins) =>
|
"open status"
|
||||||
openWins.includes("control-center") ? "open status" : "status"
|
: "status"
|
||||||
)}
|
)} onClicked={() => Windows.getDefault().toggle("control-center")}>
|
||||||
onClicked={() => Windows.getDefault().toggle("control-center")}
|
|
||||||
>
|
|
||||||
<Gtk.Box>
|
<Gtk.Box>
|
||||||
<Gtk.Box class={"volume-indicators"} spacing={5}>
|
<Gtk.Box class={"volume-indicators"} spacing={5}>
|
||||||
<BatteryStatus
|
<BatteryStatus
|
||||||
@@ -57,28 +57,21 @@ export const Status = () =>
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Gtk.Box>
|
</Gtk.Box>
|
||||||
<Gtk.Revealer
|
<Gtk.Revealer revealChild={createBinding(Recording.getDefault(), "recording")}
|
||||||
revealChild={createBinding(Recording.getDefault(), "recording")}
|
transitionDuration={500} transitionType={Gtk.RevealerTransitionType.SLIDE_LEFT}>
|
||||||
transitionDuration={500}
|
|
||||||
transitionType={Gtk.RevealerTransitionType.SLIDE_LEFT}
|
|
||||||
>
|
|
||||||
<Gtk.Box>
|
<Gtk.Box>
|
||||||
<Gtk.Image
|
<Gtk.Image class={"recording state"} iconName={"media-record-symbolic"}
|
||||||
class={"recording state"}
|
|
||||||
iconName={"media-record-symbolic"}
|
|
||||||
css={"margin-right: 6px;"}
|
css={"margin-right: 6px;"}
|
||||||
/>
|
/>
|
||||||
|
<Gtk.Label label={createBinding(Recording.getDefault(), "recordingTime")}
|
||||||
<Gtk.Label
|
|
||||||
class={"rec-time"}
|
class={"rec-time"}
|
||||||
label={createBinding(Recording.getDefault(), "recordingTime")}
|
|
||||||
/>
|
/>
|
||||||
</Gtk.Box>
|
</Gtk.Box>
|
||||||
</Gtk.Revealer>
|
</Gtk.Revealer>
|
||||||
<StatusIcons />
|
<StatusIcons />
|
||||||
</Gtk.Box>
|
</Gtk.Box>
|
||||||
</Gtk.Button>
|
</Gtk.Button> as Gtk.Button;
|
||||||
) as Gtk.Button;
|
|
||||||
|
|
||||||
function VolumeStatus(props: {
|
function VolumeStatus(props: {
|
||||||
class?: string;
|
class?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user