mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
settings: mecha re-organization
This commit is contained in:
@@ -3,6 +3,7 @@ import QtQuick.Effects
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: aboutTab
|
||||
@@ -122,13 +123,17 @@ Item {
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingL
|
||||
spacing: parent.width < 350 ? Theme.spacingM : Theme.spacingL
|
||||
|
||||
property bool compactLogo: parent.width < 400
|
||||
property bool hideLogo: parent.width < 280
|
||||
|
||||
Image {
|
||||
id: logoImage
|
||||
|
||||
visible: !parent.hideLogo
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 120
|
||||
width: parent.compactLogo ? 80 : 120
|
||||
height: width * (569.94629 / 506.50931)
|
||||
fillMode: Image.PreserveAspectFit
|
||||
smooth: true
|
||||
@@ -148,7 +153,7 @@ Item {
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "DANK LINUX"
|
||||
font.pixelSize: 48
|
||||
font.pixelSize: parent.compactLogo ? 32 : 48
|
||||
font.weight: Font.Bold
|
||||
font.family: interFont.name
|
||||
color: Theme.surfaceText
|
||||
@@ -163,7 +168,8 @@ Item {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!SystemUpdateService.shellVersion) return "dms";
|
||||
if (!SystemUpdateService.shellVersion)
|
||||
return "dms";
|
||||
|
||||
let version = SystemUpdateService.shellVersion;
|
||||
|
||||
@@ -179,7 +185,7 @@ Item {
|
||||
return `dms (git) v0.6.2-${match[1]}`;
|
||||
}
|
||||
|
||||
// Stable release format: 0.6.2
|
||||
// Stable release format: 0.6.2
|
||||
match = version.match(/^([\d.]+)$/);
|
||||
if (match) {
|
||||
return `dms v${match[1]}`;
|
||||
@@ -194,6 +200,82 @@ Item {
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Row {
|
||||
id: resourceButtonsRow
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
property bool compactMode: parent.width < 400
|
||||
|
||||
DankButton {
|
||||
id: docsButton
|
||||
text: resourceButtonsRow.compactMode ? "" : I18n.tr("Docs")
|
||||
iconName: "menu_book"
|
||||
iconSize: 18
|
||||
backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
|
||||
textColor: Theme.surfaceText
|
||||
onClicked: Qt.openUrlExternally("https://danklinux.com/docs")
|
||||
onHoveredChanged: {
|
||||
if (hovered)
|
||||
resourceTooltip.show(resourceButtonsRow.compactMode ? I18n.tr("Docs") + " - danklinux.com/docs" : "danklinux.com/docs", docsButton, 0, 0, "bottom");
|
||||
else
|
||||
resourceTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
DankButton {
|
||||
id: pluginsButton
|
||||
text: resourceButtonsRow.compactMode ? "" : I18n.tr("Plugins")
|
||||
iconName: "extension"
|
||||
iconSize: 18
|
||||
backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
|
||||
textColor: Theme.surfaceText
|
||||
onClicked: Qt.openUrlExternally("https://plugins.danklinux.com")
|
||||
onHoveredChanged: {
|
||||
if (hovered)
|
||||
resourceTooltip.show(resourceButtonsRow.compactMode ? I18n.tr("Plugins") + " - plugins.danklinux.com" : "plugins.danklinux.com", pluginsButton, 0, 0, "bottom");
|
||||
else
|
||||
resourceTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
DankButton {
|
||||
id: githubButton
|
||||
text: resourceButtonsRow.compactMode ? "" : I18n.tr("GitHub")
|
||||
iconName: "code"
|
||||
iconSize: 18
|
||||
backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
|
||||
textColor: Theme.surfaceText
|
||||
onClicked: Qt.openUrlExternally("https://github.com/AvengeMedia/DankMaterialShell")
|
||||
onHoveredChanged: {
|
||||
if (hovered)
|
||||
resourceTooltip.show(resourceButtonsRow.compactMode ? "GitHub - AvengeMedia/DankMaterialShell" : "github.com/AvengeMedia/DankMaterialShell", githubButton, 0, 0, "bottom");
|
||||
else
|
||||
resourceTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
DankButton {
|
||||
id: kofiButton
|
||||
text: resourceButtonsRow.compactMode ? "" : I18n.tr("Ko-fi")
|
||||
iconName: "favorite"
|
||||
iconSize: 18
|
||||
backgroundColor: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
textColor: Theme.primary
|
||||
onClicked: Qt.openUrlExternally("https://ko-fi.com/danklinux")
|
||||
onHoveredChanged: {
|
||||
if (hovered)
|
||||
resourceTooltip.show(resourceButtonsRow.compactMode ? I18n.tr("Ko-fi") + " - ko-fi.com/danklinux" : "ko-fi.com/danklinux", kofiButton, 0, 0, "bottom");
|
||||
else
|
||||
resourceTooltip.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankTooltipV2 {
|
||||
id: resourceTooltip
|
||||
}
|
||||
|
||||
Item {
|
||||
id: communityIcons
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -459,166 +541,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: techSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: techSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "code"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Resources")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Grid {
|
||||
width: parent.width
|
||||
columns: 2
|
||||
columnSpacing: Theme.spacingL
|
||||
rowSpacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Website:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: `<a href="https://danklinux.com" style="text-decoration:none; color:${Theme.primary};">danklinux.com</a>`
|
||||
linkColor: Theme.primary
|
||||
textFormat: Text.RichText
|
||||
onLinkActivated: url => Qt.openUrlExternally(url)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
propagateComposedEvents: true
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Plugins:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: `<a href="https://plugins.danklinux.com" style="text-decoration:none; color:${Theme.primary};">plugins.danklinux.com</a>`
|
||||
linkColor: Theme.primary
|
||||
textFormat: Text.RichText
|
||||
onLinkActivated: url => Qt.openUrlExternally(url)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
propagateComposedEvents: true
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Github:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: `<a href="https://github.com/AvengeMedia/DankMaterialShell" style="text-decoration:none; color:${Theme.primary};">DankMaterialShell</a>`
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
linkColor: Theme.primary
|
||||
textFormat: Text.RichText
|
||||
onLinkActivated: url => Qt.openUrlExternally(url)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
propagateComposedEvents: true
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("- Support Us With a Star ⭐")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("System Monitoring:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: `<a href="https://github.com/AvengeMedia/dgop" style="text-decoration:none; color:${Theme.primary};">dgop</a>`
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
linkColor: Theme.primary
|
||||
textFormat: Text.RichText
|
||||
onLinkActivated: url => Qt.openUrlExternally(url)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
propagateComposedEvents: true
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("- Stateless System Monitoring")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
visible: DMSService.isConnected
|
||||
width: parent.width
|
||||
@@ -772,57 +694,20 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Support Section
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: supportSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
id: supportSection
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: `<a href="https://github.com/AvengeMedia/DankMaterialShell/blob/master/LICENSE" style="text-decoration:none; color:${Theme.surfaceVariantText};">MIT License</a>`
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
textFormat: Text.RichText
|
||||
wrapMode: Text.NoWrap
|
||||
onLinkActivated: url => Qt.openUrlExternally(url)
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "volunteer_activism"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Support Development")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - parent.spacing - kofiButton.width - supportSection.children[0].width
|
||||
height: 1
|
||||
}
|
||||
|
||||
DankButton {
|
||||
id: kofiButton
|
||||
text: I18n.tr("Donate on Ko-fi")
|
||||
iconName: "favorite"
|
||||
iconSize: 20
|
||||
backgroundColor: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
||||
textColor: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: Qt.openUrlExternally("https://ko-fi.com/danklinux")
|
||||
}
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
propagateComposedEvents: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -120,12 +120,10 @@ Item {
|
||||
function onBindSaved(key) {
|
||||
keybindsTab._savedScrollY = flickable.contentY;
|
||||
keybindsTab._preserveScroll = true;
|
||||
keybindsTab._editingKey = key;
|
||||
}
|
||||
function onBindRemoved(key) {
|
||||
keybindsTab._savedScrollY = flickable.contentY;
|
||||
keybindsTab._preserveScroll = true;
|
||||
keybindsTab._editingKey = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,15 +595,50 @@ Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
bindData: modelData
|
||||
isExpanded: keybindsTab.expandedKey === modelData.action
|
||||
restoreKey: isExpanded ? keybindsTab._editingKey : ""
|
||||
panelWindow: keybindsTab.parentModal
|
||||
onToggleExpand: keybindsTab.toggleExpanded(modelData.action)
|
||||
onSaveBind: (originalKey, newData) => {
|
||||
KeybindsService.saveBind(originalKey, newData);
|
||||
keybindsTab._editingKey = newData.key;
|
||||
keybindsTab.expandedKey = modelData.action;
|
||||
}
|
||||
onRemoveBind: key => KeybindsService.removeBind(key)
|
||||
onRestoreKeyConsumed: keybindsTab._editingKey = ""
|
||||
onRemoveBind: key => {
|
||||
const remainingKey = bindItem.keys.find(k => k.key !== key)?.key ?? "";
|
||||
KeybindsService.removeBind(key);
|
||||
keybindsTab._editingKey = remainingKey;
|
||||
}
|
||||
onIsExpandedChanged: {
|
||||
if (!isExpanded || !keybindsTab._editingKey)
|
||||
return;
|
||||
const keyExists = keys.some(k => k.key === keybindsTab._editingKey);
|
||||
if (keyExists) {
|
||||
restoreKey = keybindsTab._editingKey;
|
||||
keybindsTab._editingKey = "";
|
||||
}
|
||||
}
|
||||
|
||||
onKeysChanged: {
|
||||
if (!isExpanded || !keybindsTab._editingKey)
|
||||
return;
|
||||
const keyExists = keys.some(k => k.key === keybindsTab._editingKey);
|
||||
if (keyExists) {
|
||||
restoreKey = keybindsTab._editingKey;
|
||||
keybindsTab._editingKey = "";
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: keybindsTab
|
||||
function on_EditingKeyChanged() {
|
||||
if (!bindItem.isExpanded || !keybindsTab._editingKey)
|
||||
return;
|
||||
const keyExists = bindItem.keys.some(k => k.key === keybindsTab._editingKey);
|
||||
if (keyExists) {
|
||||
bindItem.restoreKey = keybindsTab._editingKey;
|
||||
keybindsTab._editingKey = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
183
quickshell/Modules/Settings/LockScreenTab.qml
Normal file
183
quickshell/Modules/Settings/LockScreenTab.qml
Normal file
@@ -0,0 +1,183 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "lock"
|
||||
title: I18n.tr("Lock Screen")
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Show Power Actions")
|
||||
description: I18n.tr("Show power, restart, and logout buttons on the lock screen")
|
||||
checked: SettingsData.lockScreenShowPowerActions
|
||||
onToggled: checked => SettingsData.set("lockScreenShowPowerActions", checked)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("loginctl not available - lock integration requires DMS socket connection")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.warning
|
||||
visible: !SessionService.loginctlAvailable
|
||||
width: parent.width
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Enable loginctl lock integration")
|
||||
description: I18n.tr("Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen")
|
||||
checked: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration
|
||||
enabled: SessionService.loginctlAvailable
|
||||
onToggled: checked => {
|
||||
if (!SessionService.loginctlAvailable)
|
||||
return;
|
||||
SettingsData.set("loginctlLockIntegration", checked);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Lock before suspend")
|
||||
description: I18n.tr("Automatically lock the screen when the system prepares to suspend")
|
||||
checked: SettingsData.lockBeforeSuspend
|
||||
visible: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration
|
||||
onToggled: checked => SettingsData.set("lockBeforeSuspend", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Enable fingerprint authentication")
|
||||
description: I18n.tr("Use fingerprint reader for lock screen authentication (requires enrolled fingerprints)")
|
||||
checked: SettingsData.enableFprint
|
||||
visible: SettingsData.fprintdAvailable
|
||||
onToggled: checked => SettingsData.set("enableFprint", checked)
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "monitor"
|
||||
title: I18n.tr("Lock Screen Display")
|
||||
visible: Quickshell.screens.length > 1
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: lockScreenMonitorDropdown
|
||||
text: I18n.tr("Active Lock Screen Monitor")
|
||||
options: {
|
||||
var opts = [I18n.tr("All Monitors")];
|
||||
var screens = Quickshell.screens;
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
opts.push(SettingsData.getScreenDisplayName(screens[i]));
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.lockScreenActiveMonitor === "all") {
|
||||
currentValue = I18n.tr("All Monitors");
|
||||
return;
|
||||
}
|
||||
var screens = Quickshell.screens;
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (screens[i].name === SettingsData.lockScreenActiveMonitor) {
|
||||
currentValue = SettingsData.getScreenDisplayName(screens[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
currentValue = I18n.tr("All Monitors");
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
if (value === I18n.tr("All Monitors")) {
|
||||
SettingsData.set("lockScreenActiveMonitor", "all");
|
||||
return;
|
||||
}
|
||||
var screens = Quickshell.screens;
|
||||
for (var i = 0; i < screens.length; i++) {
|
||||
if (SettingsData.getScreenDisplayName(screens[i]) === value) {
|
||||
SettingsData.set("lockScreenActiveMonitor", screens[i].name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: SettingsData.lockScreenActiveMonitor !== "all"
|
||||
|
||||
Column {
|
||||
width: parent.width - inactiveColorPreview.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Inactive Monitor Color")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Color displayed on monitors without the lock screen")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: inactiveColorPreview
|
||||
width: 48
|
||||
height: 48
|
||||
radius: Theme.cornerRadius
|
||||
color: SettingsData.lockScreenInactiveColor
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (!PopoutService.colorPickerModal)
|
||||
return;
|
||||
PopoutService.colorPickerModal.selectedColor = SettingsData.lockScreenInactiveColor;
|
||||
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Inactive Monitor Color");
|
||||
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
||||
SettingsData.set("lockScreenInactiveColor", selectedColor);
|
||||
};
|
||||
PopoutService.colorPickerModal.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
quickshell/Modules/Settings/MediaPlayerTab.qml
Normal file
42
quickshell/Modules/Settings/MediaPlayerTab.qml
Normal file
@@ -0,0 +1,42 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "music_note"
|
||||
title: I18n.tr("Media Player Settings")
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Wave Progress Bars")
|
||||
description: I18n.tr("Use animated wave progress bars for media playback")
|
||||
checked: SettingsData.waveProgressEnabled
|
||||
onToggled: checked => SettingsData.set("waveProgressEnabled", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Scroll song title")
|
||||
description: I18n.tr("Scroll title if it doesn't fit in widget")
|
||||
checked: SettingsData.scrollTitleEnabled
|
||||
onToggled: checked => SettingsData.set("scrollTitleEnabled", checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
208
quickshell/Modules/Settings/NotificationsTab.qml
Normal file
208
quickshell/Modules/Settings/NotificationsTab.qml
Normal file
@@ -0,0 +1,208 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property var timeoutOptions: [
|
||||
{
|
||||
text: I18n.tr("Never"),
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
text: I18n.tr("1 second"),
|
||||
value: 1000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("3 seconds"),
|
||||
value: 3000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("5 seconds"),
|
||||
value: 5000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("8 seconds"),
|
||||
value: 8000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("10 seconds"),
|
||||
value: 10000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("15 seconds"),
|
||||
value: 15000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("30 seconds"),
|
||||
value: 30000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("1 minute"),
|
||||
value: 60000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("2 minutes"),
|
||||
value: 120000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("5 minutes"),
|
||||
value: 300000
|
||||
},
|
||||
{
|
||||
text: I18n.tr("10 minutes"),
|
||||
value: 600000
|
||||
}
|
||||
]
|
||||
|
||||
function getTimeoutText(value) {
|
||||
if (value === undefined || value === null || isNaN(value))
|
||||
return I18n.tr("5 seconds");
|
||||
for (let i = 0; i < timeoutOptions.length; i++) {
|
||||
if (timeoutOptions[i].value === value)
|
||||
return timeoutOptions[i].text;
|
||||
}
|
||||
if (value === 0)
|
||||
return I18n.tr("Never");
|
||||
if (value < 1000)
|
||||
return value + "ms";
|
||||
if (value < 60000)
|
||||
return Math.round(value / 1000) + " " + I18n.tr("seconds");
|
||||
return Math.round(value / 60000) + " " + I18n.tr("minutes");
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "notifications"
|
||||
title: I18n.tr("Notification Popups")
|
||||
|
||||
SettingsDropdownRow {
|
||||
text: I18n.tr("Popup Position")
|
||||
description: I18n.tr("Choose where notification popups appear on screen")
|
||||
currentValue: {
|
||||
if (SettingsData.notificationPopupPosition === -1)
|
||||
return "Top Center";
|
||||
switch (SettingsData.notificationPopupPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return "Top Right";
|
||||
case SettingsData.Position.Bottom:
|
||||
return "Bottom Left";
|
||||
case SettingsData.Position.Left:
|
||||
return "Top Left";
|
||||
case SettingsData.Position.Right:
|
||||
return "Bottom Right";
|
||||
default:
|
||||
return "Top Right";
|
||||
}
|
||||
}
|
||||
options: ["Top Right", "Top Left", "Top Center", "Bottom Right", "Bottom Left"]
|
||||
onValueChanged: value => {
|
||||
switch (value) {
|
||||
case "Top Right":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Top);
|
||||
break;
|
||||
case "Top Left":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Left);
|
||||
break;
|
||||
case "Top Center":
|
||||
SettingsData.set("notificationPopupPosition", -1);
|
||||
break;
|
||||
case "Bottom Right":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Right);
|
||||
break;
|
||||
case "Bottom Left":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Bottom);
|
||||
break;
|
||||
}
|
||||
SettingsData.sendTestNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Notification Overlay")
|
||||
description: I18n.tr("Display all priorities over fullscreen apps")
|
||||
checked: SettingsData.notificationOverlayEnabled
|
||||
onToggled: checked => SettingsData.set("notificationOverlayEnabled", checked)
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "notifications_off"
|
||||
title: I18n.tr("Do Not Disturb")
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Enable Do Not Disturb")
|
||||
description: I18n.tr("Suppress notification popups while enabled")
|
||||
checked: SessionData.doNotDisturb
|
||||
onToggled: checked => SessionData.setDoNotDisturb(checked)
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "timer"
|
||||
title: I18n.tr("Notification Timeouts")
|
||||
|
||||
SettingsDropdownRow {
|
||||
text: I18n.tr("Low Priority")
|
||||
description: I18n.tr("Timeout for low priority notifications")
|
||||
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutLow)
|
||||
options: root.timeoutOptions.map(opt => opt.text)
|
||||
onValueChanged: value => {
|
||||
for (let i = 0; i < root.timeoutOptions.length; i++) {
|
||||
if (root.timeoutOptions[i].text === value) {
|
||||
SettingsData.set("notificationTimeoutLow", root.timeoutOptions[i].value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
text: I18n.tr("Normal Priority")
|
||||
description: I18n.tr("Timeout for normal priority notifications")
|
||||
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutNormal)
|
||||
options: root.timeoutOptions.map(opt => opt.text)
|
||||
onValueChanged: value => {
|
||||
for (let i = 0; i < root.timeoutOptions.length; i++) {
|
||||
if (root.timeoutOptions[i].text === value) {
|
||||
SettingsData.set("notificationTimeoutNormal", root.timeoutOptions[i].value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
text: I18n.tr("Critical Priority")
|
||||
description: I18n.tr("Timeout for critical priority notifications")
|
||||
currentValue: root.getTimeoutText(SettingsData.notificationTimeoutCritical)
|
||||
options: root.timeoutOptions.map(opt => opt.text)
|
||||
onValueChanged: value => {
|
||||
for (let i = 0; i < root.timeoutOptions.length; i++) {
|
||||
if (root.timeoutOptions[i].text === value) {
|
||||
SettingsData.set("notificationTimeoutCritical", root.timeoutOptions[i].value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
147
quickshell/Modules/Settings/OSDTab.qml
Normal file
147
quickshell/Modules/Settings/OSDTab.qml
Normal file
@@ -0,0 +1,147 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "tune"
|
||||
title: I18n.tr("On-screen Displays")
|
||||
|
||||
SettingsDropdownRow {
|
||||
text: I18n.tr("OSD Position")
|
||||
description: I18n.tr("Choose where on-screen displays appear on screen")
|
||||
currentValue: {
|
||||
switch (SettingsData.osdPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return "Top Right";
|
||||
case SettingsData.Position.Left:
|
||||
return "Top Left";
|
||||
case SettingsData.Position.TopCenter:
|
||||
return "Top Center";
|
||||
case SettingsData.Position.Right:
|
||||
return "Bottom Right";
|
||||
case SettingsData.Position.Bottom:
|
||||
return "Bottom Left";
|
||||
case SettingsData.Position.BottomCenter:
|
||||
return "Bottom Center";
|
||||
case SettingsData.Position.LeftCenter:
|
||||
return "Left Center";
|
||||
case SettingsData.Position.RightCenter:
|
||||
return "Right Center";
|
||||
default:
|
||||
return "Bottom Center";
|
||||
}
|
||||
}
|
||||
options: ["Top Right", "Top Left", "Top Center", "Bottom Right", "Bottom Left", "Bottom Center", "Left Center", "Right Center"]
|
||||
onValueChanged: value => {
|
||||
switch (value) {
|
||||
case "Top Right":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Top);
|
||||
break;
|
||||
case "Top Left":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Left);
|
||||
break;
|
||||
case "Top Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.TopCenter);
|
||||
break;
|
||||
case "Bottom Right":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Right);
|
||||
break;
|
||||
case "Bottom Left":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Bottom);
|
||||
break;
|
||||
case "Bottom Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.BottomCenter);
|
||||
break;
|
||||
case "Left Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.LeftCenter);
|
||||
break;
|
||||
case "Right Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.RightCenter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Always Show Percentage")
|
||||
description: I18n.tr("Display volume and brightness percentage values in OSD popups")
|
||||
checked: SettingsData.osdAlwaysShowValue
|
||||
onToggled: checked => SettingsData.set("osdAlwaysShowValue", checked)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outline
|
||||
opacity: 0.15
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Volume")
|
||||
description: I18n.tr("Show on-screen display when volume changes")
|
||||
checked: SettingsData.osdVolumeEnabled
|
||||
onToggled: checked => SettingsData.set("osdVolumeEnabled", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Media Volume")
|
||||
description: I18n.tr("Show on-screen display when media player volume changes")
|
||||
checked: SettingsData.osdMediaVolumeEnabled
|
||||
onToggled: checked => SettingsData.set("osdMediaVolumeEnabled", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Brightness")
|
||||
description: I18n.tr("Show on-screen display when brightness changes")
|
||||
checked: SettingsData.osdBrightnessEnabled
|
||||
onToggled: checked => SettingsData.set("osdBrightnessEnabled", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Idle Inhibitor")
|
||||
description: I18n.tr("Show on-screen display when idle inhibitor state changes")
|
||||
checked: SettingsData.osdIdleInhibitorEnabled
|
||||
onToggled: checked => SettingsData.set("osdIdleInhibitorEnabled", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Microphone Mute")
|
||||
description: I18n.tr("Show on-screen display when microphone is muted/unmuted")
|
||||
checked: SettingsData.osdMicMuteEnabled
|
||||
onToggled: checked => SettingsData.set("osdMicMuteEnabled", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Caps Lock")
|
||||
description: I18n.tr("Show on-screen display when caps lock state changes")
|
||||
checked: SettingsData.osdCapsLockEnabled
|
||||
onToggled: checked => SettingsData.set("osdCapsLockEnabled", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Power Profile")
|
||||
description: I18n.tr("Show on-screen display when power profile changes")
|
||||
checked: SettingsData.osdPowerProfileEnabled
|
||||
onToggled: checked => SettingsData.set("osdPowerProfileEnabled", checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
459
quickshell/Modules/Settings/PowerSleepTab.qml
Normal file
459
quickshell/Modules/Settings/PowerSleepTab.qml
Normal file
@@ -0,0 +1,459 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
readonly property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
|
||||
|
||||
function getTimeoutIndex(timeout) {
|
||||
var idx = timeoutValues.indexOf(timeout);
|
||||
return idx >= 0 ? idx : 0;
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "schedule"
|
||||
title: I18n.tr("Idle Settings")
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Power source")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: BatteryService.batteryAvailable
|
||||
}
|
||||
|
||||
Item {
|
||||
width: Theme.spacingS
|
||||
height: 1
|
||||
visible: BatteryService.batteryAvailable
|
||||
}
|
||||
|
||||
DankButtonGroup {
|
||||
id: powerCategory
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: BatteryService.batteryAvailable
|
||||
model: ["AC Power", "Battery"]
|
||||
currentIndex: 0
|
||||
selectionMode: "single"
|
||||
checkEnabled: false
|
||||
}
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Prevent idle for media")
|
||||
description: I18n.tr("Inhibit idle timeout when audio or video is playing")
|
||||
checked: SettingsData.preventIdleForMedia
|
||||
visible: IdleService.idleMonitorAvailable
|
||||
onToggled: checked => SettingsData.set("preventIdleForMedia", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Fade to lock screen")
|
||||
description: I18n.tr("Gradually fade the screen before locking with a configurable grace period")
|
||||
checked: SettingsData.fadeToLockEnabled
|
||||
onToggled: checked => SettingsData.set("fadeToLockEnabled", checked)
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: fadeGracePeriodDropdown
|
||||
property var periodOptions: ["1 second", "2 seconds", "3 seconds", "4 seconds", "5 seconds", "10 seconds", "15 seconds", "20 seconds", "30 seconds"]
|
||||
property var periodValues: [1, 2, 3, 4, 5, 10, 15, 20, 30]
|
||||
|
||||
text: I18n.tr("Fade grace period")
|
||||
options: periodOptions
|
||||
visible: SettingsData.fadeToLockEnabled
|
||||
enabled: SettingsData.fadeToLockEnabled
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentPeriod = SettingsData.fadeToLockGracePeriod;
|
||||
const index = periodValues.indexOf(currentPeriod);
|
||||
currentValue = index >= 0 ? periodOptions[index] : "5 seconds";
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = periodOptions.indexOf(value);
|
||||
if (index < 0)
|
||||
return;
|
||||
SettingsData.set("fadeToLockGracePeriod", periodValues[index]);
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outline
|
||||
opacity: 0.15
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: lockDropdown
|
||||
text: I18n.tr("Automatically lock after")
|
||||
options: root.timeoutOptions
|
||||
|
||||
Connections {
|
||||
target: powerCategory
|
||||
function onCurrentIndexChanged() {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout;
|
||||
lockDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)];
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout;
|
||||
currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)];
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = root.timeoutOptions.indexOf(value);
|
||||
if (index < 0)
|
||||
return;
|
||||
const timeout = root.timeoutValues[index];
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acLockTimeout", timeout);
|
||||
} else {
|
||||
SettingsData.set("batteryLockTimeout", timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: monitorDropdown
|
||||
text: I18n.tr("Turn off monitors after")
|
||||
options: root.timeoutOptions
|
||||
|
||||
Connections {
|
||||
target: powerCategory
|
||||
function onCurrentIndexChanged() {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout;
|
||||
monitorDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)];
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout;
|
||||
currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)];
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = root.timeoutOptions.indexOf(value);
|
||||
if (index < 0)
|
||||
return;
|
||||
const timeout = root.timeoutValues[index];
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acMonitorTimeout", timeout);
|
||||
} else {
|
||||
SettingsData.set("batteryMonitorTimeout", timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: suspendDropdown
|
||||
text: I18n.tr("Suspend system after")
|
||||
options: root.timeoutOptions
|
||||
|
||||
Connections {
|
||||
target: powerCategory
|
||||
function onCurrentIndexChanged() {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout;
|
||||
suspendDropdown.currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)];
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout;
|
||||
currentValue = root.timeoutOptions[root.getTimeoutIndex(currentTimeout)];
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = root.timeoutOptions.indexOf(value);
|
||||
if (index < 0)
|
||||
return;
|
||||
const timeout = root.timeoutValues[index];
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acSuspendTimeout", timeout);
|
||||
} else {
|
||||
SettingsData.set("batterySuspendTimeout", timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
visible: SessionService.hibernateSupported
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Suspend behavior")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
leftPadding: Theme.spacingM
|
||||
}
|
||||
|
||||
DankButtonGroup {
|
||||
id: suspendBehaviorSelector
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
model: ["Suspend", "Hibernate", "Suspend then Hibernate"]
|
||||
selectionMode: "single"
|
||||
checkEnabled: false
|
||||
|
||||
Connections {
|
||||
target: powerCategory
|
||||
function onCurrentIndexChanged() {
|
||||
const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior;
|
||||
suspendBehaviorSelector.currentIndex = behavior;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior;
|
||||
currentIndex = behavior;
|
||||
}
|
||||
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected)
|
||||
return;
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acSuspendBehavior", index);
|
||||
} else {
|
||||
SettingsData.set("batterySuspendBehavior", index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Idle monitoring not supported - requires newer Quickshell version")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.error
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: !IdleService.idleMonitorAvailable
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "tune"
|
||||
title: I18n.tr("Power Menu Customization")
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Customize which actions appear in the power menu")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Use Grid Layout")
|
||||
description: I18n.tr("Display power menu actions in a grid instead of a list")
|
||||
checked: SettingsData.powerMenuGridLayout
|
||||
onToggled: checked => SettingsData.set("powerMenuGridLayout", checked)
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
id: defaultActionDropdown
|
||||
text: I18n.tr("Default selected action")
|
||||
options: ["Reboot", "Log Out", "Power Off", "Lock", "Suspend", "Restart DMS", "Hibernate"]
|
||||
property var actionValues: ["reboot", "logout", "poweroff", "lock", "suspend", "restart", "hibernate"]
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentAction = SettingsData.powerMenuDefaultAction || "logout";
|
||||
const index = actionValues.indexOf(currentAction);
|
||||
currentValue = index >= 0 ? options[index] : "Log Out";
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = options.indexOf(value);
|
||||
if (index < 0)
|
||||
return;
|
||||
SettingsData.set("powerMenuDefaultAction", actionValues[index]);
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outline
|
||||
opacity: 0.15
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: [
|
||||
{
|
||||
key: "reboot",
|
||||
label: I18n.tr("Show Reboot")
|
||||
},
|
||||
{
|
||||
key: "logout",
|
||||
label: I18n.tr("Show Log Out")
|
||||
},
|
||||
{
|
||||
key: "poweroff",
|
||||
label: I18n.tr("Show Power Off")
|
||||
},
|
||||
{
|
||||
key: "lock",
|
||||
label: I18n.tr("Show Lock")
|
||||
},
|
||||
{
|
||||
key: "suspend",
|
||||
label: I18n.tr("Show Suspend")
|
||||
},
|
||||
{
|
||||
key: "restart",
|
||||
label: I18n.tr("Show Restart DMS"),
|
||||
desc: I18n.tr("Restart the DankMaterialShell")
|
||||
},
|
||||
{
|
||||
key: "hibernate",
|
||||
label: I18n.tr("Show Hibernate"),
|
||||
desc: I18n.tr("Only visible if hibernate is supported by your system"),
|
||||
hibernate: true
|
||||
}
|
||||
]
|
||||
|
||||
SettingsToggleRow {
|
||||
required property var modelData
|
||||
text: modelData.label
|
||||
description: modelData.desc || ""
|
||||
visible: !modelData.hibernate || SessionService.hibernateSupported
|
||||
checked: SettingsData.powerMenuActions.includes(modelData.key)
|
||||
onToggled: checked => {
|
||||
let actions = [...SettingsData.powerMenuActions];
|
||||
if (checked && !actions.includes(modelData.key)) {
|
||||
actions.push(modelData.key);
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== modelData.key);
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "check_circle"
|
||||
title: I18n.tr("Power Action Confirmation")
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Hold to Confirm Power Actions")
|
||||
description: I18n.tr("Require holding button/key to confirm power off, restart, suspend, hibernate and logout")
|
||||
checked: SettingsData.powerActionConfirm
|
||||
onToggled: checked => SettingsData.set("powerActionConfirm", checked)
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
text: I18n.tr("Hold Duration")
|
||||
description: I18n.tr("How long to hold the button to confirm the action")
|
||||
minimum: 1
|
||||
maximum: 10
|
||||
unit: "s"
|
||||
visible: SettingsData.powerActionConfirm
|
||||
value: SettingsData.powerActionHoldDuration
|
||||
onSliderValueChanged: newValue => SettingsData.set("powerActionHoldDuration", newValue)
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "developer_mode"
|
||||
title: I18n.tr("Custom Power Actions")
|
||||
|
||||
Repeater {
|
||||
model: [
|
||||
{
|
||||
key: "customPowerActionLock",
|
||||
label: I18n.tr("Custom Lock Command"),
|
||||
placeholder: "/usr/bin/myLock.sh"
|
||||
},
|
||||
{
|
||||
key: "customPowerActionLogout",
|
||||
label: I18n.tr("Custom Logout Command"),
|
||||
placeholder: "/usr/bin/myLogout.sh"
|
||||
},
|
||||
{
|
||||
key: "customPowerActionSuspend",
|
||||
label: I18n.tr("Custom Suspend Command"),
|
||||
placeholder: "/usr/bin/mySuspend.sh"
|
||||
},
|
||||
{
|
||||
key: "customPowerActionHibernate",
|
||||
label: I18n.tr("Custom Hibernate Command"),
|
||||
placeholder: "/usr/bin/myHibernate.sh"
|
||||
},
|
||||
{
|
||||
key: "customPowerActionReboot",
|
||||
label: I18n.tr("Custom Reboot Command"),
|
||||
placeholder: "/usr/bin/myReboot.sh"
|
||||
},
|
||||
{
|
||||
key: "customPowerActionPowerOff",
|
||||
label: I18n.tr("Custom Power Off Command"),
|
||||
placeholder: "/usr/bin/myPowerOff.sh"
|
||||
}
|
||||
]
|
||||
|
||||
Column {
|
||||
required property var modelData
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: modelData.label
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: parent.width
|
||||
height: 48
|
||||
placeholderText: modelData.placeholder
|
||||
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency)
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
|
||||
Component.onCompleted: {
|
||||
var val = SettingsData[modelData.key];
|
||||
if (val)
|
||||
text = val;
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
SettingsData.set(modelData.key, text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
quickshell/Modules/Settings/RunningAppsTab.qml
Normal file
35
quickshell/Modules/Settings/RunningAppsTab.qml
Normal file
@@ -0,0 +1,35 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "apps"
|
||||
title: I18n.tr("Running Apps Settings")
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Running Apps Only In Current Workspace")
|
||||
description: I18n.tr("Show only apps running in current workspace")
|
||||
checked: SettingsData.runningAppsCurrentWorkspace
|
||||
onToggled: checked => SettingsData.set("runningAppsCurrentWorkspace", checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
|
||||
property string title: ""
|
||||
property string iconName: ""
|
||||
property alias content: contentLoader.sourceComponent
|
||||
property bool expanded: false
|
||||
property bool collapsible: true
|
||||
property bool lazyLoad: true
|
||||
|
||||
width: parent.width
|
||||
spacing: expanded ? Theme.spacingM : 0
|
||||
Component.onCompleted: {
|
||||
if (!collapsible)
|
||||
expanded = true;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
width: parent.width
|
||||
height: headerRow.height
|
||||
enabled: collapsible
|
||||
hoverEnabled: collapsible
|
||||
onClicked: {
|
||||
if (collapsible)
|
||||
expanded = !expanded;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: parent.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
||||
radius: Theme.radiusS
|
||||
}
|
||||
|
||||
Row {
|
||||
id: headerRow
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
topPadding: Theme.spacingS
|
||||
bottomPadding: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: root.collapsible ? (root.expanded ? "expand_less" : "expand_more") : root.iconName
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Behavior on rotation {
|
||||
NumberAnimation {
|
||||
duration: Appearance.anim.durations.fast
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.anim.curves.standard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: root.iconName
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.collapsible
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.title
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
visible: expanded || !collapsible
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: contentLoader
|
||||
|
||||
width: parent.width
|
||||
active: lazyLoad ? expanded || !collapsible : true
|
||||
visible: expanded || !collapsible
|
||||
asynchronous: true
|
||||
opacity: visible ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Appearance.anim.durations.normal
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.anim.curves.standard
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
156
quickshell/Modules/Settings/SoundsTab.qml
Normal file
156
quickshell/Modules/Settings/SoundsTab.qml
Normal file
@@ -0,0 +1,156 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
tab: "sounds"
|
||||
tags: ["sound", "audio", "notification", "volume"]
|
||||
title: I18n.tr("System Sounds")
|
||||
iconName: SettingsData.soundsEnabled ? "volume_up" : "volume_off"
|
||||
visible: AudioService.soundsAvailable
|
||||
|
||||
SettingsToggleRow {
|
||||
tab: "sounds"
|
||||
tags: ["sound", "enable", "system"]
|
||||
settingKey: "soundsEnabled"
|
||||
text: I18n.tr("Enable System Sounds")
|
||||
description: I18n.tr("Play sounds for system events")
|
||||
checked: SettingsData.soundsEnabled
|
||||
onToggled: checked => SettingsData.set("soundsEnabled", checked)
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: SettingsData.soundsEnabled
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outline
|
||||
opacity: 0.2
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
tab: "sounds"
|
||||
tags: ["sound", "theme", "system"]
|
||||
settingKey: "useSystemSoundTheme"
|
||||
visible: AudioService.gsettingsAvailable
|
||||
text: I18n.tr("Use System Theme")
|
||||
description: I18n.tr("Use sound theme from system settings")
|
||||
checked: SettingsData.useSystemSoundTheme
|
||||
onToggled: checked => SettingsData.set("useSystemSoundTheme", checked)
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
tab: "sounds"
|
||||
tags: ["sound", "theme", "select"]
|
||||
settingKey: "soundTheme"
|
||||
visible: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0
|
||||
enabled: SettingsData.useSystemSoundTheme && AudioService.availableSoundThemes.length > 0
|
||||
text: I18n.tr("Sound Theme")
|
||||
description: I18n.tr("Select system sound theme")
|
||||
options: AudioService.availableSoundThemes
|
||||
currentValue: {
|
||||
const theme = AudioService.currentSoundTheme;
|
||||
if (theme && AudioService.availableSoundThemes.includes(theme))
|
||||
return theme;
|
||||
return AudioService.availableSoundThemes.length > 0 ? AudioService.availableSoundThemes[0] : "";
|
||||
}
|
||||
onValueChanged: value => {
|
||||
if (value && value !== AudioService.currentSoundTheme)
|
||||
AudioService.setSoundTheme(value);
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outline
|
||||
opacity: 0.2
|
||||
visible: AudioService.gsettingsAvailable
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
tab: "sounds"
|
||||
tags: ["sound", "notification", "new"]
|
||||
settingKey: "soundNewNotification"
|
||||
text: I18n.tr("New Notification")
|
||||
description: I18n.tr("Play sound when new notification arrives")
|
||||
checked: SettingsData.soundNewNotification
|
||||
onToggled: checked => SettingsData.set("soundNewNotification", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
tab: "sounds"
|
||||
tags: ["sound", "volume", "changed"]
|
||||
settingKey: "soundVolumeChanged"
|
||||
text: I18n.tr("Volume Changed")
|
||||
description: I18n.tr("Play sound when volume is adjusted")
|
||||
checked: SettingsData.soundVolumeChanged
|
||||
onToggled: checked => SettingsData.set("soundVolumeChanged", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
tab: "sounds"
|
||||
tags: ["sound", "power", "plugged"]
|
||||
settingKey: "soundPluggedIn"
|
||||
visible: BatteryService.batteryAvailable
|
||||
text: I18n.tr("Plugged In")
|
||||
description: I18n.tr("Play sound when power cable is connected")
|
||||
checked: SettingsData.soundPluggedIn
|
||||
onToggled: checked => SettingsData.set("soundPluggedIn", checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: notAvailableText.implicitHeight + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12)
|
||||
visible: !AudioService.soundsAvailable
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "info"
|
||||
size: Theme.iconSizeSmall
|
||||
color: Theme.warning
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: notAvailableText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
text: I18n.tr("System sounds are not available. Install canberra-gtk-play for sound support.")
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width - Theme.iconSizeSmall - Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
133
quickshell/Modules/Settings/SystemUpdaterTab.qml
Normal file
133
quickshell/Modules/Settings/SystemUpdaterTab.qml
Normal file
@@ -0,0 +1,133 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "refresh"
|
||||
title: I18n.tr("System Updater")
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Use Custom Command")
|
||||
description: I18n.tr("Use custom command for update your system")
|
||||
checked: SettingsData.updaterUseCustomCommand
|
||||
onToggled: checked => {
|
||||
if (!checked) {
|
||||
updaterCustomCommand.text = "";
|
||||
updaterTerminalCustomClass.text = "";
|
||||
SettingsData.set("updaterCustomCommand", "");
|
||||
SettingsData.set("updaterTerminalAdditionalParams", "");
|
||||
}
|
||||
SettingsData.set("updaterUseCustomCommand", checked);
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
height: customCommandColumn.implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
|
||||
Column {
|
||||
id: customCommandColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("System update custom command")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: updaterCustomCommand
|
||||
width: parent.width
|
||||
height: 48
|
||||
placeholderText: "myPkgMngr --sysupdate"
|
||||
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency)
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.updaterCustomCommand) {
|
||||
text = SettingsData.updaterCustomCommand;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: SettingsData.set("updaterCustomCommand", text.trim())
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: mouse => {
|
||||
updaterCustomCommand.forceActiveFocus();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
height: terminalParamsColumn.implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
|
||||
Column {
|
||||
id: terminalParamsColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Terminal custom additional parameters")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: updaterTerminalCustomClass
|
||||
width: parent.width
|
||||
height: 48
|
||||
placeholderText: "-T udpClass"
|
||||
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency)
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.updaterTerminalAdditionalParams) {
|
||||
text = SettingsData.updaterTerminalAdditionalParams;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: SettingsData.set("updaterTerminalAdditionalParams", text.trim())
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: mouse => {
|
||||
updaterTerminalCustomClass.forceActiveFocus();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
285
quickshell/Modules/Settings/TypographyMotionTab.qml
Normal file
285
quickshell/Modules/Settings/TypographyMotionTab.qml
Normal file
@@ -0,0 +1,285 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var cachedFontFamilies: []
|
||||
property var cachedMonoFamilies: []
|
||||
property bool fontsEnumerated: false
|
||||
|
||||
function enumerateFonts() {
|
||||
var fonts = [];
|
||||
var availableFonts = Qt.fontFamilies();
|
||||
|
||||
for (var i = 0; i < availableFonts.length; i++) {
|
||||
var fontName = availableFonts[i];
|
||||
if (fontName.startsWith("."))
|
||||
continue;
|
||||
fonts.push(fontName);
|
||||
}
|
||||
fonts.sort();
|
||||
fonts.unshift("Default");
|
||||
cachedFontFamilies = fonts;
|
||||
|
||||
var monoFonts = [];
|
||||
for (var j = 0; j < availableFonts.length; j++) {
|
||||
var fontName2 = availableFonts[j];
|
||||
if (fontName2.startsWith("."))
|
||||
continue;
|
||||
var lowerName = fontName2.toLowerCase();
|
||||
if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("jetbrains") || lowerName.includes("fira") || lowerName.includes("hack") || lowerName.includes("source code") || lowerName.includes("cascadia")) {
|
||||
monoFonts.push(fontName2);
|
||||
}
|
||||
}
|
||||
monoFonts.sort();
|
||||
monoFonts.unshift("Default");
|
||||
cachedMonoFamilies = monoFonts;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: fontEnumerationTimer
|
||||
interval: 50
|
||||
running: false
|
||||
onTriggered: {
|
||||
if (fontsEnumerated)
|
||||
return;
|
||||
enumerateFonts();
|
||||
fontsEnumerated = true;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
fontEnumerationTimer.start();
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
tab: "typography"
|
||||
tags: ["font", "family", "text", "typography"]
|
||||
title: I18n.tr("Typography")
|
||||
iconName: "text_fields"
|
||||
|
||||
SettingsDropdownRow {
|
||||
tab: "typography"
|
||||
tags: ["font", "family", "normal", "text"]
|
||||
settingKey: "fontFamily"
|
||||
text: I18n.tr("Normal Font")
|
||||
description: I18n.tr("Select the font family for UI text")
|
||||
options: root.fontsEnumerated ? root.cachedFontFamilies : ["Default"]
|
||||
currentValue: SettingsData.fontFamily === Theme.defaultFontFamily ? "Default" : (SettingsData.fontFamily || "Default")
|
||||
enableFuzzySearch: true
|
||||
popupWidthOffset: 100
|
||||
maxPopupHeight: 400
|
||||
onValueChanged: value => {
|
||||
if (value === "Default")
|
||||
SettingsData.set("fontFamily", Theme.defaultFontFamily);
|
||||
else
|
||||
SettingsData.set("fontFamily", value);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
tab: "typography"
|
||||
tags: ["font", "monospace", "code", "terminal"]
|
||||
settingKey: "monoFontFamily"
|
||||
text: I18n.tr("Monospace Font")
|
||||
description: I18n.tr("Select monospace font for process list and technical displays")
|
||||
options: root.fontsEnumerated ? root.cachedMonoFamilies : ["Default"]
|
||||
currentValue: SettingsData.monoFontFamily === SettingsData.defaultMonoFontFamily ? "Default" : (SettingsData.monoFontFamily || "Default")
|
||||
enableFuzzySearch: true
|
||||
popupWidthOffset: 100
|
||||
maxPopupHeight: 400
|
||||
onValueChanged: value => {
|
||||
if (value === "Default")
|
||||
SettingsData.set("monoFontFamily", SettingsData.defaultMonoFontFamily);
|
||||
else
|
||||
SettingsData.set("monoFontFamily", value);
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outline
|
||||
opacity: 0.15
|
||||
}
|
||||
|
||||
SettingsDropdownRow {
|
||||
tab: "typography"
|
||||
tags: ["font", "weight", "bold", "light"]
|
||||
settingKey: "fontWeight"
|
||||
text: I18n.tr("Font Weight")
|
||||
description: I18n.tr("Select font weight for UI text")
|
||||
options: ["Thin", "Extra Light", "Light", "Regular", "Medium", "Demi Bold", "Bold", "Extra Bold", "Black"]
|
||||
currentValue: {
|
||||
switch (SettingsData.fontWeight) {
|
||||
case Font.Thin:
|
||||
return "Thin";
|
||||
case Font.ExtraLight:
|
||||
return "Extra Light";
|
||||
case Font.Light:
|
||||
return "Light";
|
||||
case Font.Normal:
|
||||
return "Regular";
|
||||
case Font.Medium:
|
||||
return "Medium";
|
||||
case Font.DemiBold:
|
||||
return "Demi Bold";
|
||||
case Font.Bold:
|
||||
return "Bold";
|
||||
case Font.ExtraBold:
|
||||
return "Extra Bold";
|
||||
case Font.Black:
|
||||
return "Black";
|
||||
default:
|
||||
return "Regular";
|
||||
}
|
||||
}
|
||||
onValueChanged: value => {
|
||||
var weight;
|
||||
switch (value) {
|
||||
case "Thin":
|
||||
weight = Font.Thin;
|
||||
break;
|
||||
case "Extra Light":
|
||||
weight = Font.ExtraLight;
|
||||
break;
|
||||
case "Light":
|
||||
weight = Font.Light;
|
||||
break;
|
||||
case "Regular":
|
||||
weight = Font.Normal;
|
||||
break;
|
||||
case "Medium":
|
||||
weight = Font.Medium;
|
||||
break;
|
||||
case "Demi Bold":
|
||||
weight = Font.DemiBold;
|
||||
break;
|
||||
case "Bold":
|
||||
weight = Font.Bold;
|
||||
break;
|
||||
case "Extra Bold":
|
||||
weight = Font.ExtraBold;
|
||||
break;
|
||||
case "Black":
|
||||
weight = Font.Black;
|
||||
break;
|
||||
default:
|
||||
weight = Font.Normal;
|
||||
break;
|
||||
}
|
||||
SettingsData.set("fontWeight", weight);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
tab: "typography"
|
||||
tags: ["font", "scale", "size", "zoom"]
|
||||
settingKey: "fontScale"
|
||||
text: I18n.tr("Font Scale")
|
||||
description: I18n.tr("Scale all font sizes throughout the shell")
|
||||
minimum: 75
|
||||
maximum: 150
|
||||
value: Math.round(SettingsData.fontScale * 100)
|
||||
unit: "%"
|
||||
defaultValue: 100
|
||||
onSliderValueChanged: newValue => SettingsData.set("fontScale", newValue / 100)
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
tab: "typography"
|
||||
tags: ["animation", "speed", "motion", "duration"]
|
||||
title: I18n.tr("Animation Speed")
|
||||
iconName: "animation"
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: animationSpeedGroup.implicitHeight
|
||||
clip: true
|
||||
|
||||
DankButtonGroup {
|
||||
id: animationSpeedGroup
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL
|
||||
minButtonWidth: parent.width < 480 ? 44 : 64
|
||||
textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
||||
model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")]
|
||||
selectionMode: "single"
|
||||
currentIndex: SettingsData.animationSpeed
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected)
|
||||
return;
|
||||
SettingsData.set("animationSpeed", index);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onAnimationSpeedChanged() {
|
||||
animationSpeedGroup.currentIndex = SettingsData.animationSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outline
|
||||
opacity: 0.15
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
id: durationSlider
|
||||
tab: "typography"
|
||||
tags: ["animation", "duration", "custom", "speed"]
|
||||
settingKey: "customAnimationDuration"
|
||||
text: I18n.tr("Custom Duration")
|
||||
description: I18n.tr("Fine-tune animation timing in milliseconds")
|
||||
minimum: 0
|
||||
maximum: 750
|
||||
value: Theme.currentAnimationBaseDuration
|
||||
unit: "ms"
|
||||
defaultValue: 200
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("animationSpeed", SettingsData.AnimationSpeed.Custom);
|
||||
SettingsData.set("customAnimationDuration", newValue);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onAnimationSpeedChanged() {
|
||||
if (SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom)
|
||||
return;
|
||||
durationSlider.value = Theme.currentAnimationBaseDuration;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Theme
|
||||
function onCurrentAnimationBaseDurationChanged() {
|
||||
if (SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom)
|
||||
return;
|
||||
durationSlider.value = Theme.currentAnimationBaseDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1282
quickshell/Modules/Settings/WallpaperTab.qml
Normal file
1282
quickshell/Modules/Settings/WallpaperTab.qml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,873 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: widgetTweaksTab
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: workspaceSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: workspaceSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "view_module"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Workspace Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Workspace Index Numbers")
|
||||
description: I18n.tr("Show workspace index numbers in the top bar workspace switcher")
|
||||
checked: SettingsData.showWorkspaceIndex
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("showWorkspaceIndex", checked);
|
||||
}
|
||||
}
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Workspace Padding")
|
||||
description: I18n.tr("Always show a minimum of 3 workspaces, even if fewer are available")
|
||||
checked: SettingsData.showWorkspacePadding
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("showWorkspacePadding", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Show Workspace Apps")
|
||||
description: I18n.tr("Display application icons in workspace indicators")
|
||||
checked: SettingsData.showWorkspaceApps
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("showWorkspaceApps", checked);
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width - Theme.spacingL
|
||||
spacing: Theme.spacingL
|
||||
visible: SettingsData.showWorkspaceApps
|
||||
opacity: visible ? 1 : 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingL
|
||||
|
||||
Column {
|
||||
width: 120
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Max apps to show")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: 100
|
||||
height: 28
|
||||
placeholderText: "#ffffff"
|
||||
text: SettingsData.maxWorkspaceIcons
|
||||
maximumLength: 7
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
topPadding: Theme.spacingXS
|
||||
bottomPadding: Theme.spacingXS
|
||||
onEditingFinished: {
|
||||
SettingsData.set("maxWorkspaceIcons", parseInt(text, 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Per-Monitor Workspaces")
|
||||
description: I18n.tr("Show only workspaces belonging to each specific monitor.")
|
||||
checked: SettingsData.workspacesPerMonitor
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("workspacesPerMonitor", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Show Occupied Workspaces Only")
|
||||
description: I18n.tr("Display only workspaces that contain windows")
|
||||
checked: SettingsData.showOccupiedWorkspacesOnly
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("showOccupiedWorkspacesOnly", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Show All Tags")
|
||||
description: I18n.tr("Show all 9 tags instead of only occupied tags (DWL only)")
|
||||
checked: SettingsData.dwlShowAllTags
|
||||
visible: CompositorService.isDwl
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("dwlShowAllTags", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: mediaSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: mediaSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "music_note"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Media Player Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Wave Progress Bars")
|
||||
description: I18n.tr("Use animated wave progress bars for media playback")
|
||||
checked: SettingsData.waveProgressEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("waveProgressEnabled", checked);
|
||||
}
|
||||
}
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Scroll song title")
|
||||
description: I18n.tr("Scroll title if it doesn't fit in widget")
|
||||
checked: SettingsData.scrollTitleEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("scrollTitleEnabled", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: updaterSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: updaterSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "refresh"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("System Updater")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Use Custom Command")
|
||||
description: I18n.tr("Use custom command for update your system")
|
||||
checked: SettingsData.updaterUseCustomCommand
|
||||
onToggled: checked => {
|
||||
if (!checked) {
|
||||
updaterCustomCommand.text = "";
|
||||
updaterTerminalCustomClass.text = "";
|
||||
SettingsData.set("updaterCustomCommand", "");
|
||||
SettingsData.set("updaterTerminalAdditionalParams", "");
|
||||
}
|
||||
return SettingsData.set("updaterUseCustomCommand", checked);
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
height: customCommandColumn.implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
|
||||
Column {
|
||||
id: customCommandColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("System update custom command")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: updaterCustomCommand
|
||||
width: parent.width
|
||||
height: 48
|
||||
placeholderText: "myPkgMngr --sysupdate"
|
||||
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency)
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.updaterCustomCommand) {
|
||||
text = SettingsData.updaterCustomCommand;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
SettingsData.set("updaterCustomCommand", text.trim());
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: mouse => {
|
||||
updaterCustomCommand.forceActiveFocus();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
height: terminalParamsColumn.implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
|
||||
Column {
|
||||
id: terminalParamsColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Terminal custom additional parameters")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: updaterTerminalCustomClass
|
||||
width: parent.width
|
||||
height: 48
|
||||
placeholderText: "-T udpClass"
|
||||
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency)
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.updaterTerminalAdditionalParams) {
|
||||
text = SettingsData.updaterTerminalAdditionalParams;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
SettingsData.set("updaterTerminalAdditionalParams", text.trim());
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: mouse => {
|
||||
updaterTerminalCustomClass.forceActiveFocus();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: runningAppsSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||
|
||||
Column {
|
||||
id: runningAppsSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "apps"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Running Apps Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Running Apps Only In Current Workspace")
|
||||
description: I18n.tr("Show only apps running in current workspace")
|
||||
checked: SettingsData.runningAppsCurrentWorkspace
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("runningAppsCurrentWorkspace", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: workspaceIconsSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
visible: SettingsData.hasNamedWorkspaces()
|
||||
|
||||
Column {
|
||||
id: workspaceIconsSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "label"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Named Workspace Icons")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("Configure icons for named workspaces. Icons take priority over numbers when both are enabled.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: SettingsData.getNamedWorkspaces()
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: workspaceIconRow.implicitHeight + Theme.spacingM
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.5)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
id: workspaceIconRow
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "\"" + modelData + "\""
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 150
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
DankIconPicker {
|
||||
id: iconPicker
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Component.onCompleted: {
|
||||
var iconData = SettingsData.getWorkspaceNameIcon(modelData);
|
||||
if (iconData) {
|
||||
setIcon(iconData.value, iconData.type);
|
||||
}
|
||||
}
|
||||
|
||||
onIconSelected: (iconName, iconType) => {
|
||||
SettingsData.setWorkspaceNameIcon(modelData, {
|
||||
"type": iconType,
|
||||
"value": iconName
|
||||
});
|
||||
setIcon(iconName, iconType);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onWorkspaceIconsUpdated() {
|
||||
var iconData = SettingsData.getWorkspaceNameIcon(modelData);
|
||||
if (iconData) {
|
||||
iconPicker.setIcon(iconData.value, iconData.type);
|
||||
} else {
|
||||
iconPicker.setIcon("", "icon");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 28
|
||||
height: 28
|
||||
radius: Theme.cornerRadius
|
||||
color: clearMouseArea.containsMouse ? Theme.errorHover : Theme.surfaceContainer
|
||||
border.color: clearMouseArea.containsMouse ? Theme.error : Theme.outline
|
||||
border.width: 0
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "close"
|
||||
size: 16
|
||||
color: clearMouseArea.containsMouse ? Theme.error : Theme.outline
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: clearMouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
SettingsData.removeWorkspaceNameIcon(modelData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - 150 - 240 - 28 - Theme.spacingM * 4
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: notificationSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: notificationSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "notifications"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Notification Popups")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
leftPadding: Theme.spacingM
|
||||
rightPadding: Theme.spacingM
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
text: I18n.tr("Popup Position")
|
||||
description: I18n.tr("Choose where notification popups appear on screen")
|
||||
currentValue: {
|
||||
if (SettingsData.notificationPopupPosition === -1) {
|
||||
return "Top Center";
|
||||
}
|
||||
switch (SettingsData.notificationPopupPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return "Top Right";
|
||||
case SettingsData.Position.Bottom:
|
||||
return "Bottom Left";
|
||||
case SettingsData.Position.Left:
|
||||
return "Top Left";
|
||||
case SettingsData.Position.Right:
|
||||
return "Bottom Right";
|
||||
default:
|
||||
return "Top Right";
|
||||
}
|
||||
}
|
||||
options: ["Top Right", "Top Left", "Top Center", "Bottom Right", "Bottom Left"]
|
||||
onValueChanged: value => {
|
||||
switch (value) {
|
||||
case "Top Right":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Top);
|
||||
break;
|
||||
case "Top Left":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Left);
|
||||
break;
|
||||
case "Top Center":
|
||||
SettingsData.set("notificationPopupPosition", -1);
|
||||
break;
|
||||
case "Bottom Right":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Right);
|
||||
break;
|
||||
case "Bottom Left":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Bottom);
|
||||
break;
|
||||
}
|
||||
SettingsData.sendTestNotifications();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: osdRow.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
id: osdRow
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "tune"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - osdToggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Always Show OSD Percentage")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Display volume and brightness percentage values by default in OSD popups")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
id: osdToggle
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.osdAlwaysShowValue
|
||||
onToggled: checked => {
|
||||
SettingsData.set("osdAlwaysShowValue", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: osdSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: osdSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "notification_important"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("On-screen Displays")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
leftPadding: Theme.spacingM
|
||||
rightPadding: Theme.spacingM
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
text: I18n.tr("OSD Position")
|
||||
description: I18n.tr("Choose where on-screen displays appear on screen")
|
||||
currentValue: {
|
||||
switch (SettingsData.osdPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return "Top Right";
|
||||
case SettingsData.Position.Left:
|
||||
return "Top Left";
|
||||
case SettingsData.Position.TopCenter:
|
||||
return "Top Center";
|
||||
case SettingsData.Position.Right:
|
||||
return "Bottom Right";
|
||||
case SettingsData.Position.Bottom:
|
||||
return "Bottom Left";
|
||||
case SettingsData.Position.BottomCenter:
|
||||
return "Bottom Center";
|
||||
case SettingsData.Position.LeftCenter:
|
||||
return "Left Center";
|
||||
case SettingsData.Position.RightCenter:
|
||||
return "Right Center";
|
||||
default:
|
||||
return "Bottom Center";
|
||||
}
|
||||
}
|
||||
options: ["Top Right", "Top Left", "Top Center", "Bottom Right", "Bottom Left", "Bottom Center", "Left Center", "Right Center"]
|
||||
onValueChanged: value => {
|
||||
switch (value) {
|
||||
case "Top Right":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Top);
|
||||
break;
|
||||
case "Top Left":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Left);
|
||||
break;
|
||||
case "Top Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.TopCenter);
|
||||
break;
|
||||
case "Bottom Right":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Right);
|
||||
break;
|
||||
case "Bottom Left":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Bottom);
|
||||
break;
|
||||
case "Bottom Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.BottomCenter);
|
||||
break;
|
||||
case "Left Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.LeftCenter);
|
||||
break;
|
||||
case "Right Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.RightCenter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Volume OSD")
|
||||
description: I18n.tr("Show on-screen display when volume changes")
|
||||
checked: SettingsData.osdVolumeEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdVolumeEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Media Volume OSD")
|
||||
description: I18n.tr("Show on-screen display when media player volume changes")
|
||||
checked: SettingsData.osdMediaVolumeEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdMediaVolumeEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Brightness OSD")
|
||||
description: I18n.tr("Show on-screen display when brightness changes")
|
||||
checked: SettingsData.osdBrightnessEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdBrightnessEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Idle Inhibitor OSD")
|
||||
description: I18n.tr("Show on-screen display when idle inhibitor state changes")
|
||||
checked: SettingsData.osdIdleInhibitorEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdIdleInhibitorEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Microphone Mute OSD")
|
||||
description: I18n.tr("Show on-screen display when microphone is muted/unmuted")
|
||||
checked: SettingsData.osdMicMuteEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdMicMuteEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Caps Lock OSD")
|
||||
description: I18n.tr("Show on-screen display when caps lock state changes")
|
||||
checked: SettingsData.osdCapsLockEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdCapsLockEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Power Profile OSD")
|
||||
description: I18n.tr("Show on-screen display when power profile changes")
|
||||
checked: SettingsData.osdPowerProfileEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdPowerProfileEnabled", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string tab: ""
|
||||
property var tags: []
|
||||
property string settingKey: ""
|
||||
|
||||
property string text: ""
|
||||
property string description: ""
|
||||
property alias model: buttonGroup.model
|
||||
property alias currentIndex: buttonGroup.currentIndex
|
||||
property alias selectionMode: buttonGroup.selectionMode
|
||||
property alias buttonHeight: buttonGroup.buttonHeight
|
||||
property alias minButtonWidth: buttonGroup.minButtonWidth
|
||||
property alias buttonPadding: buttonGroup.buttonPadding
|
||||
property alias checkIconSize: buttonGroup.checkIconSize
|
||||
property alias textSize: buttonGroup.textSize
|
||||
property alias spacing: buttonGroup.spacing
|
||||
property alias checkEnabled: buttonGroup.checkEnabled
|
||||
|
||||
signal selectionChanged(int index, bool selected)
|
||||
|
||||
width: parent?.width ?? 0
|
||||
height: 60
|
||||
|
||||
Row {
|
||||
id: contentRow
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
x: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Column {
|
||||
width: parent.width - buttonGroup.width - Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: root.text
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
visible: root.text !== ""
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.description
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
visible: root.description !== ""
|
||||
}
|
||||
}
|
||||
|
||||
DankButtonGroup {
|
||||
id: buttonGroup
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
selectionMode: "single"
|
||||
onSelectionChanged: (index, selected) => root.selectionChanged(index, selected)
|
||||
}
|
||||
}
|
||||
}
|
||||
121
quickshell/Modules/Settings/Widgets/SettingsCard.qml
Normal file
121
quickshell/Modules/Settings/Widgets/SettingsCard.qml
Normal file
@@ -0,0 +1,121 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
StyledRect {
|
||||
id: root
|
||||
|
||||
property string tab: ""
|
||||
property var tags: []
|
||||
|
||||
property string title: ""
|
||||
property string iconName: ""
|
||||
property bool collapsible: false
|
||||
property bool expanded: true
|
||||
|
||||
default property alias content: contentColumn.children
|
||||
|
||||
width: parent?.width ?? 0
|
||||
height: {
|
||||
var hasHeader = root.title !== "" || root.iconName !== "";
|
||||
if (collapsed)
|
||||
return headerRow.height + Theme.spacingL * 2;
|
||||
var h = Theme.spacingL * 2 + contentColumn.height;
|
||||
if (hasHeader)
|
||||
h += headerRow.height + Theme.spacingM;
|
||||
return h;
|
||||
}
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
|
||||
readonly property bool collapsed: collapsible && !expanded
|
||||
readonly property bool hasHeader: root.title !== "" || root.iconName !== ""
|
||||
property bool animationsEnabled: false
|
||||
|
||||
Component.onCompleted: Qt.callLater(() => animationsEnabled = true)
|
||||
|
||||
Behavior on height {
|
||||
enabled: root.animationsEnabled
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: root.hasHeader ? Theme.spacingM : 0
|
||||
clip: true
|
||||
|
||||
Item {
|
||||
id: headerRow
|
||||
width: parent.width
|
||||
height: root.hasHeader ? Math.max(headerIcon.height, headerText.height) : 0
|
||||
visible: root.hasHeader
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
id: headerIcon
|
||||
name: root.iconName
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.iconName !== ""
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: headerText
|
||||
text: root.title
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.title !== ""
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: root.expanded ? "expand_less" : "expand_more"
|
||||
size: Theme.iconSize - 2
|
||||
color: Theme.surfaceVariantText
|
||||
visible: root.collapsible
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: root.collapsible
|
||||
cursorShape: root.collapsible ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
onClicked: {
|
||||
if (!root.collapsible)
|
||||
return;
|
||||
root.expanded = !root.expanded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: contentColumn
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: !root.collapsed
|
||||
opacity: root.collapsed ? 0 : 1
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml
Normal file
15
quickshell/Modules/Settings/Widgets/SettingsDropdownRow.qml
Normal file
@@ -0,0 +1,15 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Widgets
|
||||
|
||||
DankDropdown {
|
||||
id: root
|
||||
|
||||
property string tab: ""
|
||||
property var tags: []
|
||||
property string settingKey: ""
|
||||
|
||||
width: parent?.width ?? 0
|
||||
addHorizontalPadding: true
|
||||
}
|
||||
99
quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml
Normal file
99
quickshell/Modules/Settings/Widgets/SettingsSliderRow.qml
Normal file
@@ -0,0 +1,99 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string tab: ""
|
||||
property var tags: []
|
||||
property string settingKey: ""
|
||||
|
||||
property string text: ""
|
||||
property string description: ""
|
||||
property alias value: slider.value
|
||||
property alias minimum: slider.minimum
|
||||
property alias maximum: slider.maximum
|
||||
property alias unit: slider.unit
|
||||
property alias wheelEnabled: slider.wheelEnabled
|
||||
property alias thumbOutlineColor: slider.thumbOutlineColor
|
||||
property int defaultValue: -1
|
||||
|
||||
signal sliderValueChanged(int newValue)
|
||||
|
||||
width: parent?.width ?? 0
|
||||
height: headerRow.height + Theme.spacingXS + slider.height
|
||||
|
||||
Column {
|
||||
id: contentColumn
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
x: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Row {
|
||||
id: headerRow
|
||||
width: parent.width
|
||||
height: labelColumn.height
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Column {
|
||||
id: labelColumn
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXS
|
||||
width: parent.width - resetButtonContainer.width - Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: root.text
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
visible: root.text !== ""
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.description
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
visible: root.description !== ""
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: resetButtonContainer
|
||||
width: root.defaultValue >= 0 ? 36 : 0
|
||||
height: 36
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankActionButton {
|
||||
id: resetButton
|
||||
anchors.centerIn: parent
|
||||
buttonSize: 36
|
||||
iconName: "restart_alt"
|
||||
iconSize: 20
|
||||
visible: root.defaultValue >= 0 && slider.value !== root.defaultValue
|
||||
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
iconColor: Theme.surfaceVariantText
|
||||
onClicked: {
|
||||
slider.value = root.defaultValue;
|
||||
root.sliderValueChanged(root.defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
id: slider
|
||||
width: parent.width
|
||||
height: 32
|
||||
showValue: true
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => root.sliderValueChanged(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
14
quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml
Normal file
14
quickshell/Modules/Settings/Widgets/SettingsToggleRow.qml
Normal file
@@ -0,0 +1,14 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Widgets
|
||||
|
||||
DankToggle {
|
||||
id: root
|
||||
|
||||
property string tab: ""
|
||||
property var tags: []
|
||||
property string settingKey: ""
|
||||
|
||||
width: parent?.width ?? 0
|
||||
}
|
||||
224
quickshell/Modules/Settings/WorkspacesTab.qml
Normal file
224
quickshell/Modules/Settings/WorkspacesTab.qml
Normal file
@@ -0,0 +1,224 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "view_module"
|
||||
title: I18n.tr("Workspace Settings")
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Workspace Index Numbers")
|
||||
description: I18n.tr("Show workspace index numbers in the top bar workspace switcher")
|
||||
checked: SettingsData.showWorkspaceIndex
|
||||
onToggled: checked => SettingsData.set("showWorkspaceIndex", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Workspace Padding")
|
||||
description: I18n.tr("Always show a minimum of 3 workspaces, even if fewer are available")
|
||||
checked: SettingsData.showWorkspacePadding
|
||||
onToggled: checked => SettingsData.set("showWorkspacePadding", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Show Workspace Apps")
|
||||
description: I18n.tr("Display application icons in workspace indicators")
|
||||
checked: SettingsData.showWorkspaceApps
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||
onToggled: checked => SettingsData.set("showWorkspaceApps", checked)
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width - Theme.spacingL
|
||||
spacing: Theme.spacingL
|
||||
visible: SettingsData.showWorkspaceApps
|
||||
opacity: visible ? 1 : 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingL
|
||||
|
||||
Column {
|
||||
width: 120
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Max apps to show")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: 100
|
||||
height: 28
|
||||
placeholderText: "#ffffff"
|
||||
text: SettingsData.maxWorkspaceIcons
|
||||
maximumLength: 7
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
topPadding: Theme.spacingXS
|
||||
bottomPadding: Theme.spacingXS
|
||||
onEditingFinished: SettingsData.set("maxWorkspaceIcons", parseInt(text, 10))
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Per-Monitor Workspaces")
|
||||
description: I18n.tr("Show only workspaces belonging to each specific monitor.")
|
||||
checked: SettingsData.workspacesPerMonitor
|
||||
onToggled: checked => SettingsData.set("workspacesPerMonitor", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Show Occupied Workspaces Only")
|
||||
description: I18n.tr("Display only workspaces that contain windows")
|
||||
checked: SettingsData.showOccupiedWorkspacesOnly
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||
onToggled: checked => SettingsData.set("showOccupiedWorkspacesOnly", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
text: I18n.tr("Show All Tags")
|
||||
description: I18n.tr("Show all 9 tags instead of only occupied tags (DWL only)")
|
||||
checked: SettingsData.dwlShowAllTags
|
||||
visible: CompositorService.isDwl
|
||||
onToggled: checked => SettingsData.set("dwlShowAllTags", checked)
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "label"
|
||||
title: I18n.tr("Named Workspace Icons")
|
||||
visible: SettingsData.hasNamedWorkspaces()
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("Configure icons for named workspaces. Icons take priority over numbers when both are enabled.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: SettingsData.getNamedWorkspaces()
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: workspaceIconRow.implicitHeight + Theme.spacingM
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.5)
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
id: workspaceIconRow
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "\"" + modelData + "\""
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 150
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
DankIconPicker {
|
||||
id: iconPicker
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Component.onCompleted: {
|
||||
var iconData = SettingsData.getWorkspaceNameIcon(modelData);
|
||||
if (iconData) {
|
||||
setIcon(iconData.value, iconData.type);
|
||||
}
|
||||
}
|
||||
|
||||
onIconSelected: (iconName, iconType) => {
|
||||
SettingsData.setWorkspaceNameIcon(modelData, {
|
||||
"type": iconType,
|
||||
"value": iconName
|
||||
});
|
||||
setIcon(iconName, iconType);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onWorkspaceIconsUpdated() {
|
||||
var iconData = SettingsData.getWorkspaceNameIcon(modelData);
|
||||
if (iconData) {
|
||||
iconPicker.setIcon(iconData.value, iconData.type);
|
||||
} else {
|
||||
iconPicker.setIcon("", "icon");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 28
|
||||
height: 28
|
||||
radius: Theme.cornerRadius
|
||||
color: clearMouseArea.containsMouse ? Theme.errorHover : Theme.surfaceContainer
|
||||
border.width: 0
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
name: "close"
|
||||
size: 16
|
||||
color: clearMouseArea.containsMouse ? Theme.error : Theme.outline
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: clearMouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: SettingsData.removeWorkspaceNameIcon(modelData)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - 150 - 240 - 28 - Theme.spacingM * 4
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user