diff --git a/config/ags/apps/settings/main.ts b/config/ags/apps/settings/main.ts index 472aff16..d4240aa9 100644 --- a/config/ags/apps/settings/main.ts +++ b/config/ags/apps/settings/main.ts @@ -7,12 +7,11 @@ import { Info } from "./info"; import { Apps } from "./apps"; import { MaterialIcon } from "icons"; import { Weather } from "./weather"; +import { current_tab, current_window, set_current_window } from "./variables"; const hyprland = await Service.import("hyprland"); import Gtk from "gi://Gtk?version=3.0"; globalThis.OpenSettings = OpenSettings; -let current_window; -const current_tab = Variable("network"); export async function OpenSettings(cur_tab: string = "network") { if (current_window) { @@ -43,7 +42,7 @@ function Settings(cur_tab: string) { wallpaper: Page(Wallpapers(), "Wallpapers"), info: Page(Info(), "Info"), apps: Page(Apps(), "Apps"), - "weather": Page(Weather(), "Weather") + weather: Page(Weather(), "Weather") } }); const Row = (name: string, label: string, icon: string = "image-missing") => @@ -122,7 +121,7 @@ export const SettingsWindow = (cur_tab: string) => { class_name: "settings", child: Settings(cur_tab), setup(win: any) { - current_window = win; + set_current_window(win); win.keybind("Escape", () => { win.close(); }); @@ -133,7 +132,7 @@ export const SettingsWindow = (cur_tab: string) => { window.on("delete-event", () => { // @ts-ignore window.destroy(); - current_window = undefined; + set_current_window(undefined); return true; }); return window; diff --git a/config/ags/apps/settings/network.ts b/config/ags/apps/settings/network.ts index e1fd8e2f..1c4f6ad0 100644 --- a/config/ags/apps/settings/network.ts +++ b/config/ags/apps/settings/network.ts @@ -1,8 +1,8 @@ -import Gtk from "gi://Gtk?version=3.0"; import { timeout } from "resource:///com/github/Aylur/ags/utils.js"; -import { Variable as VariableType } from "types/variable"; import { MaterialIcon } from "icons"; const systemtray = await Service.import("systemtray"); +const network = await Service.import("network"); +import { current_tab, saved_networks, current_window } from "./variables"; const MATERIAL_SYMBOL_SIGNAL_STRENGTH = { "network-wireless-signal-excellent-symbolic": "signal_wifi_4_bar", @@ -23,10 +23,9 @@ type AccessPoint = { iconName: string | undefined; }; -const network = await Service.import("network"); - -const _scan_timer = Variable(undefined, { - poll: [15000, WifiScan] +Utils.interval(1500, () => { + if (current_tab.value != "network" || !current_window?.visible) return; + WifiScan(); }); const network_state = { @@ -43,21 +42,11 @@ const network_state = { failed: "Connection failed" }; -const saved_networks: VariableType = Variable([], { - poll: [ - 5000, - () => { - const _saved = Utils.exec(`${App.configDir}/scripts/network.sh --saved`); - return _saved.split("\n"); - } - ] -}); - function WifiScan() { try { network.wifi?.scan(); } catch (error) { - print(error) + print(error); } // await Utils.execAsync("nmcli device wifi rescan").catch(print) } diff --git a/config/ags/apps/settings/variables.ts b/config/ags/apps/settings/variables.ts new file mode 100644 index 00000000..1466be23 --- /dev/null +++ b/config/ags/apps/settings/variables.ts @@ -0,0 +1,18 @@ +import { Variable as VariableType } from "types/variable"; + +export let current_window; +export function set_current_window(value: any) { + current_window = value; +} + +export const current_tab = Variable("network"); +export const saved_networks: VariableType = Variable([], { + poll: [ + 5000, + () => { + if (current_tab.value != "network" || !current_window?.visible) return saved_networks?.value || []; + const _saved = Utils.exec(`${App.configDir}/scripts/network.sh --saved`); + return _saved.split("\n"); + } + ] +}); diff --git a/config/ags/apps/settings/weather.ts b/config/ags/apps/settings/weather.ts index c7eaeae6..a7acafd2 100644 --- a/config/ags/apps/settings/weather.ts +++ b/config/ags/apps/settings/weather.ts @@ -37,7 +37,7 @@ const WeatherKey = () => on_accept: (self) => { if (self.text!.length == 32) { self.css = "border: 2px solid; border-color: #66BB6A"; - Utils.timeout(100, () => { + Utils.timeout(1000, () => { self.css = "border: 2px solid; border-color: transparent"; }); conf.set_value("weather", self.text!); @@ -82,7 +82,7 @@ const WeatherLocationKey = () => text: conf.config.weather_location_id, on_accept: (self) => { self.css = "border: 2px solid; border-color: #66BB6A"; - Utils.timeout(100, () => { + Utils.timeout(1000, () => { self.css = "border: 2px solid; border-color: transparent"; }); conf.set_value("weather_location_id", self.text!); diff --git a/config/ags/icons.ts b/config/ags/icons.ts index d6aae3cb..485fa2d4 100644 --- a/config/ags/icons.ts +++ b/config/ags/icons.ts @@ -1,7 +1,5 @@ import { LabelProps } from "types/widgets/label"; -const _icons_folder = `${App.configDir}/assets/icons`; - export const MaterialIcon = (icon: string, size: string = "24px", props?: LabelProps) => Widget.Label({ label: icon, diff --git a/config/ags/main.ts b/config/ags/main.ts index 1458e266..2c90da79 100644 --- a/config/ags/main.ts +++ b/config/ags/main.ts @@ -29,43 +29,34 @@ const Windows = () => [ forMonitors(BarCornerTopLeft), forMonitors(BarCornerTopRight), sideright, - sideleft, cheatsheet, + sideleft, forMonitors(popups) ]; -const CLOSE_ANIM_TIME = 210; -const closeWindowDelays = {}; -for (let i = 0; i < (Gdk.Display.get_default()?.get_n_monitors() || 1); i++) { - closeWindowDelays[`osk${i}`] = CLOSE_ANIM_TIME; -} - App.config({ windows: Windows().flat(1), // @ts-ignore - closeWindowDelay: closeWindowDelays, onConfigParsed: function () {} }); function ReloadCSS() { App.resetCss(); + App.applyCss(`${GLib.get_home_dir()}/.config/gtk-3.0/gtk.css`); App.applyCss(`${App.configDir}/style.css`); App.applyCss(`${App.configDir}/style-apps.css`); } -function ReloadGtkCSS() { - App.applyCss(`${GLib.get_home_dir()}/.config/gtk-3.0/gtk.css`); - ReloadCSS(); +function ReloadColors() { + App.applyCss(`${GLib.get_home_dir()}/.cache/material/colors.css`); } -Utils.monitorFile(`${App.configDir}/style.css`, ReloadCSS); +Utils.monitorFile(`${GLib.get_home_dir()}/.cache/material/colors.css`, ReloadCSS); -Utils.monitorFile(`${App.configDir}/style-apps.css`, ReloadCSS); - -Utils.monitorFile(`${GLib.get_home_dir()}/.cache/material/colors.json`, ReloadCSS); - -Utils.monitorFile(`${GLib.get_home_dir()}/.config/gtk-3.0/gtk.css`, ReloadGtkCSS); forMonitorsAsync(Bar); -ReloadGtkCSS(); +ReloadCSS(); -start_battery_warning_service() +globalThis.ReloadCSS = ReloadCSS; +globalThis.ReloadColors = ReloadColors; + +start_battery_warning_service(); diff --git a/config/ags/modules/bar.ts b/config/ags/modules/bar.ts index 2e6175a2..a6e6b3e2 100644 --- a/config/ags/modules/bar.ts +++ b/config/ags/modules/bar.ts @@ -4,13 +4,12 @@ const systemtray = await Service.import("systemtray"); const audio = await Service.import("audio"); const network = await Service.import("network"); const { GLib, Gio } = imports.gi; -const encoder = new TextEncoder(); const decoder = new TextDecoder(); import { OpenSettings } from "apps/settings/main.ts"; import { enableClickThrough } from "./misc/clickthrough.js"; import { RoundedCorner } from "./misc/cairo_roundedcorner.js"; import { Client, Workspace } from "types/service/hyprland.js"; -const { Box, Button, EventBox } = Widget; +import Button from "types/widgets/button.js"; import Icon from "types/widgets/icon.js"; import { FileEnumerator, FileInfo } from "types/@girs/gio-2.0/gio-2.0.cjs"; const mpris = await Service.import("mpris"); @@ -19,20 +18,12 @@ import Gtk from "gi://Gtk?version=3.0"; import { MaterialIcon } from "icons.js"; import config from "services/configuration.ts"; import { toggleAppsWindow, toggleMediaWindow } from "./sideleft/main.js"; +import { Variable as VariableType } from "types/variable"; - -function checkKeymap() { - const layout = Utils.execAsync(`hyprctl devices -j | jq -r '.keyboards[] | select(.main == true) | .active_keymap' | tail -n1 | cut -c1-2 | tr 'A-Z' 'a-z'`) - .then(out => { return out }) - .catch(err => { print(err); return "en" }); - return layout; -} - -const keyboard_layout = Variable("en") -keyboard_layout.setValue(await checkKeymap()) +const keyboard_layout = Variable("none"); hyprland.connect("keyboard-layout", (hyprland, keyboardname, layoutname) => { - keyboard_layout.setValue(layoutname.trim().toLowerCase().substr(0, 2)) -}) + keyboard_layout.setValue(layoutname.trim().toLowerCase().substr(0, 2)); +}); const MATERIAL_SYMBOL_SIGNAL_STRENGTH = { "network-wireless-signal-excellent-symbolic": "signal_wifi_4_bar", @@ -42,13 +33,26 @@ const MATERIAL_SYMBOL_SIGNAL_STRENGTH = { "network-wireless-signal-none-symbolic": "signal_wifi_0_bar" }; -const time = Variable("", { - poll: [1000, 'date "+%I:%M %p"'] -}); +const time = Variable(""); +const date = Variable(""); -const date = Variable("", { - poll: [1000, 'date "+%Y-%m-%d"'] -}); +function getCurrentDateAndTime() { + const _date = new Date(); + + const year = _date.getFullYear(); + const month = String(_date.getMonth() + 1).padStart(2, "0"); + const day = String(_date.getDate()).padStart(2, "0"); + + const hours = String(_date.getHours()).padStart(2, "0"); + const minutes = String(_date.getMinutes()).padStart(2, "0"); + + const formattedDate = `${year}-${month}-${day}`; + const formattedTime = `${hours}:${minutes}`; + + if (time.value != formattedTime) time.setValue(formattedTime); + if (date.value != formattedDate) date.setValue(formattedDate); +} +Utils.interval(1000, getCurrentDateAndTime); function getIconNameFromClass(windowClass: string) { let formattedClass = windowClass.replace(/\s+/g, "-").toLowerCase(); @@ -92,45 +96,72 @@ function getIconNameFromClass(windowClass: string) { return Utils.lookUpIcon(icon) ? icon : "image-missing"; } +function workspaces_ids_are_equal(arr1: Workspace[] | undefined, arr2: Workspace[] | undefined): boolean { + if (!arr1 || !arr2) return false; + if (arr1.length !== arr2.length) return false; + + return arr1.every((value, index) => { + return value.id === arr2[index].id; + }); +} + const dispatch = (ws: string) => hyprland.messageAsync(`dispatch workspace ${ws}`).catch(print); function Workspaces() { - const activeId = hyprland.active.workspace.bind("id"); - let workspaceButtons = new Map(); + let workspaceButtons = new Map(); + let _old_workspaces: Workspace[]; + const workspaceButtonsArray: VariableType[] | any> = Variable([]); function createWorkspaceButton(id: Number) { - const button = Widget.Button({ + return Widget.Button({ on_clicked: () => dispatch(`${id}`), child: Widget.Label(`${id}`), - class_name: activeId.as((i) => `${i === id ? "active" : ""}`) + attribute: { id: id }, + class_name: "workspace" }); - return button; } - function updateWorkspaceButtons(workspaces: Workspace[]): Array> { + function updateWorkspaceButtons() { + const workspaces = hyprland.workspaces; + if (workspaces_ids_are_equal(workspaces, _old_workspaces)) { + return; + } workspaces.sort((a, b) => a.id - b.id); - - const updatedButtons = new Map(); + const updatedButtons = new Map(); workspaces.forEach(({ id }) => { - if (workspaceButtons.has(id)) { - updatedButtons.set(id, workspaceButtons.get(id)); - } else { - updatedButtons.set(id, createWorkspaceButton(id)); + if (!workspaceButtons.has(id)) { + workspaceButtons.set(id, createWorkspaceButton(id)); } + updatedButtons.set(id, workspaceButtons.get(id)); }); - if (workspaceButtons != updatedButtons) workspaceButtons = updatedButtons; - return Array.from(workspaceButtons.values()); + workspaceButtons = updatedButtons; + _old_workspaces = workspaces; + workspaceButtonsArray.setValue(Array.from(workspaceButtons.values())); } - const workspaceButtonsArray = hyprland.bind("workspaces").as(updateWorkspaceButtons); + function activeWorkspace() { + workspaceButtons.forEach((workspace, key) => { + workspace.toggleClassName("active", workspace.attribute.id == hyprland.active.workspace.id); + }); + } + + updateWorkspaceButtons(); + activeWorkspace(); + hyprland.connect("notify::workspaces", () => { + activeWorkspace(); + updateWorkspaceButtons(); + }); + hyprland.connect("notify::active", () => { + activeWorkspace(); + }); return Widget.EventBox({ onScrollUp: () => dispatch("+1"), onScrollDown: () => dispatch("-1"), child: Widget.Box({ - children: workspaceButtonsArray, + children: workspaceButtonsArray.bind(), class_name: "workspaces" }) }); @@ -222,7 +253,6 @@ function BatteryLabel() { }); } - function SysTray() { return Widget.Box({ class_name: "tray", @@ -360,21 +390,15 @@ function MediaPlayer() { return button; } - function KeyboardLayout() { - const widget = Widget.Button({ + const widget = Widget.Label({ class_name: "keyboard", - //visible: keyboard_layout.bind().as((c) => c != "none"), - label: keyboard_layout.bind(), - on_primary_click_release: () => { - Utils.execAsync(`${GLib.get_home_dir()}/dotfiles/hypr/scripts/RunCMD.sh kb_changer`); - }, - + visible: keyboard_layout.bind().as((c) => c != "none"), + label: keyboard_layout.bind() }); return widget; } - function OpenSideBar() { const button = Widget.Button({ class_name: "filled_tonal_button", @@ -402,29 +426,30 @@ function TaskBar() { const currentClientIds = clients.map((client) => client.pid); globalWidgets = globalWidgets.filter((widget) => currentClientIds.includes(widget.attribute.pid)); - clients.forEach((item) => { - let widget = globalWidgets.find((w) => w.attribute.pid === item.pid); - if (item.class == "kitty") { - return; - } + clients.forEach((client) => { + if (client.class === "Alacritty") return; + + let widget = globalWidgets.find((w) => w.attribute.pid === client.pid); if (widget) { - widget.tooltip_markup = item.title; + widget.tooltip_markup = client.title; } else { let icon: string | undefined; - if (item.class == "com.github.Aylur.ags") { - if (item.initialTitle == "Settings") { - icon = "emblem-system-symbolic"; - } else if (item.initialTitle == "Emoji Picker") { - icon = "face-smile-symbolic"; - } - } else icon = getIconNameFromClass(item.class); + if (client.class === "com.github.Aylur.ags") { + icon = + client.initialTitle === "Settings" + ? "emblem-system-symbolic" + : client.initialTitle === "Emoji Picker" + ? "face-smile-symbolic" + : undefined; + } else { + icon = getIconNameFromClass(client.class); + } + widget = Widget.Button({ - attribute: { pid: item.pid }, - child: Widget.Icon({ icon: icon }), - tooltip_markup: item.title, - on_clicked: (self) => { - focus(item); - } + attribute: { pid: client.pid }, + child: Widget.Icon({ icon }), + tooltip_markup: client.title, + on_clicked: () => focus(client) }); globalWidgets.push(widget); } @@ -510,7 +535,7 @@ function Right() { class_name: "modules-right", hpack: "end", spacing: 8, - children: [/*Recorder,*/ volumeIndicator(), KeyboardLayout(), BatteryLabel(), SysTray(), Applets(), Clock(), OpenSideBar()] + children: [volumeIndicator(), KeyboardLayout(), BatteryLabel(), SysTray(), Applets(), Clock(), OpenSideBar()] }); } diff --git a/config/ags/modules/sideleft/weather.ts b/config/ags/modules/sideleft/weather.ts index 2eef7199..74da37b7 100644 --- a/config/ags/modules/sideleft/weather.ts +++ b/config/ags/modules/sideleft/weather.ts @@ -1,6 +1,8 @@ -import { weather } from "variables"; import { MaterialIcon } from "icons.ts"; import { type WeatherJson } from "variables"; +import { Variable as VariableType } from "types/variable"; +import configuration from "services/configuration.ts"; +import { sideleft } from "./main"; // prettier-ignore const MATERIAL_ICONS = { @@ -15,6 +17,28 @@ const MATERIAL_ICONS = { "13d": "weather_snowy", "13n": "weather_snowy", "40d": "air", "40n": "air" }; + +// @ts-expect-error +export const weather: VariableType = Variable({ no_data: true }); +const reload = () => { + if (configuration.config.weather != "" && configuration.config.weather_location_id != "") + Utils.execAsync( + `${App.configDir}/scripts/weather.sh weather ${configuration.config.weather} ${configuration.config.weather_location_id}` + ) + .then((out) => { + weather.setValue(JSON.parse(out)); + }) + .catch(print); +}; +const _reload = () => { + if (sideleft?.visible) reload(); +}; +Utils.interval(1500, _reload); +configuration.connect("changed", _reload); +App.connect("window-toggled", (_, window_name, visible) => { + if (window_name == "sideleft" && visible) reload(); +}); + const ICON_COLORS = { mist: "#B0BEC5", clear_day: "#FFEB3B", diff --git a/config/ags/modules/sideright/management.ts b/config/ags/modules/sideright/management.ts index 8d46e8be..f776d010 100644 --- a/config/ags/modules/sideright/management.ts +++ b/config/ags/modules/sideright/management.ts @@ -1,8 +1,9 @@ const notifications = await Service.import("notifications"); const network = await Service.import("network"); +const bluetooth = await Service.import("bluetooth"); import { OpenSettings } from "apps/settings/main.ts"; import { WINDOW_NAME } from "./main.ts"; -import { bluetooth_enabled, idle_inhibitor, night_light, theme } from "variables.ts"; +import { idle_inhibitor, night_light, theme } from "variables.ts"; import { MaterialIcon } from "icons.ts"; import Gtk from "gi://Gtk?version=3.0"; @@ -10,32 +11,32 @@ import Gtk from "gi://Gtk?version=3.0"; const currentPage = Variable(0); function WifiIndicator() { + const ssid = Widget.Label({ + label: "Unknown", + visible: false, + class_name: "ssid", + xalign: 0, + vpack: "center", + truncate: "end" + }); + const name = Widget.Box({ + vertical: true, + vpack: "center", + children: [ + Widget.Box([ + Widget.Label({ + label: "Internet", + vpack: "center" + }) + ]), + ssid + ] + }); return Widget.Box({ css: "padding-left: 15px; padding-right: 15px; padding-top: 5px; padding-bottom: 5px;", children: [ MaterialIcon("signal_wifi_4_bar", "20px"), - Widget.Box({ - visible: network.wifi.bind("enabled"), - orientation: Gtk.Orientation.VERTICAL, - children: [ - Widget.Box([ - Widget.Label({ - label: "Internet" - }) - ]), - Widget.Label({ - label: network.wifi.bind("ssid").as((ssid) => ssid || "Unknown"), - class_name: "ssid", - xalign: 0, - vpack: "center", - truncate: "end" - }) - ] - }), - Widget.Label({ - visible: network.wifi.bind("enabled").as((enabled) => !enabled), - label: "Internet" - }), + name, Widget.Box({ hpack: "end", hexpand: true, @@ -43,7 +44,13 @@ function WifiIndicator() { class_name: "material_icon icon arrow" }) }) - ] + ], + setup: (self) => { + self.hook(network, () => { + ssid.label = network.wifi.ssid || "Unknown"; + ssid.visible = !!network.wifi.ssid; + }); + } }); } @@ -106,9 +113,7 @@ function Page1() { children: [ Widget.Button({ hexpand: true, - class_name: network.wifi - .bind("enabled") - .as((enabled) => (enabled ? "management_button active" : "management_button")), + class_name: "management_button", child: NetworkIndicator(), on_primary_click_release: () => { network.toggleWifi(); @@ -116,26 +121,33 @@ function Page1() { on_secondary_click_release: () => { App.closeWindow(WINDOW_NAME); OpenSettings("network"); + }, + setup: (self) => { + if (network.wifi) + self.hook(network.wifi, () => { + self.toggleClassName("active", network.wifi.enabled); + }); } }), Widget.Button({ hexpand: true, - class_name: bluetooth_enabled - .bind() - .as((state) => (state.trim() == "yes" ? "management_button active" : "management_button")), + class_name: "management_button", child: IconAndName({ label: "Bluetooth", icon: "bluetooth", arrow: true }), on_primary_click_release: () => { - Utils.execAsync(`${App.configDir}/scripts/bluetooth.sh --toggle`).then((out) => { - bluetooth_enabled.setValue(out); - }); + bluetooth.toggle(); }, on_secondary_click_release: () => { OpenSettings("bluetooth"); App.closeWindow(WINDOW_NAME); + }, + setup: (self) => { + self.hook(bluetooth, () => { + self.toggleClassName("active", bluetooth.enabled); + }); } }) ] @@ -147,9 +159,7 @@ function Page1() { children: [ Widget.Button({ hexpand: true, - class_name: theme.bind().as((str) => { - return str.trim() == "dark" ? "management_button active" : "management_button"; - }), + class_name: "management_button", on_clicked: () => { Utils.execAsync(`${App.configDir}/scripts/dark-theme.sh --toggle`).catch(print); theme.setValue(theme.value.trim() == "dark" ? "light" : "dark"); @@ -157,22 +167,31 @@ function Page1() { child: IconAndName({ label: "Dark theme", icon: "contrast" - }) + }), + setup: (self) => { + self.hook(theme, () => { + self.toggleClassName("active", theme.value.trim() == "dark"); + }); + } }), Widget.Button({ hexpand: true, - class_name: notifications.bind("dnd").as((bool) => { - return bool ? "management_button active" : "management_button"; - }), + class_name: "management_button", on_clicked: () => { - notifications.dnd = notifications.dnd ? false : true; + notifications.dnd = !notifications.dnd; }, child: IconAndName({ label: "Do Not Disturb", - icon: notifications - .bind("dnd") - .as((bool) => (bool ? "do_not_disturb_on" : "do_not_disturb_off")) - }) + icon: "do_not_disturb_off" + }), + setup: (self) => { + notifications.connect("notify::dnd", (_) => { + self.toggleClassName("active", notifications.dnd); + self.child.children[0].label = notifications.dnd + ? "do_not_disturb_on" + : "do_not_disturb_off"; + }); + } }) ] }), @@ -183,9 +202,7 @@ function Page1() { children: [ Widget.Button({ hexpand: true, - class_name: idle_inhibitor - .bind() - .as((bool) => (bool ? "management_button active" : "management_button")), + class_name: "management_button", child: IconAndName({ label: "Idle inhibitor", icon: "schedule" @@ -200,15 +217,16 @@ function Page1() { ]).catch(print); else Utils.execAsync("pkill -f wayland-idle-inhibitor.py").catch(print); }, - setup: () => { + setup: (self) => { idle_inhibitor.setValue(!!Utils.exec("pidof wayland-idle-inhibitor.py")); + self.hook(idle_inhibitor, () => { + self.toggleClassName("active", idle_inhibitor.value); + }); } }), Widget.Button({ hexpand: true, - class_name: night_light - .bind() - .as((mode) => (mode ? "management_button active" : "management_button")), + class_name: "management_button", child: IconAndName({ label: "Night Light", icon: "nightlight" @@ -217,20 +235,16 @@ function Page1() { night_light.setValue(!night_light.value); Utils.execAsync(`${App.configDir}/scripts/night-light.sh --toggle`) .then((out) => { - if (out.trim() == "enabled") night_light.setValue(true); - else if (out.trim() == "disabled") night_light.setValue(false); + night_light.setValue(out.trim() == "enabled"); }) .catch((err) => { night_light.setValue(!night_light.value); }); }, - setup: () => { - Utils.execAsync(`${App.configDir}/scripts/night-light.sh --get`) - .then((out) => { - if (out.trim() == "enabled") night_light.setValue(true); - else if (out.trim() == "disabled") night_light.setValue(false); - }) - .catch(print); + setup: (self) => { + self.hook(night_light, () => { + self.toggleClassName("active", night_light.value); + }); } }) ] @@ -288,8 +302,13 @@ const createDotButton = (index: number) => Widget.Button({ label: "●", onClicked: () => currentPage.setValue(index), - class_name: currentPage.bind().as((v) => (v == index ? "dotbutton active" : "dotbutton")), - hexpand: false + class_name: "dotbutton", + hexpand: false, + setup: (self) => { + self.hook(currentPage, () => { + self.toggleClassName("active", currentPage.value == index); + }); + } }); export function Management() { diff --git a/config/ags/modules/sideright/navigation.ts b/config/ags/modules/sideright/navigation.ts index c92cc398..50681087 100644 --- a/config/ags/modules/sideright/navigation.ts +++ b/config/ags/modules/sideright/navigation.ts @@ -3,7 +3,6 @@ import { SystemBox } from "./system.ts"; let shown = Variable("Messages"); import Gtk from "gi://Gtk?version=3.0"; import { MaterialIcon } from "icons.ts"; -import { enableClickThrough } from "modules/misc/clickthrough.js"; type ButtonType = { page: string; @@ -13,8 +12,9 @@ type ButtonType = { function Button({ page, label, icon }: ButtonType) { return Widget.Button({ - class_name: shown.bind().as((_page) => (_page == page ? "navigation_button active" : "navigation_button")), + class_name: "navigation_button", hexpand: true, + attribute: { page: page }, child: Widget.Box({ orientation: Gtk.Orientation.VERTICAL, class_name: "container_outer", @@ -72,7 +72,14 @@ export function Navigation() { label: "System", icon: "info" }) - ] + ], + setup: (self) => { + self.hook(shown, () => { + for (const button of self.children) { + button.toggleClassName("active", button.attribute.page == shown.value); + } + }); + } }); return Widget.Box({ vexpand: true, diff --git a/config/ags/modules/sideright/system.ts b/config/ags/modules/sideright/system.ts index 3797fa58..ea21bc30 100644 --- a/config/ags/modules/sideright/system.ts +++ b/config/ags/modules/sideright/system.ts @@ -1,15 +1,8 @@ -import { - cpu_cores, - cpu_name, - kernel_name, - amount_of_ram, - gpu_name, - cur_uptime, - current_brightness -} from "variables.ts"; +import { cpu_cores, cpu_name, kernel_name, amount_of_ram, gpu_name, cur_uptime } from "variables.ts"; import Gtk from "gi://Gtk?version=3.0"; import { Variable as VariableType } from "types/variable"; import backlight_service from "services/backlight.ts"; +import { sideright } from "./main"; type InfoType = { cpu: string; @@ -51,23 +44,40 @@ async function SystemInfo(): Promise { }; } -const usage = Variable( - { - cpu: "0", - ram: "0", - swap: "0", - cpu_temp: "0" - } as unknown as Promise, - { - poll: [ - 1000, - async () => { - const result = await SystemInfo().then((result) => result); - return result; - } - ] - } -); +function checkBrightness() { + const get = Utils.execAsync(`${App.configDir}/scripts/brightness.sh --get`) + .then((out) => Number(out.trim())) + .catch(print); + return get; +} + +export const current_brightness = Variable(100, { + poll: [ + 500, + () => { + if (sideright?.visible) return checkBrightness(); + else return current_brightness?.value || 100; + } + ] +}); + +const usage_default = { + cpu: "0", + ram: "0", + swap: "0", + cpu_temp: "0" +}; + +const usage = Variable(usage_default); +Utils.interval(1000, async () => { + Utils.idle(() => { + if (sideright?.visible) { + SystemInfo().then((result) => { + usage.setValue(result); + }); + } + }); +}); const Usage = (name: string, var_name: keyof InfoType, class_name: string | undefined) => { const usage_progress_bar = Widget.ProgressBar({ @@ -132,7 +142,7 @@ export function SystemBox() { draw_value: false, class_name: "system_scale backlight", // @ts-ignore - value: backlight_service.bind("screen_value").as(n => n * 100), + value: backlight_service.bind("screen_value").as((n) => n * 100), on_change: (self) => { backlight_service.screen_value = self.value / 100; }, diff --git a/config/ags/scripts/brightness.sh b/config/ags/scripts/brightness.sh index 37cf835e..bbd2831c 100755 --- a/config/ags/scripts/brightness.sh +++ b/config/ags/scripts/brightness.sh @@ -1,6 +1,10 @@ #!/bin/bash -# I tried to make it smooth, but it didn't work - +wl_gammarelay() { + if ! busctl --user list | grep rs.wl.gammarelay; then + systemctl --user restart wl-gammarelay.service + fi +} +wl_gammarelay >/dev/null LOCKFILE=/tmp/brightness.lock @@ -9,19 +13,12 @@ get_brightness() { } set_brightness() { - # if [ -e "$LOCKFILE" ] && kill -0 "$(cat $LOCKFILE)"; then - # exit 0 - # fi - # trap "rm -f $LOCKFILE; exit" INT TERM EXIT - # echo $$ > "$LOCKFILE" - if (( $(echo "$1 < 0.05" | bc -l) )); then + if (($(echo "$1 < 0.05" | bc -l))); then BRIGHTNESS=0.05 else BRIGHTNESS=$1 fi busctl --user -- set-property rs.wl-gammarelay / rs.wl.gammarelay Brightness d $BRIGHTNESS - # rm -f "$LOCKFILE" - # trap - INT TERM EXIT } set() { @@ -46,6 +43,6 @@ get() { if [[ "$1" == "--set" ]]; then set $2 - elif [[ "$1" == "--get" ]]; then +elif [[ "$1" == "--get" ]]; then get fi diff --git a/config/ags/scripts/keybindings.py b/config/ags/scripts/keybindings.py index 3b7c2285..49aa11bf 100644 --- a/config/ags/scripts/keybindings.py +++ b/config/ags/scripts/keybindings.py @@ -15,12 +15,15 @@ variables_dict: dict[str, str] = {} category_pattern = r"\n#! @(\w+): (.+)" variable_pattern = r"\n\$(\w+)\s*=\s*(.*)" +text = "" bindings: dict[str, dict[str, str]] = {} -def extract_category_and_description(line: str) -> tuple[str | None, str | None, tuple | None]: - pattern2 = r'bind\s*=\s*.*! @description:\s*"((?:[^"]|\\")*)"\s*;\s*@(\w+);\s*@replace\s*"([^"]*)"\s*>\s*"([^"]*)";.*' - pattern = r'bind\s*=\s*.*! @description:\s*"((?:[^"]|\\")*)"\s*;\s*@(\w+);.*' +def extract_category_and_description( + line: str +) -> tuple[str | None, str | None, tuple | None]: + pattern2 = r'bind\s*=\s*.*! @description:\s*"((?:[^"]|\\")*)"\s*;\s*@(\w+);\s*@replace\s*"([^"]*)"\s*>\s*"([^"]*)";.*' # noqa + pattern = r'bind\s*=\s*.*! @description:\s*"((?:[^"]|\\")*)"\s*;\s*@(\w+);.*' # noqa match = re.search(pattern, line) match2 = re.search(pattern2, line) @@ -66,11 +69,22 @@ def load_categories(content: str): for key, value in matches: categories_dict[key] = value - if value not in bindings: - bindings[value] = {} + bindings[value] = {} return content +def load_sources(file: str): + with open(file) as f: + content = f.read() + for line in content.split("\n"): + line = line.replace(" = ", "=") + if not line.startswith("source="): + continue + file = os.path.expanduser(line.replace("source=", "")) + if file not in files: + files.append(file) + + def load_variables(content: str): matches = re.findall(variable_pattern, content) @@ -80,12 +94,13 @@ def load_variables(content: str): content_lines = content.split("\n") content_lines = [ line for line in content_lines if not line.startswith("$") - ] + ] content = "\n".join(content_lines) return content def load_file(file: str): + global text with open(file) as f: content = f.read() @@ -94,34 +109,42 @@ def load_file(file: str): # remove comments content = re.sub(r'^#.*$\n', '', content, flags=re.MULTILINE) - return content + text += f"\n{content}" def load(): - global bindings + global text, bindings + text = re.sub(r"\$(\w+)", replace_variable, text) + for line in text.split('\n'): + if not line.replace(" ", "").startswith("bind="): + continue + + description, category, replace = extract_category_and_description(line) + if category is None or description is None: + continue + + binding = extract_binding(line) + if binding is None: + continue + + category_name = categories_dict[category] + if category_name not in bindings: + bindings[category_name] = {} + + if replace is not None: + binding = binding.replace(*replace) + + bindings[category_name][binding.strip()] = description.strip() + + +while True: + old_list = files for file in files: - content = load_file(file) - for line in content.split('\n'): - if not line.replace(" ", "").startswith("bind="): - continue - - description, category, replace = extract_category_and_description(line) - if category is None or description is None: - continue - - binding = extract_binding(line) - if binding is None: - continue - - category_name = categories_dict[category] - if category_name not in bindings: - bindings[category_name] = {} - - if replace is not None: - binding = binding.replace(*replace) - - bindings[category_name][binding.strip()] = description.strip() - + load_sources(file) + if old_list == files: + break +for file in files: + load_file(file) load() print(json.dumps(bindings, indent=4)) diff --git a/config/ags/variables.ts b/config/ags/variables.ts index 33892054..23814d23 100644 --- a/config/ags/variables.ts +++ b/config/ags/variables.ts @@ -1,6 +1,4 @@ -import { Variable as VariableType } from "types/variable"; const GLib = imports.gi.GLib; -import configuration from "services/configuration.ts"; export type WeatherJson = { coord: { @@ -61,32 +59,21 @@ export type WeatherJson = { export const theme = Variable("dark"); export const main_color = Variable("#000000"); export const current_wallpaper = Variable(`${GLib.get_home_dir()}/Pictures/wallpapers/default.png`); -// @ts-expect-error -export const weather: VariableType = Variable({ no_data: true }); -const reload = () => { - if (configuration.config.weather != "" && configuration.config.weather_location_id != "") - Utils.execAsync( - `${App.configDir}/scripts/weather.sh weather ${configuration.config.weather} ${configuration.config.weather_location_id}` - ) - .then((out) => { - weather.setValue(JSON.parse(out)); - }) - .catch(print); -}; -Utils.interval(150, reload); -configuration.connect("changed", reload); export const idle_inhibitor = Variable(false); export const cur_uptime = Variable("error"); -Utils.interval(5000, () => { +Utils.interval(60000, () => { Utils.execAsync(`${App.configDir}/scripts/system.sh --uptime`) .then((out) => cur_uptime.setValue(out)) .catch(print); }); export const night_light = Variable(false); -export const bluetooth_enabled = Variable("off", { - poll: [1000, `${App.configDir}/scripts/bluetooth.sh --get`] -}); +Utils.execAsync(`${App.configDir}/scripts/night-light.sh --get`) + .then((out) => { + if (out.trim() == "enabled") night_light.setValue(true); + else if (out.trim() == "disabled") night_light.setValue(false); + }) + .catch(print); export const theme_settings = { color: Variable("none"), scheme: Variable("tonalSpot") @@ -103,17 +90,6 @@ export const current_os = await Utils.execAsync(`${App.configDir}/scripts/system export const settings_file = `${GLib.get_home_dir()}/dotfiles/.settings/settings.json`; export const wallpaper_cache_file = `${GLib.get_home_dir()}/.cache/current_wallpaper`; -function checkBrightness() { - const get = Utils.execAsync(`${App.configDir}/scripts/brightness.sh --get`) - .then((out) => Number(out.trim())) - .catch(print); - return get; -} - -export const current_brightness = Variable(100, { - poll: [500, checkBrightness] -}); - function readSettingsFile() { Utils.readFileAsync(settings_file) .then((out) => {