From 84e85b168e9fe01088607c6db91756ebe1764b99 Mon Sep 17 00:00:00 2001 From: Jas Singh Date: Fri, 16 Aug 2024 00:49:24 -0700 Subject: [PATCH] Implement a CLI command to change themes. (#136) * Implement cli based theme applier. * Remove references to old globalMousePos * Use direct file path instead. --- globals.ts | 5 --- globals/mousePos.ts | 3 ++ globals/useTheme.ts | 84 +++++++++++++++++++++++++++++++++++ main.ts | 14 +++--- modules/bar/utils.ts | 2 - modules/menus/DropdownMenu.ts | 1 - 6 files changed, 95 insertions(+), 14 deletions(-) delete mode 100644 globals.ts create mode 100644 globals/mousePos.ts create mode 100644 globals/useTheme.ts diff --git a/globals.ts b/globals.ts deleted file mode 100644 index 913a682..0000000 --- a/globals.ts +++ /dev/null @@ -1,5 +0,0 @@ -const globalMousePos = Variable([0, 0]); - -globalThis["globalMousePos"] = globalMousePos; - -export { globalMousePos }; diff --git a/globals/mousePos.ts b/globals/mousePos.ts new file mode 100644 index 0000000..7e127a3 --- /dev/null +++ b/globals/mousePos.ts @@ -0,0 +1,3 @@ +const globalMousePosVar = Variable([0, 0]); + +globalThis["globalMousePos"] = globalMousePosVar; diff --git a/globals/useTheme.ts b/globals/useTheme.ts new file mode 100644 index 0000000..f87f01a --- /dev/null +++ b/globals/useTheme.ts @@ -0,0 +1,84 @@ +import Gio from "gi://Gio" +import { bash, Notify } from "lib/utils"; +import icons from "lib/icons" + +globalThis.useTheme = (filePath: string): void => { + const themeOnly = true; + let file = Gio.File.new_for_path(filePath as string); + let [success, content] = file.load_contents(null); + + if (!success) { + console.error(`Failed to import: ${filePath}`); + return; + } + + Notify({ + summary: `Importing ${themeOnly ? "Theme" : "Config"}`, + body: `Importing: ${filePath}`, + iconName: icons.ui.info, + timeout: 7000 + }); + + let jsonString = new TextDecoder("utf-8").decode(content); + let importedConfig = JSON.parse(jsonString); + + const hexColorPattern = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/; + + const saveConfigToFile = (config: object, filePath: string) => { + let file = Gio.File.new_for_path(filePath); + let outputStream = file.replace(null, false, Gio.FileCreateFlags.NONE, null); + let dataOutputStream = new Gio.DataOutputStream({ base_stream: outputStream }); + + let jsonString = JSON.stringify(config, null, 2); + dataOutputStream.put_string(jsonString, null); + dataOutputStream.close(null); + }; + + const filterConfigForThemeOnly = (config: object) => { + let filteredConfig = {}; + for (let key in config) { + if (typeof config[key] === 'string' && hexColorPattern.test(config[key])) { + filteredConfig[key] = config[key]; + } + } + return filteredConfig; + }; + + const filterConfigForNonTheme = (config: object) => { + let filteredConfig = {}; + for (let key in config) { + if (!(typeof config[key] === 'string' && hexColorPattern.test(config[key]))) { + filteredConfig[key] = config[key]; + } + } + return filteredConfig; + }; + + let tmpConfigFile = Gio.File.new_for_path(`${TMP}/config.json`); + let optionsConfigFile = Gio.File.new_for_path(OPTIONS); + + let [tmpSuccess, tmpContent] = tmpConfigFile.load_contents(null); + let [optionsSuccess, optionsContent] = optionsConfigFile.load_contents(null); + + if (!tmpSuccess || !optionsSuccess) { + console.error("Failed to read existing configuration files."); + return; + } + + let tmpConfig = JSON.parse(new TextDecoder("utf-8").decode(tmpContent)); + let optionsConfig = JSON.parse(new TextDecoder("utf-8").decode(optionsContent)); + + if (themeOnly) { + const filteredConfig = filterConfigForThemeOnly(importedConfig); + tmpConfig = { ...tmpConfig, ...filteredConfig }; + optionsConfig = { ...optionsConfig, ...filteredConfig }; + } else { + const filteredConfig = filterConfigForNonTheme(importedConfig); + tmpConfig = { ...tmpConfig, ...filteredConfig }; + optionsConfig = { ...optionsConfig, ...filteredConfig }; + } + + saveConfigToFile(tmpConfig, `${TMP}/config.json`); + saveConfigToFile(optionsConfig, OPTIONS); + bash("pkill ags && ags"); +} diff --git a/main.ts b/main.ts index 636b0e1..8e55a66 100644 --- a/main.ts +++ b/main.ts @@ -1,12 +1,14 @@ -import "lib/session" -import "scss/style" +import "lib/session"; +import "scss/style"; +import "globals/useTheme"; +import "globals/mousePos"; -import { Bar } from "modules/bar/Bar" +import { Bar } from "modules/bar/Bar"; import MenuWindows from "./modules/menus/main.js"; -import SettingsDialog from "widget/settings/SettingsDialog" +import SettingsDialog from "widget/settings/SettingsDialog"; import Notifications from "./modules/notifications/index.js"; -import { forMonitors } from "lib/utils" -import OSD from "modules/osd/index" +import { forMonitors } from "lib/utils"; +import OSD from "modules/osd/index"; App.config({ onConfigParsed: () => Utils.execAsync(`python3 ${App.configDir}/services/bluetooth.py`), diff --git a/modules/bar/utils.ts b/modules/bar/utils.ts index d1db2be..c8ee55e 100644 --- a/modules/bar/utils.ts +++ b/modules/bar/utils.ts @@ -1,7 +1,5 @@ import Gdk from 'gi://Gdk?version=3.0'; -import { globalMousePos } from 'globals'; - export const closeAllMenus = () => { const menuWindows = App.windows .filter((w) => { diff --git a/modules/menus/DropdownMenu.ts b/modules/menus/DropdownMenu.ts index 411f3fe..e525318 100644 --- a/modules/menus/DropdownMenu.ts +++ b/modules/menus/DropdownMenu.ts @@ -1,5 +1,4 @@ const hyprland = await Service.import("hyprland"); -import { globalMousePos } from "globals"; import { Exclusivity } from "lib/types/widget"; import { bash } from "lib/utils"; import { Monitor } from "types/service/hyprland";