🔧 chore(scripts/config): stop using singleton instance, add type declarations(for completion)
this will make easier to work with multiple configuration files at the same time
This commit is contained in:
@@ -5,8 +5,8 @@ import { timeout } from "ags/time";
|
||||
import { Runner } from "../runner/Runner";
|
||||
import { showWorkspaceNumber } from "../widget/bar/Workspaces";
|
||||
import { playSystemBell } from "./utils";
|
||||
import { Config } from "./config";
|
||||
import { player, setPlayer } from "../widget/bar/Media";
|
||||
import { generalConfig } from "../app";
|
||||
|
||||
import AstalIO from "gi://AstalIO";
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
@@ -236,7 +236,7 @@ function handleVolumeArgs(args: Array<string>) {
|
||||
Wireplumber.getDefault().increaseSinkVolume(Number.parseInt(args[2]))
|
||||
: Wireplumber.getDefault().increaseSourceVolume(Number.parseInt(args[2]))
|
||||
|
||||
Config.getDefault().getProperty("misc.play_bell_on_volume_change", "boolean") === true &&
|
||||
generalConfig.getProperty("misc.play_bell_on_volume_change", "boolean") === true &&
|
||||
playSystemBell();
|
||||
|
||||
return `Done increasing volume by ${args[2]}`;
|
||||
@@ -246,7 +246,7 @@ function handleVolumeArgs(args: Array<string>) {
|
||||
Wireplumber.getDefault().decreaseSinkVolume(Number.parseInt(args[2]))
|
||||
: Wireplumber.getDefault().decreaseSourceVolume(Number.parseInt(args[2]))
|
||||
|
||||
Config.getDefault().getProperty("misc.play_bell_on_volume_change", "boolean") === true &&
|
||||
generalConfig.getProperty("misc.play_bell_on_volume_change", "boolean") === true &&
|
||||
playSystemBell();
|
||||
|
||||
return `Done decreasing volume to ${args[2]}`;
|
||||
|
||||
+19
-89
@@ -12,99 +12,36 @@ import { Accessor } from "ags";
|
||||
|
||||
|
||||
export { Config };
|
||||
|
||||
export type ConfigEntries = Partial<{
|
||||
workspaces: Partial<{
|
||||
/** this is the function that shows the Workspace's IDs
|
||||
* around the current workspace if one breaks the crescent order.
|
||||
* It basically helps keyboard navigation between workspaces.
|
||||
* ---
|
||||
* Example: 1(empty, current, shows ID), 2(empty, does not appear(makes
|
||||
* the previous not to be in a crescent order)), 3(not empty, shows ID) */
|
||||
enable_helper: boolean;
|
||||
/** breaks `enable_helper`, makes all workspaces show their respective ID
|
||||
* by default */
|
||||
always_show_id: boolean;
|
||||
}>;
|
||||
|
||||
clock: Partial<{
|
||||
/** use the same format as gnu's `date` command */
|
||||
date_format: string;
|
||||
}>;
|
||||
|
||||
notifications: Partial<{
|
||||
timeout_low: number;
|
||||
timeout_normal: number;
|
||||
timeout_critical: number;
|
||||
}>;
|
||||
|
||||
night_light: Partial<{
|
||||
/** whether to save night light values to disk */
|
||||
save_on_shutdown: boolean;
|
||||
}>;
|
||||
|
||||
misc: Partial<{
|
||||
play_bell_on_volume_change: boolean;
|
||||
}>;
|
||||
}>;
|
||||
|
||||
type ValueTypes = "string" | "boolean" | "object" | "number" | "undefined" | "any";
|
||||
|
||||
interface ConfigSignals extends GObject.Object.SignalSignatures {
|
||||
"notify::entries": (entries: ConfigEntries) => void;
|
||||
}
|
||||
|
||||
@register({ GTypeName: "Config" })
|
||||
class Config extends GObject.Object {
|
||||
private static instance: Config;
|
||||
|
||||
declare $signals: ConfigSignals;
|
||||
|
||||
private readonly defaultFile = Gio.File.new_for_path(
|
||||
`${GLib.get_user_config_dir()}/colorshell/config.json`);
|
||||
class Config<K extends NonNullable<string|number|symbol>, V extends string|object|any> extends GObject.Object {
|
||||
declare $signals: GObject.Object.SignalSignatures & {
|
||||
"notify::entries": (entries: Record<K, V>) => void;
|
||||
};
|
||||
|
||||
/** unmodified object with default entries. User-values are stored
|
||||
* in the `entries` field */
|
||||
public readonly defaults: ConfigEntries = {
|
||||
notifications: {
|
||||
timeout_low: 4000,
|
||||
timeout_normal: 6000,
|
||||
timeout_critical: 0
|
||||
},
|
||||
|
||||
night_light: {
|
||||
save_on_shutdown: true
|
||||
},
|
||||
|
||||
workspaces: {
|
||||
always_show_id: false,
|
||||
enable_helper: true
|
||||
},
|
||||
|
||||
clock: {
|
||||
date_format: "%A %d, %H:%M"
|
||||
},
|
||||
|
||||
misc: {
|
||||
play_bell_on_volume_change: true
|
||||
}
|
||||
};
|
||||
public readonly defaults: Record<K, V>;
|
||||
|
||||
@getter(Object)
|
||||
public get entries() { return this.#entries; }
|
||||
public get entries(): object { return this.#entries; }
|
||||
|
||||
#file: Gio.File;
|
||||
#entries: ConfigEntries = this.defaults;
|
||||
#entries: Record<K, V>;
|
||||
|
||||
private timeout: (AstalIO.Time|boolean|undefined);
|
||||
public get file() { return this.#file; };
|
||||
|
||||
constructor(filePath?: (Gio.File|string)) {
|
||||
constructor(filePath: Gio.File|string, defaults?: Record<K, V>) {
|
||||
super();
|
||||
|
||||
this.defaults = (defaults ?? {}) as Record<K, V>;
|
||||
this.#entries = { ...defaults } as Record<K, V>;
|
||||
|
||||
this.#file = (typeof filePath === "string") ?
|
||||
Gio.File.new_for_path(filePath)
|
||||
: (filePath ?? this.defaultFile);
|
||||
: filePath;
|
||||
|
||||
if(!this.#file.query_exists(null)) {
|
||||
this.#file.make_directory_with_parents(null);
|
||||
@@ -156,19 +93,12 @@ class Config extends GObject.Object {
|
||||
);
|
||||
}
|
||||
|
||||
public static getDefault(): Config {
|
||||
if(!this.instance)
|
||||
this.instance = new Config();
|
||||
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
private async readFile(): Promise<void> {
|
||||
await readFileAsync(this.#file.get_path()!).then((content) => {
|
||||
let config: (ConfigEntries|undefined);
|
||||
let config: (Record<K, V>|undefined);
|
||||
|
||||
try {
|
||||
config = JSON.parse(content) as ConfigEntries;
|
||||
config = JSON.parse(content) as Record<K, V>;
|
||||
} catch(e) {
|
||||
Notifications.getDefault().sendNotification({
|
||||
urgency: AstalNotifd.Urgency.NORMAL,
|
||||
@@ -189,7 +119,7 @@ class Config extends GObject.Object {
|
||||
return;
|
||||
|
||||
// TODO needs more work, like object-recursive(infinite depth) entry attributions
|
||||
this.entries[k as keyof typeof this.entries] = config[k as keyof typeof config];
|
||||
this.#entries[k as keyof Record<K, V>] = config[k as keyof typeof config];
|
||||
}
|
||||
|
||||
this.notify("entries");
|
||||
@@ -204,22 +134,22 @@ class Config extends GObject.Object {
|
||||
});
|
||||
}
|
||||
|
||||
public bindProperty(propertyPath: (keyof ConfigEntries|string), expectType?: ValueTypes): Accessor<any|undefined> {
|
||||
return new Accessor<ConfigEntries>(() => this.getProperty(propertyPath, expectType), (callback: () => void) => {
|
||||
public bindProperty(propertyPath: string, expectType?: ValueTypes): Accessor<any|undefined> {
|
||||
return new Accessor<Record<K, V>>(() => this.getProperty(propertyPath, expectType), (callback: () => void) => {
|
||||
const id = this.connect("notify::entries", () => callback());
|
||||
return () => this.disconnect(id);
|
||||
});
|
||||
}
|
||||
|
||||
public getProperty(path: string, expectType?: ValueTypes): (any|undefined) {
|
||||
return this._getProperty(path, this.entries, expectType);
|
||||
return this._getProperty(path, this.#entries, expectType);
|
||||
}
|
||||
|
||||
public getPropertyDefault(path: string, expectType?: ValueTypes): (any|undefined) {
|
||||
return this._getProperty(path, this.defaults, expectType);
|
||||
}
|
||||
|
||||
private _getProperty(path: string, entries: ConfigEntries, expectType?: ValueTypes): (any|undefined) {
|
||||
private _getProperty(path: string, entries: Record<K, V>, expectType?: ValueTypes): (any|undefined) {
|
||||
let property: any = entries;
|
||||
const pathArray = path.split('.').filter(str => str);
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Config } from "./config";
|
||||
import { timeout } from "ags/time";
|
||||
import { execAsync } from "ags/process";
|
||||
|
||||
import { readFile } from "ags/file";
|
||||
import { generalConfig } from "../app";
|
||||
import { onCleanup } from "ags";
|
||||
import GObject, { getter, property, register, signal } from "ags/gobject";
|
||||
|
||||
import AstalNotifd from "gi://AstalNotifd";
|
||||
import AstalIO from "gi://AstalIO";
|
||||
import { onCleanup } from "ags";
|
||||
import Gio from "gi://Gio?version=2.0";
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
import { readFile } from "ags/file";
|
||||
|
||||
|
||||
export interface HistoryNotification {
|
||||
@@ -53,7 +53,7 @@ class Notifications extends GObject.Object {
|
||||
this.#connections.push(
|
||||
AstalNotifd.get_default().connect("notified", (notifd, id) => {
|
||||
const notification = notifd.get_notification(id);
|
||||
const notifTimeout = Config.getDefault().getProperty(
|
||||
const notifTimeout = generalConfig.getProperty(
|
||||
`notifications.timeout_${this.getUrgencyString(notification.urgency).toLowerCase()}`,
|
||||
"number") as number;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user