From 8783a3a95a7be02eb42d29441ff199b161d6cb82 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Sun, 9 Nov 2025 17:55:03 -0500 Subject: config: settings in bar --- config/BarConfig.qml | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'config') diff --git a/config/BarConfig.qml b/config/BarConfig.qml index 34819b1..745cda6 100644 --- a/config/BarConfig.qml +++ b/config/BarConfig.qml @@ -45,6 +45,10 @@ JsonObject { id: "statusIcons", enabled: true }, + { + id: "settings", + enabled: true + }, { id: "power", enabled: true -- cgit v1.2.3-freya From f1234bc96705b7f5bd35f2c1e5cfd532712f6f86 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Sun, 9 Nov 2025 19:10:11 -0500 Subject: fix: window title while keeping new panels modified: config/BarConfig.qml modified: modules/BatteryMonitor.qml modified: modules/background/DesktopClock.qml modified: modules/bar/Bar.qml modified: modules/controlcenter/WindowFactory.qml modified: modules/controlcenter/WindowTitle.qml --- config/BarConfig.qml | 4 ---- modules/BatteryMonitor.qml | 2 +- modules/background/DesktopClock.qml | 1 + modules/bar/Bar.qml | 6 ------ modules/controlcenter/WindowFactory.qml | 2 +- modules/controlcenter/WindowTitle.qml | 2 +- 6 files changed, 4 insertions(+), 13 deletions(-) (limited to 'config') diff --git a/config/BarConfig.qml b/config/BarConfig.qml index 745cda6..34819b1 100644 --- a/config/BarConfig.qml +++ b/config/BarConfig.qml @@ -45,10 +45,6 @@ JsonObject { id: "statusIcons", enabled: true }, - { - id: "settings", - enabled: true - }, { id: "power", enabled: true diff --git a/modules/BatteryMonitor.qml b/modules/BatteryMonitor.qml index 7a3be12..d24cff2 100644 --- a/modules/BatteryMonitor.qml +++ b/modules/BatteryMonitor.qml @@ -15,7 +15,7 @@ Scope { function onOnBatteryChanged(): void { if (UPower.onBattery) { if (Config.utilities.toasts.chargingChanged) - Toaster.toast(qsTr("Charger unplugged"), qsTr("Battery is now on AC"), "power_off"); + Toaster.toast(qsTr("Charger unplugged"), qsTr("Battery is discharging"), "power_off"); } else { if (Config.utilities.toasts.chargingChanged) Toaster.toast(qsTr("Charger plugged in"), qsTr("Battery is charging"), "power"); diff --git a/modules/background/DesktopClock.qml b/modules/background/DesktopClock.qml index 6dc6b6b..2de325c 100644 --- a/modules/background/DesktopClock.qml +++ b/modules/background/DesktopClock.qml @@ -12,6 +12,7 @@ Item { anchors.centerIn: parent text: Time.format(Config.services.useTwelveHourClock ? "hh:mm:ss A" : "hh:mm:ss") + font.family: Appearance.font.family.clock font.pointSize: Appearance.font.size.extraLarge font.bold: true } diff --git a/modules/bar/Bar.qml b/modules/bar/Bar.qml index 32e362b..1dceea4 100644 --- a/modules/bar/Bar.qml +++ b/modules/bar/Bar.qml @@ -158,12 +158,6 @@ ColumnLayout { sourceComponent: StatusIcons {} } } - DelegateChoice { - roleValue: "settings" - delegate: WrappedLoader { - sourceComponent: SettingsIcon {} - } - } DelegateChoice { roleValue: "power" delegate: WrappedLoader { diff --git a/modules/controlcenter/WindowFactory.qml b/modules/controlcenter/WindowFactory.qml index 14d85da..c5b7535 100644 --- a/modules/controlcenter/WindowFactory.qml +++ b/modules/controlcenter/WindowFactory.qml @@ -38,7 +38,7 @@ Singleton { implicitWidth: cc.implicitWidth implicitHeight: cc.implicitHeight - title: qsTr("Settings") + title: qsTr("Caelestia Settings - %1").arg(cc.active.slice(0, 1).toUpperCase() + cc.active.slice(1)) ControlCenter { id: cc diff --git a/modules/controlcenter/WindowTitle.qml b/modules/controlcenter/WindowTitle.qml index b65746b..fb71608 100644 --- a/modules/controlcenter/WindowTitle.qml +++ b/modules/controlcenter/WindowTitle.qml @@ -19,7 +19,7 @@ StyledRect { anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom - text: qsTr("Settings") + text: qsTr("Caelestia Settings - %1").arg(root.session.active) font.capitalization: Font.Capitalize font.pointSize: Appearance.font.size.larger font.weight: 500 -- cgit v1.2.3-freya From 47dfcf4baf42c33ca5ee78dd4c0877e894aec1fb Mon Sep 17 00:00:00 2001 From: ATMDA Date: Mon, 10 Nov 2025 00:46:45 -0500 Subject: launcher: python execution like calculator functionality --- config/LauncherConfig.qml | 8 +++ modules/launcher/AppList.qml | 18 ++++- modules/launcher/Content.qml | 2 +- modules/launcher/items/PythonItem.qml | 124 ++++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 modules/launcher/items/PythonItem.qml (limited to 'config') diff --git a/config/LauncherConfig.qml b/config/LauncherConfig.qml index 9d9c50c..30b3e8b 100644 --- a/config/LauncherConfig.qml +++ b/config/LauncherConfig.qml @@ -38,6 +38,14 @@ JsonObject { enabled: true, dangerous: false }, + { + name: "Python", + icon: "code", + description: "Execute Python one-liners", + command: ["autocomplete", "python"], + enabled: true, + dangerous: false + }, { name: "Scheme", icon: "palette", diff --git a/modules/launcher/AppList.qml b/modules/launcher/AppList.qml index 7f7b843..6217237 100644 --- a/modules/launcher/AppList.qml +++ b/modules/launcher/AppList.qml @@ -52,7 +52,7 @@ StyledListView { const text = search.text; const prefix = Config.launcher.actionPrefix; if (text.startsWith(prefix)) { - for (const action of ["calc", "scheme", "variant"]) + for (const action of ["calc", "python", "scheme", "variant"]) if (text.startsWith(`${prefix}${action} `)) return action; @@ -92,6 +92,14 @@ StyledListView { root.delegate: calcItem } }, + State { + name: "python" + + PropertyChanges { + model.values: [0] + root.delegate: pythonItem + } + }, State { name: "scheme" @@ -239,6 +247,14 @@ StyledListView { } } + Component { + id: pythonItem + + PythonItem { + list: root + } + } + Component { id: schemeItem diff --git a/modules/launcher/Content.qml b/modules/launcher/Content.qml index f674569..3a90a74 100644 --- a/modules/launcher/Content.qml +++ b/modules/launcher/Content.qml @@ -90,7 +90,7 @@ Item { Wallpapers.setWallpaper(currentItem.modelData.path); root.visibilities.launcher = false; } else if (text.startsWith(Config.launcher.actionPrefix)) { - if (text.startsWith(`${Config.launcher.actionPrefix}calc `)) + if (text.startsWith(`${Config.launcher.actionPrefix}calc `) || text.startsWith(`${Config.launcher.actionPrefix}python `)) currentItem.onClicked(); else currentItem.modelData.onClicked(list.currentList); diff --git a/modules/launcher/items/PythonItem.qml b/modules/launcher/items/PythonItem.qml new file mode 100644 index 0000000..8384e71 --- /dev/null +++ b/modules/launcher/items/PythonItem.qml @@ -0,0 +1,124 @@ +import qs.components +import qs.services +import qs.config +import Quickshell +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property var list + readonly property string code: list.search.text.slice(`${Config.launcher.actionPrefix}python `.length) + + function onClicked(): void { + // Execute Python code and copy result to clipboard + // Escape single quotes in code for shell safety + const escapedCode = root.code.replace(/'/g, "'\\''"); + Quickshell.execDetached(["sh", "-c", `python3 -c '${escapedCode}' 2>&1 | wl-copy`]); + root.list.visibilities.launcher = false; + } + + implicitHeight: Config.launcher.sizes.itemHeight + + anchors.left: parent?.left + anchors.right: parent?.right + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + root.onClicked(); + } + } + + RowLayout { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: Appearance.padding.larger + + spacing: Appearance.spacing.normal + + MaterialIcon { + text: "code" + font.pointSize: Appearance.font.size.extraLarge + Layout.alignment: Qt.AlignVCenter + } + + StyledText { + id: result + + color: { + if (!root.code) + return Colours.palette.m3onSurfaceVariant; + return Colours.palette.m3onSurface; + } + + text: root.code.length > 0 ? qsTr("Press Enter to execute: %1").arg(root.code) : qsTr("Type Python code to execute") + elide: Text.ElideLeft + + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + } + + StyledRect { + color: Colours.palette.m3tertiary + radius: Appearance.rounding.normal + clip: true + + implicitWidth: (stateLayer.containsMouse ? label.implicitWidth + label.anchors.rightMargin : 0) + icon.implicitWidth + Appearance.padding.normal * 2 + implicitHeight: Math.max(label.implicitHeight, icon.implicitHeight) + Appearance.padding.small * 2 + + Layout.alignment: Qt.AlignVCenter + + StateLayer { + id: stateLayer + + color: Colours.palette.m3onTertiary + + function onClicked(): void { + const escapedCode = root.code.replace(/'/g, "'\\''"); + Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.terminal, "fish", "-C", `python3 -i -c '${escapedCode}'`]); + root.list.visibilities.launcher = false; + } + } + + StyledText { + id: label + + anchors.verticalCenter: parent.verticalCenter + anchors.right: icon.left + anchors.rightMargin: Appearance.spacing.small + + text: qsTr("Open in terminal") + color: Colours.palette.m3onTertiary + font.pointSize: Appearance.font.size.normal + + opacity: stateLayer.containsMouse ? 1 : 0 + + Behavior on opacity { + Anim {} + } + } + + MaterialIcon { + id: icon + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: Appearance.padding.normal + + text: "open_in_new" + color: Colours.palette.m3onTertiary + font.pointSize: Appearance.font.size.large + } + + Behavior on implicitWidth { + Anim { + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + } + } +} -- cgit v1.2.3-freya From bd61cbaac5ef765696bfa786dabff977ab6d03e9 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Mon, 10 Nov 2025 14:25:06 -0500 Subject: statusicons: added ethernet when active and popout --- config/BarConfig.qml | 1 + modules/bar/components/StatusIcons.qml | 12 +++ modules/bar/popouts/Content.qml | 5 + modules/bar/popouts/Ethernet.qml | 179 +++++++++++++++++++++++++++++++++ 4 files changed, 197 insertions(+) create mode 100644 modules/bar/popouts/Ethernet.qml (limited to 'config') diff --git a/config/BarConfig.qml b/config/BarConfig.qml index 34819b1..b81d7e9 100644 --- a/config/BarConfig.qml +++ b/config/BarConfig.qml @@ -90,6 +90,7 @@ JsonObject { property bool showMicrophone: false property bool showKbLayout: false property bool showNetwork: true + property bool showEthernet: true property bool showBluetooth: true property bool showBattery: true property bool showLockStatus: true diff --git a/modules/bar/components/StatusIcons.qml b/modules/bar/components/StatusIcons.qml index 27fd9f8..6113539 100644 --- a/modules/bar/components/StatusIcons.qml +++ b/modules/bar/components/StatusIcons.qml @@ -152,6 +152,18 @@ StyledRect { } } + // Ethernet icon + WrappedLoader { + name: "ethernet" + active: Config.bar.status.showEthernet && Network.activeEthernet + + sourceComponent: MaterialIcon { + animate: true + text: "cable" + color: root.colour + } + } + // Bluetooth section WrappedLoader { Layout.preferredHeight: implicitHeight diff --git a/modules/bar/popouts/Content.qml b/modules/bar/popouts/Content.qml index e3f569d..f8ef549 100644 --- a/modules/bar/popouts/Content.qml +++ b/modules/bar/popouts/Content.qml @@ -36,6 +36,11 @@ Item { sourceComponent: Network {} } + Popout { + name: "ethernet" + sourceComponent: Ethernet {} + } + Popout { name: "bluetooth" sourceComponent: Bluetooth { diff --git a/modules/bar/popouts/Ethernet.qml b/modules/bar/popouts/Ethernet.qml new file mode 100644 index 0000000..b4a753c --- /dev/null +++ b/modules/bar/popouts/Ethernet.qml @@ -0,0 +1,179 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + spacing: Appearance.spacing.small + width: Config.bar.sizes.networkWidth + + StyledText { + Layout.topMargin: Appearance.padding.normal + Layout.rightMargin: Appearance.padding.small + text: qsTr("Ethernet") + font.weight: 500 + } + + StyledText { + Layout.topMargin: Appearance.spacing.small + Layout.rightMargin: Appearance.padding.small + text: qsTr("%1 devices available").arg(Network.ethernetDeviceCount || Network.ethernetDevices.length) + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + + Repeater { + model: ScriptModel { + values: [...Network.ethernetDevices].sort((a, b) => { + if (a.connected !== b.connected) + return b.connected - a.connected; + return (a.interface || "").localeCompare(b.interface || ""); + }).slice(0, 8) + } + + RowLayout { + id: ethernetItem + + required property var modelData + readonly property bool loading: false + + Layout.fillWidth: true + Layout.rightMargin: Appearance.padding.small + spacing: Appearance.spacing.small + + opacity: 0 + scale: 0.7 + + Component.onCompleted: { + opacity = 1; + scale = 1; + } + + Behavior on opacity { + Anim {} + } + + Behavior on scale { + Anim {} + } + + MaterialIcon { + text: "cable" + color: ethernetItem.modelData.connected ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant + } + + StyledText { + Layout.leftMargin: Appearance.spacing.small / 2 + Layout.rightMargin: Appearance.spacing.small / 2 + Layout.fillWidth: true + text: ethernetItem.modelData.interface || qsTr("Unknown") + elide: Text.ElideRight + font.weight: ethernetItem.modelData.connected ? 500 : 400 + color: ethernetItem.modelData.connected ? Colours.palette.m3primary : Colours.palette.m3onSurface + } + + StyledRect { + id: connectBtn + + implicitWidth: implicitHeight + implicitHeight: connectIcon.implicitHeight + Appearance.padding.small + + radius: Appearance.rounding.full + color: Qt.alpha(Colours.palette.m3primary, ethernetItem.modelData.connected ? 1 : 0) + + CircularIndicator { + anchors.fill: parent + running: ethernetItem.loading + } + + StateLayer { + color: ethernetItem.modelData.connected ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + disabled: ethernetItem.loading + + function onClicked(): void { + if (ethernetItem.modelData.connected && ethernetItem.modelData.connection) { + Network.disconnectEthernet(ethernetItem.modelData.connection); + } else { + Network.connectEthernet(ethernetItem.modelData.connection || "", ethernetItem.modelData.interface || ""); + } + } + } + + MaterialIcon { + id: connectIcon + + anchors.centerIn: parent + animate: true + text: ethernetItem.modelData.connected ? "link_off" : "link" + color: ethernetItem.modelData.connected ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + opacity: ethernetItem.loading ? 0 : 1 + + Behavior on opacity { + Anim {} + } + } + } + } + } + + StyledRect { + Layout.topMargin: Appearance.spacing.small + Layout.fillWidth: true + implicitHeight: refreshBtn.implicitHeight + Appearance.padding.small * 2 + + radius: Appearance.rounding.full + color: Colours.palette.m3primaryContainer + + StateLayer { + color: Colours.palette.m3onPrimaryContainer + disabled: Network.ethernetProcessRunning + + function onClicked(): void { + Network.getEthernetDevices(); + } + } + + RowLayout { + id: refreshBtn + + anchors.centerIn: parent + spacing: Appearance.spacing.small + opacity: Network.ethernetProcessRunning ? 0 : 1 + + MaterialIcon { + id: refreshIcon + + animate: true + text: "refresh" + color: Colours.palette.m3onPrimaryContainer + } + + StyledText { + text: qsTr("Refresh devices") + color: Colours.palette.m3onPrimaryContainer + } + + Behavior on opacity { + Anim {} + } + } + + CircularIndicator { + anchors.centerIn: parent + strokeWidth: Appearance.padding.small / 2 + bgColour: "transparent" + implicitHeight: parent.implicitHeight - Appearance.padding.smaller * 2 + running: Network.ethernetProcessRunning + } + } +} + -- cgit v1.2.3-freya From 2ebdba6cc4a6b3fe6acd3498c774d2ed8678eb2a Mon Sep 17 00:00:00 2001 From: ATMDA Date: Thu, 13 Nov 2025 13:57:35 -0500 Subject: launcher: reverted python launcher item to not exist, changes back to c0ea060f --- config/LauncherConfig.qml | 8 --- modules/launcher/AppList.qml | 18 +---- modules/launcher/Content.qml | 2 +- modules/launcher/items/PythonItem.qml | 124 ---------------------------------- 4 files changed, 2 insertions(+), 150 deletions(-) delete mode 100644 modules/launcher/items/PythonItem.qml (limited to 'config') diff --git a/config/LauncherConfig.qml b/config/LauncherConfig.qml index 30b3e8b..9d9c50c 100644 --- a/config/LauncherConfig.qml +++ b/config/LauncherConfig.qml @@ -38,14 +38,6 @@ JsonObject { enabled: true, dangerous: false }, - { - name: "Python", - icon: "code", - description: "Execute Python one-liners", - command: ["autocomplete", "python"], - enabled: true, - dangerous: false - }, { name: "Scheme", icon: "palette", diff --git a/modules/launcher/AppList.qml b/modules/launcher/AppList.qml index 6217237..7f7b843 100644 --- a/modules/launcher/AppList.qml +++ b/modules/launcher/AppList.qml @@ -52,7 +52,7 @@ StyledListView { const text = search.text; const prefix = Config.launcher.actionPrefix; if (text.startsWith(prefix)) { - for (const action of ["calc", "python", "scheme", "variant"]) + for (const action of ["calc", "scheme", "variant"]) if (text.startsWith(`${prefix}${action} `)) return action; @@ -92,14 +92,6 @@ StyledListView { root.delegate: calcItem } }, - State { - name: "python" - - PropertyChanges { - model.values: [0] - root.delegate: pythonItem - } - }, State { name: "scheme" @@ -247,14 +239,6 @@ StyledListView { } } - Component { - id: pythonItem - - PythonItem { - list: root - } - } - Component { id: schemeItem diff --git a/modules/launcher/Content.qml b/modules/launcher/Content.qml index 3a90a74..f674569 100644 --- a/modules/launcher/Content.qml +++ b/modules/launcher/Content.qml @@ -90,7 +90,7 @@ Item { Wallpapers.setWallpaper(currentItem.modelData.path); root.visibilities.launcher = false; } else if (text.startsWith(Config.launcher.actionPrefix)) { - if (text.startsWith(`${Config.launcher.actionPrefix}calc `) || text.startsWith(`${Config.launcher.actionPrefix}python `)) + if (text.startsWith(`${Config.launcher.actionPrefix}calc `)) currentItem.onClicked(); else currentItem.modelData.onClicked(list.currentList); diff --git a/modules/launcher/items/PythonItem.qml b/modules/launcher/items/PythonItem.qml deleted file mode 100644 index 8384e71..0000000 --- a/modules/launcher/items/PythonItem.qml +++ /dev/null @@ -1,124 +0,0 @@ -import qs.components -import qs.services -import qs.config -import Quickshell -import QtQuick -import QtQuick.Layouts - -Item { - id: root - - required property var list - readonly property string code: list.search.text.slice(`${Config.launcher.actionPrefix}python `.length) - - function onClicked(): void { - // Execute Python code and copy result to clipboard - // Escape single quotes in code for shell safety - const escapedCode = root.code.replace(/'/g, "'\\''"); - Quickshell.execDetached(["sh", "-c", `python3 -c '${escapedCode}' 2>&1 | wl-copy`]); - root.list.visibilities.launcher = false; - } - - implicitHeight: Config.launcher.sizes.itemHeight - - anchors.left: parent?.left - anchors.right: parent?.right - - StateLayer { - radius: Appearance.rounding.normal - - function onClicked(): void { - root.onClicked(); - } - } - - RowLayout { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.margins: Appearance.padding.larger - - spacing: Appearance.spacing.normal - - MaterialIcon { - text: "code" - font.pointSize: Appearance.font.size.extraLarge - Layout.alignment: Qt.AlignVCenter - } - - StyledText { - id: result - - color: { - if (!root.code) - return Colours.palette.m3onSurfaceVariant; - return Colours.palette.m3onSurface; - } - - text: root.code.length > 0 ? qsTr("Press Enter to execute: %1").arg(root.code) : qsTr("Type Python code to execute") - elide: Text.ElideLeft - - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - } - - StyledRect { - color: Colours.palette.m3tertiary - radius: Appearance.rounding.normal - clip: true - - implicitWidth: (stateLayer.containsMouse ? label.implicitWidth + label.anchors.rightMargin : 0) + icon.implicitWidth + Appearance.padding.normal * 2 - implicitHeight: Math.max(label.implicitHeight, icon.implicitHeight) + Appearance.padding.small * 2 - - Layout.alignment: Qt.AlignVCenter - - StateLayer { - id: stateLayer - - color: Colours.palette.m3onTertiary - - function onClicked(): void { - const escapedCode = root.code.replace(/'/g, "'\\''"); - Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.terminal, "fish", "-C", `python3 -i -c '${escapedCode}'`]); - root.list.visibilities.launcher = false; - } - } - - StyledText { - id: label - - anchors.verticalCenter: parent.verticalCenter - anchors.right: icon.left - anchors.rightMargin: Appearance.spacing.small - - text: qsTr("Open in terminal") - color: Colours.palette.m3onTertiary - font.pointSize: Appearance.font.size.normal - - opacity: stateLayer.containsMouse ? 1 : 0 - - Behavior on opacity { - Anim {} - } - } - - MaterialIcon { - id: icon - - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: Appearance.padding.normal - - text: "open_in_new" - color: Colours.palette.m3onTertiary - font.pointSize: Appearance.font.size.large - } - - Behavior on implicitWidth { - Anim { - easing.bezierCurve: Appearance.anim.curves.emphasized - } - } - } - } -} -- cgit v1.2.3-freya From 8d8afba79a58f917906c2457708950d050fa30e7 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Thu, 13 Nov 2025 21:40:50 -0500 Subject: tray: removed ethernet config options (network covers it) --- README.md | 1 - config/BarConfig.qml | 1 - modules/bar/components/StatusIcons.qml | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) (limited to 'config') diff --git a/README.md b/README.md index 112a174..a2322eb 100644 --- a/README.md +++ b/README.md @@ -372,7 +372,6 @@ default, you must create it manually. "showAudio": false, "showBattery": true, "showBluetooth": true, - "showEthernet": true, "showKbLayout": false, "showMicrophone": false, "showNetwork": true, diff --git a/config/BarConfig.qml b/config/BarConfig.qml index b81d7e9..34819b1 100644 --- a/config/BarConfig.qml +++ b/config/BarConfig.qml @@ -90,7 +90,6 @@ JsonObject { property bool showMicrophone: false property bool showKbLayout: false property bool showNetwork: true - property bool showEthernet: true property bool showBluetooth: true property bool showBattery: true property bool showLockStatus: true diff --git a/modules/bar/components/StatusIcons.qml b/modules/bar/components/StatusIcons.qml index 1afa616..80e8fe0 100644 --- a/modules/bar/components/StatusIcons.qml +++ b/modules/bar/components/StatusIcons.qml @@ -155,7 +155,7 @@ StyledRect { // Ethernet icon WrappedLoader { name: "network" - active: Config.bar.status.showEthernet && Nmcli.activeEthernet + active: Config.bar.status.showNetwork && Nmcli.activeEthernet sourceComponent: MaterialIcon { animate: true -- cgit v1.2.3-freya From cc74308800af5146791e953ab25a270fec50fdf3 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Sat, 15 Nov 2025 19:40:19 -0500 Subject: config: added save to singleton, updated relevant settings panes --- config/Config.qml | 381 ++++++++++++++++++++- .../controlcenter/appearance/AppearancePane.qml | 3 + 2 files changed, 382 insertions(+), 2 deletions(-) (limited to 'config') diff --git a/config/Config.qml b/config/Config.qml index 267a184..3756043 100644 --- a/config/Config.qml +++ b/config/Config.qml @@ -4,6 +4,7 @@ import qs.utils import Caelestia import Quickshell import Quickshell.Io +import QtQuick Singleton { id: root @@ -26,16 +27,392 @@ Singleton { property alias services: adapter.services property alias paths: adapter.paths + // Public save function - call this to persist config changes + function save(): void { + saveTimer.restart(); + } + ElapsedTimer { id: timer } + Timer { + id: saveTimer + + interval: 500 + onTriggered: { + try { + // Parse current config to preserve structure and comments if possible + let config = {}; + try { + config = JSON.parse(fileView.text()); + } catch (e) { + // If parsing fails, start with empty object + config = {}; + } + + // Update config with current values + config = serializeConfig(); + + // Save to file with pretty printing + fileView.setText(JSON.stringify(config, null, 2)); + } catch (e) { + Toaster.toast(qsTr("Failed to serialize config"), e.message, "settings_alert", Toast.Error); + } + } + } + + // Helper function to serialize the config object + function serializeConfig(): var { + return { + appearance: serializeAppearance(), + general: serializeGeneral(), + background: serializeBackground(), + bar: serializeBar(), + border: serializeBorder(), + dashboard: serializeDashboard(), + controlCenter: serializeControlCenter(), + launcher: serializeLauncher(), + notifs: serializeNotifs(), + osd: serializeOsd(), + session: serializeSession(), + winfo: serializeWinfo(), + lock: serializeLock(), + utilities: serializeUtilities(), + sidebar: serializeSidebar(), + services: serializeServices(), + paths: serializePaths() + }; + } + + function serializeAppearance(): var { + return { + rounding: { scale: appearance.rounding.scale }, + spacing: { scale: appearance.spacing.scale }, + padding: { scale: appearance.padding.scale }, + font: { + family: { + sans: appearance.font.family.sans, + mono: appearance.font.family.mono, + material: appearance.font.family.material, + clock: appearance.font.family.clock + }, + size: { scale: appearance.font.size.scale } + }, + anim: { + durations: { scale: appearance.anim.durations.scale } + }, + transparency: { + enabled: appearance.transparency.enabled, + base: appearance.transparency.base, + layers: appearance.transparency.layers + } + }; + } + + function serializeGeneral(): var { + return { + apps: { + terminal: general.apps.terminal, + audio: general.apps.audio, + playback: general.apps.playback, + explorer: general.apps.explorer + }, + idle: { + lockBeforeSleep: general.idle.lockBeforeSleep, + inhibitWhenAudio: general.idle.inhibitWhenAudio, + timeouts: general.idle.timeouts + }, + battery: { + warnLevels: general.battery.warnLevels, + criticalLevel: general.battery.criticalLevel + } + }; + } + + function serializeBackground(): var { + return { + enabled: background.enabled, + desktopClock: { + enabled: background.desktopClock.enabled + }, + visualiser: { + enabled: background.visualiser.enabled, + autoHide: background.visualiser.autoHide, + blur: background.visualiser.blur, + rounding: background.visualiser.rounding, + spacing: background.visualiser.spacing + } + }; + } + + function serializeBar(): var { + return { + persistent: bar.persistent, + showOnHover: bar.showOnHover, + dragThreshold: bar.dragThreshold, + scrollActions: { + workspaces: bar.scrollActions.workspaces, + volume: bar.scrollActions.volume, + brightness: bar.scrollActions.brightness + }, + popouts: { + activeWindow: bar.popouts.activeWindow, + tray: bar.popouts.tray, + statusIcons: bar.popouts.statusIcons + }, + workspaces: { + shown: bar.workspaces.shown, + activeIndicator: bar.workspaces.activeIndicator, + occupiedBg: bar.workspaces.occupiedBg, + showWindows: bar.workspaces.showWindows, + showWindowsOnSpecialWorkspaces: bar.workspaces.showWindowsOnSpecialWorkspaces, + activeTrail: bar.workspaces.activeTrail, + perMonitorWorkspaces: bar.workspaces.perMonitorWorkspaces, + label: bar.workspaces.label, + occupiedLabel: bar.workspaces.occupiedLabel, + activeLabel: bar.workspaces.activeLabel, + capitalisation: bar.workspaces.capitalisation, + specialWorkspaceIcons: bar.workspaces.specialWorkspaceIcons + }, + tray: { + background: bar.tray.background, + recolour: bar.tray.recolour, + compact: bar.tray.compact, + iconSubs: bar.tray.iconSubs + }, + status: { + showAudio: bar.status.showAudio, + showMicrophone: bar.status.showMicrophone, + showKbLayout: bar.status.showKbLayout, + showNetwork: bar.status.showNetwork, + showBluetooth: bar.status.showBluetooth, + showBattery: bar.status.showBattery, + showLockStatus: bar.status.showLockStatus + }, + clock: { + showIcon: bar.clock.showIcon + }, + sizes: { + innerWidth: bar.sizes.innerWidth, + windowPreviewSize: bar.sizes.windowPreviewSize, + trayMenuWidth: bar.sizes.trayMenuWidth, + batteryWidth: bar.sizes.batteryWidth, + networkWidth: bar.sizes.networkWidth + }, + entries: bar.entries + }; + } + + function serializeBorder(): var { + return { + thickness: border.thickness, + rounding: border.rounding + }; + } + + function serializeDashboard(): var { + return { + enabled: dashboard.enabled, + showOnHover: dashboard.showOnHover, + mediaUpdateInterval: dashboard.mediaUpdateInterval, + dragThreshold: dashboard.dragThreshold, + sizes: { + tabIndicatorHeight: dashboard.sizes.tabIndicatorHeight, + tabIndicatorSpacing: dashboard.sizes.tabIndicatorSpacing, + infoWidth: dashboard.sizes.infoWidth, + infoIconSize: dashboard.sizes.infoIconSize, + dateTimeWidth: dashboard.sizes.dateTimeWidth, + mediaWidth: dashboard.sizes.mediaWidth, + mediaProgressSweep: dashboard.sizes.mediaProgressSweep, + mediaProgressThickness: dashboard.sizes.mediaProgressThickness, + resourceProgessThickness: dashboard.sizes.resourceProgessThickness, + weatherWidth: dashboard.sizes.weatherWidth, + mediaCoverArtSize: dashboard.sizes.mediaCoverArtSize, + mediaVisualiserSize: dashboard.sizes.mediaVisualiserSize, + resourceSize: dashboard.sizes.resourceSize + } + }; + } + + function serializeControlCenter(): var { + return { + sizes: { + heightMult: controlCenter.sizes.heightMult, + ratio: controlCenter.sizes.ratio + } + }; + } + + function serializeLauncher(): var { + return { + enabled: launcher.enabled, + showOnHover: launcher.showOnHover, + maxShown: launcher.maxShown, + maxWallpapers: launcher.maxWallpapers, + specialPrefix: launcher.specialPrefix, + actionPrefix: launcher.actionPrefix, + enableDangerousActions: launcher.enableDangerousActions, + dragThreshold: launcher.dragThreshold, + vimKeybinds: launcher.vimKeybinds, + hiddenApps: launcher.hiddenApps, + useFuzzy: { + apps: launcher.useFuzzy.apps, + actions: launcher.useFuzzy.actions, + schemes: launcher.useFuzzy.schemes, + variants: launcher.useFuzzy.variants, + wallpapers: launcher.useFuzzy.wallpapers + }, + sizes: { + itemWidth: launcher.sizes.itemWidth, + itemHeight: launcher.sizes.itemHeight, + wallpaperWidth: launcher.sizes.wallpaperWidth, + wallpaperHeight: launcher.sizes.wallpaperHeight + }, + actions: launcher.actions + }; + } + + function serializeNotifs(): var { + return { + expire: notifs.expire, + defaultExpireTimeout: notifs.defaultExpireTimeout, + clearThreshold: notifs.clearThreshold, + expandThreshold: notifs.expandThreshold, + actionOnClick: notifs.actionOnClick, + groupPreviewNum: notifs.groupPreviewNum, + sizes: { + width: notifs.sizes.width, + image: notifs.sizes.image, + badge: notifs.sizes.badge + } + }; + } + + function serializeOsd(): var { + return { + enabled: osd.enabled, + hideDelay: osd.hideDelay, + enableBrightness: osd.enableBrightness, + enableMicrophone: osd.enableMicrophone, + sizes: { + sliderWidth: osd.sizes.sliderWidth, + sliderHeight: osd.sizes.sliderHeight + } + }; + } + + function serializeSession(): var { + return { + enabled: session.enabled, + dragThreshold: session.dragThreshold, + vimKeybinds: session.vimKeybinds, + commands: { + logout: session.commands.logout, + shutdown: session.commands.shutdown, + hibernate: session.commands.hibernate, + reboot: session.commands.reboot + }, + sizes: { + button: session.sizes.button + } + }; + } + + function serializeWinfo(): var { + return { + sizes: { + heightMult: winfo.sizes.heightMult, + detailsWidth: winfo.sizes.detailsWidth + } + }; + } + + function serializeLock(): var { + return { + recolourLogo: lock.recolourLogo, + enableFprint: lock.enableFprint, + maxFprintTries: lock.maxFprintTries, + sizes: { + heightMult: lock.sizes.heightMult, + ratio: lock.sizes.ratio, + centerWidth: lock.sizes.centerWidth + } + }; + } + + function serializeUtilities(): var { + return { + enabled: utilities.enabled, + maxToasts: utilities.maxToasts, + sizes: { + width: utilities.sizes.width, + toastWidth: utilities.sizes.toastWidth + }, + toasts: { + configLoaded: utilities.toasts.configLoaded, + chargingChanged: utilities.toasts.chargingChanged, + gameModeChanged: utilities.toasts.gameModeChanged, + dndChanged: utilities.toasts.dndChanged, + audioOutputChanged: utilities.toasts.audioOutputChanged, + audioInputChanged: utilities.toasts.audioInputChanged, + capsLockChanged: utilities.toasts.capsLockChanged, + numLockChanged: utilities.toasts.numLockChanged, + kbLayoutChanged: utilities.toasts.kbLayoutChanged, + vpnChanged: utilities.toasts.vpnChanged, + nowPlaying: utilities.toasts.nowPlaying + }, + vpn: { + enabled: utilities.vpn.enabled, + provider: utilities.vpn.provider + } + }; + } + + function serializeSidebar(): var { + return { + enabled: sidebar.enabled, + dragThreshold: sidebar.dragThreshold, + sizes: { + width: sidebar.sizes.width + } + }; + } + + function serializeServices(): var { + return { + weatherLocation: services.weatherLocation, + useFahrenheit: services.useFahrenheit, + useTwelveHourClock: services.useTwelveHourClock, + gpuType: services.gpuType, + visualiserBars: services.visualiserBars, + audioIncrement: services.audioIncrement, + maxVolume: services.maxVolume, + smartScheme: services.smartScheme, + defaultPlayer: services.defaultPlayer, + playerAliases: services.playerAliases + }; + } + + function serializePaths(): var { + return { + wallpaperDir: paths.wallpaperDir, + sessionGif: paths.sessionGif, + mediaGif: paths.mediaGif + }; + } + FileView { + id: fileView + path: `${Paths.config}/shell.json` watchChanges: true onFileChanged: { - timer.restart(); - reload(); + // Prevent reload loop - don't reload if we just saved + if (!saveTimer.running) { + timer.restart(); + reload(); + } } onLoaded: { try { diff --git a/modules/controlcenter/appearance/AppearancePane.qml b/modules/controlcenter/appearance/AppearancePane.qml index 388fc88..22e5580 100644 --- a/modules/controlcenter/appearance/AppearancePane.qml +++ b/modules/controlcenter/appearance/AppearancePane.qml @@ -84,6 +84,9 @@ RowLayout { // Update border Config.border.rounding = root.borderRounding; Config.border.thickness = root.borderThickness; + + // Persist changes to disk + Config.save(); } Item { -- cgit v1.2.3-freya From 0d57edcade29fa1da2eef510dc83d5bb26528d57 Mon Sep 17 00:00:00 2001 From: ATMDA Date: Sun, 16 Nov 2025 09:03:16 -0500 Subject: config: 0ms bug on save corrected --- config/Config.qml | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'config') diff --git a/config/Config.qml b/config/Config.qml index 3756043..b875eef 100644 --- a/config/Config.qml +++ b/config/Config.qml @@ -30,8 +30,12 @@ Singleton { // Public save function - call this to persist config changes function save(): void { saveTimer.restart(); + recentlySaved = true; + recentSaveCooldown.restart(); } + property bool recentlySaved: false + ElapsedTimer { id: timer } @@ -41,6 +45,7 @@ Singleton { interval: 500 onTriggered: { + timer.restart(); try { // Parse current config to preserve structure and comments if possible let config = {}; @@ -62,6 +67,15 @@ Singleton { } } + Timer { + id: recentSaveCooldown + + interval: 2000 + onTriggered: { + recentlySaved = false; + } + } + // Helper function to serialize the config object function serializeConfig(): var { return { @@ -409,16 +423,24 @@ Singleton { watchChanges: true onFileChanged: { // Prevent reload loop - don't reload if we just saved - if (!saveTimer.running) { + if (!recentlySaved) { timer.restart(); reload(); + } else { + // Self-initiated save - reload without toast + reload(); } } onLoaded: { try { JSON.parse(text()); - if (adapter.utilities.toasts.configLoaded) - Toaster.toast(qsTr("Config loaded"), qsTr("Config loaded in %1ms").arg(timer.elapsedMs()), "rule_settings"); + const elapsed = timer.elapsedMs(); + // Only show toast for external changes (not our own saves) and when elapsed time is meaningful + if (adapter.utilities.toasts.configLoaded && !recentlySaved && elapsed > 0) { + Toaster.toast(qsTr("Config loaded"), qsTr("Config loaded in %1ms").arg(elapsed), "rule_settings"); + } else if (adapter.utilities.toasts.configLoaded && recentlySaved && elapsed > 0) { + Toaster.toast(qsTr("Config saved"), qsTr("Config reloaded in %1ms").arg(elapsed), "rule_settings"); + } } catch (e) { Toaster.toast(qsTr("Failed to load config"), e.message, "settings_alert", Toast.Error); } -- cgit v1.2.3-freya