From 5d1a9b1e9c4ff54eafcd27ff2782457e7c468e56 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 18 Oct 2025 19:07:10 +0200 Subject: [PATCH] sidebar: android-style quick toggles & sliders (#2217) Co-Authored-By: Vague Syntax <173799252+vaguesyntax@users.noreply.github.com> --- .../quickshell/ii/modules/common/Config.qml | 24 +- .../ii/modules/common/widgets/ButtonGroup.qml | 1 + .../ii/modules/common/widgets/GroupButton.qml | 8 +- .../ii/modules/settings/InterfaceConfig.qml | 80 +++ .../ii/modules/sidebarRight/QuickSliders.qml | 111 ++++ .../sidebarRight/SidebarRightContent.qml | 201 ++++--- .../quickToggles/AbstractQuickPanel.qml | 12 + .../quickToggles/AndroidQuickPanel.qml | 156 ++++++ .../quickToggles/ClassicQuickPanel.qml | 39 ++ .../androidStyle/AndroidAudioToggle.qml | 18 + .../androidStyle/AndroidBluetoothToggle.qml | 27 + .../AndroidCloudflareWarpToggle.qml | 80 +++ .../androidStyle/AndroidColorPickerToggle.qml | 26 + .../androidStyle/AndroidDarkModeToggle.qml | 23 + .../androidStyle/AndroidEasyEffectsToggle.qml | 32 ++ .../androidStyle/AndroidGameModeToggle.qml | 34 ++ .../AndroidIdleInhibitorToggle.qml | 21 + .../androidStyle/AndroidMicToggle.qml | 18 + .../androidStyle/AndroidNetworkToggle.qml | 23 + .../androidStyle/AndroidNightLightToggle.qml | 33 ++ .../AndroidNotificationToggle.qml | 18 + .../AndroidOnScreenKeyboardToggle.qml | 17 + .../AndroidPowerProfileToggle.qml | 42 ++ .../androidStyle/AndroidQuickToggleButton.qml | 173 ++++++ .../androidStyle/AndroidScreenSnipToggle.qml | 27 + .../AndroidToggleDelegateChooser.qml | 225 ++++++++ .../{ => classicStyle}/BluetoothToggle.qml | 0 .../{ => classicStyle}/CloudflareWarp.qml | 0 .../{ => classicStyle}/EasyEffectsToggle.qml | 2 +- .../{ => classicStyle}/GameMode.qml | 0 .../{ => classicStyle}/IdleInhibitor.qml | 0 .../{ => classicStyle}/NetworkToggle.qml | 0 .../{ => classicStyle}/NightLight.qml | 3 +- .../{ => classicStyle}/QuickToggleButton.qml | 0 .../quickshell/ii/translations/en_US.json.bak | 511 ++++++++++++++++++ 35 files changed, 1895 insertions(+), 90 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/QuickSliders.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AbstractQuickPanel.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/ClassicQuickPanel.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml create mode 100644 dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml rename dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/{ => classicStyle}/BluetoothToggle.qml (100%) rename dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/{ => classicStyle}/CloudflareWarp.qml (100%) rename dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/{ => classicStyle}/EasyEffectsToggle.qml (100%) rename dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/{ => classicStyle}/GameMode.qml (100%) rename dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/{ => classicStyle}/IdleInhibitor.qml (100%) rename dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/{ => classicStyle}/NetworkToggle.qml (100%) rename dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/{ => classicStyle}/NightLight.qml (89%) rename dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/{ => classicStyle}/QuickToggleButton.qml (100%) create mode 100644 dots/.config/quickshell/ii/translations/en_US.json.bak diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 2ff5d7772..06e9850d8 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -352,7 +352,7 @@ Singleton { property JsonObject search: JsonObject { property int nonAppResultDelay: 30 // This prevents lagging when typing property string engineBaseUrl: "https://www.google.com/search?q=" - property list excludedSites: ["quora.com"] + property list excludedSites: ["quora.com", "facebook.com"] property bool sloppy: false // Uses levenshtein distance based scoring instead of fuzzy sort. Very weird. property JsonObject prefix: JsonObject { property bool showDefaultActionsWithoutPrefix: true @@ -393,6 +393,28 @@ Singleton { property bool visualize: false property bool clicklessCornerEnd: true } + + property JsonObject quickToggles: JsonObject { + property string style: "android" // Options: classic, android + property JsonObject android: JsonObject { + property int columns: 5 + property list toggles: [ + { type: "network", size: 2 }, + { type: "bluetooth", size: 2 }, + { type: "idleinhibitor", size: 1 }, + { type: "easyeffects", size: 1 }, + { type: "nightlight", size: 2 }, + { type: "darkmode", size: 2 } + ] + } + } + + property JsonObject quickSliders: JsonObject { + property bool enable: false + property bool showMic: false + property bool showVolume: true + property bool showBrightness: true + } } property JsonObject time: JsonObject { diff --git a/dots/.config/quickshell/ii/modules/common/widgets/ButtonGroup.qml b/dots/.config/quickshell/ii/modules/common/widgets/ButtonGroup.qml index e58354d44..32cd5e04f 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/ButtonGroup.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/ButtonGroup.qml @@ -14,6 +14,7 @@ Rectangle { property real spacing: 5 property real padding: 0 property int clickIndex: rowLayout.clickIndex + property int childrenCount: rowLayout.children.length property real contentWidth: { let total = 0; diff --git a/dots/.config/quickshell/ii/modules/common/widgets/GroupButton.qml b/dots/.config/quickshell/ii/modules/common/widgets/GroupButton.qml index ce6547c7f..bc02e77e1 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/GroupButton.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/GroupButton.qml @@ -22,13 +22,15 @@ Button { property bool bounce: true property real baseWidth: contentItem.implicitWidth + horizontalPadding * 2 property real baseHeight: contentItem.implicitHeight + verticalPadding * 2 - property real clickedWidth: baseWidth + 20 + property real clickedWidth: baseWidth + (isAtSide ? 10 : 20) property real clickedHeight: baseHeight property var parentGroup: root.parent + property int indexInParent: parentGroup?.children.indexOf(root) ?? 0 property int clickIndex: parentGroup?.clickIndex ?? -1 + property bool isAtSide: indexInParent === 0 || indexInParent === (parentGroup?.childrenCount - 1) - Layout.fillWidth: (clickIndex - 1 <= parentGroup?.children.indexOf(root) && parentGroup?.children.indexOf(root) <= clickIndex + 1) - Layout.fillHeight: (clickIndex - 1 <= parentGroup?.children.indexOf(root) && parentGroup?.children.indexOf(root) <= clickIndex + 1) + Layout.fillWidth: (clickIndex - 1 <= indexInParent && indexInParent <= clickIndex + 1) + Layout.fillHeight: (clickIndex - 1 <= indexInParent && indexInParent <= clickIndex + 1) implicitWidth: (root.down && bounce) ? clickedWidth : baseWidth implicitHeight: (root.down && bounce) ? clickedHeight : baseHeight diff --git a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index 6d40a130f..72469843c 100644 --- a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -599,6 +599,86 @@ ContentPage { } } + ContentSubsection { + title: Translation.tr("Quick toggles") + + ConfigSelectionArray { + Layout.fillWidth: false + currentValue: Config.options.sidebar.quickToggles.style + onSelected: newValue => { + Config.options.sidebar.quickToggles.style = newValue; + } + options: [ + { + displayName: Translation.tr("Classic"), + icon: "password_2", + value: "classic" + }, + { + displayName: Translation.tr("Android"), + icon: "action_key", + value: "android" + } + ] + } + + ConfigSpinBox { + enabled: Config.options.sidebar.quickToggles.style === "android" + icon: "splitscreen_left" + text: Translation.tr("Columns") + value: Config.options.sidebar.quickToggles.android.columns + from: 1 + to: 8 + stepSize: 1 + onValueChanged: { + Config.options.sidebar.quickToggles.android.columns = value; + } + } + } + + ContentSubsection { + title: Translation.tr("Sliders") + + ConfigSwitch { + buttonIcon: "check" + text: Translation.tr("Enable") + checked: Config.options.sidebar.quickSliders.enable + onCheckedChanged: { + Config.options.sidebar.quickSliders.enable = checked; + } + } + + ConfigSwitch { + buttonIcon: "brightness_6" + text: Translation.tr("Brightness") + enabled: Config.options.sidebar.quickSliders.enable + checked: Config.options.sidebar.quickSliders.showBrightness + onCheckedChanged: { + Config.options.sidebar.quickSliders.showBrightness = checked; + } + } + + ConfigSwitch { + buttonIcon: "volume_up" + text: Translation.tr("Volume") + enabled: Config.options.sidebar.quickSliders.enable + checked: Config.options.sidebar.quickSliders.showVolume + onCheckedChanged: { + Config.options.sidebar.quickSliders.showVolume = checked; + } + } + + ConfigSwitch { + buttonIcon: "mic" + text: Translation.tr("Microphone") + enabled: Config.options.sidebar.quickSliders.enable + checked: Config.options.sidebar.quickSliders.showMic + onCheckedChanged: { + Config.options.sidebar.quickSliders.showMic = checked; + } + } + } + ContentSubsection { title: Translation.tr("Corner open") tooltip: Translation.tr("Allows you to open sidebars by clicking or hovering screen corners regardless of bar position") diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/QuickSliders.qml b/dots/.config/quickshell/ii/modules/sidebarRight/QuickSliders.qml new file mode 100644 index 000000000..26925001e --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/QuickSliders.qml @@ -0,0 +1,111 @@ +import qs +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Hyprland +import Quickshell.Services.UPower + +Rectangle { + id: root + + property var screen: root.QsWindow.window?.screen + property var brightnessMonitor: Brightness.getMonitorForScreen(screen) + + implicitWidth: contentItem.implicitWidth + root.horizontalPadding * 2 + implicitHeight: contentItem.implicitHeight + root.verticalPadding * 2 + radius: Appearance.rounding.normal + color: Appearance.colors.colLayer1 + property real verticalPadding: 4 + property real horizontalPadding: 12 + + Column { + id: contentItem + anchors { + fill: parent + leftMargin: root.horizontalPadding + rightMargin: root.horizontalPadding + topMargin: root.verticalPadding + bottomMargin: root.verticalPadding + } + + Loader { + anchors { + left: parent.left + right: parent.right + } + visible: active + active: Config.options.sidebar.quickSliders.showBrightness + sourceComponent: QuickSlider { + materialSymbol: "brightness_6" + value: root.brightnessMonitor.brightness + onMoved: { + root.brightnessMonitor.setBrightness(value) + } + } + } + + Loader { + anchors { + left: parent.left + right: parent.right + } + visible: active + active: Config.options.sidebar.quickSliders.showVolume + sourceComponent: QuickSlider { + materialSymbol: "volume_up" + value: Audio.sink.audio.volume + onMoved: { + Audio.sink.audio.volume = value + } + } + } + + Loader { + anchors { + left: parent.left + right: parent.right + } + visible: active + active: Config.options.sidebar.quickSliders.showMic + sourceComponent: QuickSlider { + materialSymbol: "mic" + value: Audio.source.audio.volume + onMoved: { + Audio.source.audio.volume = value + } + } + } + } + + component QuickSlider: StyledSlider { + id: quickSlider + required property string materialSymbol + configuration: StyledSlider.Configuration.M + stopIndicatorValues: [] + + MaterialSymbol { + id: icon + property bool nearFull: quickSlider.value >= 0.9 + anchors { + verticalCenter: parent.verticalCenter + right: nearFull ? quickSlider.handle.right : parent.right + rightMargin: quickSlider.nearFull ? 14 : 8 + } + iconSize: 20 + color: nearFull ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer + text: quickSlider.materialSymbol + + Behavior on color { + animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) + } + Behavior on anchors.rightMargin { + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } + + } + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/SidebarRightContent.qml b/dots/.config/quickshell/ii/modules/sidebarRight/SidebarRightContent.qml index ed2e4376f..316c4eb5e 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/SidebarRightContent.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/SidebarRightContent.qml @@ -2,9 +2,6 @@ import qs import qs.services import qs.modules.common import qs.modules.common.widgets -import "./quickToggles/" -import "./wifiNetworks/" -import "./bluetoothDevices/" import QtQuick import QtQuick.Controls import QtQuick.Layouts @@ -12,6 +9,11 @@ import Quickshell import Quickshell.Bluetooth import Quickshell.Hyprland +import "./quickToggles/" +import "./quickToggles/classicStyle/" +import "./wifiNetworks/" +import "./bluetoothDevices/" + Item { id: root property int sidebarWidth: Appearance.sizes.sidebarWidth @@ -19,6 +21,7 @@ Item { property string settingsQmlPath: Quickshell.shellPath("settings.qml") property bool showWifiDialog: false property bool showBluetoothDialog: false + property bool editMode: false Connections { target: GlobalStates @@ -52,94 +55,36 @@ Item { anchors.margins: sidebarPadding spacing: sidebarPadding - RowLayout { + SystemButtonRow { Layout.fillHeight: false - spacing: 10 Layout.margins: 10 Layout.topMargin: 5 Layout.bottomMargin: 0 - - CustomIcon { - id: distroIcon - width: 25 - height: 25 - source: SystemInfo.distroIcon - colorize: true - color: Appearance.colors.colOnLayer0 - } - - StyledText { - font.pixelSize: Appearance.font.pixelSize.normal - color: Appearance.colors.colOnLayer0 - text: Translation.tr("Up %1").arg(DateTime.uptime) - textFormat: Text.MarkdownText - } - - Item { - Layout.fillWidth: true - } - - ButtonGroup { - QuickToggleButton { - toggled: false - buttonIcon: "restart_alt" - onClicked: { - Hyprland.dispatch("reload"); - Quickshell.reload(true); - } - StyledToolTip { - text: Translation.tr("Reload Hyprland & Quickshell") - } - } - QuickToggleButton { - toggled: false - buttonIcon: "settings" - onClicked: { - GlobalStates.sidebarRightOpen = false; - Quickshell.execDetached(["qs", "-p", root.settingsQmlPath]); - } - StyledToolTip { - text: Translation.tr("Settings") - } - } - QuickToggleButton { - toggled: false - buttonIcon: "power_settings_new" - onClicked: { - GlobalStates.sessionOpen = true; - } - StyledToolTip { - text: Translation.tr("Session") - } - } - } } - ButtonGroup { - Layout.alignment: Qt.AlignHCenter - spacing: 5 - padding: 5 - color: Appearance.colors.colLayer1 + Loader { + id: slidersLoader + Layout.fillWidth: true + visible: active + active: { + const configQuickSliders = Config.options.sidebar.quickSliders + if (!configQuickSliders.enable) return false + if (!configQuickSliders.showMic && !configQuickSliders.showVolume && !configQuickSliders.showBrightness) return false; + return true; + } + sourceComponent: QuickSliders {} + } - NetworkToggle { - altAction: () => { - Network.enableWifi(); - Network.rescanWifi(); - root.showWifiDialog = true; - } + LoaderedQuickPanelImplementation { + styleName: "classic" + sourceComponent: ClassicQuickPanel {} + } + + LoaderedQuickPanelImplementation { + styleName: "android" + sourceComponent: AndroidQuickPanel { + editMode: root.editMode } - BluetoothToggle { - altAction: () => { - Bluetooth.defaultAdapter.enabled = true; - Bluetooth.defaultAdapter.discovering = true; - root.showBluetoothDialog = true; - } - } - NightLight {} - GameMode {} - IdleInhibitor {} - EasyEffectsToggle {} - CloudflareWarp {} } CenterWidgetGroup { @@ -207,4 +152,94 @@ Item { } } } + + component LoaderedQuickPanelImplementation: Loader { + id: quickPanelImplLoader + required property string styleName + Layout.alignment: item?.Layout.alignment ?? Qt.AlignHCenter + Layout.fillWidth: item?.Layout.fillWidth ?? false + visible: active + active: Config.options.sidebar.quickToggles.style === styleName + Connections { + target: quickPanelImplLoader.item + function onOpenWifiDialog() { + Network.enableWifi(); + Network.rescanWifi(); + root.showWifiDialog = true; + } + function onOpenBluetoothDialog() { + Bluetooth.defaultAdapter.enabled = true; + Bluetooth.defaultAdapter.discovering = true; + root.showBluetoothDialog = true; + } + } + } + + component SystemButtonRow: RowLayout { + spacing: 10 + + CustomIcon { + id: distroIcon + width: 25 + height: 25 + source: SystemInfo.distroIcon + colorize: true + color: Appearance.colors.colOnLayer0 + } + + StyledText { + font.pixelSize: Appearance.font.pixelSize.normal + color: Appearance.colors.colOnLayer0 + text: Translation.tr("Up %1").arg(DateTime.uptime) + textFormat: Text.MarkdownText + } + + Item { + Layout.fillWidth: true + } + + ButtonGroup { + QuickToggleButton { + toggled: root.editMode + visible: Config.options.sidebar.quickToggles.style === "android" + buttonIcon: "edit" + onClicked: root.editMode = !root.editMode + StyledToolTip { + text: Translation.tr("Edit quick toggles") + (root.editMode ? Translation.tr("\nLMB to enable/disable\nRMB to toggle size\nScroll to swap position") : "") + } + } + QuickToggleButton { + toggled: false + buttonIcon: "restart_alt" + onClicked: { + Hyprland.dispatch("reload"); + Quickshell.reload(true); + } + StyledToolTip { + text: Translation.tr("Reload Hyprland & Quickshell") + } + } + QuickToggleButton { + toggled: false + buttonIcon: "settings" + onClicked: { + GlobalStates.sidebarRightOpen = false; + Quickshell.execDetached(["qs", "-p", root.settingsQmlPath]); + } + StyledToolTip { + text: Translation.tr("Settings") + } + } + QuickToggleButton { + toggled: false + buttonIcon: "power_settings_new" + onClicked: { + GlobalStates.sessionOpen = true; + } + StyledToolTip { + text: Translation.tr("Session") + } + } + } + } } diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AbstractQuickPanel.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AbstractQuickPanel.qml new file mode 100644 index 000000000..9bc9d44de --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AbstractQuickPanel.qml @@ -0,0 +1,12 @@ +import QtQuick +import qs.modules.common + +Rectangle { + id: root + + radius: Appearance.rounding.normal + color: Appearance.colors.colLayer1 + + signal openWifiDialog() + signal openBluetoothDialog() +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml new file mode 100644 index 000000000..fab308d7e --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/AndroidQuickPanel.qml @@ -0,0 +1,156 @@ +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Bluetooth + +import "./androidStyle/" + +AbstractQuickPanel { + id: root + property bool editMode: false + Layout.fillWidth: true + implicitHeight: (editMode ? contentItem.implicitHeight : usedRows.implicitHeight) + root.padding * 2 + + Behavior on implicitHeight { + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + + property real spacing: 6 + property real padding: 6 + + readonly property list availableToggleTypes: ["network", "bluetooth", "idleInhibitor", "easyEffects", "nightLight", "darkMode", "cloudflareWarp", "gameMode", "screenSnip", "colorPicker", "onScreenKeyboard", "mic", "audio", "notifications", "powerProfile"] + readonly property int columns: Config.options.sidebar.quickToggles.android.columns + readonly property list toggles: Config.options.sidebar.quickToggles.android.toggles + readonly property list toggleRows: toggleRowsForList(toggles) + readonly property list unusedToggles: { + const types = availableToggleTypes.filter(type => !toggles.some(toggle => (toggle && toggle.type === type))) + return types.map(type => { return { type: type, size: 1 } }) + } + readonly property list unusedToggleRows: toggleRowsForList(unusedToggles) + readonly property real baseCellWidth: { + // This is the wrong calculation, but it looks correct in reality??? + // (theoretically spacing should be multiplied by 1 column less) + const availableWidth = root.width - (root.padding * 2) - (root.spacing * (root.columns)) + return availableWidth / root.columns + } + readonly property real baseCellHeight: 56 + + function toggleRowsForList(togglesList) { + var rows = []; + var row = []; + var totalSize = 0; // Total cols taken in current row + for (var i = 0; i < togglesList.length; i++) { + if (!togglesList[i]) continue; + if (totalSize + togglesList[i].size > columns) { + rows.push(row); + row = []; + totalSize = 0; + } + row.push(togglesList[i]); + totalSize += togglesList[i].size; + } + if (row.length > 0) { + rows.push(row); + } + return rows; + } + + Column { + id: contentItem + anchors { + fill: parent + margins: root.padding + } + spacing: 12 + + Column { + id: usedRows + spacing: root.spacing + + Repeater { + id: usedRowsRepeater + model: ScriptModel { + values: root.toggleRows + } + delegate: ButtonGroup { + id: toggleRow + required property var modelData + required property int index + property int startingIndex: { + const rows = usedRowsRepeater.model.values; + let sum = 0; + for (let i = 0; i < index; i++) { + sum += rows[i].length; + } + return sum; + } + spacing: root.spacing + + Repeater { + model: ScriptModel { + values: toggleRow.modelData + } + delegate: AndroidToggleDelegateChooser { + startingIndex: toggleRow.startingIndex + editMode: root.editMode + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + spacing: root.spacing + onOpenWifiDialog: root.openWifiDialog() + onOpenBluetoothDialog: root.openBluetoothDialog() + } + } + } + } + } + + FadeLoader { + shown: root.editMode + anchors { + left: parent.left + right: parent.right + leftMargin: root.baseCellHeight / 2 + rightMargin: root.baseCellHeight / 2 + } + sourceComponent: Rectangle { + implicitHeight: 1 + color: Appearance.colors.colOutlineVariant + } + } + + FadeLoader { + shown: root.editMode + sourceComponent: Column { + id: unusedRows + spacing: root.spacing + + Repeater { + model: ScriptModel { + values: root.unusedToggleRows + } + delegate: ButtonGroup { + id: unusedToggleRow + required property var modelData + spacing: root.spacing + + Repeater { + model: ScriptModel { + values: unusedToggleRow.modelData + } + delegate: AndroidToggleDelegateChooser { + startingIndex: -1 + editMode: root.editMode + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + spacing: root.spacing + } + } + } + } + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/ClassicQuickPanel.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/ClassicQuickPanel.qml new file mode 100644 index 000000000..c6855dfaa --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/ClassicQuickPanel.qml @@ -0,0 +1,39 @@ +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import QtQuick +import QtQuick.Layouts +import Quickshell.Bluetooth + +import "./classicStyle/" + +AbstractQuickPanel { + id: root + Layout.alignment: Qt.AlignHCenter + implicitWidth: buttonGroup.implicitWidth + implicitHeight: buttonGroup.implicitHeight + color: "transparent" + + ButtonGroup { + id: buttonGroup + spacing: 5 + padding: 5 + color: Appearance.colors.colLayer1 + + NetworkToggle { + altAction: () => { + root.openWifiDialog(); + } + } + BluetoothToggle { + altAction: () => { + root.openBluetoothDialog(); + } + } + NightLight {} + GameMode {} + IdleInhibitor {} + EasyEffectsToggle {} + CloudflareWarp {} + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml new file mode 100644 index 000000000..2cf206d4f --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidAudioToggle.qml @@ -0,0 +1,18 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Audio") + statusText: toggled ? Translation.tr("Unmuted") : Translation.tr("Muted") + toggled: !Audio.sink?.audio?.muted + buttonIcon: Audio.sink?.audio?.muted ? "volume_off" : "volume_up" + onClicked: { + Audio.sink.audio.muted = !Audio.sink.audio.muted + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml new file mode 100644 index 000000000..9d5a3d81a --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidBluetoothToggle.qml @@ -0,0 +1,27 @@ +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import QtQuick +import Quickshell +import Quickshell.Bluetooth + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Bluetooth") + statusText: BluetoothStatus.firstActiveDevice?.name ?? Translation.tr("No device") + + toggled: BluetoothStatus.enabled + buttonIcon: BluetoothStatus.connected ? "bluetooth_connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth_disabled" + onClicked: { + Bluetooth.defaultAdapter.enabled = !Bluetooth.defaultAdapter?.enabled + } + StyledToolTip { + text: Translation.tr("%1 | Right-click to configure").arg( + (BluetoothStatus.firstActiveDevice?.name ?? Translation.tr("Bluetooth")) + + (BluetoothStatus.activeDeviceCount > 1 ? ` +${BluetoothStatus.activeDeviceCount - 1}` : "") + ) + } +} + diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml new file mode 100644 index 000000000..d703c67dd --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidCloudflareWarpToggle.qml @@ -0,0 +1,80 @@ +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell +import Quickshell.Io + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Cloudflare WARP") + + toggled: false + buttonIcon: "cloud_lock" + + onClicked: { + if (toggled) { + root.toggled = false + Quickshell.execDetached(["warp-cli", "disconnect"]) + } else { + root.toggled = true + Quickshell.execDetached(["warp-cli", "connect"]) + } + } + + Process { + id: connectProc + command: ["warp-cli", "connect"] + onExited: (exitCode, exitStatus) => { + if (exitCode !== 0) { + Quickshell.execDetached(["notify-send", + Translation.tr("Cloudflare WARP"), + Translation.tr("Connection failed. Please inspect manually with the warp-cli command") + , "-a", "Shell" + ]) + } + } + } + + Process { + id: registrationProc + command: ["warp-cli", "registration", "new"] + onExited: (exitCode, exitStatus) => { + console.log("Warp registration exited with code and status:", exitCode, exitStatus) + if (exitCode === 0) { + connectProc.running = true + } else { + Quickshell.execDetached(["notify-send", + Translation.tr("Cloudflare WARP"), + Translation.tr("Registration failed. Please inspect manually with the warp-cli command"), + "-a", "Shell" + ]) + } + } + } + + Process { + id: fetchActiveState + running: true + command: ["bash", "-c", "warp-cli status"] + stdout: StdioCollector { + id: warpStatusCollector + onStreamFinished: { + if (warpStatusCollector.text.length > 0) { + root.visible = true + } + if (warpStatusCollector.text.includes("Unable")) { + registrationProc.running = true + } else if (warpStatusCollector.text.includes("Connected")) { + root.toggled = true + } else if (warpStatusCollector.text.includes("Disconnected")) { + root.toggled = false + } + } + } + } + StyledToolTip { + text: Translation.tr("Cloudflare WARP (1.1.1.1)") + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml new file mode 100644 index 000000000..d395f7960 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidColorPickerToggle.qml @@ -0,0 +1,26 @@ +import qs +import qs.modules.common +import qs.services +import QtQuick +import Quickshell + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Color Picker") + toggled: false + buttonIcon: "colorize" + + onClicked: { + GlobalStates.sidebarRightOpen = false; + delayedActionTimer.start() + } + Timer { + id: delayedActionTimer + interval: 300 + repeat: false + onTriggered: { + Quickshell.execDetached(["hyprpicker", "-a"]) + } + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml new file mode 100644 index 000000000..9847bb9ff --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidDarkModeToggle.qml @@ -0,0 +1,23 @@ +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Dark Mode") + statusText: Appearance.m3colors.darkmode ? Translation.tr("Dark") : Translation.tr("Light") + + toggled: Appearance.m3colors.darkmode + buttonIcon: Appearance.m3colors.darkmode ? "contrast" : "light_mode" + + onClicked: event => { + if (Appearance.m3colors.darkmode) { + Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "light", "--noswitch"]); + } else { + Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "dark", "--noswitch"]); + } + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml new file mode 100644 index 000000000..c907abf77 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidEasyEffectsToggle.qml @@ -0,0 +1,32 @@ +import qs +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("EasyEffects") + + toggled: EasyEffects.active + buttonIcon: "graphic_eq" + + Component.onCompleted: { + EasyEffects.fetchActiveState() + } + + onClicked: { + EasyEffects.toggle() + } + + altAction: () => { + Quickshell.execDetached(["bash", "-c", "flatpak run com.github.wwmm.easyeffects || easyeffects"]) + GlobalStates.sidebarRightOpen = false + } + + StyledToolTip { + text: Translation.tr("EasyEffects | Right-click to configure") + } +} + diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml new file mode 100644 index 000000000..3b1942143 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidGameModeToggle.qml @@ -0,0 +1,34 @@ +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell +import Quickshell.Io + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Game mode") + toggled: toggled + buttonIcon: "gamepad" + + onClicked: { + root.toggled = !root.toggled + if (root.toggled) { + Quickshell.execDetached(["bash", "-c", `hyprctl --batch "keyword animations:enabled 0; keyword decoration:shadow:enabled 0; keyword decoration:blur:enabled 0; keyword general:gaps_in 0; keyword general:gaps_out 0; keyword general:border_size 1; keyword decoration:rounding 0; keyword general:allow_tearing 1"`]) + } else { + Quickshell.execDetached(["hyprctl", "reload"]) + } + } + Process { + id: fetchActiveState + running: true + command: ["bash", "-c", `test "$(hyprctl getoption animations:enabled -j | jq ".int")" -ne 0`] + onExited: (exitCode, exitStatus) => { + root.toggled = exitCode !== 0 // Inverted because enabled = nonzero exit + } + } + StyledToolTip { + text: Translation.tr("Game mode") + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml new file mode 100644 index 000000000..b28756549 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidIdleInhibitorToggle.qml @@ -0,0 +1,21 @@ +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import QtQuick + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Idle Inhibitor") + + toggled: Idle.inhibit + buttonIcon: "coffee" + onClicked: { + Idle.toggleInhibit() + } + StyledToolTip { + text: Translation.tr("Keep system awake") + } +} + diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml new file mode 100644 index 000000000..6860d53ce --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidMicToggle.qml @@ -0,0 +1,18 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Microphone") + statusText: toggled ? Translation.tr("Enabled") : Translation.tr("Muted") + toggled: !Audio.source?.audio?.muted + buttonIcon: Audio.source?.audio?.muted ? "mic_off" : "mic" + onClicked: { + Audio.source.audio.muted = !Audio.source.audio.muted + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml new file mode 100644 index 000000000..53576febb --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNetworkToggle.qml @@ -0,0 +1,23 @@ +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import QtQuick + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Internet") + statusText: Network.networkName + + toggled: Network.wifiStatus !== "disabled" + buttonIcon: Network.materialSymbol + onClicked: Network.toggleWifi() + altAction: () => { + root.openMenu() + } + StyledToolTip { + text: Translation.tr("%1 | Right-click to configure").arg(Network.networkName) + } +} + diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml new file mode 100644 index 000000000..378dd0284 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNightLightToggle.qml @@ -0,0 +1,33 @@ +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell + +AndroidQuickToggleButton { + id: root + + property bool auto: Config.options.light.night.automatic + + name: Translation.tr("Night Light") + statusText: (auto ? Translation.tr("Auto, ") : "") + (toggled ? Translation.tr("Active") : Translation.tr("Inactive")) + + toggled: Hyprsunset.active + buttonIcon: auto ? "night_sight_auto" : "bedtime" + onClicked: { + Hyprsunset.toggle() + } + + altAction: () => { + Config.options.light.night.automatic = !Config.options.light.night.automatic + } + + Component.onCompleted: { + Hyprsunset.fetchState() + } + + StyledToolTip { + text: Translation.tr("Night Light | Right-click to toggle Auto mode") + } +} + diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml new file mode 100644 index 000000000..2b907e609 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidNotificationToggle.qml @@ -0,0 +1,18 @@ +import qs +import qs.modules.common +import qs.services +import QtQuick +import Quickshell + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Notifications") + statusText: toggled ? Translation.tr("Show") : Translation.tr("Silent") + toggled: !Notifications.silent + buttonIcon: toggled ? "notifications_active" : "notifications_paused" + + onClicked: { + Notifications.silent = !Notifications.silent; + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml new file mode 100644 index 000000000..77c1cf9e1 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidOnScreenKeyboardToggle.qml @@ -0,0 +1,17 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Virtual Keyboard") + toggled: GlobalStates.oskOpen + buttonIcon: toggled ? "keyboard_hide" : "keyboard" + onClicked: { + GlobalStates.oskOpen = !GlobalStates.oskOpen + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml new file mode 100644 index 000000000..916e9be51 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidPowerProfileToggle.qml @@ -0,0 +1,42 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell +import Quickshell.Services.UPower + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Power Profile") + toggled: PowerProfiles.profile !== PowerProfile.Balanced + buttonIcon: switch(PowerProfiles.profile) { + case PowerProfile.PowerSaver: return "energy_savings_leaf" + case PowerProfile.Balanced: return "settings_slow_motion" + case PowerProfile.Performance: return "local_fire_department" + } + statusText: switch(PowerProfiles.profile) { + case PowerProfile.PowerSaver: return "Power Saver" + case PowerProfile.Balanced: return "Balanced" + case PowerProfile.Performance: return "Performance" + } + + onClicked: (event) => { + if (PowerProfiles.hasPerformanceProfile) { + switch(PowerProfiles.profile) { + case PowerProfile.PowerSaver: PowerProfiles.profile = PowerProfile.Balanced + break; + case PowerProfile.Balanced: PowerProfiles.profile = PowerProfile.Performance + break; + case PowerProfile.Performance: PowerProfiles.profile = PowerProfile.PowerSaver + break; + } + } else { + PowerProfiles.profile = PowerProfiles.profile == PowerProfile.Balanced ? PowerProfile.PowerSaver : PowerProfile.Balanced + } + } + StyledToolTip { + text: Translation.tr("Click to cycle through power profiles") + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml new file mode 100644 index 000000000..418245047 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidQuickToggleButton.qml @@ -0,0 +1,173 @@ +import QtQuick +import QtQuick.Layouts +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets + +GroupButton { + id: root + + required property int buttonIndex + required property var buttonData + required property bool expandedSize + required property string buttonIcon + required property string name + property string statusText: toggled ? Translation.tr("Active") : Translation.tr("Inactive") + + required property real baseCellWidth + required property real baseCellHeight + required property real cellSpacing + required property int cellSize + baseWidth: root.baseCellWidth * cellSize + cellSpacing * (cellSize - 1) + baseHeight: root.baseCellHeight + + Behavior on baseWidth { + animation: Appearance.animation.elementMove.numberAnimation.createObject(this) + } + + property bool editMode: false + + signal openMenu() + + padding: 6 + horizontalPadding: padding + verticalPadding: padding + + colBackground: Appearance.colors.colLayer2 + colBackgroundToggled: (altAction && expandedSize) ? Appearance.colors.colLayer2 : Appearance.colors.colPrimary + colBackgroundToggledHover: (altAction && expandedSize) ? Appearance.colors.colLayer2Hover : Appearance.colors.colPrimaryHover + colBackgroundToggledActive: (altAction && expandedSize) ? Appearance.colors.colLayer2Active : Appearance.colors.colPrimaryActive + buttonRadius: toggled ? Appearance.rounding.large : height / 2 + buttonRadiusPressed: Appearance.rounding.normal + property color colText: (toggled && !(altAction && expandedSize)) ? Appearance.colors.colOnPrimary : Appearance.colors.colOnLayer2 + property color colIcon: expandedSize ? (root.toggled ? Appearance.colors.colOnPrimary : Appearance.colors.colOnLayer3) : colText + + contentItem: RowLayout { + id: contentItem + spacing: 4 + anchors { + centerIn: root.expandedSize ? undefined : parent + fill: root.expandedSize ? parent : undefined + leftMargin: root.horizontalPadding + rightMargin: root.horizontalPadding + } + + Rectangle { + Layout.alignment: Qt.AlignHCenter + Layout.fillHeight: true + Layout.topMargin: root.verticalPadding + Layout.bottomMargin: root.verticalPadding + implicitWidth: height + radius: root.radius - root.verticalPadding + color: { + const baseColor = root.toggled ? Appearance.colors.colPrimary : Appearance.colors.colLayer3 + const transparentizeAmount = (root.altAction && root.expandedSize) ? 0 : 1 + return ColorUtils.transparentize(baseColor, transparentizeAmount) + } + + MaterialSymbol { + anchors.centerIn: parent + fill: root.toggled ? 1 : 0 + iconSize: Appearance.font.pixelSize.huge + color: root.colIcon + text: root.buttonIcon + } + } + + Loader { + Layout.alignment: Qt.AlignVCenter + Layout.fillWidth: true + visible: root.expandedSize + active: visible + sourceComponent: Column { + StyledText { + anchors { + left: parent.left + right: parent.right + } + font.pixelSize: Appearance.font.pixelSize.smallie + color: root.colText + elide: Text.ElideRight + text: root.name + } + + StyledText { + visible: root.statusText + anchors { + left: parent.left + right: parent.right + } + font { + pixelSize: Appearance.font.pixelSize.smaller + weight: Font.Light + } + color: root.colText + elide: Text.ElideRight + text: root.statusText + } + } + } + } + + MouseArea { // Blocking MouseArea for edit interactions + id: editModeInteraction + visible: root.editMode + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + acceptedButtons: Qt.AllButtons + + function toggleEnabled() { + const index = root.buttonIndex; + const toggleList = Config.options.sidebar.quickToggles.android.toggles; + const buttonType = root.buttonData.type; + if (!toggleList.find(toggle => toggle.type === buttonType)) { + toggleList.push({ type: buttonType, size: 1 }); + } else { + toggleList.splice(index, 1); + } + } + + function toggleSize() { + const index = root.buttonIndex; + const toggleList = Config.options.sidebar.quickToggles.android.toggles; + const buttonType = root.buttonData.type; + if (!toggleList.find(toggle => toggle.type === buttonType)) return; + toggleList[index].size = 3 - toggleList[index].size; // Alternate between 1 and 2 + } + + function movePositionBy(offset) { + const index = root.buttonIndex; + const toggleList = Config.options.sidebar.quickToggles.android.toggles; + const buttonType = root.buttonData.type; + const targetIndex = index + offset; + if (targetIndex < 0 || targetIndex >= toggleList.length) return; + const temp = toggleList[index]; + toggleList[index] = toggleList[targetIndex]; + toggleList[targetIndex] = temp; + } + + onReleased: (event) => { + if (event.button === Qt.LeftButton) + toggleEnabled(); + } + onPressed: (event) => { + if (event.button === Qt.RightButton) toggleSize(); + } + onPressAndHold: (event) => { // Also toggle size + toggleSize(); + } + onWheel: (event) => { + const index = root.buttonIndex; + const toggleList = Config.options.sidebar.quickToggles.android.toggles; + const buttonType = root.buttonData.type; + if (event.angleDelta.y < 0) { // Move to right + movePositionBy(1); + } else if (event.angleDelta.y > 0) { // Move to left + movePositionBy(-1); + } + event.accepted = true; + } + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml new file mode 100644 index 000000000..70d623027 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidScreenSnipToggle.qml @@ -0,0 +1,27 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import Quickshell + +AndroidQuickToggleButton { + id: root + + name: Translation.tr("Screen snip") + toggled: false + buttonIcon: "screenshot_region" + + onClicked: { + GlobalStates.sidebarRightOpen = false; + delayedActionTimer.start() + } + Timer { + id: delayedActionTimer + interval: 300 + repeat: false + onTriggered: { + Quickshell.execDetached(["qs", "-p", Quickshell.shellPath("screenshot.qml")]) + } + } +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml new file mode 100644 index 000000000..5a64753b7 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/androidStyle/AndroidToggleDelegateChooser.qml @@ -0,0 +1,225 @@ +pragma ComponentBehavior: Bound +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Bluetooth + +import "./androidStyle/" + +DelegateChooser { + id: root + property bool editMode: false + required property real baseCellWidth + required property real baseCellHeight + required property real spacing + required property int startingIndex + signal openWifiDialog() + signal openBluetoothDialog() + + role: "type" + + DelegateChoice { roleValue: "network"; AndroidNetworkToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + altAction: () => { + root.openWifiDialog() + } + } } + + DelegateChoice { roleValue: "bluetooth"; AndroidBluetoothToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + altAction: () => { + root.openBluetoothDialog() + } + } } + + DelegateChoice { roleValue: "idleInhibitor"; AndroidIdleInhibitorToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "easyEffects"; AndroidEasyEffectsToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "nightLight"; AndroidNightLightToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "darkMode"; AndroidDarkModeToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "cloudflareWarp"; AndroidCloudflareWarpToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "gameMode"; AndroidGameModeToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "screenSnip"; AndroidScreenSnipToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "colorPicker"; AndroidColorPickerToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "onScreenKeyboard"; AndroidOnScreenKeyboardToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "mic"; AndroidMicToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "audio"; AndroidAudioToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "notifications"; AndroidNotificationToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + + DelegateChoice { roleValue: "powerProfile"; AndroidPowerProfileToggle { + required property int index + required property var modelData + buttonIndex: root.startingIndex + index + buttonData: modelData + editMode: root.editMode + expandedSize: modelData.size > 1 + baseCellWidth: root.baseCellWidth + baseCellHeight: root.baseCellHeight + cellSpacing: root.spacing + cellSize: modelData.size + } } + +} diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/BluetoothToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/BluetoothToggle.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/BluetoothToggle.qml rename to dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/BluetoothToggle.qml diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/CloudflareWarp.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/CloudflareWarp.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/CloudflareWarp.qml rename to dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/CloudflareWarp.qml diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/EasyEffectsToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/EasyEffectsToggle.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/EasyEffectsToggle.qml rename to dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/EasyEffectsToggle.qml index 643764ff3..0bbe22d68 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/EasyEffectsToggle.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/EasyEffectsToggle.qml @@ -8,8 +8,8 @@ import Quickshell.Hyprland QuickToggleButton { id: root - toggled: EasyEffects.active visible: EasyEffects.available + toggled: EasyEffects.active buttonIcon: "instant_mix" Component.onCompleted: { diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/GameMode.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/GameMode.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/GameMode.qml rename to dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/GameMode.qml diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/IdleInhibitor.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/IdleInhibitor.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/IdleInhibitor.qml rename to dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/IdleInhibitor.qml diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/NetworkToggle.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/NetworkToggle.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/NetworkToggle.qml rename to dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/NetworkToggle.qml diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/NightLight.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/NightLight.qml similarity index 89% rename from dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/NightLight.qml rename to dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/NightLight.qml index 3e112a16b..8b7e69a5a 100644 --- a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/NightLight.qml +++ b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/NightLight.qml @@ -6,8 +6,7 @@ import Quickshell.Io QuickToggleButton { id: nightLightButton - property bool enabled: Hyprsunset.active - toggled: enabled + toggled: Hyprsunset.active buttonIcon: Config.options.light.night.automatic ? "night_sight_auto" : "bedtime" onClicked: { Hyprsunset.toggle() diff --git a/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/QuickToggleButton.qml b/dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/QuickToggleButton.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/QuickToggleButton.qml rename to dots/.config/quickshell/ii/modules/sidebarRight/quickToggles/classicStyle/QuickToggleButton.qml diff --git a/dots/.config/quickshell/ii/translations/en_US.json.bak b/dots/.config/quickshell/ii/translations/en_US.json.bak new file mode 100644 index 000000000..9e042fbe6 --- /dev/null +++ b/dots/.config/quickshell/ii/translations/en_US.json.bak @@ -0,0 +1,511 @@ +{ + "Material cookie": "Material cookie", + "Style: Blurred": "Style: Blurred", + "Unknown device": "Unknown device", + "Change any time later with /dark, /light, /wallpaper in the launcher\nIf the shell's colors aren't changing:\n 1. Open the right sidebar with Super+N\n 2. Click \"Reload Hyprland & Quickshell\" in the top-right corner": "Change any time later with /dark, /light, /wallpaper in the launcher\nIf the shell's colors aren't changing:\n 1. Open the right sidebar with Super+N\n 2. Click \"Reload Hyprland & Quickshell\" in the top-right corner", + "No pending tasks": "No pending tasks", + "Positioning": "Positioning", + "Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.": "Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.", + "Critical warning": "Critical warning", + "Unknown Artist": "Unknown Artist", + "Web search": "Web search", + "Load prompt from %1": "Load prompt from %1", + "Attach a file. Only works with Gemini.": "Attach a file. Only works with Gemini.", + "Reboot": "Reboot", + "API key:\n\n```txt\n%1\n```": "API key:\n\n```txt\n%1\n```", + "Pinned on startup": "Pinned on startup", + "Right": "Right", + "Reboot to firmware settings": "Reboot to firmware settings", + "Automatically hide": "Automatically hide", + "Waiting for response...": "Waiting for response...", + "To Do": "To Do", + "Full": "Full", + "Select Language": "Select Language", + "Password": "Password", + "Bluetooth devices": "Bluetooth devices", + "Enable": "Enable", + "Elements": "Elements", + "Start": "Start", + "Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers": "Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers", + "The popular one | Best quantity, but quality can vary wildly": "The popular one | Best quantity, but quality can vary wildly", + "System uptime:": "System uptime:", + "illogical-impulse Welcome": "illogical-impulse Welcome", + "Code saved to file": "Code saved to file", + "Info": "Info", + "Preferred wallpaper zoom (%)": "Preferred wallpaper zoom (%)", + "Time": "Time", + "Help & Support": "Help & Support", + "Bubble": "Bubble", + "Large images | God tier quality, no NSFW.": "Large images | God tier quality, no NSFW.", + "Dark": "Dark", + "Center clock": "Center clock", + "Search, calculate or run": "Search, calculate or run", + "Region height": "Region height", + "Load chat": "Load chat", + "Gives the model search capabilities (immediately)": "Gives the model search capabilities (immediately)", + "Depends on workspace": "Depends on workspace", + "Blurred style": "Blurred style", + "Screenshot tool": "Screenshot tool", + "Enter password": "Enter password", + "Search the web": "Search the web", + "Local only": "Local only", + "at": "at", + "Math": "Math", + "Consider plugging in your device": "Consider plugging in your device", + "Workspaces shown": "Workspaces shown", + "Place the corners to trigger at the bottom": "Place the corners to trigger at the bottom", + "No API key\nSet it with /key YOUR_API_KEY": "No API key\nSet it with /key YOUR_API_KEY", + "Auto (System)": "Auto (System)", + "Arrow keys to navigate, Enter to select\nEsc or click anywhere to cancel": "Arrow keys to navigate, Enter to select\nEsc or click anywhere to cancel", + "Critically low battery": "Critically low battery", + "Open editor": "Open editor", + "%1 notifications": "%1 notifications", + "Region width": "Region width", + "Max allowed increase": "Max allowed increase", + "Enable translator": "Enable translator", + "Constantly rotate": "Constantly rotate", + "Automatically suspends the system when battery is low": "Automatically suspends the system when battery is low", + "Cannot find a GPS service. Using the fallback method instead.": "Cannot find a GPS service. Using the fallback method instead.", + "Qt apps": "Qt apps", + "Color picker": "Color picker", + "Interface": "Interface", + "Tint app icons": "Tint app icons", + "Select the language for the user interface.\n\"Auto\" will use your system's locale.": "Select the language for the user interface.\n\"Auto\" will use your system's locale.", + "Show quote": "Show quote", + "Local Ollama model | %1": "Local Ollama model | %1", + "Show clock": "Show clock", + "Usage: %1superpaste NUM_OF_ENTRIES[i]\nSupply i when you want images\nExamples:\n%1superpaste 4i for the last 4 images\n%1superpaste 7 for the last 7 entries": "Usage: %1superpaste NUM_OF_ENTRIES[i]\nSupply i when you want images\nExamples:\n%1superpaste 4i for the last 4 images\n%1superpaste 7 for the last 7 entries", + "Audio": "Audio", + "Corner style": "Corner style", + "No media": "No media", + "Unknown function call: %1": "Unknown function call: %1", + "Online | %1's model | Delivers fast, responsive and well-formatted answers. Disadvantages: not very eager to do stuff; might make up unknown function calls": "Online | %1's model | Delivers fast, responsive and well-formatted answers. Disadvantages: not very eager to do stuff; might make up unknown function calls", + "Volume": "Volume", + "Medium": "Medium", + "Copy code": "Copy code", + "Exceeded max allowed": "Exceeded max allowed", + "Keep right sidebar loaded": "Keep right sidebar loaded", + "Left": "Left", + "High": "High", + "Rect": "Rect", + "Lap": "Lap", + "Clear": "Clear", + "Screen snip": "Screen snip", + "Reset": "Reset", + "Back": "Back", + "Dark/Light toggle": "Dark/Light toggle", + "12h am/pm": "12h am/pm", + "Download complete": "Download complete", + "Enable blur": "Enable blur", + "Second hand": "Second hand", + "Bar & screen": "Bar & screen", + "Discharging:": "Discharging:", + "Up %1": "Up %1", + "Low": "Low", + "Hour hand": "Hour hand", + "Clear chat history": "Clear chat history", + "Fruit Salad": "Fruit Salad", + "%1 Safe Storage": "%1 Safe Storage", + "Hibernate": "Hibernate", + "Delete": "Delete", + "OK": "OK", + "Settings": "Settings", + "This is usually safe and needed for your browser and AI sidebar anyway\nMostly useful for those who use lock on startup instead of a display manager that does it (GDM, SDDM, etc.)": "This is usually safe and needed for your browser and AI sidebar anyway\nMostly useful for those who use lock on startup instead of a display manager that does it (GDM, SDDM, etc.)", + "Use Hyprlock (instead of Quickshell)": "Use Hyprlock (instead of Quickshell)", + "Crosshair code (in Valorant's format)": "Crosshair code (in Valorant's format)", + "Silent": "Silent", + "Useless buttons": "Useless buttons", + "Hover to reveal": "Hover to reveal", + "Wallpaper & Colors": "Wallpaper & Colors", + "Auto": "Auto", + "Visibility": "Visibility", + "Shell & utilities": "Shell & utilities", + "Hollow": "Hollow", + "illogical-impulse": "illogical-impulse", + "Use the system file picker instead\nRight-click to make this the default behavior": "Use the system file picker instead\nRight-click to make this the default behavior", + "On-screen display": "On-screen display", + "Dotfiles": "Dotfiles", + "Search wallpapers": "Search wallpapers", + "Mic toggle": "Mic toggle", + "Input": "Input", + "Also unlock keyring": "Also unlock keyring", + "Configuration": "Configuration", + "Keep system awake": "Keep system awake", + "Unknown command:": "Unknown command:", + "Anime boorus": "Anime boorus", + "To Do:": "To Do:", + "Uses Gemini to categorize the wallpaper then picks a preset based on it.\nYou'll need to set Gemini API key on the left sidebar first.\nImages are downscaled for performance, but just to be safe,\ndo not select wallpapers with sensitive information.": "Uses Gemini to categorize the wallpaper then picks a preset based on it.\nYou'll need to set Gemini API key on the left sidebar first.\nImages are downscaled for performance, but just to be safe,\ndo not select wallpapers with sensitive information.", + "Bottom": "Bottom", + "Clear the current list of images": "Clear the current list of images", + "Sunrise": "Sunrise", + "Show app icons": "Show app icons", + "Format": "Format", + "Make sure your player has MPRIS support\nor try turning off duplicate player filtering": "Make sure your player has MPRIS support\nor try turning off duplicate player filtering", + "Pause": "Pause", + "Desktop": "Desktop", + "Conflicts with the shell's system tray implementation": "Conflicts with the shell's system tray implementation", + "Your package manager is running": "Your package manager is running", + "Conflicts with the shell's notification implementation": "Conflicts with the shell's notification implementation", + "Unknown Album": "Unknown Album", + "Pick wallpaper image on your system": "Pick wallpaper image on your system", + "Used:": "Used:", + "Cheat sheet": "Cheat sheet", + "Clock style": "Clock style", + "No audio source": "No audio source", + "Paired": "Paired", + "Documentation": "Documentation", + "No": "No", + "Pills": "Pills", + "Thought": "Thought", + "When this is off you'll have to click": "When this is off you'll have to click", + "Select output device": "Select output device", + "Logout": "Logout", + "Tip: Close a window with Super+Q": "Tip: Close a window with Super+Q", + "Finished tasks will go here": "Finished tasks will go here", + "Terminal: Harmony (%)": "Terminal: Harmony (%)", + "Corner open": "Corner open", + "Shell conflicts killer": "Shell conflicts killer", + "Clean stuff | Excellent quality, no NSFW": "Clean stuff | Excellent quality, no NSFW", + "Scroll to change volume": "Scroll to change volume", + "Wind": "Wind", + "API key is set\nChange with /key YOUR_API_KEY": "API key is set\nChange with /key YOUR_API_KEY", + "Neutral": "Neutral", + "12h AM/PM": "12h AM/PM", + "Number show delay when pressing Super (ms)": "Number show delay when pressing Super (ms)", + "Fill": "Fill", + "Always show numbers": "Always show numbers", + "Dot": "Dot", + "Provider set to": "Provider set to", + "Unknown Title": "Unknown Title", + "Click to toggle light/dark mode (applied when wallpaper is chosen)": "Click to toggle light/dark mode (applied when wallpaper is chosen)", + "Anime": "Anime", + "Refreshing (manually triggered)": "Refreshing (manually triggered)", + "Dock": "Dock", + "Require password to power off/restart": "Require password to power off/restart", + "Line": "Line", + "Weather": "Weather", + "All-rounder | Good quality, decent quantity": "All-rounder | Good quality, decent quantity", + "Scale (%)": "Scale (%)", + "Copy": "Copy", + "Usage": "Usage", + "Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window": "Type /key to get started with online models\nCtrl+O to expand the sidebar\nCtrl+P to detach sidebar into a window", + "Set the tool to use for the model.": "Set the tool to use for the model.", + "Disable tools": "Disable tools", + "Connect": "Connect", + "Allow NSFW": "Allow NSFW", + "Registration failed. Please inspect manually with the warp-cli command": "Registration failed. Please inspect manually with the warp-cli command", + "Time to full:": "Time to full:", + "Session": "Session", + "Services": "Services", + "Nothing here!": "Nothing here!", + "Overview": "Overview", + "Random: osu! seasonal": "Random: osu! seasonal", + "If you want to somehow use fingerprint unlock...": "If you want to somehow use fingerprint unlock...", + "Minute hand": "Minute hand", + "Notifications": "Notifications", + "Enable if you want clocks to show seconds accurately": "Enable if you want clocks to show seconds accurately", + "Timer": "Timer", + "Quote settings": "Quote settings", + "System prompt": "System prompt", + "Classic": "Classic", + "Close": "Close", + "Disconnect": "Disconnect", + "Go to source (%1)": "Go to source (%1)", + "EasyEffects | Right-click to configure": "EasyEffects | Right-click to configure", + "Forget": "Forget", + "Output": "Output", + "Date style": "Date style", + "System": "System", + "Usage: %1tool TOOL_NAME": "Usage: %1tool TOOL_NAME", + "Workspaces": "Workspaces", + "Calendar": "Calendar", + "**Instructions**: Log into Mistral account, go to Keys on the sidebar, click Create new key": "**Instructions**: Log into Mistral account, go to Keys on the sidebar, click Create new key", + "Volume limit": "Volume limit", + "Sunset": "Sunset", + "Dial style": "Dial style", + "Hi there! First things first...": "Hi there! First things first...", + "Save chat to %1": "Save chat to %1", + "Security": "Security", + "Total token count\nInput: %1\nOutput: %2": "Total token count\nInput: %1\nOutput: %2", + "Cancel wallpaper selection": "Cancel wallpaper selection", + "Please charge!\nAutomatic suspend triggers at %1": "Please charge!\nAutomatic suspend triggers at %1", + "Terminal: Harmonize threshold": "Terminal: Harmonize threshold", + "Be patient...": "Be patient...", + "Utility buttons": "Utility buttons", + "Tonal Spot": "Tonal Spot", + "Prevents abrupt increments and restricts volume limit": "Prevents abrupt increments and restricts volume limit", + "Set the current API provider": "Set the current API provider", + "Connection failed. Please inspect manually with the warp-cli command": "Connection failed. Please inspect manually with the warp-cli command", + "Networking": "Networking", + "Tint icons": "Tint icons", + "Low battery": "Low battery", + "Make icons pinned by default": "Make icons pinned by default", + "Get the next page of results": "Get the next page of results", + "Invalid API provider. Supported: \n-": "Invalid API provider. Supported: \n-", + "Show \"Locked\" text": "Show \"Locked\" text", + "**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key": "**Pricing**: free. Data use policy varies depending on your OpenRouter account settings.\n\n**Instructions**: Log into OpenRouter account, go to Keys on the topright menu, click Create API Key", + "Not visible to model": "Not visible to model", + "Lock screen": "Lock screen", + "Save to Downloads": "Save to Downloads", + "Expressive": "Expressive", + "Suspend at": "Suspend at", + "Jump to current month": "Jump to current month", + "Bold": "Bold", + "Waifus only | Excellent quality, limited quantity": "Waifus only | Excellent quality, limited quantity", + "Click to toggle light/dark mode\n(applied when wallpaper is chosen)": "Click to toggle light/dark mode\n(applied when wallpaper is chosen)", + "Visualize region": "Visualize region", + "Quote": "Quote", + "Sleep": "Sleep", + "Hit \"/\" to search": "Hit \"/\" to search", + "Hug": "Hug", + "Report a Bug": "Report a Bug", + "Precipitation": "Precipitation", + "Crosshair": "Crosshair", + "Model set to %1": "Model set to %1", + "Rows": "Rows", + "Top": "Top", + "Long break": "Long break", + "Superpaste": "Superpaste", + "Screen round corner": "Screen round corner", + "Online | Google's model\nNewer model that's slower than its predecessor but should deliver higher quality answers": "Online | Google's model\nNewer model that's slower than its predecessor but should deliver higher quality answers", + "Rainbow": "Rainbow", + "Weeb": "Weeb", + "Large language models": "Large language models", + "Online models disallowed\n\nControlled by `policies.ai` config option": "Online models disallowed\n\nControlled by `policies.ai` config option", + "Policies": "Policies", + "Temperature must be between 0 and 2": "Temperature must be between 0 and 2", + "Automatic suspend": "Automatic suspend", + "Extra wallpaper zoom (%)": "Extra wallpaper zoom (%)", + "GitHub": "GitHub", + "%1 | Right-click to configure": "%1 | Right-click to configure", + "**Pricing**: Free tier available with limited rates. See https://docs.github.com/en/billing/concepts/product-billing/github-models\n\n**Instructions**: Generate a GitHub personal access token with Models permission, then set as API key here\n\n**Note**: To use this you will have to set the temperature parameter to 1": "**Pricing**: Free tier available with limited rates. See https://docs.github.com/en/billing/concepts/product-billing/github-models\n\n**Instructions**: Generate a GitHub personal access token with Models permission, then set as API key here\n\n**Note**: To use this you will have to set the temperature parameter to 1", + "Edit directory": "Edit directory", + "Action": "Action", + "Search": "Search", + "Tip: right-clicking a group\nalso expands it": "Tip: right-clicking a group\nalso expands it", + "Bar": "Bar", + "Show regions of potential interest": "Show regions of potential interest", + "Clipboard": "Clipboard", + "Stopwatch": "Stopwatch", + "Enter text to translate...": "Enter text to translate...", + "App": "App", + "Sides": "Sides", + "No active player": "No active player", + "Use the system file picker instead": "Use the system file picker instead", + "Not all options are available in this app. You should also check the config file by hitting the \"Config file\" button on the topleft corner or opening %1 manually.": "Not all options are available in this app. You should also check the config file by hitting the \"Config file\" button on the topleft corner or opening %1 manually.", + "There might be a download in progress": "There might be a download in progress", + "Math result": "Math result", + "Fidelity": "Fidelity", + "Prefixes": "Prefixes", + "Terminal": "Terminal", + "Incorrect password": "Incorrect password", + "Line-separated": "Line-separated", + "Always": "Always", + "☕ Break: %1 minutes": "☕ Break: %1 minutes", + "Depends on sidebars": "Depends on sidebars", + "Tool set to: %1": "Tool set to: %1", + "Save chat": "Save chat", + "Crosshair overlay": "Crosshair overlay", + "Keybinds": "Keybinds", + "Launch": "Launch", + "Could be better if you make a ton of typos,\nbut results can be weird and might not work with acronyms\n(e.g. \"GIMP\" might not give you the paint program)": "Could be better if you make a ton of typos,\nbut results can be weird and might not work with acronyms\n(e.g. \"GIMP\" might not give you the paint program)", + "Choose model": "Choose model", + "Base URL": "Base URL", + "Float": "Float", + "Wallpaper parallax": "Wallpaper parallax", + "Invalid arguments. Must provide `command`.": "Invalid arguments. Must provide `command`.", + "Fully charged": "Fully charged", + "Earbang protection": "Earbang protection", + "Low warning": "Low warning", + "Advanced": "Advanced", + "Scroll to change brightness": "Scroll to change brightness", + "Loaded the following system prompt\n\n---\n\n%1": "Loaded the following system prompt\n\n---\n\n%1", + "Show next time": "Show next time", + "Current tool: %1\nSet it with %2tool TOOL": "Current tool: %1\nSet it with %2tool TOOL", + "Unread indicator: show count": "Unread indicator: show count", + "Press Super+G to toggle appearance": "Press Super+G to toggle appearance", + "That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number", + "Dots": "Dots", + "Cloudflare WARP (1.1.1.1)": "Cloudflare WARP (1.1.1.1)", + "Volume mixer": "Volume mixer", + "Config file": "Config file", + "API key set for %1": "API key set for %1", + "Online via %1 | %2's model": "Online via %1 | %2's model", + "Shell command": "Shell command", + "Such regions could be images or parts of the screen that have some containment.\nMight not always be accurate.\nThis is done with an image processing algorithm run locally and no AI is used.": "Such regions could be images or parts of the screen that have some containment.\nMight not always be accurate.\nThis is done with an image processing algorithm run locally and no AI is used.", + "Reload Hyprland & Quickshell": "Reload Hyprland & Quickshell", + "Resources": "Resources", + "Brightness": "Brightness", + "Unknown": "Unknown", + "Polling interval (ms)": "Polling interval (ms)", + "Lock": "Lock", + "Thinking": "Thinking", + "Approve": "Approve", + "Unfinished": "Unfinished", + "Random: Konachan": "Random: Konachan", + "Connected": "Connected", + "Wallpaper safety enforced": "Wallpaper safety enforced", + "Invalid arguments. Must provide `key` and `value`.": "Invalid arguments. Must provide `key` and `value`.", + "24h": "24h", + "Allows you to open sidebars by clicking or hovering screen corners regardless of bar position": "Allows you to open sidebars by clicking or hovering screen corners regardless of bar position", + "Bar style": "Bar style", + "Load:": "Load:", + "Open file link": "Open file link", + "Ignored if terminal theming is not enabled": "Ignored if terminal theming is not enabled", + "Shutdown": "Shutdown", + "Hour marks": "Hour marks", + "Random osu! seasonal background\nImage is saved to ~/Pictures/Wallpapers": "Random osu! seasonal background\nImage is saved to ~/Pictures/Wallpapers", + "Online | Google's model\nFast, can perform searches for up-to-date information": "Online | Google's model\nFast, can perform searches for up-to-date information", + "Current model: %1\nSet it with %2model MODEL": "Current model: %1\nSet it with %2model MODEL", + "Select input device": "Select input device", + "Connect to Wi-Fi": "Connect to Wi-Fi", + "... and %1 more": "... and %1 more", + "Cookie clock settings": "Cookie clock settings", + "Brightness and volume": "Brightness and volume", + "Choose file": "Choose file", + "Invalid model. Supported: \n```": "Invalid model. Supported: \n```", + "Task Manager": "Task Manager", + "Charging:": "Charging:", + "Illegal increment": "Illegal increment", + "Total:": "Total:", + "or": "or", + "Battery": "Battery", + "Timeout duration (if not defined by notification) (ms)": "Timeout duration (if not defined by notification) (ms)", + "Cancel": "Cancel", + "Locked": "Locked", + "Temperature: %1": "Temperature: %1", + "Hover to trigger": "Hover to trigger", + "Command rejected by user": "Command rejected by user", + "User agent (for services that require it)": "User agent (for services that require it)", + "Saved to %1": "Saved to %1", + "Emojis": "Emojis", + "Color generation": "Color generation", + "Welcome app": "Welcome app", + "Humidity": "Humidity", + "Page %1": "Page %1", + "Feels like %1": "Feels like %1", + "Distro": "Distro", + "Transparency": "Transparency", + "%1 • %2 tasks": "%1 • %2 tasks", + "Markdown test": "Markdown test", + "Invalid tool. Supported tools:\n- %1": "Invalid tool. Supported tools:\n- %1", + "No notifications": "No notifications", + "The hentai one | Great quantity, a lot of NSFW, quality varies wildly": "The hentai one | Great quantity, a lot of NSFW, quality varies wildly", + "Bluetooth": "Bluetooth", + "Resume": "Resume", + "Work safety": "Work safety", + "Temperature\nChange with /temp VALUE": "Temperature\nChange with /temp VALUE", + "Terminal: Foreground boost (%)": "Terminal: Foreground boost (%)", + "Night Light | Right-click to toggle Auto mode": "Night Light | Right-click to toggle Auto mode", + "Closet": "Closet", + "Yes": "Yes", + "Columns": "Columns", + "To set an API key, pass it with the %4 command\n\nTo view the key, pass \"get\" with the command
\n\n### For %1:\n\n**Link**: %2\n\n%3": "To set an API key, pass it with the %4 command\n\nTo view the key, pass \"get\" with the command
\n\n### For %1:\n\n**Link**: %2\n\n%3", + "Kill conflicting programs?": "Kill conflicting programs?", + "For storing API keys and other sensitive information": "For storing API keys and other sensitive information", + "Reject": "Reject", + "Set API key": "Set API key", + ". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!": ". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!", + "Content": "Content", + "Pomodoro": "Pomodoro", + "Vertical": "Vertical", + "Pick a wallpaper": "Pick a wallpaper", + "Load chat from %1": "Load chat from %1", + "Launch on startup": "Launch on startup", + "Add": "Add", + "Style: general": "Style: general", + "Use Levenshtein distance-based algorithm instead of fuzzy": "Use Levenshtein distance-based algorithm instead of fuzzy", + "Shell & utilities theming must also be enabled": "Shell & utilities theming must also be enabled", + "Workspace": "Workspace", + "Translator": "Translator", + "Free:": "Free:", + "🌿 Long break: %1 minutes": "🌿 Long break: %1 minutes", + "Value scroll": "Value scroll", + "Bar position": "Bar position", + "Language": "Language", + "Current API endpoint: %1\nSet it with %2mode PROVIDER": "Current API endpoint: %1\nSet it with %2mode PROVIDER", + "Remember that on most devices one can always hold the power button to force shutdown\nThis only makes it a tiny bit harder for accidents to happen": "Remember that on most devices one can always hold the power button to force shutdown\nThis only makes it a tiny bit harder for accidents to happen", + "AI": "AI", + "Task description": "Task description", + "Add task": "Add task", + "Donate": "Donate", + "Disable NSFW content": "Disable NSFW content", + "Set the system prompt for the model.": "Set the system prompt for the model.", + "Done": "Done", + "Focus": "Focus", + "Open the shell config file.\nIf the button doesn't work or doesn't open in your favorite editor,\nyou can manually open ~/.config/illogical-impulse/config.json": "Open the shell config file.\nIf the button doesn't work or doesn't open in your favorite editor,\nyou can manually open ~/.config/illogical-impulse/config.json", + "View Markdown source": "View Markdown source", + "Border": "Border", + "Temperature set to %1": "Temperature set to %1", + "Online | Google's model\nGoogle's state-of-the-art multipurpose model that excels at coding and complex reasoning tasks.": "Online | Google's model\nGoogle's state-of-the-art multipurpose model that excels at coding and complex reasoning tasks.", + "Message the model... \"%1\" for commands": "Message the model... \"%1\" for commands", + "Translation goes here...": "Translation goes here...", + "When enabled keeps the content of the right sidebar loaded to reduce the delay when opening,\nat the cost of around 15MB of consistent RAM usage. Delay significance depends on your system's performance.\nUsing a custom kernel like linux-cachyos might help": "When enabled keeps the content of the right sidebar loaded to reduce the delay when opening,\nat the cost of around 15MB of consistent RAM usage. Delay significance depends on your system's performance.\nUsing a custom kernel like linux-cachyos might help", + "For desktop wallpapers | Good quality": "For desktop wallpapers | Good quality", + "🔴 Focus: %1 minutes": "🔴 Focus: %1 minutes", + "The current system prompt is\n\n---\n\n%1": "The current system prompt is\n\n---\n\n%1", + "About": "About", + "Quick": "Quick", + "General": "General", + "UV Index": "UV Index", + "Force dark mode in terminal": "Force dark mode in terminal", + "Drag or click a region • LMB: Copy • RMB: Edit": "Drag or click a region • LMB: Copy • RMB: Edit", + "%1 characters": "%1 characters", + "Cloudflare WARP": "Cloudflare WARP", + "**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key": "**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key", + "Monochrome": "Monochrome", + "Details": "Details", + "Issues": "Issues", + "Keyboard toggle": "Keyboard toggle", + "Might look ass. Unsupported.": "Might look ass. Unsupported.", + "Download": "Download", + "%1 does not require an API key": "%1 does not require an API key", + "Style & wallpaper": "Style & wallpaper", + "Second precision": "Second precision", + "Group style": "Group style", + "Break": "Break", + "Run": "Run", + "Enjoy! You can reopen the welcome app any time with Super+Shift+Alt+/. To open the settings app, hit Super+I": "Enjoy! You can reopen the welcome app any time with Super+Shift+Alt+/. To open the settings app, hit Super+I", + "Interface Language": "Interface Language", + "Game mode": "Game mode", + "Usage: %1save CHAT_NAME": "Usage: %1save CHAT_NAME", + "Thin": "Thin", + "Light": "Light", + "When not fullscreen": "When not fullscreen", + "Commands, edit configs, search.\nTakes an extra turn to switch to search mode if that's needed": "Commands, edit configs, search.\nTakes an extra turn to switch to search mode if that's needed", + "Privacy Policy": "Privacy Policy", + "Timeout (ms)": "Timeout (ms)", + "Allow NSFW content": "Allow NSFW content", + "Edit": "Edit", + "Digits in the middle": "Digits in the middle", + "Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput.": "Online | Google's model\nA Gemini 2.5 Flash model optimized for cost-efficiency and high throughput.", + "Weather Service": "Weather Service", + "Background": "Background", + "Pick random from this folder": "Pick random from this folder", + "Pressure": "Pressure", + "Save": "Save", + "Run command": "Run command", + "Time to empty:": "Time to empty:", + "Place at bottom": "Place at bottom", + "Switched to search mode. Continue with the user's request.": "Switched to search mode. Continue with the user's request.", + "Performance Profile toggle": "Performance Profile toggle", + "Sidebars": "Sidebars", + "Usage: %1load CHAT_NAME": "Usage: %1load CHAT_NAME", + "Auto styling with Gemini": "Auto styling with Gemini", + "Simple digital": "Simple digital", + "No API key set for %1": "No API key set for %1", + "Enter tags, or \"%1\" for commands": "Enter tags, or \"%1\" for commands", + "%1 queries pending": "%1 queries pending", + "Discussions": "Discussions", + "Tray": "Tray", + "Numbers": "Numbers", + "Intelligence": "Intelligence", + "Open network portal": "Open network portal", + "No further instruction provided": "No further instruction provided", + "Language not listed or incomplete translations?\nYou can choose to generate translations for it with Gemini.\n1. Open the left sidebar with Super+A, set model to Gemini (if it isn't already)\n2. Type /key, hit Enter and follow the instructions\n3. Type /key YOUR_API_KEY\n4. Type the locale of your language below and press Generate": "Language not listed or incomplete translations?\nYou can choose to generate translations for it with Gemini.\n1. Open the left sidebar with Super+A, set model to Gemini (if it isn't already)\n2. Type /key, hit Enter and follow the instructions\n3. Type /key YOUR_API_KEY\n4. Type the locale of your language below and press Generate", + "Locale code, e.g. fr_FR, de_DE, zh_CN...": "Locale code, e.g. fr_FR, de_DE, zh_CN...", + "Select language": "Select language", + "Generate translation with Gemini": "Generate translation with Gemini", + "Generating...\nDon't close this window!": "Generating...\nDon't close this window!", + "Generate\nTypically takes 2 minutes": "Generate\nTypically takes 2 minutes" +} \ No newline at end of file