summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/controlcenter/NavRail.qml5
-rw-r--r--modules/controlcenter/Panes.qml8
-rw-r--r--modules/controlcenter/Session.qml2
-rw-r--r--modules/controlcenter/taskbar/TaskbarPane.qml402
4 files changed, 416 insertions, 1 deletions
diff --git a/modules/controlcenter/NavRail.qml b/modules/controlcenter/NavRail.qml
index b4fbf94..1f8c6b3 100644
--- a/modules/controlcenter/NavRail.qml
+++ b/modules/controlcenter/NavRail.qml
@@ -181,6 +181,11 @@ Item {
icon: "palette"
label: "appearance"
}
+
+ NavItem {
+ icon: "task_alt"
+ label: "taskbar"
+ }
}
component NavItem: Item {
diff --git a/modules/controlcenter/Panes.qml b/modules/controlcenter/Panes.qml
index 4f4a337..b30bcf2 100644
--- a/modules/controlcenter/Panes.qml
+++ b/modules/controlcenter/Panes.qml
@@ -5,6 +5,7 @@ import "bluetooth"
import "network"
import "audio"
import "appearance"
+import "taskbar"
import qs.components
import qs.services
import qs.config
@@ -60,6 +61,13 @@ ClippingRectangle {
}
}
+ Pane {
+ index: 5
+ sourceComponent: TaskbarPane {
+ session: root.session
+ }
+ }
+
Behavior on y {
Anim {}
}
diff --git a/modules/controlcenter/Session.qml b/modules/controlcenter/Session.qml
index f7c07e4..cf31ec3 100644
--- a/modules/controlcenter/Session.qml
+++ b/modules/controlcenter/Session.qml
@@ -2,7 +2,7 @@ import Quickshell.Bluetooth
import QtQuick
QtObject {
- readonly property list<string> panes: ["ethernet", "wireless", "bluetooth", "audio", "appearance"]
+ readonly property list<string> panes: ["ethernet", "wireless", "bluetooth", "audio", "appearance", "taskbar"]
required property var root
property bool floating: false
diff --git a/modules/controlcenter/taskbar/TaskbarPane.qml b/modules/controlcenter/taskbar/TaskbarPane.qml
new file mode 100644
index 0000000..a367635
--- /dev/null
+++ b/modules/controlcenter/taskbar/TaskbarPane.qml
@@ -0,0 +1,402 @@
+pragma ComponentBehavior: Bound
+
+import ".."
+import qs.components
+import qs.components.controls
+import qs.components.effects
+import qs.components.containers
+import qs.services
+import qs.config
+import qs.utils
+import Quickshell
+import Quickshell.Io
+import QtQuick
+import QtQuick.Layouts
+
+RowLayout {
+ id: root
+
+ required property Session session
+
+ anchors.fill: parent
+
+ spacing: 0
+
+ FileView {
+ id: configFile
+
+ path: `${Paths.config}/shell.json`
+ watchChanges: true
+
+ onLoaded: {
+ try {
+ const config = JSON.parse(text());
+ updateFromConfig(config);
+ } catch (e) {
+ console.error("Failed to parse config:", e);
+ }
+ }
+ }
+
+ function updateFromConfig(config) {
+ // Update clock toggle
+ if (config.bar && config.bar.clock) {
+ clockShowIconSwitch.checked = config.bar.clock.showIcon !== false;
+ }
+
+ // Update entries
+ if (config.bar && config.bar.entries) {
+ entriesModel.clear();
+ for (const entry of config.bar.entries) {
+ entriesModel.append({
+ id: entry.id,
+ enabled: entry.enabled !== false
+ });
+ }
+ }
+ }
+
+ function saveConfig(entryIndex, entryEnabled) {
+ if (!configFile.loaded) {
+ root.lastSaveStatus = "Error: Config file not loaded yet";
+ root.debugInfo = "Config file not loaded yet, cannot save";
+ return;
+ }
+
+ try {
+ const config = JSON.parse(configFile.text());
+
+ // Update clock setting (same simple approach - read directly from the switch)
+ if (!config.bar) config.bar = {};
+ if (!config.bar.clock) config.bar.clock = {};
+ config.bar.clock.showIcon = clockShowIconSwitch.checked;
+
+ // Update entries from the model (same approach as clock - use provided value if available)
+ if (!config.bar.entries) config.bar.entries = [];
+ config.bar.entries = [];
+
+ let debugInfo = `saveConfig called\n`;
+ debugInfo += `entryIndex: ${entryIndex}\n`;
+ debugInfo += `entryEnabled: ${entryEnabled}\n`;
+ debugInfo += `entriesModel.count: ${entriesModel.count}\n\n`;
+
+ for (let i = 0; i < entriesModel.count; i++) {
+ const entry = entriesModel.get(i);
+ // If this is the entry being updated, use the provided value (same as clock toggle reads from switch)
+ // Otherwise use the value from the model
+ let enabled = entry.enabled;
+ if (entryIndex !== undefined && i === entryIndex) {
+ enabled = entryEnabled;
+ debugInfo += `Entry ${i} (${entry.id}): Using provided value = ${entryEnabled}\n`;
+ } else {
+ debugInfo += `Entry ${i} (${entry.id}): Using model value = ${entry.enabled}\n`;
+ }
+ config.bar.entries.push({
+ id: entry.id,
+ enabled: enabled
+ });
+ }
+
+ debugInfo += `\nFinal entries array:\n${JSON.stringify(config.bar.entries, null, 2)}\n`;
+ debugInfo += `\nFinal clock.showIcon: ${config.bar.clock.showIcon}\n`;
+ root.debugInfo = debugInfo;
+
+ // Write back to file using setText (same simple approach that worked for clock)
+ const jsonString = JSON.stringify(config, null, 4);
+ configFile.setText(jsonString);
+ root.lastSaveStatus = `Saved! Entries count: ${config.bar.entries.length}`;
+ } catch (e) {
+ root.lastSaveStatus = `Error: ${e.message}`;
+ root.debugInfo = `Failed to save config:\n${e.message}\n${e.stack}`;
+ }
+ }
+
+ ListModel {
+ id: entriesModel
+ }
+
+ // Debug info
+ property string debugInfo: ""
+ property string lastSaveStatus: ""
+
+ Item {
+ Layout.preferredWidth: Math.floor(parent.width * 0.4)
+ Layout.minimumWidth: 420
+ Layout.fillHeight: true
+
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: Appearance.padding.large + Appearance.padding.normal
+ anchors.leftMargin: Appearance.padding.large
+ anchors.rightMargin: Appearance.padding.large + Appearance.padding.normal / 2
+
+ spacing: Appearance.spacing.small
+
+ RowLayout {
+ spacing: Appearance.spacing.smaller
+
+ StyledText {
+ text: qsTr("Settings")
+ font.pointSize: Appearance.font.size.large
+ font.weight: 500
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.large
+ text: qsTr("Clock")
+ font.pointSize: Appearance.font.size.larger
+ font.weight: 500
+ }
+
+ StyledText {
+ text: qsTr("Clock display settings")
+ color: Colours.palette.m3outline
+ }
+
+ StyledRect {
+ Layout.fillWidth: true
+ implicitHeight: clockRow.implicitHeight + Appearance.padding.large * 2
+
+ radius: Appearance.rounding.normal
+ color: Colours.tPalette.m3surfaceContainer
+
+ RowLayout {
+ id: clockRow
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.margins: Appearance.padding.large
+
+ spacing: Appearance.spacing.normal
+
+ StyledText {
+ Layout.fillWidth: true
+ text: qsTr("Show clock icon")
+ }
+
+ StyledSwitch {
+ id: clockShowIconSwitch
+ checked: true
+ onToggled: {
+ root.saveConfig();
+ }
+ }
+ }
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.large
+ text: qsTr("Taskbar Entries")
+ font.pointSize: Appearance.font.size.larger
+ font.weight: 500
+ }
+
+ StyledText {
+ text: qsTr("Enable or disable taskbar entries")
+ color: Colours.palette.m3outline
+ }
+
+ StyledListView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.topMargin: 0
+
+ model: entriesModel
+ spacing: Appearance.spacing.small / 2
+ clip: true
+
+ StyledScrollBar.vertical: StyledScrollBar {
+ flickable: parent
+ }
+
+ delegate: StyledRect {
+ id: delegate
+ required property string id
+ required property bool enabled
+ required property int index
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ color: Colours.tPalette.m3surfaceContainer
+ radius: Appearance.rounding.normal
+
+ RowLayout {
+ id: entryRow
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.margins: Appearance.padding.normal
+
+ spacing: Appearance.spacing.normal
+
+ StyledText {
+ Layout.fillWidth: true
+ text: id.charAt(0).toUpperCase() + id.slice(1)
+ font.weight: enabled ? 500 : 400
+ }
+
+ StyledSwitch {
+ checked: enabled
+ onToggled: {
+ // Store the values in local variables to ensure they're accessible
+ // Access index from the delegate
+ const entryIndex = delegate.index;
+ const entryEnabled = checked;
+ console.log(`Entry toggle: index=${entryIndex}, checked=${entryEnabled}`);
+ // Update the model first
+ entriesModel.setProperty(entryIndex, "enabled", entryEnabled);
+ // Save immediately with the value directly (same technique as clock toggle)
+ // Clock toggle reads directly from clockShowIconSwitch.checked
+ // We pass the value directly here (same approach)
+ root.saveConfig(entryIndex, entryEnabled);
+ }
+ }
+ }
+
+ implicitHeight: entryRow.implicitHeight + Appearance.padding.normal * 2
+ }
+ }
+ }
+
+ InnerBorder {
+ leftThickness: 0
+ rightThickness: Appearance.padding.normal / 2
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ StyledFlickable {
+ anchors.fill: parent
+ anchors.margins: Appearance.padding.large * 2
+
+ flickableDirection: Flickable.VerticalFlick
+ contentHeight: contentLayout.implicitHeight
+
+ StyledScrollBar.vertical: StyledScrollBar {
+ flickable: parent
+ }
+
+ ColumnLayout {
+ id: contentLayout
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+
+ spacing: Appearance.spacing.normal
+
+ MaterialIcon {
+ Layout.alignment: Qt.AlignHCenter
+ text: "task_alt"
+ font.pointSize: Appearance.font.size.extraLarge * 3
+ font.bold: true
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Taskbar settings")
+ font.pointSize: Appearance.font.size.large
+ font.bold: true
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.large
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Clock")
+ font.pointSize: Appearance.font.size.larger
+ font.weight: 500
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignHCenter
+ text: clockShowIconSwitch.checked ? qsTr("Clock icon enabled") : qsTr("Clock icon disabled")
+ color: Colours.palette.m3outline
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.large
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Taskbar Entries")
+ font.pointSize: Appearance.font.size.larger
+ font.weight: 500
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Configure which entries appear in the taskbar")
+ color: Colours.palette.m3outline
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.large
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Debug Info")
+ font.pointSize: Appearance.font.size.larger
+ font.weight: 500
+ }
+
+ StyledRect {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 200
+ Layout.maximumHeight: 300
+
+ radius: Appearance.rounding.normal
+ color: Colours.tPalette.m3surfaceContainer
+ clip: true
+
+ StyledFlickable {
+ id: debugFlickable
+ anchors.fill: parent
+ anchors.margins: Appearance.padding.normal
+ contentHeight: debugText.implicitHeight
+ clip: true
+
+ StyledScrollBar.vertical: StyledScrollBar {
+ flickable: debugFlickable
+ }
+
+ TextEdit {
+ id: debugText
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ width: parent.width
+
+ text: root.debugInfo || "No debug info yet"
+ font.pointSize: Appearance.font.size.small
+ color: Colours.palette.m3onSurface
+ wrapMode: TextEdit.Wrap
+ readOnly: true
+ selectByMouse: true
+ selectByKeyboard: true
+ }
+ }
+ }
+
+ StyledText {
+ Layout.topMargin: Appearance.spacing.small
+ Layout.alignment: Qt.AlignHCenter
+ text: root.lastSaveStatus || ""
+ font.pointSize: Appearance.font.size.small
+ color: root.lastSaveStatus.includes("Error") ? Colours.palette.m3error : Colours.palette.m3primary
+ }
+ }
+ }
+
+ InnerBorder {
+ leftThickness: Appearance.padding.normal / 2
+ }
+ }
+}
+