From 0a038fa3c9cd246dc7b28e3dde8a98227b4850f6 Mon Sep 17 00:00:00 2001 From: purian23 Date: Wed, 1 Oct 2025 11:49:29 -0400 Subject: [PATCH] Revert "wip binds" This reverts commit 841e55d37f456c50bbb367e67f46693e34a4ef96. --- Modals/Settings/SettingsContent.qml | 9 +- Modals/Settings/SettingsSidebar.qml | 6 +- Modules/Settings/KeybindsTab.qml | 181 ------- Modules/Settings/TimeWeatherTab.qml | 717 ---------------------------- Widgets/ActionEditor.qml | 141 ------ Widgets/KeyCaptureField.qml | 207 -------- Widgets/KeybindRow.qml | 643 ------------------------- 7 files changed, 7 insertions(+), 1897 deletions(-) delete mode 100644 Modules/Settings/KeybindsTab.qml delete mode 100644 Modules/Settings/TimeWeatherTab.qml delete mode 100644 Widgets/ActionEditor.qml delete mode 100644 Widgets/KeyCaptureField.qml delete mode 100644 Widgets/KeybindRow.qml diff --git a/Modals/Settings/SettingsContent.qml b/Modals/Settings/SettingsContent.qml index 5b424c35..3a99d546 100644 --- a/Modals/Settings/SettingsContent.qml +++ b/Modals/Settings/SettingsContent.qml @@ -34,28 +34,27 @@ Item { } Loader { - id: timeWeatherLoader + id: timeLoader anchors.fill: parent active: root.currentIndex === 1 visible: active asynchronous: true - sourceComponent: TimeWeatherTab { + sourceComponent: TimeTab { } } Loader { - id: keybindsLoader + id: weatherLoader anchors.fill: parent active: root.currentIndex === 2 visible: active asynchronous: true - sourceComponent: KeybindsTab { - parentModal: root.parentModal + sourceComponent: WeatherTab { } } diff --git a/Modals/Settings/SettingsSidebar.qml b/Modals/Settings/SettingsSidebar.qml index d60ceb28..48fee320 100644 --- a/Modals/Settings/SettingsSidebar.qml +++ b/Modals/Settings/SettingsSidebar.qml @@ -12,11 +12,11 @@ Rectangle { "text": "Personalization", "icon": "person" }, { - "text": "Time & Weather", + "text": "Time & Date", "icon": "schedule" }, { - "text": "Key Bindings", - "icon": "keyboard" + "text": "Weather", + "icon": "cloud" }, { "text": "Dank Bar", "icon": "toolbar" diff --git a/Modules/Settings/KeybindsTab.qml b/Modules/Settings/KeybindsTab.qml deleted file mode 100644 index 461053f8..00000000 --- a/Modules/Settings/KeybindsTab.qml +++ /dev/null @@ -1,181 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -Item { - id: keybindsTab - - property var parentModal: null - - ListModel { - id: bindingsModel - } - - function addBinding() { - console.log("Adding binding, current count:", bindingsModel.count) - bindingsModel.append({ - token: "", - configType: "dms", - actionName: "", - args: [], - shellCmd: "", - repeatEnabled: true, - cooldownMs: 0, - allowWhenLocked: false, - overlayTitle: "" - }) - console.log("After append, count:", bindingsModel.count) - } - - function removeBinding(index) { - bindingsModel.remove(index) - } - - function exportBindings() { - const lines = [] - for (let i = 0; i < bindingsRepeater.count; i++) { - const item = bindingsRepeater.itemAt(i) - if (item) { - const line = item.toConfigLine() - if (line) { - const existingToken = line.split(" {")[0].trim() - const duplicate = lines.some(l => l.split(" {")[0].trim() === existingToken) - if (duplicate) { - console.warn("Duplicate binding found:", existingToken) - } - lines.push(line) - } - } - } - const block = "binds {\n " + lines.join("\n ") + "\n}\n" - console.log("Exported bindings block:") - console.log(block) - return block - } - - DankFlickable { - anchors.fill: parent - anchors.topMargin: Theme.spacingL - clip: true - contentHeight: mainColumn.height - contentWidth: width - - Column { - id: mainColumn - - width: parent.width - spacing: Theme.spacingL - - StyledRect { - width: parent.width - height: headerSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Row { - id: headerSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - DankIcon { - name: "keyboard" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - addButton.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: "Key Bindings Editor" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: "Configure keyboard shortcuts, mouse bindings, and scroll gestures" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - } - - DankActionButton { - id: addButton - width: 40 - height: 40 - circular: false - iconName: "add" - iconSize: Theme.iconSize - iconColor: Theme.primary - anchors.verticalCenter: parent.verticalCenter - onClicked: keybindsTab.addBinding() - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: "Bindings count: " + bindingsModel.count - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - visible: bindingsModel.count === 0 - } - - Repeater { - id: bindingsRepeater - model: bindingsModel - - delegate: KeybindRow { - width: parent.width - token: model.token || "" - configType: model.configType || "dms" - actionName: model.actionName || "" - args: model.args || [] - shellCmd: model.shellCmd || "" - repeatEnabled: model.repeatEnabled ?? true - cooldownMs: model.cooldownMs || 0 - allowWhenLocked: model.allowWhenLocked ?? false - overlayTitle: model.overlayTitle || "" - panelWindow: keybindsTab.parentModal - onRemoveRequested: keybindsTab.removeBinding(index) - onChanged: { - bindingsModel.set(index, { - token: token, - configType: configType, - actionName: actionName, - args: args, - shellCmd: shellCmd, - repeatEnabled: repeatEnabled, - cooldownMs: cooldownMs, - allowWhenLocked: allowWhenLocked, - overlayTitle: overlayTitle - }) - } - } - } - } - - Item { - width: parent.width - height: Theme.spacingXL - } - } - } - - Component.onCompleted: { - addBinding() - } -} \ No newline at end of file diff --git a/Modules/Settings/TimeWeatherTab.qml b/Modules/Settings/TimeWeatherTab.qml deleted file mode 100644 index b192f7b5..00000000 --- a/Modules/Settings/TimeWeatherTab.qml +++ /dev/null @@ -1,717 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -Item { - id: timeWeatherTab - - DankFlickable { - anchors.fill: parent - anchors.topMargin: Theme.spacingL - clip: true - contentHeight: mainColumn.height - contentWidth: width - - Column { - id: mainColumn - - width: parent.width - spacing: Theme.spacingXL - - StyledRect { - width: parent.width - height: timeSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: timeSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "schedule" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - toggle.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: "24-Hour Format" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: "Use 24-hour time format instead of 12-hour AM/PM" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - } - - DankToggle { - id: toggle - - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.use24HourClock - onToggled: checked => { - return SettingsData.setClockFormat(checked) - } - } - } - } - } - - StyledRect { - width: parent.width - height: dateSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: dateSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "calendar_today" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "Date Format" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - DankDropdown { - width: parent.width - height: 50 - text: "Top Bar Format" - description: "Preview: " + (SettingsData.clockDateFormat ? new Date().toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat) : new Date().toLocaleDateString(Qt.locale(), "ddd d")) - currentValue: { - if (!SettingsData.clockDateFormat || SettingsData.clockDateFormat.length === 0) { - return "System Default" - } - const presets = [{ - "format": "ddd d", - "label": "Day Date" - }, { - "format": "ddd MMM d", - "label": "Day Month Date" - }, { - "format": "MMM d", - "label": "Month Date" - }, { - "format": "M/d", - "label": "Numeric (M/D)" - }, { - "format": "d/M", - "label": "Numeric (D/M)" - }, { - "format": "ddd d MMM yyyy", - "label": "Full with Year" - }, { - "format": "yyyy-MM-dd", - "label": "ISO Date" - }, { - "format": "dddd, MMMM d", - "label": "Full Day & Month" - }] - const match = presets.find(p => { - return p.format === SettingsData.clockDateFormat - }) - return match ? match.label : "Custom: " + SettingsData.clockDateFormat - } - options: ["System Default", "Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."] - onValueChanged: value => { - const formatMap = { - "System Default": "", - "Day Date": "ddd d", - "Day Month Date": "ddd MMM d", - "Month Date": "MMM d", - "Numeric (M/D)": "M/d", - "Numeric (D/M)": "d/M", - "Full with Year": "ddd d MMM yyyy", - "ISO Date": "yyyy-MM-dd", - "Full Day & Month": "dddd, MMMM d" - } - if (value === "Custom...") { - customFormatInput.visible = true - } else { - customFormatInput.visible = false - SettingsData.setClockDateFormat(formatMap[value]) - } - } - } - - DankDropdown { - width: parent.width - height: 50 - text: "Lock Screen Format" - description: "Preview: " + (SettingsData.lockDateFormat ? new Date().toLocaleDateString(Qt.locale(), SettingsData.lockDateFormat) : new Date().toLocaleDateString(Qt.locale(), Locale.LongFormat)) - currentValue: { - if (!SettingsData.lockDateFormat || SettingsData.lockDateFormat.length === 0) { - return "System Default" - } - const presets = [{ - "format": "ddd d", - "label": "Day Date" - }, { - "format": "ddd MMM d", - "label": "Day Month Date" - }, { - "format": "MMM d", - "label": "Month Date" - }, { - "format": "M/d", - "label": "Numeric (M/D)" - }, { - "format": "d/M", - "label": "Numeric (D/M)" - }, { - "format": "ddd d MMM yyyy", - "label": "Full with Year" - }, { - "format": "yyyy-MM-dd", - "label": "ISO Date" - }, { - "format": "dddd, MMMM d", - "label": "Full Day & Month" - }] - const match = presets.find(p => { - return p.format === SettingsData.lockDateFormat - }) - return match ? match.label : "Custom: " + SettingsData.lockDateFormat - } - options: ["System Default", "Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."] - onValueChanged: value => { - const formatMap = { - "System Default": "", - "Day Date": "ddd d", - "Day Month Date": "ddd MMM d", - "Month Date": "MMM d", - "Numeric (M/D)": "M/d", - "Numeric (D/M)": "d/M", - "Full with Year": "ddd d MMM yyyy", - "ISO Date": "yyyy-MM-dd", - "Full Day & Month": "dddd, MMMM d" - } - if (value === "Custom...") { - customLockFormatInput.visible = true - } else { - customLockFormatInput.visible = false - SettingsData.setLockDateFormat(formatMap[value]) - } - } - } - - DankTextField { - id: customFormatInput - - width: parent.width - visible: false - placeholderText: "Enter custom top bar format (e.g., ddd MMM d)" - text: SettingsData.clockDateFormat - onTextChanged: { - if (visible && text) - SettingsData.setClockDateFormat(text) - } - } - - DankTextField { - id: customLockFormatInput - - width: parent.width - visible: false - placeholderText: "Enter custom lock screen format (e.g., dddd, MMMM d)" - text: SettingsData.lockDateFormat - onTextChanged: { - if (visible && text) - SettingsData.setLockDateFormat(text) - } - } - - Rectangle { - width: parent.width - height: formatHelp.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - border.width: 0 - - Column { - id: formatHelp - - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingXS - - StyledText { - text: "Format Legend" - font.pixelSize: Theme.fontSizeSmall - color: Theme.primary - font.weight: Font.Medium - } - - Row { - width: parent.width - spacing: Theme.spacingL - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: 2 - - StyledText { - text: "• d - Day (1-31)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "• dd - Day (01-31)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "• ddd - Day name (Mon)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "• dddd - Day name (Monday)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "• M - Month (1-12)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - Column { - width: (parent.width - Theme.spacingL) / 2 - spacing: 2 - - StyledText { - text: "• MM - Month (01-12)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "• MMM - Month (Jan)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "• MMMM - Month (January)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "• yy - Year (24)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - StyledText { - text: "• yyyy - Year (2024)" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - } - } - } - } - } - - StyledRect { - width: parent.width - height: enableWeatherSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - - Column { - id: enableWeatherSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "cloud" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - enableToggle.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: "Enable Weather" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: "Show weather information in top bar and control center" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - } - - DankToggle { - id: enableToggle - - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.weatherEnabled - onToggled: checked => { - return SettingsData.setWeatherEnabled(checked) - } - } - } - } - } - - StyledRect { - width: parent.width - height: temperatureSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - visible: SettingsData.weatherEnabled - opacity: visible ? 1 : 0 - - Column { - id: temperatureSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "thermostat" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - temperatureToggle.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: "Use Fahrenheit" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: "Use Fahrenheit instead of Celsius for temperature" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - } - - DankToggle { - id: temperatureToggle - - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.useFahrenheit - onToggled: checked => { - return SettingsData.setTemperatureUnit(checked) - } - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - - StyledRect { - width: parent.width - height: locationSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Theme.surfaceContainerHigh - border.width: 0 - visible: SettingsData.weatherEnabled - opacity: visible ? 1 : 0 - - Column { - id: locationSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "location_on" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Column { - width: parent.width - Theme.iconSize - Theme.spacingM - autoLocationToggle.width - Theme.spacingM - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: "Auto Location" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - } - - StyledText { - text: "Automatically determine your location using your IP address" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - wrapMode: Text.WordWrap - width: parent.width - } - } - - DankToggle { - id: autoLocationToggle - - anchors.verticalCenter: parent.verticalCenter - checked: SettingsData.useAutoLocation - onToggled: checked => { - return SettingsData.setAutoLocation(checked) - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - visible: !SettingsData.useAutoLocation - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.2 - } - - StyledText { - text: "Custom Location" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - font.weight: Font.Medium - } - - Row { - width: parent.width - spacing: Theme.spacingM - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: "Latitude" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: latitudeInput - width: parent.width - height: 48 - placeholderText: "40.7128" - backgroundColor: Theme.surfaceVariant - normalBorderColor: Theme.primarySelected - focusedBorderColor: Theme.primary - keyNavigationTab: longitudeInput - - Component.onCompleted: { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(',') - if (coords.length > 0) { - text = coords[0].trim() - } - } - } - - Connections { - target: SettingsData - function onWeatherCoordinatesChanged() { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(',') - if (coords.length > 0) { - latitudeInput.text = coords[0].trim() - } - } - } - } - - onTextEdited: { - if (text && longitudeInput.text) { - const coords = text + "," + longitudeInput.text - SettingsData.weatherCoordinates = coords - SettingsData.saveSettings() - } - } - } - } - - Column { - width: (parent.width - Theme.spacingM) / 2 - spacing: Theme.spacingXS - - StyledText { - text: "Longitude" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - - DankTextField { - id: longitudeInput - width: parent.width - height: 48 - placeholderText: "-74.0060" - backgroundColor: Theme.surfaceVariant - normalBorderColor: Theme.primarySelected - focusedBorderColor: Theme.primary - keyNavigationTab: locationSearchInput - keyNavigationBacktab: latitudeInput - - Component.onCompleted: { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(',') - if (coords.length > 1) { - text = coords[1].trim() - } - } - } - - Connections { - target: SettingsData - function onWeatherCoordinatesChanged() { - if (SettingsData.weatherCoordinates) { - const coords = SettingsData.weatherCoordinates.split(',') - if (coords.length > 1) { - longitudeInput.text = coords[1].trim() - } - } - } - } - - onTextEdited: { - if (text && latitudeInput.text) { - const coords = latitudeInput.text + "," + text - SettingsData.weatherCoordinates = coords - SettingsData.saveSettings() - } - } - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingXS - - StyledText { - text: "Location Search" - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - font.weight: Font.Medium - } - - DankLocationSearch { - id: locationSearchInput - width: parent.width - currentLocation: "" - placeholderText: "New York, NY" - keyNavigationBacktab: longitudeInput - onLocationSelected: (displayName, coordinates) => { - SettingsData.setWeatherLocation(displayName, coordinates) - - const coords = coordinates.split(',') - if (coords.length >= 2) { - latitudeInput.text = coords[0].trim() - longitudeInput.text = coords[1].trim() - } - } - } - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.mediumDuration - easing.type: Theme.emphasizedEasing - } - } - } - } - } -} \ No newline at end of file diff --git a/Widgets/ActionEditor.qml b/Widgets/ActionEditor.qml deleted file mode 100644 index 5d6cc76d..00000000 --- a/Widgets/ActionEditor.qml +++ /dev/null @@ -1,141 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -Item { - id: root - - property string actionName: "" - property var args: [] - property string shellCmd: "" - - signal changed() - - implicitWidth: actionRow.implicitWidth - implicitHeight: actionRow.implicitHeight - - readonly property var niriActions: [ - "spawn", - "spawn-sh", - "quit", - "close-window", - "focus-workspace-down", - "focus-workspace-up", - "focus-window-down", - "focus-window-up", - "focus-window-left", - "focus-window-right", - "move-window-down", - "move-window-up", - "move-window-left", - "move-window-right", - "fullscreen-window", - "toggle-window-floating", - "screenshot", - "screenshot-screen", - "screenshot-window", - "do-screen-transition", - "toggle-keyboard-shortcuts-inhibit" - ] - - Column { - id: actionRow - width: parent.width - spacing: Theme.spacingM - - DankDropdown { - id: actionBox - width: parent.width - height: 48 - text: "Action" - currentValue: root.actionName || "Select action..." - options: root.niriActions - onValueChanged: value => { - root.actionName = value - if (value === "spawn") { - if (root.args.length === 0) { - root.args = [""] - } - } else if (value !== "spawn-sh") { - root.args = [] - root.shellCmd = "" - } - root.changed() - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: root.actionName === "spawn" && root.args.length > 0 - - Repeater { - model: root.actionName === "spawn" ? root.args.length : 0 - - DankTextField { - width: parent.width - height: 48 - placeholderText: index === 0 ? "program/binary" : "arg " + index - text: root.args[index] || "" - onTextChanged: { - if (root.args[index] !== text) { - root.args[index] = text - root.changed() - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingS - - DankActionButton { - width: 36 - height: 36 - circular: false - iconName: "add" - iconSize: Theme.iconSize - 4 - iconColor: Theme.primary - onClicked: { - root.args.push("") - root.args = root.args - root.changed() - } - } - - DankActionButton { - width: 36 - height: 36 - circular: false - iconName: "remove" - iconSize: Theme.iconSize - 4 - iconColor: Theme.error - enabled: root.args.length > 1 - onClicked: { - if (root.args.length > 1) { - root.args.pop() - root.args = root.args - root.changed() - } - } - } - } - } - - DankTextField { - width: parent.width - height: 48 - visible: root.actionName === "spawn-sh" - placeholderText: "shell command" - text: root.shellCmd - onTextChanged: { - if (root.shellCmd !== text) { - root.shellCmd = text - root.changed() - } - } - } - } -} \ No newline at end of file diff --git a/Widgets/KeyCaptureField.qml b/Widgets/KeyCaptureField.qml deleted file mode 100644 index e307ddb2..00000000 --- a/Widgets/KeyCaptureField.qml +++ /dev/null @@ -1,207 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Widgets - -Item { - id: root - - property bool recording: false - property string capturedToken: "" - - signal captured(string xkbToken) - - implicitWidth: 320 - implicitHeight: captureRow.implicitHeight - - function startRecording() { - root.recording = true - captureField.forceActiveFocus() - root.capturedToken = "" - } - - function stopRecording(cancel) { - root.recording = false - } - - function modsFromEvent(mods) { - const result = [] - if (mods & Qt.ControlModifier) result.push("Ctrl") - if (mods & Qt.ShiftModifier) result.push("Shift") - if (mods & Qt.AltModifier) result.push("Alt") - if (mods & Qt.MetaModifier) result.push("Mod") - return result - } - - function xkbKeyFromQtKey(qk) { - if (qk >= Qt.Key_A && qk <= Qt.Key_Z) { - return String.fromCharCode(qk) - } - if (qk >= Qt.Key_0 && qk <= Qt.Key_9) { - return String.fromCharCode(qk) - } - - const map = { - [Qt.Key_Left]: "Left", - [Qt.Key_Right]: "Right", - [Qt.Key_Up]: "Up", - [Qt.Key_Down]: "Down", - [Qt.Key_Comma]: "Comma", - [Qt.Key_Period]: "Period", - [Qt.Key_Slash]: "Slash", - [Qt.Key_Semicolon]: "Semicolon", - [Qt.Key_Apostrophe]: "Apostrophe", - [Qt.Key_BracketLeft]: "BracketLeft", - [Qt.Key_BracketRight]: "BracketRight", - [Qt.Key_Backslash]: "Backslash", - [Qt.Key_Minus]: "Minus", - [Qt.Key_Equal]: "Equal", - [Qt.Key_QuoteLeft]: "grave", - [Qt.Key_Space]: "space", - [Qt.Key_Print]: "Print", - [Qt.Key_Return]: "Return", - [Qt.Key_Enter]: "Return", - [Qt.Key_Tab]: "Tab", - [Qt.Key_Backspace]: "BackSpace", - [Qt.Key_Delete]: "Delete", - [Qt.Key_Insert]: "Insert", - [Qt.Key_Home]: "Home", - [Qt.Key_End]: "End", - [Qt.Key_PageUp]: "Page_Up", - [Qt.Key_PageDown]: "Page_Down" - } - - if (qk >= Qt.Key_F1 && qk <= Qt.Key_F35) { - return "F" + (qk - Qt.Key_F1 + 1) - } - - return map[qk] || "" - } - - function formatToken(mods, key) { - return (mods.length ? mods.join("+") + "+" : "") + key - } - - Row { - id: captureRow - width: parent.width - spacing: Theme.spacingM - - FocusScope { - id: captureField - width: parent.width - recordButton.width - Theme.spacingM - height: 48 - focus: root.recording - - Rectangle { - id: captureBackground - anchors.fill: parent - radius: Theme.cornerRadius - color: root.recording ? Theme.primaryContainer : Theme.surfaceVariant - border.color: root.recording ? Theme.primary : Theme.primarySelected - border.width: root.recording ? 2 : 1 - - StyledText { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - text: root.capturedToken || (root.recording ? "Press keys / click / scroll... (Esc cancels)" : "Click Record to capture") - font.pixelSize: Theme.fontSizeMedium - color: root.capturedToken ? Theme.surfaceText : Theme.surfaceVariantText - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Keys.onPressed: (event) => { - if (!root.recording) return - - if (event.key === Qt.Key_Escape) { - root.stopRecording(true) - event.accepted = true - return - } - - const onlyModifier = [Qt.Key_Control, Qt.Key_Shift, Qt.Key_Alt, Qt.Key_Meta].includes(event.key) - if (onlyModifier) { - event.accepted = true - return - } - - const mods = root.modsFromEvent(event.modifiers) - const key = root.xkbKeyFromQtKey(event.key) - if (key) { - const token = root.formatToken(mods, key) - root.capturedToken = token - root.captured(token) - root.stopRecording(false) - event.accepted = true - } - } - - TapHandler { - acceptedButtons: Qt.AllButtons - enabled: root.recording - onTapped: (eventPoint, button) => { - const mods = root.modsFromEvent(eventPoint.modifiers) - let key = "" - if (button === Qt.LeftButton) key = "MouseLeft" - else if (button === Qt.RightButton) key = "MouseRight" - else if (button === Qt.MiddleButton) key = "MouseMiddle" - else if (button === Qt.BackButton) key = "MouseBack" - else if (button === Qt.ForwardButton) key = "MouseForward" - - if (key) { - const token = root.formatToken(mods, key) - root.capturedToken = token - root.captured(token) - root.stopRecording(false) - } - } - } - - WheelHandler { - enabled: root.recording - onWheel: (event) => { - const mods = root.modsFromEvent(event.modifiers) - let key = "" - if (Math.abs(event.angleDelta.y) >= Math.abs(event.angleDelta.x)) { - key = event.angleDelta.y < 0 ? "WheelScrollDown" : "WheelScrollUp" - } else { - key = event.angleDelta.x < 0 ? "WheelScrollRight" : "WheelScrollLeft" - } - const token = root.formatToken(mods, key) - root.capturedToken = token - root.captured(token) - root.stopRecording(false) - event.accepted = true - } - } - } - - DankActionButton { - id: recordButton - width: 48 - height: 48 - circular: false - iconName: recording ? "close" : "radio_button_checked" - iconSize: Theme.iconSize - iconColor: recording ? Theme.error : Theme.primary - onClicked: recording ? root.stopRecording(true) : root.startRecording() - } - } -} \ No newline at end of file diff --git a/Widgets/KeybindRow.qml b/Widgets/KeybindRow.qml deleted file mode 100644 index bab8b179..00000000 --- a/Widgets/KeybindRow.qml +++ /dev/null @@ -1,643 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Quickshell.Wayland -import qs.Common -import qs.Widgets - -Item { - id: row - - property string token: "" - property string configType: "dms" - property string actionName: "" - property var args: [] - property string shellCmd: "" - property bool repeatEnabled: true - property int cooldownMs: 0 - property bool allowWhenLocked: false - property string overlayTitle: "" - property bool expanded: false - property bool recording: false - property var panelWindow: null - - signal removeRequested() - signal changed() - - width: parent.width - height: mainContent.height - - function startRecording() { - recording = true - captureScope.forceActiveFocus() - } - - function stopRecording() { - recording = false - } - - function modsFromEvent(mods) { - const result = [] - if (mods & Qt.ControlModifier) result.push("Ctrl") - if (mods & Qt.ShiftModifier) result.push("Shift") - if (mods & Qt.AltModifier) result.push("Alt") - if (mods & Qt.MetaModifier) result.push("Mod") - return result - } - - function xkbKeyFromQtKey(qk) { - if (qk >= Qt.Key_A && qk <= Qt.Key_Z) { - return String.fromCharCode(qk) - } - if (qk >= Qt.Key_0 && qk <= Qt.Key_9) { - return String.fromCharCode(qk) - } - - const map = { - [Qt.Key_Left]: "Left", - [Qt.Key_Right]: "Right", - [Qt.Key_Up]: "Up", - [Qt.Key_Down]: "Down", - [Qt.Key_Comma]: "Comma", - [Qt.Key_Period]: "Period", - [Qt.Key_Slash]: "Slash", - [Qt.Key_Semicolon]: "Semicolon", - [Qt.Key_Apostrophe]: "Apostrophe", - [Qt.Key_BracketLeft]: "BracketLeft", - [Qt.Key_BracketRight]: "BracketRight", - [Qt.Key_Backslash]: "Backslash", - [Qt.Key_Minus]: "Minus", - [Qt.Key_Equal]: "Equal", - [Qt.Key_QuoteLeft]: "grave", - [Qt.Key_Space]: "space", - [Qt.Key_Print]: "Print", - [Qt.Key_Return]: "Return", - [Qt.Key_Enter]: "Return", - [Qt.Key_Tab]: "Tab", - [Qt.Key_Backspace]: "BackSpace", - [Qt.Key_Delete]: "Delete", - [Qt.Key_Insert]: "Insert", - [Qt.Key_Home]: "Home", - [Qt.Key_End]: "End", - [Qt.Key_PageUp]: "Page_Up", - [Qt.Key_PageDown]: "Page_Down" - } - - if (qk >= Qt.Key_F1 && qk <= Qt.Key_F35) { - return "F" + (qk - Qt.Key_F1 + 1) - } - - return map[qk] || "" - } - - function formatToken(mods, key) { - return (mods.length ? mods.join("+") + "+" : "") + key - } - - function toConfigLine() { - if (!row.token || !row.actionName) return "" - - const flags = [] - if (!row.repeatEnabled) flags.push("repeat=false") - if (row.cooldownMs > 0) flags.push(`cooldown-ms=${row.cooldownMs}`) - if (row.allowWhenLocked) flags.push("allow-when-locked=true") - if (row.overlayTitle === "null") flags.push("hotkey-overlay-title=null") - else if (row.overlayTitle.length > 0) { - const escaped = row.overlayTitle.replace(/"/g, '\\"') - flags.push(`hotkey-overlay-title="${escaped}"`) - } - - let actionStr = "" - if (row.actionName === "spawn") { - const parts = (row.args || []).filter(s => s && s.length > 0) - .map(s => `"${s.replace(/"/g, '\\"')}"`).join(" ") - actionStr = `{ spawn ${parts}; }` - } else if (row.actionName === "spawn-sh") { - const escaped = (row.shellCmd || "").replace(/"/g, '\\"') - actionStr = `{ spawn-sh "${escaped}"; }` - } else { - actionStr = `{ ${row.actionName}; }` - } - - const head = flags.length ? `${row.token} ${flags.join(" ")} ` : `${row.token} ` - return head + actionStr - } - - ShortcutsInhibitor { - window: row.panelWindow - enabled: row.recording - } - - StyledRect { - id: mainContent - width: parent.width - height: mainColumn.height - color: Theme.surfaceContainerHigh - radius: Theme.cornerRadius - border.width: 0 - - Column { - id: mainColumn - width: parent.width - spacing: Theme.spacingM - - Column { - width: parent.width - spacing: Theme.spacingM - - Row { - width: parent.width - height: 60 - spacing: Theme.spacingM - padding: Theme.spacingM - - FocusScope { - id: captureScope - width: 180 - height: 48 - anchors.verticalCenter: parent.verticalCenter - focus: row.recording - - Rectangle { - anchors.fill: parent - radius: Theme.cornerRadius - color: row.recording ? Theme.primaryContainer : Theme.surfaceVariant - border.color: row.recording ? Theme.primary : Theme.primarySelected - border.width: row.recording ? 2 : 1 - - StyledText { - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - text: row.token || (row.recording ? "Press combo..." : "Not set") - font.pixelSize: Theme.fontSizeMedium - color: row.token ? Theme.surfaceText : Theme.surfaceVariantText - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - } - - Behavior on color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - - Behavior on border.color { - ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Keys.onPressed: (event) => { - if (!row.recording) return - - if (event.key === Qt.Key_Escape) { - row.stopRecording() - event.accepted = true - return - } - - const onlyModifier = [Qt.Key_Control, Qt.Key_Shift, Qt.Key_Alt, Qt.Key_Meta].includes(event.key) - if (onlyModifier) { - event.accepted = true - return - } - - const mods = row.modsFromEvent(event.modifiers) - const key = row.xkbKeyFromQtKey(event.key) - if (key) { - const token = row.formatToken(mods, key) - row.token = token - row.changed() - row.stopRecording() - event.accepted = true - } - } - - TapHandler { - acceptedButtons: Qt.AllButtons - enabled: row.recording - onTapped: (eventPoint, button) => { - const mods = row.modsFromEvent(eventPoint.modifiers) - let key = "" - if (button === Qt.LeftButton) key = "MouseLeft" - else if (button === Qt.RightButton) key = "MouseRight" - else if (button === Qt.MiddleButton) key = "MouseMiddle" - else if (button === Qt.BackButton) key = "MouseBack" - else if (button === Qt.ForwardButton) key = "MouseForward" - - if (key) { - const token = row.formatToken(mods, key) - row.token = token - row.changed() - row.stopRecording() - } - } - } - - WheelHandler { - enabled: row.recording - onWheel: (event) => { - const mods = row.modsFromEvent(event.modifiers) - let key = "" - if (Math.abs(event.angleDelta.y) >= Math.abs(event.angleDelta.x)) { - key = event.angleDelta.y < 0 ? "WheelScrollDown" : "WheelScrollUp" - } else { - key = event.angleDelta.x < 0 ? "WheelScrollRight" : "WheelScrollLeft" - } - const token = row.formatToken(mods, key) - row.token = token - row.changed() - row.stopRecording() - event.accepted = true - } - } - } - - DankActionButton { - id: recordButton - width: 36 - height: 36 - circular: false - iconName: recording ? "close" : "radio_button_checked" - iconSize: Theme.iconSize - 4 - iconColor: recording ? Theme.error : Theme.primary - anchors.verticalCenter: parent.verticalCenter - onClicked: recording ? row.stopRecording() : row.startRecording() - } - - Column { - width: parent.width - captureScope.width - recordButton.width - expandButton.width - deleteButton.width - parent.padding * 2 - Theme.spacingM * 4 - spacing: Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - - StyledText { - text: { - if (row.configType === "dms") { - return row.actionName || "DMS Action..." - } else if (row.configType === "compositor") { - return row.actionName || "Compositor Action..." - } else { - if (row.args.length > 0 && row.args[0]) { - return row.args[0] - } - return "Custom Command..." - } - } - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - elide: Text.ElideRight - width: parent.width - } - - StyledText { - text: { - if (row.configType === "dms") { - return "DMS" - } else if (row.configType === "compositor") { - return "Compositor" - } else { - return "Custom Command" - } - } - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - } - } - - DankActionButton { - id: expandButton - width: 36 - height: 36 - circular: false - iconName: row.expanded ? "expand_less" : "expand_more" - iconSize: Theme.iconSize - iconColor: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - onClicked: row.expanded = !row.expanded - } - - DankActionButton { - id: deleteButton - width: 36 - height: 36 - circular: false - iconName: "delete" - iconSize: Theme.iconSize - iconColor: Theme.error - anchors.verticalCenter: parent.verticalCenter - onClicked: row.removeRequested() - } - } - } - - Column { - width: parent.width - spacing: Theme.spacingM - padding: Theme.spacingM - visible: row.expanded - opacity: row.expanded ? 1 : 0 - - DankButtonGroup { - width: parent.width - parent.padding * 2 - model: ["dms", "compositor", "command"] - currentIndex: { - if (row.configType === "dms") return 0 - if (row.configType === "compositor") return 1 - if (row.configType === "command") return 2 - return 0 - } - onSelectionChanged: (index, selected) => { - if (selected) { - if (index === 0) row.configType = "dms" - else if (index === 1) row.configType = "compositor" - else if (index === 2) row.configType = "command" - row.changed() - } - } - } - - Column { - width: parent.width - parent.padding * 2 - spacing: Theme.spacingM - visible: row.configType === "dms" - - DankDropdown { - width: parent.width - height: 48 - text: "DMS Action" - currentValue: row.actionName || "Select action..." - options: [ - "Spotlight Launcher", - "App Drawer", - "Control Center", - "Notifications", - "Settings", - "Power Menu", - "Lock Screen", - "Screenshot" - ] - onValueChanged: value => { - row.actionName = value - row.changed() - } - } - } - - Column { - width: parent.width - parent.padding * 2 - spacing: Theme.spacingM - visible: row.configType === "compositor" - - DankDropdown { - width: parent.width - height: 48 - text: "Compositor Action" - currentValue: row.actionName || "Select action..." - options: [ - "quit", - "close-window", - "focus-workspace-down", - "focus-workspace-up", - "focus-window-down", - "focus-window-up", - "focus-window-left", - "focus-window-right", - "move-window-down", - "move-window-up", - "move-window-left", - "move-window-right", - "fullscreen-window", - "toggle-window-floating", - "screenshot", - "screenshot-screen", - "screenshot-window", - "do-screen-transition", - "toggle-keyboard-shortcuts-inhibit" - ] - onValueChanged: value => { - row.actionName = value - row.changed() - } - } - } - - Column { - width: parent.width - parent.padding * 2 - spacing: Theme.spacingS - visible: row.configType === "command" - - StyledText { - text: "Command" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - DankTextField { - width: parent.width - height: 48 - text: row.args.length > 0 ? row.args[0] : "" - placeholderText: "Enter command (e.g., kitty, firefox)" - onTextChanged: { - if (row.args.length === 0) { - row.args = [text] - } else { - row.args[0] = text - } - row.actionName = "spawn" - row.changed() - } - } - - StyledText { - text: "Arguments (optional)" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - Column { - width: parent.width - spacing: Theme.spacingS - - Repeater { - model: Math.max(1, row.args.length - 1) - - Row { - width: parent.width - spacing: Theme.spacingS - - DankTextField { - width: parent.width - removeArgButton.width - Theme.spacingS - height: 40 - text: row.args.length > index + 1 ? row.args[index + 1] : "" - placeholderText: "Argument " + (index + 1) - onTextChanged: { - if (row.args.length > index + 1) { - row.args[index + 1] = text - } else { - row.args.push(text) - } - row.changed() - } - } - - DankActionButton { - id: removeArgButton - width: 36 - height: 36 - circular: false - iconName: "remove" - iconSize: Theme.iconSize - 4 - iconColor: Theme.error - anchors.verticalCenter: parent.verticalCenter - onClicked: { - row.args.splice(index + 1, 1) - row.args = row.args.slice() - row.changed() - } - } - } - } - - DankActionButton { - width: parent.width - height: 36 - circular: false - iconName: "add" - iconSize: Theme.iconSize - 4 - iconColor: Theme.primary - onClicked: { - row.args.push("") - row.args = row.args.slice() - row.changed() - } - } - } - } - - Rectangle { - width: parent.width - parent.padding * 2 - height: 1 - color: Theme.outline - opacity: 0.2 - } - - Column { - width: parent.width - parent.padding * 2 - spacing: Theme.spacingM - - StyledText { - text: "Options" - font.pixelSize: Theme.fontSizeMedium - font.weight: Font.Medium - color: Theme.surfaceText - } - - Row { - width: parent.width - spacing: Theme.spacingM - - DankToggle { - id: repeatToggle - checked: row.repeatEnabled - anchors.verticalCenter: parent.verticalCenter - onToggled: checked => { - row.repeatEnabled = checked - row.changed() - } - } - - StyledText { - text: "Allow repeat" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - StyledText { - text: "Cooldown (ms)" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - DankTextField { - width: 120 - height: 40 - text: row.cooldownMs.toString() - placeholderText: "0" - onTextChanged: { - const val = parseInt(text) || 0 - if (row.cooldownMs !== val) { - row.cooldownMs = val - row.changed() - } - } - } - } - - Row { - width: parent.width - spacing: Theme.spacingM - - DankToggle { - id: lockedToggle - checked: row.allowWhenLocked - anchors.verticalCenter: parent.verticalCenter - onToggled: checked => { - row.allowWhenLocked = checked - row.changed() - } - } - - StyledText { - text: "Allow when locked" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - } - - Column { - width: parent.width - spacing: Theme.spacingS - - StyledText { - text: "Hotkey overlay title" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - } - - DankTextField { - width: parent.width - height: 40 - text: row.overlayTitle - placeholderText: "" - onTextChanged: { - if (row.overlayTitle !== text) { - row.overlayTitle = text - row.changed() - } - } - } - } - } - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - } - } -} \ No newline at end of file