🔧 chore(modules/backlight, modules/config): fix property name not found, add support for setting properties in config
This commit is contained in:
+14
@@ -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<keyof typeof generalConfigDefaults,
|
export const generalConfig = new Config<keyof typeof generalConfigDefaults,
|
||||||
typeof generalConfigDefaults[keyof typeof generalConfigDefaults]>(
|
typeof generalConfigDefaults[keyof typeof generalConfigDefaults]>(
|
||||||
`${GLib.get_user_config_dir()}/colorshell/config.json`, generalConfigDefaults
|
`${GLib.get_user_config_dir()}/colorshell/config.json`, generalConfigDefaults
|
||||||
|
|||||||
+10
-18
@@ -1,15 +1,12 @@
|
|||||||
import { monitorFile, readFile } from "ags/file";
|
import { monitorFile, readFile } from "ags/file";
|
||||||
import { exec } from "ags/process";
|
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";
|
import Gio from "gi://Gio?version=2.0";
|
||||||
|
|
||||||
|
|
||||||
export namespace Backlights {
|
export namespace Backlights {
|
||||||
|
|
||||||
const BacklightsParamSpec = (name: string, flags: GObject.ParamFlags) =>
|
|
||||||
GObject.ParamSpec.object(name, null, null, flags) as ParamSpec<Backlights>;
|
|
||||||
|
|
||||||
const BacklightParamSpec = (name: string, flags: GObject.ParamFlags) =>
|
const BacklightParamSpec = (name: string, flags: GObject.ParamFlags) =>
|
||||||
GObject.ParamSpec.object(name, null, null, flags) as ParamSpec<Backlight>;
|
GObject.ParamSpec.object(name, null, null, flags) as ParamSpec<Backlight>;
|
||||||
|
|
||||||
@@ -22,13 +19,8 @@ export namespace Backlights {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Backlights extends GObject.Object {
|
@register({ GTypeName: "Backlights" })
|
||||||
static {
|
class _Backlights extends GObject.Object {
|
||||||
GObject.registerClass({
|
|
||||||
GTypeName: "Backlights"
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#backlights: Array<Backlight> = [];
|
#backlights: Array<Backlight> = [];
|
||||||
#default: Backlight|null = null;
|
#default: Backlight|null = null;
|
||||||
@@ -101,13 +93,8 @@ export namespace Backlights {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Backlight extends GObject.Object {
|
@register({ GTypeName: "Backlight" })
|
||||||
static {
|
class _Backlight extends GObject.Object {
|
||||||
GObject.registerClass({
|
|
||||||
GTypeName: "Backlight"
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
declare $signals: GObject.Object.SignalSignatures & {
|
declare $signals: GObject.Object.SignalSignatures & {
|
||||||
"brightness-changed": (value: number) => void
|
"brightness-changed": (value: number) => void
|
||||||
@@ -207,4 +194,9 @@ export namespace Backlights {
|
|||||||
super.emit(signal, ...args);
|
super.emit(signal, ...args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const Backlights = _Backlights;
|
||||||
|
export const Backlight = _Backlight;
|
||||||
|
export type Backlight = InstanceType<typeof Backlight>;
|
||||||
|
export type Backlights = InstanceType<typeof Backlights>;
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-26
@@ -1,11 +1,9 @@
|
|||||||
import { timeout } from "ags/time";
|
import { timeout } from "ags/time";
|
||||||
import { monitorFile, readFileAsync } from "ags/file";
|
import { monitorFile, readFileAsync, writeFileAsync } from "ags/file";
|
||||||
import { Notifications } from "./notifications";
|
import { Notifications } from "./notifications";
|
||||||
import { encoder } from "./utils";
|
|
||||||
import { Accessor } from "ags";
|
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 Gio from "gi://Gio?version=2.0";
|
||||||
import AstalIO from "gi://AstalIO";
|
import AstalIO from "gi://AstalIO";
|
||||||
import AstalNotifd from "gi://AstalNotifd";
|
import AstalNotifd from "gi://AstalNotifd";
|
||||||
@@ -24,8 +22,8 @@ class Config<K extends NonNullable<string|number|symbol>, V extends string|objec
|
|||||||
* in the `entries` field */
|
* in the `entries` field */
|
||||||
public readonly defaults: Record<K, V>;
|
public readonly defaults: Record<K, V>;
|
||||||
|
|
||||||
@getter(Object)
|
@getter(Object as unknown as ParamSpec<Record<K, V>>)
|
||||||
public get entries(): object { return this.#entries; }
|
public get entries() { return this.#entries; }
|
||||||
|
|
||||||
#file: Gio.File;
|
#file: Gio.File;
|
||||||
#entries: Record<K, V>;
|
#entries: Record<K, V>;
|
||||||
@@ -47,26 +45,12 @@ class Config<K extends NonNullable<string|number|symbol>, V extends string|objec
|
|||||||
this.#file.make_directory_with_parents(null);
|
this.#file.make_directory_with_parents(null);
|
||||||
this.#file.delete(null);
|
this.#file.delete(null);
|
||||||
|
|
||||||
this.#file.create_readwrite_async(
|
this.writeFile().catch(e => Notifications.getDefault().sendNotification({
|
||||||
Gio.FileCreateFlags.NONE, GLib.PRIORITY_DEFAULT,
|
appName: "colorshell",
|
||||||
null, (_, asyncRes) => {
|
summary: "Write error",
|
||||||
const ioStream = this.#file.create_readwrite_finish(asyncRes);
|
body: `Couldn't write default configuration file to "${this.#file.get_path()!
|
||||||
|
}".\nStderr: ${e}`
|
||||||
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()!}"`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
monitorFile(this.#file.get_path()!,
|
monitorFile(this.#file.get_path()!,
|
||||||
@@ -97,6 +81,13 @@ class Config<K extends NonNullable<string|number|symbol>, V extends string|objec
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async writeFile(): Promise<void> {
|
||||||
|
this.timeout = true;
|
||||||
|
await writeFileAsync(
|
||||||
|
this.#file.get_path()!, JSON.stringify(this.entries, undefined, 4)
|
||||||
|
).finally(() => this.timeout = false);
|
||||||
|
}
|
||||||
|
|
||||||
private async readFile(): Promise<void> {
|
private async readFile(): Promise<void> {
|
||||||
await readFileAsync(this.#file.get_path()!).then((content) => {
|
await readFileAsync(this.#file.get_path()!).then((content) => {
|
||||||
let config: (Record<K, V>|undefined);
|
let config: (Record<K, V>|undefined);
|
||||||
@@ -174,6 +165,29 @@ class Config<K extends NonNullable<string|number|symbol>, V extends string|objec
|
|||||||
return this._getProperty(path, this.defaults, expectType);
|
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<K, V>, expectType?: ValueTypes): (any|undefined) {
|
private _getProperty(path: string, entries: Record<K, V>, expectType?: ValueTypes): (any|undefined) {
|
||||||
let property: any = entries;
|
let property: any = entries;
|
||||||
const pathArray = path.split('.').filter(str => str);
|
const pathArray = path.split('.').filter(str => str);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Astal, Gtk } from "ags/gtk4";
|
import { Astal, Gtk } from "ags/gtk4";
|
||||||
import { tr } from "../../../i18n/intl";
|
import { tr } from "../../../i18n/intl";
|
||||||
import { Backlights } from "../../../modules/backlight";
|
import { Backlights } from "../../../modules/backlight";
|
||||||
import { Page } from "./Page";
|
import { Page, PageButton } from "./Page";
|
||||||
import { createBinding, With } from "ags";
|
import { createBinding, For, With } from "ags";
|
||||||
import { addSliderMarksFromMinMax } from "../../../modules/utils";
|
import { addSliderMarksFromMinMax } from "../../../modules/utils";
|
||||||
|
import { userData } from "../../../app";
|
||||||
|
|
||||||
|
|
||||||
export const PageBacklight = new Page({
|
export const PageBacklight = new Page({
|
||||||
@@ -13,22 +14,53 @@ export const PageBacklight = new Page({
|
|||||||
content: () => (
|
content: () => (
|
||||||
<With value={createBinding(Backlights.getDefault(), "backlights")}>
|
<With value={createBinding(Backlights.getDefault(), "backlights")}>
|
||||||
{(bklights: Array<Backlights.Backlight>) => bklights.length > 0 &&
|
{(bklights: Array<Backlights.Backlight>) => bklights.length > 0 &&
|
||||||
<Gtk.Box orientation={Gtk.Orientation.VERTICAL} spacing={6}>
|
<Gtk.Box orientation={Gtk.Orientation.VERTICAL} spacing={4}>
|
||||||
{bklights.map((bklight, i) =>
|
<Gtk.Box class={"list"} visible={createBinding(Backlights.getDefault(), "backlights")
|
||||||
<Gtk.Box class={"bklight"} orientation={Gtk.Orientation.VERTICAL}
|
.as((bklights) => bklights.length > 1)}>
|
||||||
spacing={4}>
|
|
||||||
|
|
||||||
<Gtk.Label class={"subheader"} label={`Backlight ${i+1} (${bklight.name})`}
|
<Gtk.Label label={"Default"} />
|
||||||
xalign={0} />
|
<For each={createBinding(Backlights.getDefault(), "backlights")}>
|
||||||
<Astal.Slider $={(self) => addSliderMarksFromMinMax(self)}
|
{(bk: Backlights.Backlight) =>
|
||||||
min={0} max={bklight.maxBrightness}
|
<PageButton class={createBinding(bk, "isDefault").as(is => is ? "highlight" : "")}
|
||||||
value={createBinding(bklight, "brightness")}
|
title={bk.name}
|
||||||
onChangeValue={(_, __, value) => {
|
icon={"video-display-symbolic"}
|
||||||
bklight.brightness = value
|
actionClicked={() => {
|
||||||
}}
|
if(Backlights.getDefault().default?.path !== bk.path) {
|
||||||
/>
|
Backlights.getDefault().setDefault(bk);
|
||||||
</Gtk.Box>
|
// save data
|
||||||
)}
|
userData.setProperty(
|
||||||
|
"control_center.default_backlight",
|
||||||
|
bk.name,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
endWidget={
|
||||||
|
<Gtk.Image iconName={"object-select-symbolic"}
|
||||||
|
visible={createBinding(bk, "isDefault")}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</For>
|
||||||
|
</Gtk.Box>
|
||||||
|
<Gtk.Box class={"sliders"} orientation={Gtk.Orientation.VERTICAL} spacing={6}>
|
||||||
|
{bklights.map((bklight, i) =>
|
||||||
|
<Gtk.Box class={"bklight"} orientation={Gtk.Orientation.VERTICAL}
|
||||||
|
spacing={4}>
|
||||||
|
|
||||||
|
<Gtk.Label class={"subheader"} label={`Backlight ${i+1} (${bklight.name})`}
|
||||||
|
xalign={0} />
|
||||||
|
<Astal.Slider $={(self) => addSliderMarksFromMinMax(self)}
|
||||||
|
min={0} max={bklight.maxBrightness}
|
||||||
|
value={createBinding(bklight, "brightness")}
|
||||||
|
onChangeValue={(_, __, value) => {
|
||||||
|
bklight.brightness = value
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Gtk.Box>
|
||||||
|
)}
|
||||||
|
</Gtk.Box>
|
||||||
</Gtk.Box>
|
</Gtk.Box>
|
||||||
}
|
}
|
||||||
</With>
|
</With>
|
||||||
|
|||||||
Reference in New Issue
Block a user