remove old Settings, rename new
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 11s
Python / lint-format (pull_request) Successful in 18s
Python / test (pull_request) Successful in 46s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m39s
C++ / build (pull_request) Successful in 2m26s

This commit is contained in:
2026-06-30 13:43:34 +02:00
parent deaeac4dbd
commit 38b9362515
93 changed files with 88 additions and 7943 deletions
+117
View File
@@ -0,0 +1,117 @@
import QtQuick
import QtQuick.Layouts
import Quickshell.Io
import ZShell
import qs.Modules.Settings.Common
import qs.Config
import qs.Helpers
import qs.Components
PageBase {
id: root
property string cliVersion
readonly property int pluginCount: 0
property string quickshellVersion
title: qsTr("About")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
Process {
command: ["quickshell", "--version"]
running: true
stdout: StdioCollector {
onStreamFinished: root.quickshellVersion = text.trim().split(" ")[1] ?? ""
}
}
ConnectedRect {
Layout.fillWidth: true
first: true
implicitHeight: hero.implicitHeight + Appearance.padding.extraLarge * 2
last: true
ColumnLayout {
id: hero
anchors.centerIn: parent
spacing: Appearance.spacing.small
width: parent.width - Appearance.padding.largeIncreased * 2
CustomText {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Appearance.spacing.small
font.pointSize: Appearance.font.size.large
text: "ZShell"
}
CustomText {
Layout.alignment: Qt.AlignHCenter
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.medium
text: ZUtils.version ? `v${ZUtils.version}` : "…"
}
}
}
// System
SectionHeader {
text: qsTr("System")
}
InfoRow {
first: true
label: qsTr("Hostname")
value: SystemInfo.hostname
}
InfoRow {
label: qsTr("Device")
value: SystemInfo.device
}
InfoRow {
label: qsTr("Distro")
value: SystemInfo.osPrettyName || SystemInfo.osName
}
InfoRow {
label: qsTr("Kernel")
value: SystemInfo.kernel
}
InfoRow {
label: qsTr("Firmware")
last: true
value: SystemInfo.firmware
}
// Software
SectionHeader {
text: qsTr("Software")
}
InfoRow {
first: true
label: qsTr("Shell")
value: ZUtils.version || "…"
}
InfoRow {
label: qsTr("Quickshell")
value: root.quickshellVersion || "…"
}
InfoRow {
label: qsTr("Qt")
last: true
value: ZUtils.qtVersion || "…"
}
}
}
+100
View File
@@ -0,0 +1,100 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import qs.Components
import qs.Config
import qs.Helpers
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("All apps")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
Repeater {
id: list
model: [...DesktopEntries.applications.values].sort((a, b) => a.name.localeCompare(b.name))
ConnectedRect {
id: appItem
required property int index
required property DesktopEntry modelData
Layout.fillWidth: true
first: index === 0
implicitHeight: appRow.implicitHeight + appRow.anchors.margins * 2
last: index === list.count - 1
StateLayer {
onClicked: {
root.sState.selectedApp = appItem.modelData;
root.sState.openSubPage(2);
}
}
RowLayout {
id: appRow
anchors.fill: parent
anchors.leftMargin: Appearance.padding.largeIncreased
anchors.margins: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.largeIncreased
spacing: Appearance.spacing.small
IconImage {
asynchronous: true
implicitSize: Math.round(Appearance.font.size.large * 1.8)
source: Quickshell.iconPath(appItem.modelData.icon, "image-missing")
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
CustomText {
Layout.fillWidth: true
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
text: appItem.modelData.name
}
CustomText {
Layout.fillWidth: true
color: DynamicColors.palette.m3outline
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
text: (appItem.modelData.comment || appItem.modelData.genericName) ?? ""
visible: text
}
}
MaterialIcon {
color: DynamicColors.palette.m3primary
fill: 1
font.pointSize: Appearance.font.size.small
text: "favorite"
visible: Strings.testRegexList(Config.launcher.favoriteApps, appItem.modelData.id)
}
MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.medium
text: "chevron_right"
}
}
}
}
}
}
+172
View File
@@ -0,0 +1,172 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import qs.Components
import qs.Config
import qs.Helpers
import qs.Modules.Settings.Common
PageBase {
id: root
readonly property DesktopEntry app: sState.selectedApp
readonly property bool favoriteByRegex: app && matchedByRegex(Config.launcher.favoriteApps, app.id)
readonly property bool hiddenByRegex: app && matchedByRegex(Config.launcher.hiddenApps, app.id)
function isRegexEntry(s: string): bool {
return /^\^.*\$$/.test(s);
}
function matchedByRegex(filterList: list<string>, id: string): bool {
return filterList.some(f => isRegexEntry(f) && new RegExp(f).test(id));
}
isSubPage: true
title: qsTr("App info")
onAppChanged: {
// Auto close when app lost
if (!app)
sState.closeSubPage();
}
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// Header
RowLayout {
Layout.bottomMargin: Appearance.spacing.large
Layout.fillWidth: true
Layout.leftMargin: Appearance.padding.small
spacing: Appearance.spacing.large
IconImage {
asynchronous: true
implicitSize: Math.round(Appearance.font.size.large * 3)
source: Quickshell.iconPath(root.app?.icon, "image-missing")
}
ColumnLayout {
Layout.fillWidth: true
spacing: Appearance.spacing.extraSmall / 2
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.medium
text: root.app?.name ?? ""
wrapMode: Text.WordWrap
}
CustomText {
Layout.fillWidth: true
color: DynamicColors.palette.m3outline
font.pointSize: Appearance.font.size.small
text: (root.app?.comment || root.app?.genericName) ?? ""
visible: text
wrapMode: Text.WordWrap
}
}
}
// Launcher
SectionHeader {
first: true
text: qsTr("Launcher")
}
ToggleRow {
checked: root.app && Strings.testRegexList(Config.launcher.favoriteApps, root.app.id)
enabled: !root.favoriteByRegex
first: true
subtext: root.favoriteByRegex ? qsTr("Matched by a regex in favoriteApps — edit the config file to change") : qsTr("Pin to the bottom of the launcher")
text: qsTr("Favorite")
onToggled: {
const apps = Config.launcher.favoriteApps;
Config.launcher.favoriteApps = checked ? [...apps, root.app.id] : apps.filter(a => a !== root.app.id);
}
}
ToggleRow {
checked: root.app && Strings.testRegexList(Config.launcher.hiddenApps, root.app.id)
enabled: !root.hiddenByRegex
last: true
subtext: root.hiddenByRegex ? qsTr("Matched by a regex in hiddenApps — edit the config file to change") : qsTr("Hide from the launcher")
text: qsTr("Hidden")
onToggled: {
const apps = Config.launcher.hiddenApps;
Config.launcher.hiddenApps = checked ? [...apps, root.app.id] : apps.filter(a => a !== root.app.id);
}
}
// Details
SectionHeader {
text: qsTr("Details")
}
WrapInfoRow {
id: appId
first: true
label: qsTr("App ID")
labelComp.Layout.preferredWidth: Math.max(labelComp.implicitWidth, command.labelComp.implicitWidth)
value: root.app?.id ?? ""
}
WrapInfoRow {
id: command
label: qsTr("Command")
labelComp.Layout.preferredWidth: Math.max(labelComp.implicitWidth, appId.labelComp.implicitWidth)
last: true
value: (root.app?.command ?? []).join(" ")
}
}
component WrapInfoRow: ConnectedRect {
id: row
property alias label: label.text
readonly property alias labelComp: label
property alias value: value.text
Layout.fillWidth: true
implicitHeight: rowLayout.implicitHeight + rowLayout.anchors.margins * 2
RowLayout {
id: rowLayout
anchors.fill: parent
anchors.leftMargin: Appearance.padding.largeIncreased
anchors.margins: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.largeIncreased
spacing: Appearance.spacing.small
CustomText {
id: label
Layout.alignment: Qt.AlignTop
font.pointSize: Appearance.font.size.small
}
Item {
Layout.fillWidth: true
}
CustomText {
id: value
Layout.fillWidth: true
Layout.maximumWidth: implicitWidth + 1 // Whyyyyyyyyy
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.small
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
}
}
}
}
+177
View File
@@ -0,0 +1,177 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import ZShell
import qs.Helpers
import qs.Components
import qs.Config
import qs.Modules.Settings.Common
PageBase {
id: root
title: qsTr("Apps")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// Default applications
SectionHeader {
first: true
text: qsTr("Default applications")
}
DefaultRow {
first: true
icon: "terminal"
status: Config.general.apps.terminal.join(" ")
text: qsTr("Terminal")
onSelected: app => Config.general.apps.terminal = app.command
}
DefaultRow {
icon: "volume_up"
status: Config.general.apps.audio.join(" ")
text: qsTr("Audio")
onSelected: app => Config.general.apps.audio = app.command
}
DefaultRow {
icon: "play_circle"
status: Config.general.apps.playback.join(" ")
text: qsTr("Media playback")
onSelected: app => Config.general.apps.playback = app.command
}
DefaultRow {
icon: "folder"
last: true
status: Config.general.apps.explorer.join(" ")
text: qsTr("File manager")
onSelected: app => Config.general.apps.explorer = app.command
}
// Library
SectionHeader {
text: qsTr("Library")
}
NavRow {
first: true
icon: "apps"
last: true
status: qsTr("Browse installed apps, set favorites and hidden")
text: qsTr("All apps")
onClicked: root.sState.openSubPage(1)
}
}
component DefaultRow: PopupRow {
id: row
readonly property int popupHeight: root.flickable.height - y + root.flickable.contentY - Appearance.padding.large - Appearance.padding.extraLarge
signal selected(app: DesktopEntry)
keepPopupAsChild: {
if (root.sState.animatingContainer || root.opacity < 1)
return true;
let p = root.parent;
while (p && p.objectName !== "PageContainer")
p = p.parent;
return p?.opacity < 1;
}
popup.topMovement: Appearance.padding.large
Loader {
active: row.popup.animDriver > 0
anchors.centerIn: parent
sourceComponent: VerticalFadeListView {
id: list
fadeAmount: 0.05
implicitHeight: ZUtils.clamp(row.popupHeight, 200, 800)
implicitWidth: 300
model: {
const apps = [...DesktopEntries.applications.values];
const favorited = new Set(apps.filter(a => Strings.testRegexList(Config.launcher.favoriteApps, a.id)));
return apps.sort((a, b) => (favorited.has(b) - favorited.has(a)) || a.name.localeCompare(b.name));
}
delegate: StateLayer {
id: appItem
required property int index
required property DesktopEntry modelData
anchors.fill: undefined
anchors.left: list.contentItem.left
anchors.right: list.contentItem.right
implicitHeight: itemLayout.implicitHeight + itemLayout.anchors.margins * 2
radius: Appearance.rounding.small
onClicked: {
row.popup.open = false;
row.selected(modelData);
}
RowLayout {
id: itemLayout
anchors.fill: parent
anchors.margins: Appearance.padding.normal
spacing: Appearance.spacing.small
IconImage {
asynchronous: true
implicitSize: Math.round(Appearance.font.size.large * 1.8)
source: Quickshell.iconPath(appItem.modelData.icon, "image-missing")
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
CustomText {
Layout.fillWidth: true
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
text: appItem.modelData.name
}
CustomText {
Layout.fillWidth: true
color: DynamicColors.palette.m3outline
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
text: (appItem.modelData.comment || appItem.modelData.genericName) ?? ""
visible: text
}
}
MaterialIcon {
color: DynamicColors.palette.m3primary
fill: 1
font.pointSize: Appearance.font.size.small
text: "favorite"
visible: Strings.testRegexList(Config.launcher.favoriteApps, appItem.modelData.id)
}
}
}
}
}
}
}
@@ -0,0 +1,69 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Pipewire
import qs.Modules.Settings.Common
import qs.Helpers
import qs.Components
import qs.Config
import qs.Daemons
PageBase {
id: root
isSubPage: true
title: qsTr("App volumes")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
CustomText {
Layout.bottomMargin: Appearance.spacing.small
Layout.fillWidth: true
Layout.leftMargin: Appearance.padding.small
color: DynamicColors.palette.m3outline
font.pointSize: Appearance.font.size.small
text: qsTr("Adjust the volume of individual apps currently playing audio.")
wrapMode: Text.WordWrap
}
ItemList {
id: streamList
color: list.count === 0 ? DynamicColors.tPalette.m3surfaceContainer : "transparent"
first: true
last: true
list.spacing: Appearance.spacing.extraSmall / 2
placeholderIcon: "music_off"
placeholderText: qsTr("No apps playing audio")
showList: true
delegate: SliderRow {
id: stream
required property int index
required property PwNode modelData
anchors.left: streamList.list.contentItem.left
anchors.right: streamList.list.contentItem.right
enabled: !stream.modelData?.audio?.muted
first: index === 0
icon: Icons.getVolumeIcon(stream.modelData?.audio?.volume ?? 0, stream.modelData?.audio?.muted ?? false)
label: Audio.getStreamName(stream.modelData)
last: index === streamList.list.count - 1
value: stream.modelData?.audio?.volume ?? 0
valueLabel: Math.round(value * 100) + "%"
onMoved: v => Audio.setStreamVolume(stream.modelData, v)
}
model: ScriptModel {
values: [...Audio.streams]
}
}
}
}
+136
View File
@@ -0,0 +1,136 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Daemons
import qs.Config
import qs.Components
import qs.Modules.Settings.Common
import qs.Helpers
PageBase {
id: root
title: qsTr("Audio")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// Output
SliderRow {
enabled: !Audio.muted
first: true
icon: Icons.getVolumeIcon(Audio.volume, Audio.muted)
label: qsTr("Output")
value: Audio.volume
valueLabel: Math.round(value * 100) + "%"
onMoved: v => Audio.setVolume(v)
}
ToggleRow {
checked: Audio.muted
text: qsTr("Muted")
onToggled: Audio.setStreamMuted(Audio.sink, checked)
}
AudioDeviceList {
currentId: Audio.sink?.id ?? -1
iconName: "speaker"
nodes: Audio.sinks
placeholderIcon: "speaker"
placeholderText: qsTr("No output devices")
onSelected: node => Audio.setAudioSink(node)
}
// Input
SliderRow {
Layout.topMargin: Appearance.spacing.large - parent.spacing
enabled: !Audio.sourceMuted
first: true
icon: Icons.getMicVolumeIcon(Audio.sourceVolume, Audio.sourceMuted)
label: qsTr("Input")
value: Audio.sourceVolume
valueLabel: Math.round(value * 100) + "%"
onMoved: v => Audio.setSourceVolume(v)
}
ToggleRow {
checked: Audio.sourceMuted
text: qsTr("Muted")
onToggled: Audio.setStreamMuted(Audio.source, checked)
}
AudioDeviceList {
currentId: Audio.source?.id ?? -1
iconName: "mic"
nodes: Audio.sources
placeholderIcon: "mic_off"
placeholderText: qsTr("No input devices")
onSelected: node => Audio.setAudioSource(node)
}
// Per-app volumes
ConnectedRect {
Layout.fillWidth: true
Layout.topMargin: Appearance.spacing.large - parent.spacing
first: true
implicitHeight: appLayout.implicitHeight + appLayout.anchors.margins * 2
last: true
StateLayer {
onClicked: root.sState.openSubPage(1)
}
RowLayout {
id: appLayout
anchors.fill: parent
anchors.leftMargin: Appearance.padding.largeIncreased
anchors.margins: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.largeIncreased
spacing: Appearance.spacing.small
MaterialIcon {
font.pointSize: Appearance.font.size.medium
text: "tune"
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
CustomText {
Layout.fillWidth: true
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
text: qsTr("App volumes")
}
CustomText {
Layout.fillWidth: true
animate: true
color: DynamicColors.palette.m3outline
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
text: Audio.streams.length === 0 ? qsTr("No apps playing audio") : Audio.streams.length === 1 ? qsTr("1 app playing audio") : qsTr("%1 apps playing audio").arg(Audio.streams.length)
}
}
MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.medium
text: "chevron_right"
}
}
}
}
}
@@ -0,0 +1,61 @@
pragma ComponentBehavior: Bound
import QtQuick.Layouts
import qs.Config
import qs.Components
import qs.Modules.Settings.Common
PageBase {
id: root
readonly property list<MenuItem> clockFormats: [
MenuItem {
text: qsTr("Long format")
value: "dddd d MMM - hh:mm"
},
MenuItem {
text: qsTr("Short format")
value: "ddd d MMM - hh:mm"
},
MenuItem {
text: qsTr("Time only")
value: "hh:mm"
},
MenuItem {
text: qsTr("Long format seconds")
value: "dddd d MMM - hh:mm:ss"
},
MenuItem {
text: qsTr("Short format seconds")
value: "ddd d MMM - hh:mm:ss"
},
MenuItem {
text: qsTr("Time only seconds")
value: "hh:mm:ss"
}
]
isSubPage: true
title: qsTr("Clock")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
SelectRow {
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
active: root.clockFormats.find(item => item.value === Config.general.dateFormat)
first: true
last: true
menuItems: root.clockFormats
subtext: qsTr("Change how time is displayed in the widget")
text: qsTr("Time format")
onSelected: item => {
Config.general.dateFormat = item.value;
}
}
}
}
@@ -0,0 +1,93 @@
pragma ComponentBehavior: Bound
import QtQuick.Layouts
import qs.Config
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("System icons")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// Visible icons
SectionHeader {
first: true
text: qsTr("Visible icons")
}
ToggleRow {
checked: Config.bar.tray.showAudio
first: true
text: qsTr("Speakers")
onToggled: Config.bar.tray.showAudio = checked
}
ToggleRow {
checked: Config.bar.tray.showMicrophone
text: qsTr("Microphone")
onToggled: Config.bar.tray.showMicrophone = checked
}
//////// FOR LATER:
// ToggleRow {
// checked: Config.bar.tray.showNetwork
// text: qsTr("Network")
//
// onToggled: Config.bar.tray.showNetwork = checked
// }
//
// ToggleRow {
// checked: Config.bar.tray.showWifi
// text: qsTr("Wi-Fi")
//
// onToggled: Config.bar.tray.showWifi = checked
// }
//
// ToggleRow {
// checked: Config.bar.tray.showBluetooth
// text: qsTr("Bluetooth")
//
// onToggled: Config.bar.tray.showBluetooth = checked
// }
ToggleRow {
checked: Config.bar.tray.showPower
last: true
text: qsTr("Battery")
onToggled: Config.bar.tray.showPower = checked
}
// Behaviour
SectionHeader {
text: qsTr("Behavior")
}
ToggleRow {
checked: Config.bar.popouts.audio
first: true
subtext: qsTr("Show a details popout when hovering the audio icons")
text: qsTr("Audio popout on hover")
onToggled: Config.bar.popouts.audio = checked
}
ToggleRow {
checked: Config.bar.popouts.upower
last: true
subtext: qsTr("Show a details popout when hovering the power icon")
text: qsTr("Power popout on hover")
onToggled: Config.bar.popouts.upower = checked
}
}
}
@@ -0,0 +1,31 @@
pragma ComponentBehavior: Bound
import QtQuick.Layouts
import qs.Config
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("Tray")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
SpinRow {
first: true
from: 12
last: true
stepSize: 1
text: qsTr("Icon size")
to: 24
value: Config.bar.tray.trayIconSize
onMoved: value => Config.bar.tray.trayIconSize = value
}
}
}
@@ -0,0 +1,66 @@
pragma ComponentBehavior: Bound
import QtQuick.Layouts
import qs.Config
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("Taskbar")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// Behavior
SectionHeader {
first: true
text: qsTr("Behavior")
}
ToggleRow {
checked: Config.bar.autoHide
first: true
last: true
subtext: qsTr("Hide the bar, reveal on hover")
text: qsTr("Auto hide")
onToggled: Config.bar.autoHide = checked
}
// Components
SectionHeader {
text: qsTr("Components")
}
NavRow {
first: true
icon: "widgets"
status: qsTr("System tray icons")
text: qsTr("Tray")
onClicked: root.sState.openSubPage(6)
}
NavRow {
icon: "signal_cellular_alt"
status: qsTr("Visible indicators")
text: qsTr("Status icons")
onClicked: root.sState.openSubPage(7)
}
NavRow {
icon: "schedule"
last: true
status: qsTr("Date, icon, background")
text: qsTr("Clock")
onClicked: root.sState.openSubPage(8)
}
}
}
@@ -0,0 +1,36 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Config
import qs.Components
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("Dashboard")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// General
SectionHeader {
first: true
text: qsTr("General")
}
ToggleRow {
checked: Config.dashboard.enabled
first: true
last: true
text: qsTr("Enabled")
onToggled: Config.dashboard.enabled = checked
}
}
}
@@ -0,0 +1,131 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Config
import qs.Components
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("Launcher")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// General
SectionHeader {
first: true
text: qsTr("General")
}
ToggleRow {
checked: Config.launcher.enabled
first: true
last: true
text: qsTr("Enabled")
onToggled: Config.launcher.enabled = checked
}
// Display
SectionHeader {
text: qsTr("Display")
}
SpinRow {
first: true
from: 1
stepSize: 1
text: qsTr("Max items shown")
to: 20
value: Config.launcher.maxAppsShown
onMoved: v => Config.launcher.maxShown = v
}
SpinRow {
from: 1
stepSize: 1
text: qsTr("Max wallpapers")
to: 30
value: Config.launcher.maxWallpapers
onMoved: v => Config.launcher.maxWallpapers = v
}
SpinRow {
from: 0
last: true
stepSize: 5
subtext: qsTr("Pixels dragged before the launcher opens")
text: qsTr("Drag threshold")
to: 200
value: Config.launcher.dragThreshold
onMoved: v => Config.launcher.dragThreshold = v
}
// Behavior
SectionHeader {
text: qsTr("Behavior")
}
ToggleRow {
checked: Config.launcher.enableDangerousActions
first: true
last: true
subtext: qsTr("Allow actions that shut down or log out")
text: qsTr("Enable dangerous actions")
onToggled: Config.launcher.enableDangerousActions = checked
}
// Fuzzy search
SectionHeader {
text: qsTr("Fuzzy search")
}
ToggleRow {
checked: Config.launcher.useFuzzy.apps
first: true
text: qsTr("Apps")
onToggled: Config.launcher.useFuzzy.apps = checked
}
ToggleRow {
checked: Config.launcher.useFuzzy.actions
text: qsTr("Actions")
onToggled: Config.launcher.useFuzzy.actions = checked
}
ToggleRow {
checked: Config.launcher.useFuzzy.schemes
text: qsTr("Schemes")
onToggled: Config.launcher.useFuzzy.schemes = checked
}
ToggleRow {
checked: Config.launcher.useFuzzy.variants
text: qsTr("Variants")
onToggled: Config.launcher.useFuzzy.variants = checked
}
ToggleRow {
checked: Config.launcher.useFuzzy.wallpapers
last: true
text: qsTr("Wallpapers")
onToggled: Config.launcher.useFuzzy.wallpapers = checked
}
}
}
@@ -0,0 +1,85 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Config
import qs.Components
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("Resources")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// General
SectionHeader {
first: true
text: qsTr("General")
}
ToggleRow {
checked: Config.dashboard.performance.enabled
first: true
last: true
text: qsTr("Enabled")
onToggled: Config.dashboard.performance.enabled = checked
}
// Performance widgets
SectionHeader {
text: qsTr("Performance widgets")
}
ToggleRow {
checked: Config.dashboard.performance.showBattery
first: true
text: qsTr("Battery")
onToggled: Config.dashboard.performance.showBattery = checked
}
ToggleRow {
checked: Config.dashboard.performance.showGpu
text: qsTr("GPU")
onToggled: Config.dashboard.performance.showGpu = checked
}
ToggleRow {
checked: Config.dashboard.performance.showCpu
text: qsTr("CPU")
onToggled: Config.dashboard.performance.showCpu = checked
}
ToggleRow {
checked: Config.dashboard.performance.showMemory
text: qsTr("Memory")
onToggled: Config.dashboard.performance.showMemory = checked
}
ToggleRow {
checked: Config.dashboard.performance.showStorage
text: qsTr("Storage")
onToggled: Config.dashboard.performance.showStorage = checked
}
ToggleRow {
checked: Config.dashboard.performance.showNetwork
last: true
text: qsTr("Network")
onToggled: Config.dashboard.performance.showNetwork = checked
}
}
}
@@ -0,0 +1,46 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Config
import qs.Components
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("Sidebar")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
SectionHeader {
first: true
text: qsTr("General")
}
ToggleRow {
checked: Config.sidebar.enabled
first: true
text: qsTr("Enabled")
onToggled: Config.sidebar.enabled = checked
}
SpinRow {
from: 0
last: true
stepSize: 5
subtext: qsTr("Pixels dragged before the sidebar opens")
text: qsTr("Drag threshold")
to: 200
value: Config.sidebar.dragThreshold
onMoved: v => Config.sidebar.dragThreshold = v
}
}
}
+58
View File
@@ -0,0 +1,58 @@
import QtQuick.Layouts
import qs.Config
import qs.Modules.Settings.Common
PageBase {
id: root
title: qsTr("Panels")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
NavRow {
first: true
icon: "dock_to_bottom"
status: !Config.bar.autoHide ? qsTr("Always visible") : qsTr("Reveal on hover")
text: qsTr("Bar")
onClicked: root.sState.openSubPage(1)
}
NavRow {
icon: "dashboard"
status: Config.dashboard.enabled ? qsTr("Enabled") : qsTr("Disabled")
text: qsTr("Dashboard")
onClicked: root.sState.openSubPage(2)
}
NavRow {
icon: "insert_chart"
status: Config.dashboard.performance.enabled ? qsTr("Enabled") : qsTr("Disabled")
text: qsTr("Resources")
onClicked: root.sState.openSubPage(3)
}
NavRow {
icon: "apps"
status: Config.launcher.enabled ? qsTr("Enabled") : qsTr("Disabled")
text: qsTr("Launcher")
onClicked: root.sState.openSubPage(4)
}
NavRow {
icon: "dock_to_right"
last: true
status: Config.sidebar.enabled ? qsTr("Enabled") : qsTr("Disabled")
text: qsTr("Sidebar")
onClicked: root.sState.openSubPage(5)
}
}
}
+146
View File
@@ -0,0 +1,146 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Helpers
import qs.Components
import qs.Config
import qs.Modules.Settings
import qs.Modules.Settings.Common
PageBase {
id: root
title: qsTr("Screenshot effects")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
SectionHeader {
first: true
text: qsTr("Effects")
}
ToggleRow {
checked: Config.screenshot.enable_pp
first: true
text: qsTr("Enable effects")
onToggled: Config.screenshot.enable_pp = checked
}
SelectRow {
active: Config.screenshot.mode === "manual" ? menuItems[0] : menuItems[1]
enabled: Config.screenshot.enable_pp
last: true
subtext: qsTr("Automatic or manual effect values")
text: qsTr("Effects mode")
menuItems: [
MenuItem {
icon: "build"
text: qsTr("Manual")
value: "manual"
},
MenuItem {
icon: "rotate_auto"
text: qsTr("Auto")
value: "auto"
}
]
onSelected: item => {
Config.screenshot.mode = item.value;
Config.save();
}
}
SectionHeader {
text: qsTr("Rounded corners")
}
ToggleRow {
checked: Config.screenshot.rounding
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual"
first: true
text: qsTr("Enable rounded corners")
onToggled: Config.screenshot.rounding = checked
}
SpinRow {
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual" && Config.screenshot.rounding
from: 0
last: true
stepSize: 1
text: qsTr("Corner radius")
to: 50
value: Config.screenshot.radius
onMoved: value => {
const newVal = Math.floor(value);
Config.screenshot.radius = newVal;
}
}
SectionHeader {
text: qsTr("Shadow")
}
ToggleRow {
checked: Config.screenshot.shadow
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual"
first: true
text: qsTr("Enable shadow")
onToggled: Config.screenshot.shadow = checked
}
SpinRow {
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual" && Config.screenshot.shadow
from: 0
stepSize: 1
text: qsTr("Shadow blur amount")
to: 100
value: Config.screenshot.shadow_blur
onMoved: value => {
const newVal = Math.floor(value);
Config.screenshot.shadow_blur = newVal;
}
}
SpinRow {
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual" && Config.screenshot.shadow
from: -100
stepSize: 10
text: qsTr("Shadow horizontal offset")
to: 100
value: Config.screenshot.shadow_offset_x
onMoved: value => {
const newVal = Math.floor(value);
Config.screenshot.shadow_offset_x = newVal;
}
}
SpinRow {
enabled: Config.screenshot.enable_pp && Config.screenshot.mode === "manual" && Config.screenshot.shadow
from: -100
last: true
stepSize: 10
text: qsTr("Shadow vertical offset")
to: 100
value: Config.screenshot.shadow_offset_y
onMoved: value => {
const newVal = Math.floor(value);
Config.screenshot.shadow_offset_y = newVal;
}
}
}
}
@@ -0,0 +1,162 @@
import QtQuick
import QtQuick.Layouts
import qs.Config
import qs.Components
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("Notifications")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// Notifications
SectionHeader {
first: true
text: qsTr("Notifications")
}
ToggleRow {
checked: Config.notifs.showInFullscreen
first: true
subtext: qsTr("Whether notifications appear over fullscreen apps")
text: qsTr("Show in fullscreen")
onToggled: Config.notifs.showInFullscreen = checked
}
ToggleRow {
checked: Config.notifs.expire
subtext: qsTr("Dismiss notifications after their timeout")
text: qsTr("Expire automatically")
onToggled: Config.notifs.expire = checked
}
ToggleRow {
checked: Config.notifs.openExpanded
subtext: qsTr("Show notifications expanded by default")
text: qsTr("Open expanded")
onToggled: Config.notifs.openExpanded = checked
}
SpinRow {
from: 1000
stepSize: 500
subtext: qsTr("Time before a notification dismisses (ms)")
text: qsTr("Default timeout")
to: 60000
value: Config.notifs.defaultExpireTimeout
onMoved: v => Config.notifs.defaultExpireTimeout = Math.round(v)
}
SpinRow {
from: 1
last: true
stepSize: 1
subtext: qsTr("Notifications shown per group before collapsing")
text: qsTr("Group preview count")
to: 10
value: Config.notifs.groupPreviewNum
onMoved: v => Config.notifs.groupPreviewNum = Math.round(v)
}
// Toasts
SectionHeader {
text: qsTr("Toasts")
}
SpinRow {
first: true
from: 1
stepSize: 1
subtext: qsTr("Maximum number of toasts shown at once")
text: qsTr("Visible toasts")
to: 10
value: Config.utilities.maxToasts
onMoved: v => Config.utilities.maxToasts = Math.round(v)
}
ToggleRow {
checked: Config.utilities.toasts.chargingChanged
text: qsTr("Charging changes")
onToggled: Config.utilities.toasts.chargingChanged = checked
}
ToggleRow {
checked: Config.utilities.toasts.gameModeChanged
text: qsTr("Game mode changes")
onToggled: Config.utilities.toasts.gameModeChanged = checked
}
// ToggleRow {
// checked: Config.utilities.toasts.dndChanged
// text: qsTr("Do not disturb changes")
//
// onToggled: Config.utilities.toasts.dndChanged = checked
// }
ToggleRow {
checked: Config.utilities.toasts.audioOutputChanged
text: qsTr("Audio output changes")
onToggled: Config.utilities.toasts.audioOutputChanged = checked
}
ToggleRow {
checked: Config.utilities.toasts.audioInputChanged
last: true
text: qsTr("Audio input changes")
onToggled: Config.utilities.toasts.audioInputChanged = checked
}
// ToggleRow {
// checked: Config.utilities.toasts.capsLockChanged
// text: qsTr("Caps lock changes")
//
// onToggled: Config.utilities.toasts.capsLockChanged = checked
// }
//
// ToggleRow {
// checked: Config.utilities.toasts.numLockChanged
// text: qsTr("Num lock changes")
//
// onToggled: Config.utilities.toasts.numLockChanged = checked
// }
//
// ToggleRow {
// checked: Config.utilities.toasts.kbLayoutChanged
// text: qsTr("Keyboard layout changes")
//
// onToggled: Config.utilities.toasts.kbLayoutChanged = checked
// }
//
// ToggleRow {
// checked: Config.utilities.toasts.vpnChanged
// text: qsTr("VPN changes")
//
// onToggled: Config.utilities.toasts.vpnChanged = checked
// }
//
// ToggleRow {
// checked: Config.utilities.toasts.nowPlaying
// last: true
// text: qsTr("Now playing")
//
// onToggled: Config.utilities.toasts.nowPlaying = checked
// }
}
}
+214
View File
@@ -0,0 +1,214 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import ZShell.Services
import qs.Components
import qs.Helpers
import qs.Config
import qs.Modules.Settings.Common
PageBase {
id: root
// GPU options + the config string each maps to (see Gpu::parseType)
readonly property list<MenuItem> gpuItems: [
MenuItem {
text: qsTr("Auto")
},
MenuItem {
text: "NVIDIA"
},
MenuItem {
text: qsTr("Generic")
},
MenuItem {
text: qsTr("None")
}
]
readonly property list<string> gpuValues: ["", "NVIDIA", "GENERIC", "None"]
function gpuKeyToIndex(key: string): int {
const u = (key ?? "").trim().toUpperCase();
if (u === "")
return 0; // Auto
if (u === "NVIDIA")
return 1;
if (u === "GENERIC")
return 2;
return 3; // None
}
title: qsTr("Services")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.extraSmall / 2
width: root.cappedWidth
// Detected running players, used as default-player options
Variants {
id: playerVariants
model: [...new Set(Players.list.map(p => Players.getIdentity(p)).filter(id => id))]
MenuItem {
required property string modelData
activeIcon: "music_note"
icon: modelData === Config.services.defaultPlayer ? "check" : ""
text: modelData
}
}
// Notifications
SectionHeader {
first: true
text: qsTr("Notifications")
}
NavRow {
first: true
icon: "notifications"
last: true
status: qsTr("Notifications, toasts, timeouts")
text: qsTr("Notifications")
onClicked: root.sState.openSubPage(1)
}
// Polling
SectionHeader {
text: qsTr("Polling")
}
SpinRow {
first: true
from: 100
stepSize: 50
subtext: qsTr("How often the media position updates (ms)")
text: qsTr("Media refresh")
to: 2000
value: Config.dashboard.mediaUpdateInterval
onMoved: v => Config.dashboard.mediaUpdateInterval = v
}
SpinRow {
from: 0.5
last: true
stepSize: 0.5
subtext: qsTr("CPU, memory and GPU update interval (seconds)")
text: qsTr("System stats refresh")
to: 10
value: Config.dashboard.resourceUpdateInterval / 1000
onMoved: v => Config.dashboard.resourceUpdateInterval = Math.round(v * 1000)
}
// Media & lyrics
SectionHeader {
text: qsTr("Media")
}
SelectRow {
active: menuItems.find(i => i.text === Config.services.defaultPlayer) ?? null
fallbackIcon: "music_note"
fallbackText: Config.services.defaultPlayer || qsTr("Auto")
first: true
last: true
menuItems: playerVariants.instances
subtext: qsTr("Preferred media player when several are open")
text: qsTr("Default player")
onSelected: item => Config.services.defaultPlayer = item.text
}
// Input increments
SectionHeader {
text: qsTr("Input increments")
}
SpinRow {
first: true
from: 1
stepSize: 1
subtext: qsTr("Amount the volume changes per input (%)")
text: qsTr("Volume step")
to: 50
value: Math.round(Config.services.audioIncrement * 100)
onMoved: v => Config.services.audioIncrement = v / 100
}
SpinRow {
from: 1
stepSize: 1
subtext: qsTr("Amount the brightness changes per input (%)")
text: qsTr("Brightness step")
to: 50
value: Math.round(Config.services.brightnessIncrement * 100)
onMoved: v => Config.services.brightnessIncrement = v / 100
}
SpinRow {
from: 1
stepSize: 1
subtext: qsTr("Lowest allowed brightness (%)")
text: qsTr("Brightness minimum")
to: 20
value: Math.round(Config.services.minBrightness * 100)
onMoved: v => Config.services.minBrightness = v / 100
}
SpinRow {
from: 50
last: true
stepSize: 5
subtext: qsTr("Upper limit for output volume (%)")
text: qsTr("Max volume")
to: 200
value: Math.round(Config.services.maxVolume * 100)
onMoved: v => Config.services.maxVolume = v / 100
}
// Service tuning
SectionHeader {
text: qsTr("Service tuning")
}
SpinRow {
first: true
from: 10
stepSize: 2
subtext: qsTr("Resolution of the audio visualizer")
text: qsTr("Visualizer resolution")
to: 120
value: Config.services.visualizerBars
onMoved: v => Config.services.visualiserBars = v
}
ToggleRow {
checked: Config.general.color.smart
subtext: qsTr("Derive theme mode from the wallpaper")
text: qsTr("Smart color scheme")
onToggled: Config.general.color.smart = checked
}
SelectRow {
active: root.gpuItems[root.gpuKeyToIndex(Config.services.gpuType)]
last: true
menuItems: root.gpuItems
menuOnTop: true
subtext: Gpu.name ? qsTr("Monitoring: %1").arg(Gpu.name) : qsTr("Override for GPU type")
text: qsTr("GPU")
onSelected: item => Config.services.gpuType = root.gpuValues[root.gpuItems.indexOf(item)]
}
}
}
@@ -0,0 +1,119 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Models
import qs.Paths
import qs.Helpers
import qs.Components
import qs.Config
import qs.Modules.Settings.Common
PageBase {
id: root
isSubPage: true
title: qsTr("Wallpapers")
ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
spacing: Appearance.spacing.small
width: root.cappedWidth
CustomText {
Layout.topMargin: Appearance.spacing.large
font.pointSize: Appearance.font.size.large
text: qsTr("Wallpapers")
}
GridLayout {
Layout.fillWidth: true
columnSpacing: Appearance.spacing.extraSmall
columns: 4
rowSpacing: Appearance.spacing.extraSmall
visible: localWalls.count > 0
Repeater {
id: localWalls
model: {
const walls = Wallpapers.list;
var baseDir = Paths.wallsdir;
const categories = {};
const list = [];
for (const w of walls) {
var parentDir = w.parentDir;
if (!parentDir.endsWith("/"))
parentDir = parentDir + "/";
if (!baseDir.endsWith("/"))
baseDir = baseDir + "/";
if (parentDir !== baseDir) {
const category = Wallpapers.getCategoryFor(w);
if (category && (!(category in categories) || categories[category].name.localeCompare(w.name) > 0))
categories[category] = w;
} else {
list.push(w);
}
}
list.push(...Object.values(categories));
list.sort((a, b) => ((a.parentDir === baseDir) - (b.parentDir === baseDir)) || a.name.localeCompare(b.name));
while (list.length < 4)
list.push(null);
return list;
}
WallItem {
required property FileSystemEntry modelData
enabled: modelData
// Empty placeholders for sizing
opacity: modelData ? 1 : 0
source: String(modelData?.path ?? "")
onClicked: {
Wallpapers.setWallpaper(modelData.path);
root.sState.closeSubPage();
}
}
}
}
Loader {
Layout.fillWidth: true
active: localWalls.count === 0
asynchronous: true
visible: active
sourceComponent: CustomRect {
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: noWallsLayout.implicitHeight + Appearance.padding.extraLarge * 3
radius: Appearance.rounding.large
ColumnLayout {
id: noWallsLayout
anchors.centerIn: parent
spacing: Appearance.spacing.extraSmall
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
color: DynamicColors.palette.m3outline
text: "hide_image"
}
CustomText {
Layout.alignment: Qt.AlignHCenter
color: DynamicColors.palette.m3outline
text: qsTr("No local wallpapers found")
}
}
}
}
}
}
+156
View File
@@ -0,0 +1,156 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Helpers
import qs.Components
import qs.Config
import qs.Modules.Settings
import qs.Modules.Settings.Common
PageBase {
id: root
title: qsTr("Wallpaper & style")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
spacing: Appearance.spacing.large
width: root.cappedWidth
Item {
id: wallWrapper
Layout.alignment: Qt.AlignHCenter
implicitHeight: cropper.height
implicitWidth: root.cappedWidth
WallpaperCropper {
id: cropper
}
}
IconTextButton {
Layout.alignment: Qt.AlignHCenter
enabled: Config.background.enabled
horizontalPadding: Appearance.padding.extraLarge
icon: "wallpaper"
isRound: true
shapeMorph: true
text: qsTr("Wallpapers")
type: IconTextButton.Tonal
verticalPadding: Appearance.padding.normal
onClicked: root.sState.openSubPage(1) // Wallpaper page
}
ToggleRow {
checked: Config.background.enabled
first: true
text: qsTr("Display wallpaper")
onToggled: Config.background.enabled = checked
}
ToggleRow {
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
checked: DynamicColors.transparency.enabled
subtext: qsTr("Base %1, layers %2").arg(DynamicColors.transparency.base).arg(DynamicColors.transparency.layers)
text: qsTr("Transparency")
onToggled: Config.appearance.transparency.enabled = checked
}
ToggleRow {
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
checked: !DynamicColors.light
last: true
text: qsTr("Dark theme")
onToggled: DynamicColors.setMode(checked ? "dark" : "light")
}
OverlayRow {
id: darkMode
readonly property string endTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(Config.general.color.scheduleDarkEnd);
return Qt.formatTime(d, "hh:mm AP");
}
readonly property string startTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(Config.general.color.scheduleDarkStart);
return Qt.formatTime(d, "hh:mm AP");
}
checked: Config.general.color.scheduleDark
first: true
subtext: qsTr("Dark mode will turn on at %1, and turn off at %2.").arg(startTime).arg(endTime)
text: qsTr("Schedule dark mode")
popup: Component {
TimeInput {
object: Config.general.color
settings: ["scheduleDark", "scheduleDarkStart", "scheduleDarkEnd"]
onApplySettings: (start, end) => {
Config.general.color.scheduleDarkStart = start;
Config.general.color.scheduleDarkEnd = end;
Config.save();
ModeScheduler.checkStartup();
PopupManager.requestClose();
}
onClose: PopupManager.requestClose()
}
}
onClicked: value => {
Config.general.color.scheduleDark = value;
}
}
OverlayRow {
id: hyprsunset
readonly property string endTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(Config.general.color.scheduleHyprsunsetEnd);
return Qt.formatTime(d, "hh:mm AP");
}
readonly property string startTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(Config.general.color.scheduleHyprsunsetStart);
return Qt.formatTime(d, "hh:mm AP");
}
Layout.topMargin: Appearance.spacing.extraSmall / 2 - parent.spacing
checked: Config.general.color.scheduleHyprsunset
last: true
subtext: qsTr("Hyprsunset will turn on at %1, and turn off at %2.").arg(startTime).arg(endTime)
text: qsTr("Schedule hyprsunset")
popup: Component {
TimeInput {
object: Config.general.color
settings: ["scheduleHyprsunset", "scheduleHyprsunsetStart", "scheduleHyprsunsetEnd"]
onApplySettings: (start, end) => {
Config.general.color.scheduleHyprsunsetStart = start;
Config.general.color.scheduleHyprsunsetEnd = end;
Config.save();
Hyprsunset.checkStartup();
PopupManager.requestClose();
}
onClose: PopupManager.requestClose()
}
}
onClicked: value => {
Config.general.color.scheduleHyprsunset = value;
}
}
}
}