From f213d994aac88804a1def52fe80e927d45c08868 Mon Sep 17 00:00:00 2001 From: retrozinndev Date: Thu, 28 Aug 2025 18:33:39 -0300 Subject: [PATCH] :wrench: chore(modules/backlight, modules/config): fix property name not found, add support for setting properties in config --- src/app.ts | 14 ++++ src/modules/backlight.ts | 28 +++----- src/modules/config.ts | 66 +++++++++++-------- src/widget/control-center/pages/Backlight.tsx | 66 ++++++++++++++----- 4 files changed, 113 insertions(+), 61 deletions(-) diff --git a/src/app.ts b/src/app.ts index eb7abfe..2a05352 100644 --- a/src/app.ts +++ b/src/app.ts @@ -350,6 +350,20 @@ const generalConfigDefaults = { } }; +const userDataDefaults = { + control_center: { + default_backlight: undefined + } +}; + +export const userData = new Config< + keyof typeof userDataDefaults, + (typeof userDataDefaults)[keyof typeof userDataDefaults] +>( + `${GLib.get_user_data_dir()}/colorshell/data.json`, + userDataDefaults +); + export const generalConfig = new Config( `${GLib.get_user_config_dir()}/colorshell/config.json`, generalConfigDefaults diff --git a/src/modules/backlight.ts b/src/modules/backlight.ts index fac9e18..ea752ea 100644 --- a/src/modules/backlight.ts +++ b/src/modules/backlight.ts @@ -1,15 +1,12 @@ import { monitorFile, readFile } from "ags/file"; import { exec } from "ags/process"; -import GObject, { getter, ParamSpec, setter, signal } from "ags/gobject"; +import GObject, { getter, ParamSpec, register, setter, signal } from "ags/gobject"; import Gio from "gi://Gio?version=2.0"; export namespace Backlights { - const BacklightsParamSpec = (name: string, flags: GObject.ParamFlags) => - GObject.ParamSpec.object(name, null, null, flags) as ParamSpec; - const BacklightParamSpec = (name: string, flags: GObject.ParamFlags) => GObject.ParamSpec.object(name, null, null, flags) as ParamSpec; @@ -22,13 +19,8 @@ export namespace Backlights { return instance; } - export class Backlights extends GObject.Object { - static { - GObject.registerClass({ - GTypeName: "Backlights" - }, this); - } - + @register({ GTypeName: "Backlights" }) + class _Backlights extends GObject.Object { #backlights: Array = []; #default: Backlight|null = null; @@ -101,13 +93,8 @@ export namespace Backlights { } } - export class Backlight extends GObject.Object { - static { - GObject.registerClass({ - GTypeName: "Backlight" - }, this); - } - + @register({ GTypeName: "Backlight" }) + class _Backlight extends GObject.Object { declare $signals: GObject.Object.SignalSignatures & { "brightness-changed": (value: number) => void @@ -207,4 +194,9 @@ export namespace Backlights { super.emit(signal, ...args); } } + + export const Backlights = _Backlights; + export const Backlight = _Backlight; + export type Backlight = InstanceType; + export type Backlights = InstanceType; } diff --git a/src/modules/config.ts b/src/modules/config.ts index f764ff2..bb3aad6 100644 --- a/src/modules/config.ts +++ b/src/modules/config.ts @@ -1,11 +1,9 @@ import { timeout } from "ags/time"; -import { monitorFile, readFileAsync } from "ags/file"; +import { monitorFile, readFileAsync, writeFileAsync } from "ags/file"; import { Notifications } from "./notifications"; -import { encoder } from "./utils"; import { Accessor } from "ags"; -import GObject, { getter, register } from "ags/gobject"; +import GObject, { getter, ParamSpec, register } from "ags/gobject"; -import GLib from "gi://GLib?version=2.0"; import Gio from "gi://Gio?version=2.0"; import AstalIO from "gi://AstalIO"; import AstalNotifd from "gi://AstalNotifd"; @@ -24,8 +22,8 @@ class Config, V extends string|objec * in the `entries` field */ public readonly defaults: Record; - @getter(Object) - public get entries(): object { return this.#entries; } + @getter(Object as unknown as ParamSpec>) + public get entries() { return this.#entries; } #file: Gio.File; #entries: Record; @@ -47,26 +45,12 @@ class Config, V extends string|objec this.#file.make_directory_with_parents(null); this.#file.delete(null); - this.#file.create_readwrite_async( - Gio.FileCreateFlags.NONE, GLib.PRIORITY_DEFAULT, - null, (_, asyncRes) => { - const ioStream = this.#file.create_readwrite_finish(asyncRes); - - ioStream.outputStream.write_bytes_async( - GLib.Bytes.new(encoder.encode(JSON.stringify(this.entries, undefined, 4))), - GLib.PRIORITY_DEFAULT, null, - (_, asyncRes) => { - const writtenBytes = ioStream.outputStream.write_bytes_finish(asyncRes); - - if(!writtenBytes) - Notifications.getDefault().sendNotification({ - appName: "colorshell", - summary: "Write error", - body: `Couldn't write default configuration file to "${this.#file.get_path()!}"` - }); - } - ); - }); + this.writeFile().catch(e => Notifications.getDefault().sendNotification({ + appName: "colorshell", + summary: "Write error", + body: `Couldn't write default configuration file to "${this.#file.get_path()! + }".\nStderr: ${e}` + })); } monitorFile(this.#file.get_path()!, @@ -97,6 +81,13 @@ class Config, V extends string|objec )); } + private async writeFile(): Promise { + this.timeout = true; + await writeFileAsync( + this.#file.get_path()!, JSON.stringify(this.entries, undefined, 4) + ).finally(() => this.timeout = false); + } + private async readFile(): Promise { await readFileAsync(this.#file.get_path()!).then((content) => { let config: (Record|undefined); @@ -174,6 +165,29 @@ class Config, V extends string|objec return this._getProperty(path, this.defaults, expectType); } + public setProperty(path: string, value: any, write?: boolean): void { + let property: any = this.#entries, + obj: typeof this.entries = property; + const pathArray = path.split('.').filter(str => str); + + for(let i = 0; i < pathArray.length; i++) { + const currentPath = pathArray[i]; + + + property = property[currentPath as keyof typeof property]; + if(typeof property === "object") { + obj = property; + } else { + obj[pathArray[pathArray.length - 1] as keyof typeof obj] = value; + break; + } + } + + write && this.writeFile().catch(e => console.error( + `Config: Couldn't save file. Stderr: ${e}` + )); + } + private _getProperty(path: string, entries: Record, expectType?: ValueTypes): (any|undefined) { let property: any = entries; const pathArray = path.split('.').filter(str => str); diff --git a/src/widget/control-center/pages/Backlight.tsx b/src/widget/control-center/pages/Backlight.tsx index 6fa92b7..e75c67f 100644 --- a/src/widget/control-center/pages/Backlight.tsx +++ b/src/widget/control-center/pages/Backlight.tsx @@ -1,9 +1,10 @@ import { Astal, Gtk } from "ags/gtk4"; import { tr } from "../../../i18n/intl"; import { Backlights } from "../../../modules/backlight"; -import { Page } from "./Page"; -import { createBinding, With } from "ags"; +import { Page, PageButton } from "./Page"; +import { createBinding, For, With } from "ags"; import { addSliderMarksFromMinMax } from "../../../modules/utils"; +import { userData } from "../../../app"; export const PageBacklight = new Page({ @@ -13,22 +14,53 @@ export const PageBacklight = new Page({ content: () => ( {(bklights: Array) => bklights.length > 0 && - - {bklights.map((bklight, i) => - + + bklights.length > 1)}> + + + + {(bk: Backlights.Backlight) => + is ? "highlight" : "")} + title={bk.name} + icon={"video-display-symbolic"} + actionClicked={() => { + if(Backlights.getDefault().default?.path !== bk.path) { + Backlights.getDefault().setDefault(bk); + // save data + userData.setProperty( + "control_center.default_backlight", + bk.name, + true + ); + } + }} + endWidget={ + + } + /> + } + + + + {bklights.map((bklight, i) => + - - addSliderMarksFromMinMax(self)} - min={0} max={bklight.maxBrightness} - value={createBinding(bklight, "brightness")} - onChangeValue={(_, __, value) => { - bklight.brightness = value - }} - /> - - )} + + addSliderMarksFromMinMax(self)} + min={0} max={bklight.maxBrightness} + value={createBinding(bklight, "brightness")} + onChangeValue={(_, __, value) => { + bklight.brightness = value + }} + /> + + )} + }