1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-31 00:42:50 -05:00

Completely redesign settings

This commit is contained in:
bbedward
2025-08-19 19:05:12 -04:00
parent c87b66fe35
commit c9adb8faa3
14 changed files with 3716 additions and 1714 deletions

View File

@@ -1,40 +1,61 @@
pragma ComponentBehavior
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Modules.Settings
import qs.Widgets
pragma ComponentBehavior
DankModal {
id: settingsModal
objectName: "settingsModal"
signal closingModal
property Component settingsContent
signal closingModal()
function show() {
open()
open();
}
function hide() {
close()
close();
}
function toggle() {
if (shouldBeVisible)
hide()
hide();
else
show()
show();
}
objectName: "settingsModal"
width: 750
height: 750
visible: false
onBackgroundClicked: hide()
content: settingsContent
property Component settingsContent: Component {
IpcHandler {
function open() {
settingsModal.show();
return "SETTINGS_OPEN_SUCCESS";
}
function close() {
settingsModal.hide();
return "SETTINGS_CLOSE_SUCCESS";
}
function toggle() {
settingsModal.toggle();
return "SETTINGS_TOGGLE_SUCCESS";
}
target: "settings"
}
settingsContent: Component {
Item {
anchors.fill: parent
focus: true
@@ -44,6 +65,7 @@ DankModal {
anchors.margins: Theme.spacingM
spacing: Theme.spacingS
// Header row with title and close button
Row {
width: parent.width
spacing: Theme.spacingM
@@ -64,7 +86,7 @@ DankModal {
}
Item {
width: parent.width - 175 // Spacer to push close button to the right
width: parent.width - 175
height: 1
}
@@ -76,126 +98,288 @@ DankModal {
hoverColor: Theme.errorHover
onClicked: settingsModal.hide()
}
}
Column {
// Main content with side navigation
Row {
width: parent.width
height: parent.height - 50
height: parent.height - 65
spacing: 0
DankTabBar {
id: settingsTabBar
// Left sidebar navigation
Rectangle {
id: sidebarContainer
width: parent.width
property int currentIndex: 0
width: 220
height: parent.height
color: Theme.surfaceContainer
radius: Theme.cornerRadius
Column {
anchors.fill: parent
anchors.leftMargin: Theme.spacingS
anchors.rightMargin: Theme.spacingS
anchors.bottomMargin: Theme.spacingS
anchors.topMargin: Theme.spacingM + 2
spacing: Theme.spacingXS
Repeater {
id: sidebarRepeater
model: [{
"text": "Personalization",
"icon": "person"
}, {
"text": "Time & Weather",
"text": "Time & Date",
"icon": "schedule"
}, {
"text": "Weather",
"icon": "cloud"
}, {
"text": "Top Bar",
"icon": "toolbar"
}, {
"text": "Widgets",
"icon": "widgets"
}, {
"text": "Launcher",
"icon": "apps"
"text": "Dock",
"icon": "dock_to_bottom"
}, {
"text": "Appearance",
"text": "Recent Apps",
"icon": "history"
}, {
"text": "Theme & Colors",
"icon": "palette"
}, {
"text": "System Themes",
"icon": "extension"
}, {
"text": "About",
"icon": "info"
}]
Rectangle {
property bool isActive: sidebarContainer.currentIndex === index
width: parent.width - Theme.spacingS * 2
height: 44
radius: Theme.cornerRadius
color: isActive ? Theme.primaryContainer : tabMouseArea.containsMouse ? Theme.surfaceHover : "transparent"
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: modelData.icon || ""
size: Theme.iconSize - 2
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: modelData.text || ""
font.pixelSize: Theme.fontSizeMedium
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
font.weight: parent.parent.isActive ? Font.Medium : Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: tabMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
sidebarContainer.currentIndex = index;
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
// Main content area
Item {
width: parent.width
height: parent.height - settingsTabBar.height
width: parent.width - sidebarContainer.width
height: parent.height
Rectangle {
anchors.fill: parent
anchors.margins: Theme.spacingL
anchors.leftMargin: Theme.spacingM
anchors.rightMargin: Theme.spacingM
anchors.bottomMargin: Theme.spacingM
anchors.topMargin: 0
color: "transparent"
Loader {
id: personalizationLoader
anchors.fill: parent
active: settingsTabBar.currentIndex === 0
active: sidebarContainer.currentIndex === 0
visible: active
asynchronous: true
sourceComponent: Component {
PersonalizationTab {
parentModal: settingsModal
}
}
}
Loader {
id: timeWeatherLoader
id: timeLoader
anchors.fill: parent
active: settingsTabBar.currentIndex === 1
active: sidebarContainer.currentIndex === 1
visible: active
asynchronous: true
sourceComponent: Component {
TimeWeatherTab {}
sourceComponent: TimeTab {}
}
Loader {
id: weatherLoader
anchors.fill: parent
active: sidebarContainer.currentIndex === 2
visible: active
asynchronous: true
sourceComponent: WeatherTab {}
}
Loader {
id: topBarLoader
anchors.fill: parent
active: sidebarContainer.currentIndex === 3
visible: active
asynchronous: true
sourceComponent: TopBarTab {}
}
Loader {
id: widgetsLoader
anchors.fill: parent
active: settingsTabBar.currentIndex === 2
active: sidebarContainer.currentIndex === 4
visible: active
asynchronous: true
sourceComponent: Component {
WidgetsTab {}
}
sourceComponent: WidgetTweaksTab {}
}
Loader {
id: launcherLoader
id: dockLoader
anchors.fill: parent
active: settingsTabBar.currentIndex === 3
active: sidebarContainer.currentIndex === 5
visible: active
asynchronous: true
sourceComponent: Component {
LauncherTab {}
DockTab {
}
}
}
Loader {
id: appearanceLoader
id: recentAppsLoader
anchors.fill: parent
active: settingsTabBar.currentIndex === 4
active: sidebarContainer.currentIndex === 6
visible: active
asynchronous: true
sourceComponent: Component {
AppearanceTab {}
}
}
}
}
}
}
}
sourceComponent: RecentAppsTab {}
}
content: settingsContent
Loader {
id: themeColorsLoader
IpcHandler {
function open() {
settingsModal.show()
return "SETTINGS_OPEN_SUCCESS"
anchors.fill: parent
active: sidebarContainer.currentIndex === 7
visible: active
asynchronous: true
sourceComponent: ThemeColorsTab {}
}
function close() {
settingsModal.hide()
return "SETTINGS_CLOSE_SUCCESS"
Loader {
id: systemThemesLoader
anchors.fill: parent
active: sidebarContainer.currentIndex === 8
visible: active
asynchronous: true
sourceComponent: SystemThemesTab {}
}
function toggle() {
settingsModal.toggle()
return "SETTINGS_TOGGLE_SUCCESS"
Loader {
id: aboutLoader
anchors.fill: parent
active: sidebarContainer.currentIndex === 9
visible: active
asynchronous: true
sourceComponent: AboutTab {}
}
target: "settings"
}
}
}
// Footer
StyledText {
id: footerText
width: parent.width
text: `DankMaterialShell - <a href="https://github.com/AvengeMedia/DankMaterialShell">github</a> - optimized for <a href="https://github.com/YaLTeR/niri">niri</a> - <a href="https://matrix.to/#/#niri:matrix.org">niri matrix</a> - <a href="https://discord.gg/vT8Sfjy7sx">niri discord</a>`
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
linkColor: Theme.primary
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
onLinkActivated: link => Qt.openUrlExternally(link)
MouseArea {
anchors.fill: parent
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.NoButton
propagateComposedEvents: true
}
}
}
}
}
}

View File

@@ -33,15 +33,7 @@ DankPopout {
}
popupWidth: 400
popupHeight: {
let baseHeight = Theme.spacingL * 2
baseHeight += 40 // notificationHeader height estimate
baseHeight += 0 // notificationSettings when collapsed
baseHeight += Theme.spacingM * 2
let listHeight = 200 // default list height
baseHeight += Math.min(listHeight, 600)
return Math.max(300, Math.min(baseHeight, Screen.height * 0.8))
}
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
triggerX: Screen.width - 400 - Theme.spacingL
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.spacingXS
triggerWidth: 40

View File

@@ -0,0 +1,374 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
Item {
id: aboutTab
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingXL
// ASCII Art Header
StyledRect {
width: parent.width
height: asciiSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: asciiSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Item {
width: parent.width
height: asciiText.implicitHeight
StyledText {
id: asciiText
text: "██████╗ █████╗ ███╗ ██╗██╗ ██╗\n██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝\n██║ ██║███████║██╔██╗ ██║█████╔╝ \n██║ ██║██╔══██║██║╚██╗██║██╔═██╗ \n██████╔╝██║ ██║██║ ╚████║██║ ██╗\n╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝"
isMonospace: true
font.pixelSize: Theme.fontSizeMedium
color: "#D0BCFF"
anchors.centerIn: parent
}
}
StyledText {
text: "DankMaterialShell"
font.pixelSize: Theme.fontSizeXLarge
font.weight: Font.Bold
color: Theme.surfaceText
horizontalAlignment: Text.AlignHCenter
width: parent.width
}
StyledText {
text: "A desktop shell built with <a href=\"https://quickshell.org\">Quickshell</a>"
font.pixelSize: Theme.fontSizeMedium
linkColor: Theme.primary
onLinkActivated: (url) => Qt.openUrlExternally(url)
color: Theme.surfaceVariantText
horizontalAlignment: Text.AlignHCenter
width: parent.width
wrapMode: Text.WordWrap
}
}
}
// Project Information
StyledRect {
width: parent.width
height: projectSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: projectSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "info"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "About"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
text: `DankMaterialShell is a modern desktop inspired by <a href="https://m3.material.io/">MUI 3</a>.
<br /><br/>The goal is to provide a high level of functionality and customization so that it can be a suitable replacement for complete desktop environments like Gnome, KDE, or Cosmic.
`
font.pixelSize: Theme.fontSizeMedium
linkColor: Theme.primary
onLinkActivated: (url) => Qt.openUrlExternally(url)
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
}
}
// Technical Details
StyledRect {
width: parent.width
height: techSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
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: "Technical Details"
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: "Framework:"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Quickshell"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
}
StyledText {
text: "Language:"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "QML (Qt Modeling Language)"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
}
StyledText {
text: "Compositor:"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Niri (Hyprland Coming Soon™)"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
}
StyledText {
text: "Github:"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "<a href=\"https://github.com/AvengeMedia/DankMaterialShell\">DankMaterialShell</a> - Support Us With a Star ⭐"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
linkColor: Theme.primary
onLinkActivated: (url) => Qt.openUrlExternally(url)
}
StyledText {
text: "System Monitoring:"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "<a href=\"https://github.com/AvengeMedia/dgop\">dgop</a> - Dank Stateless System Monitoring"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
linkColor: Theme.primary
onLinkActivated: (url) => Qt.openUrlExternally(url)
}
}
}
}
// Features
StyledRect {
width: parent.width
height: featuresSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: featuresSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "star"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Features"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "• Fully Customizable TopBar - 10+ Widgets"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
StyledText {
text: "• App Launcher - With Auto-Sorting"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
StyledText {
text: "• Numerous <a href=\"https://github.com/AvengeMedia/DankMaterialShell/blob/master/docs/IPC.md\">IPCs</a> for external control"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
linkColor: Theme.primary
onLinkActivated: (url) => Qt.openUrlExternally(url)
width: parent.width
wrapMode: Text.WordWrap
}
StyledText {
text: "• A Dock"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
StyledText {
text: "• Auto Theming with <a href=\"https://github.com/InioX/matugen\">matugen</a>"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
linkColor: Theme.primary
onLinkActivated: (url) => Qt.openUrlExternally(url)
width: parent.width
wrapMode: Text.WordWrap
}
StyledText {
text: "• Notifications with Auto-Grouping"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
StyledText {
text: "• Process Monitor"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
StyledText {
text: "• A Custom Lock Screen"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
StyledText {
text: "• (and more)"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: parent.width
wrapMode: Text.WordWrap
}
}
}
}
}
}
}

View File

@@ -0,0 +1,232 @@
import QtQuick
import QtQuick.Controls
import Quickshell.Widgets
import qs.Common
import qs.Widgets
Item {
id: dockTab
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingXL
// Enable Dock
StyledRect {
width: parent.width
height: enableDockSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: enableDockSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "dock_to_bottom"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - enableToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Show Dock"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Display a dock at the bottom of the screen with pinned and running applications"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: enableToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.showDock
onToggled: checked => {
SettingsData.setShowDock(checked)
}
}
}
}
}
// Auto-hide Dock
StyledRect {
width: parent.width
height: autoHideSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
visible: SettingsData.showDock
opacity: visible ? 1 : 0
Column {
id: autoHideSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "visibility_off"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - autoHideToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Auto-hide Dock"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Hide the dock when not in use and reveal it when hovering near the bottom of the screen"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: autoHideToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.dockAutoHide
onToggled: checked => {
SettingsData.setDockAutoHide(checked)
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
// Dock Transparency Section
StyledRect {
width: parent.width
height: transparencySection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
visible: SettingsData.showDock
opacity: visible ? 1 : 0
Column {
id: transparencySection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "opacity"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Dock Transparency"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankSlider {
width: parent.width
height: 32
value: Math.round(SettingsData.dockTransparency * 100)
minimum: 0
maximum: 100
unit: "%"
showValue: true
onSliderValueChanged: newValue => {
SettingsData.setDockTransparency(
newValue / 100)
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
}

View File

@@ -22,7 +22,6 @@ Item {
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
anchors.bottomMargin: Theme.spacingXL
clip: true
contentHeight: mainColumn.height
contentWidth: width
@@ -492,7 +491,11 @@ Item {
}
// Wallpaper Cycling Section
}
}
// Wallpaper Cycling Section - Full Width
Rectangle {
width: parent.width
height: 1
@@ -533,8 +536,6 @@ Item {
text: "Automatically cycle through wallpapers in the same folder"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
elide: Text.ElideRight
maximumLineCount: 1
width: parent.width
}
@@ -727,7 +728,6 @@ Item {
if (isValid)
SessionData.setWallpaperCyclingTime(text);
else
// Reset to current value if invalid
text = SessionData.wallpaperCyclingTime;
}
onEditingFinished: {
@@ -735,7 +735,6 @@ Item {
if (isValid)
SessionData.setWallpaperCyclingTime(text);
else
// Reset to current value if invalid
text = SessionData.wallpaperCyclingTime;
}
anchors.verticalCenter: parent.verticalCenter
@@ -763,10 +762,6 @@ Item {
}
}
}
// Dynamic Theme Section
StyledRect {
width: parent.width
@@ -846,71 +841,6 @@ Item {
}
// TopBar Auto-hide Section
StyledRect {
width: parent.width
height: topBarAutoHideSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: topBarAutoHideSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "visibility_off"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - autoHideToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "TopBar Auto-hide"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Automatically hide the top bar to expand screen real estate"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: autoHideToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.topBarAutoHide
onToggled: (toggled) => {
return SettingsData.setTopBarAutoHide(toggled);
}
}
}
}
}
}
}
@@ -929,7 +859,9 @@ Item {
onDialogClosed: {
if (parentModal) {
parentModal.allowFocusOverride = false;
parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible);
parentModal.shouldHaveFocus = Qt.binding(() => {
return parentModal.shouldBeVisible;
});
}
}
}
@@ -948,7 +880,9 @@ Item {
onDialogClosed: {
if (parentModal) {
parentModal.allowFocusOverride = false;
parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible);
parentModal.shouldHaveFocus = Qt.binding(() => {
return parentModal.shouldBeVisible;
});
}
}
}

View File

@@ -5,12 +5,11 @@ import qs.Common
import qs.Widgets
Item {
id: launcherTab
id: recentAppsTab
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
anchors.bottomMargin: Theme.spacingXL
clip: true
contentHeight: mainColumn.height
contentWidth: width
@@ -20,236 +19,6 @@ Item {
width: parent.width
spacing: Theme.spacingXL
StyledRect {
width: parent.width
height: appLauncherSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: appLauncherSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
DankToggle {
width: parent.width
text: "Use OS Logo"
description: "Display operating system logo instead of apps icon"
checked: SettingsData.useOSLogo
onToggled: checked => {
return SettingsData.setUseOSLogo(checked)
}
}
Row {
width: parent.width - Theme.spacingL
spacing: Theme.spacingL
visible: SettingsData.useOSLogo
opacity: visible ? 1 : 0
anchors.left: parent.left
anchors.leftMargin: Theme.spacingL
Column {
width: 120
spacing: Theme.spacingS
StyledText {
text: "Color Override"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
width: 100
height: 28
placeholderText: "#ffffff"
text: SettingsData.osLogoColorOverride
maximumLength: 7
font.pixelSize: Theme.fontSizeSmall
topPadding: Theme.spacingXS
bottomPadding: Theme.spacingXS
onEditingFinished: {
var color = text.trim()
if (color === "" || /^#[0-9A-Fa-f]{6}$/.test(color))
SettingsData.setOSLogoColorOverride(color)
else
text = SettingsData.osLogoColorOverride
}
}
}
Column {
width: 120
spacing: Theme.spacingS
StyledText {
text: "Brightness"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: 100
height: 20
minimum: 0
maximum: 100
value: Math.round(SettingsData.osLogoBrightness * 100)
unit: "%"
showValue: true
onSliderValueChanged: newValue => {
SettingsData.setOSLogoBrightness(
newValue / 100)
}
}
}
Column {
width: 120
spacing: Theme.spacingS
StyledText {
text: "Contrast"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: 100
height: 20
minimum: 0
maximum: 200
value: Math.round(SettingsData.osLogoContrast * 100)
unit: "%"
showValue: true
onSliderValueChanged: newValue => {
SettingsData.setOSLogoContrast(
newValue / 100)
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
StyledRect {
width: parent.width
height: dockSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: dockSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "dock_to_bottom"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Dock"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Show Dock"
description: "Display a dock at the bottom of the screen with pinned and running applications"
checked: SettingsData.showDock
onToggled: checked => {
SettingsData.setShowDock(checked)
}
}
DankToggle {
width: parent.width
text: "Auto-hide Dock"
description: "Hide the dock when not in use and reveal it when hovering near the bottom of the screen"
checked: SettingsData.dockAutoHide
visible: SettingsData.showDock
opacity: visible ? 1 : 0
onToggled: checked => {
SettingsData.setDockAutoHide(checked)
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
visible: SettingsData.showDock
opacity: visible ? 1 : 0
StyledText {
text: "Dock Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: Math.round(SettingsData.dockTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
onSliderValueChanged: newValue => {
SettingsData.setDockTransparency(
newValue / 100)
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
StyledRect {
width: parent.width
height: recentlyUsedSection.implicitHeight + Theme.spacingL * 2
@@ -468,5 +237,4 @@ Item {
}
}
}
}

View File

@@ -0,0 +1,181 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
Item {
id: systemThemesTab
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingXL
// System Configuration Warning
Rectangle {
width: parent.width
height: warningText.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12)
border.color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3)
border.width: 1
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: warningText
text: "Changing these settings will manipulate GTK and Qt configurations on the system"
font.pixelSize: Theme.fontSizeSmall
color: Theme.warning
wrapMode: Text.WordWrap
width: parent.width - Theme.iconSizeSmall - Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
}
}
}
// Icon Theme
StyledRect {
width: parent.width
height: iconThemeSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: iconThemeSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingXS
DankIcon {
name: "image"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
DankDropdown {
width: parent.width - Theme.iconSize - Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
text: "Icon Theme"
description: "DankShell & System Icons"
currentValue: SettingsData.iconTheme
enableFuzzySearch: true
popupWidthOffset: 100
maxPopupHeight: 400
options: {
SettingsData.detectAvailableIconThemes();
return SettingsData.availableIconThemes;
}
onValueChanged: (value) => {
SettingsData.setIconTheme(value);
if (value !== "System Default" && !SettingsData.qt5ctAvailable && !SettingsData.qt6ctAvailable)
ToastService.showWarning("qt5ct or qt6ct not found - Qt app themes may not update without these tools");
}
}
}
}
}
// System App Theming
StyledRect {
width: parent.width
height: systemThemingSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
visible: Theme.isDynamicTheme && Colors.matugenAvailable
Column {
id: systemThemingSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "extension"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "System App Theming"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Theme GTK Applications"
description: Colors.gtkThemingEnabled ? "File managers, text editors, and system dialogs will match your theme" : "GTK theming not available (install gsettings)"
enabled: Colors.gtkThemingEnabled
checked: Colors.gtkThemingEnabled && SettingsData.gtkThemingEnabled
onToggled: function(checked) {
SettingsData.setGtkThemingEnabled(checked);
}
}
DankToggle {
width: parent.width
text: "Theme Qt Applications"
description: Colors.qtThemingEnabled ? "Qt applications will match your theme colors" : "Qt theming not available (install qt5ct or qt6ct)"
enabled: Colors.qtThemingEnabled
checked: Colors.qtThemingEnabled && SettingsData.qtThemingEnabled
onToggled: function(checked) {
SettingsData.setQtThemingEnabled(checked);
}
}
}
}
}
}
}

View File

@@ -1,30 +1,18 @@
import QtQuick
import QtQuick.Controls
import Quickshell.Io
import qs.Common
import qs.Services
import qs.Widgets
Item {
id: appearanceTab
id: themeColorsTab
property var cachedFontFamilies: []
property var cachedMonoFamilies: []
property bool fontsEnumerated: false
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
anchors.bottomMargin: Theme.spacingXL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
function enumerateFonts() {
var fonts = ["Default (" + SettingsData.defaultFontFamily + ")"];
var fonts = ["Default"];
var availableFonts = Qt.fontFamilies();
var rootFamilies = [];
var seenFamilies = new Set();
@@ -68,8 +56,6 @@ Item {
cachedMonoFamilies = monoFonts.concat(monoFamilies.sort());
}
width: parent.width
spacing: Theme.spacingXL
Component.onCompleted: {
if (!fontsEnumerated) {
enumerateFonts();
@@ -77,499 +63,19 @@ Item {
}
}
// Display Settings
StyledRect {
width: parent.width
height: displaySection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: displaySection
DankFlickable {
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "monitor"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Display Settings"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: nightModeToggle
width: parent.width
text: "Night Mode"
description: "Apply warm color temperature to reduce eye strain"
checked: BrightnessService.nightModeActive
onToggled: (checked) => {
if (checked !== BrightnessService.nightModeActive) {
if (checked)
BrightnessService.enableNightMode();
else
BrightnessService.disableNightMode();
}
}
Connections {
function onNightModeActiveChanged() {
nightModeToggle.checked = BrightnessService.nightModeActive;
}
target: BrightnessService
}
}
DankDropdown {
width: parent.width
text: "Night Mode Temperature"
description: BrightnessService.nightModeActive ? "Disable night mode to adjust" : "Set temperature for night mode"
enabled: !BrightnessService.nightModeActive
opacity: !BrightnessService.nightModeActive ? 1 : 0.6
currentValue: SessionData.nightModeTemperature + "K"
options: {
var temps = [];
for (var i = 2500; i <= 6000; i += 500) {
temps.push(i + "K");
}
return temps;
}
onValueChanged: (value) => {
var temp = parseInt(value.replace("K", ""));
SessionData.setNightModeTemperature(temp);
}
}
DankToggle {
width: parent.width
text: "Light Mode"
description: "Use light theme instead of dark theme"
checked: SessionData.isLightMode
onToggled: (checked) => {
SessionData.setLightMode(checked);
Theme.isLightMode = checked;
PortalService.setLightMode(checked);
}
}
DankDropdown {
width: parent.width
text: "Icon Theme"
description: "Select icon theme"
currentValue: SettingsData.iconTheme
enableFuzzySearch: true
popupWidthOffset: 100
maxPopupHeight: 400
options: {
SettingsData.detectAvailableIconThemes();
return SettingsData.availableIconThemes;
}
onValueChanged: (value) => {
SettingsData.setIconTheme(value);
if (value !== "System Default" && !SettingsData.qt5ctAvailable && !SettingsData.qt6ctAvailable)
ToastService.showWarning("qt5ct or qt6ct not found - Qt app themes may not update without these tools");
}
}
DankDropdown {
width: parent.width
text: "Font Family"
description: "Select system font family"
currentValue: {
if (SettingsData.fontFamily === SettingsData.defaultFontFamily)
return "Default (" + SettingsData.defaultFontFamily + ")";
else
return SettingsData.fontFamily || "Default (" + SettingsData.defaultFontFamily + ")";
}
enableFuzzySearch: true
popupWidthOffset: 100
maxPopupHeight: 400
options: cachedFontFamilies
onValueChanged: (value) => {
if (value.startsWith("Default ("))
SettingsData.setFontFamily(SettingsData.defaultFontFamily);
else
SettingsData.setFontFamily(value);
}
}
DankDropdown {
width: parent.width
text: "Font Weight"
description: "Select font weight"
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";
}
}
options: ["Thin", "Extra Light", "Light", "Regular", "Medium", "Demi Bold", "Bold", "Extra Bold", "Black"]
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.setFontWeight(weight);
}
}
DankDropdown {
width: parent.width
text: "Monospace Font"
description: "Select monospace font for process list and technical displays"
currentValue: {
if (SettingsData.monoFontFamily === SettingsData.defaultMonoFontFamily)
return "Default";
return SettingsData.monoFontFamily || "Default";
}
enableFuzzySearch: true
popupWidthOffset: 100
maxPopupHeight: 400
options: cachedMonoFamilies
onValueChanged: (value) => {
if (value === "Default")
SettingsData.setMonoFontFamily(SettingsData.defaultMonoFontFamily);
else
SettingsData.setMonoFontFamily(value);
}
}
}
}
// Transparency Settings
StyledRect {
width: parent.width
height: transparencySection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
anchors.topMargin: Theme.spacingL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: transparencySection
id: mainColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
spacing: Theme.spacingXL
DankIcon {
name: "opacity"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Transparency Settings"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Top Bar Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: Math.round(SettingsData.topBarTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setTopBarTransparency(newValue / 100);
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Top Bar Widget Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: Math.round(SettingsData.topBarWidgetTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setTopBarWidgetTransparency(newValue / 100);
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Popup Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: Math.round(SettingsData.popupTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setPopupTransparency(newValue / 100);
}
}
}
}
}
// Corner Radius
StyledRect {
width: parent.width
height: cornerRadiusSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: cornerRadiusSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "rounded_corner"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Corner Radius"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Bar & Widget Corner Roundness"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: SettingsData.cornerRadius
minimum: 0
maximum: 32
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setCornerRadius(newValue);
}
}
}
}
}
// Top Bar Spacing
StyledRect {
width: parent.width
height: topBarSpacingSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: topBarSpacingSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "space_bar"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Top Bar Spacing"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Gap Around Top Bar (0 = edge-to-edge)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: SettingsData.topBarSpacing
minimum: 0
maximum: 32
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setTopBarSpacing(newValue);
}
}
}
DankToggle {
width: parent.width
text: "Square Corners"
description: "Disable corner radius for the top bar (always square corners)"
checked: SettingsData.topBarSquareCorners
onToggled: (checked) => {
SettingsData.setTopBarSquareCorners(checked);
}
}
}
}
// Theme Color
StyledRect {
width: parent.width
@@ -939,18 +445,17 @@ Item {
}
// System App Theming
// Transparency Settings
StyledRect {
width: parent.width
height: systemThemingSection.implicitHeight + Theme.spacingL * 2
height: transparencySection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
visible: Theme.isDynamicTheme && Colors.matugenAvailable
Column {
id: systemThemingSection
id: transparencySection
anchors.fill: parent
anchors.margins: Theme.spacingL
@@ -961,14 +466,133 @@ Item {
spacing: Theme.spacingM
DankIcon {
name: "extension"
name: "opacity"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "System App Theming"
text: "Transparency Settings"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Top Bar Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: Math.round(SettingsData.topBarTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setTopBarTransparency(newValue / 100);
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Top Bar Widget Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: Math.round(SettingsData.topBarWidgetTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setTopBarWidgetTransparency(newValue / 100);
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Popup Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: Math.round(SettingsData.popupTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setPopupTransparency(newValue / 100);
}
}
}
}
}
// Display Settings
StyledRect {
width: parent.width
height: displaySection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: displaySection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "monitor"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Display Settings"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
@@ -978,24 +602,212 @@ Item {
}
DankToggle {
id: nightModeToggle
width: parent.width
text: "Theme GTK Applications"
description: Colors.gtkThemingEnabled ? "File managers, text editors, and system dialogs will match your theme" : "GTK theming not available (install gsettings)"
enabled: Colors.gtkThemingEnabled
checked: Colors.gtkThemingEnabled && SettingsData.gtkThemingEnabled
onToggled: function(checked) {
SettingsData.setGtkThemingEnabled(checked);
text: "Night Mode"
description: "Apply warm color temperature to reduce eye strain"
checked: BrightnessService.nightModeActive
onToggled: (checked) => {
if (checked !== BrightnessService.nightModeActive) {
if (checked)
BrightnessService.enableNightMode();
else
BrightnessService.disableNightMode();
}
}
Connections {
function onNightModeActiveChanged() {
nightModeToggle.checked = BrightnessService.nightModeActive;
}
target: BrightnessService
}
}
DankDropdown {
width: parent.width
text: "Night Mode Temperature"
description: BrightnessService.nightModeActive ? "Disable night mode to adjust" : "Set temperature for night mode"
enabled: !BrightnessService.nightModeActive
opacity: !BrightnessService.nightModeActive ? 1 : 0.6
currentValue: SessionData.nightModeTemperature + "K"
options: {
var temps = [];
for (var i = 2500; i <= 6000; i += 500) {
temps.push(i + "K");
}
return temps;
}
onValueChanged: (value) => {
var temp = parseInt(value.replace("K", ""));
SessionData.setNightModeTemperature(temp);
}
}
DankToggle {
width: parent.width
text: "Theme Qt Applications"
description: Colors.qtThemingEnabled ? "Qt applications will match your theme colors" : "Qt theming not available (install qt5ct or qt6ct)"
enabled: Colors.qtThemingEnabled
checked: Colors.qtThemingEnabled && SettingsData.qtThemingEnabled
onToggled: function(checked) {
SettingsData.setQtThemingEnabled(checked);
text: "Light Mode"
description: "Use light theme instead of dark theme"
checked: SessionData.isLightMode
onToggled: (checked) => {
SessionData.setLightMode(checked);
Theme.isLightMode = checked;
PortalService.setLightMode(checked);
}
}
}
}
// Font Settings
StyledRect {
width: parent.width
height: fontSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: fontSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "font_download"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Font Settings"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankDropdown {
width: parent.width
text: "Font Family"
description: "Select system font family"
currentValue: {
if (SettingsData.fontFamily === SettingsData.defaultFontFamily)
return "Default";
else
return SettingsData.fontFamily || "Default";
}
enableFuzzySearch: true
popupWidthOffset: 100
maxPopupHeight: 400
options: cachedFontFamilies
onValueChanged: (value) => {
if (value.startsWith("Default"))
SettingsData.setFontFamily(SettingsData.defaultFontFamily);
else
SettingsData.setFontFamily(value);
}
}
DankDropdown {
width: parent.width
text: "Font Weight"
description: "Select font weight"
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";
}
}
options: ["Thin", "Extra Light", "Light", "Regular", "Medium", "Demi Bold", "Bold", "Extra Bold", "Black"]
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.setFontWeight(weight);
}
}
DankDropdown {
width: parent.width
text: "Monospace Font"
description: "Select monospace font for process list and technical displays"
currentValue: {
if (SettingsData.monoFontFamily === SettingsData.defaultMonoFontFamily)
return "Default";
return SettingsData.monoFontFamily || "Default";
}
enableFuzzySearch: true
popupWidthOffset: 100
maxPopupHeight: 400
options: cachedMonoFamilies
onValueChanged: (value) => {
if (value === "Default")
SettingsData.setMonoFontFamily(SettingsData.defaultMonoFontFamily);
else
SettingsData.setMonoFontFamily(value);
}
}

View File

@@ -0,0 +1,380 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
Item {
id: timeTab
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingXL
// Time Format
StyledRect {
width: parent.width
height: timeSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: timeSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "schedule"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - toggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "24-Hour Format"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Use 24-hour time format instead of 12-hour AM/PM"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: toggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.use24HourClock
onToggled: (checked) => {
return SettingsData.setClockFormat(checked);
}
}
}
}
}
// Date Format Section
StyledRect {
width: parent.width
height: dateSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: dateSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "calendar_today"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Date Format"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankDropdown {
width: parent.width
height: 50
text: "Top Bar Format"
description: "Preview: " + Qt.formatDate(new Date(), SettingsData.clockDateFormat)
currentValue: {
// Find matching preset or show "Custom"
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}];
const match = presets.find((p) => {
return p.format === SettingsData.clockDateFormat;
});
return match ? match.label : "Custom: " + SettingsData.clockDateFormat;
}
options: ["Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: (value) => {
const formatMap = {
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
};
if (value === "Custom...") {
customFormatInput.visible = true;
} else {
customFormatInput.visible = false;
SettingsData.setClockDateFormat(formatMap[value]);
}
}
}
DankDropdown {
width: parent.width
height: 50
text: "Lock Screen Format"
description: "Preview: " + Qt.formatDate(new Date(), SettingsData.lockDateFormat)
currentValue: {
// Find matching preset or show "Custom"
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}];
const match = presets.find((p) => {
return p.format === SettingsData.lockDateFormat;
});
return match ? match.label : "Custom: " + SettingsData.lockDateFormat;
}
options: ["Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: (value) => {
const formatMap = {
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
};
if (value === "Custom...") {
customLockFormatInput.visible = true;
} else {
customLockFormatInput.visible = false;
SettingsData.setLockDateFormat(formatMap[value]);
}
}
}
DankTextField {
id: customFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom top bar format (e.g., ddd MMM d)"
text: SettingsData.clockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setClockDateFormat(text);
}
}
DankTextField {
id: customLockFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom lock screen format (e.g., dddd, MMMM d)"
text: SettingsData.lockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setLockDateFormat(text);
}
}
Rectangle {
width: parent.width
height: formatHelp.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
border.width: 1
Column {
id: formatHelp
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingXS
StyledText {
text: "Format Legend"
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
font.weight: Font.Medium
}
Row {
width: parent.width
spacing: Theme.spacingL
Column {
width: (parent.width - Theme.spacingL) / 2
spacing: 2
StyledText {
text: "• d - Day (1-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dd - Day (01-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• ddd - Day name (Mon)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dddd - Day name (Monday)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• M - Month (1-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Column {
width: (parent.width - Theme.spacingL) / 2
spacing: 2
StyledText {
text: "• MM - Month (01-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMM - Month (Jan)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMMM - Month (January)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• yy - Year (24)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• yyyy - Year (2024)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
}
}
}
}
}
}
}

View File

@@ -1,422 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
Item {
id: timeWeatherTab
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
anchors.bottomMargin: Theme.spacingXL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingXL
// Time Format
StyledRect {
width: parent.width
height: timeSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: timeSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "schedule"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Time Format"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "24-Hour Format"
description: "Use 24-hour time format instead of 12-hour AM/PM"
checked: SettingsData.use24HourClock
onToggled: (checked) => {
return SettingsData.setClockFormat(checked);
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Date Format"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
DankDropdown {
width: parent.width
height: 50
text: "Top Bar Format"
description: "Preview: " + Qt.formatDate(new Date(), SettingsData.clockDateFormat)
currentValue: {
// Find matching preset or show "Custom"
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}];
const match = presets.find((p) => {
return p.format === SettingsData.clockDateFormat;
});
return match ? match.label : "Custom: " + SettingsData.clockDateFormat;
}
options: ["Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: (value) => {
const formatMap = {
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
};
if (value === "Custom...") {
customFormatInput.visible = true;
} else {
customFormatInput.visible = false;
SettingsData.setClockDateFormat(formatMap[value]);
}
}
}
DankDropdown {
width: parent.width
height: 50
text: "Lock Screen Format"
description: "Preview: " + Qt.formatDate(new Date(), SettingsData.lockDateFormat)
currentValue: {
// Find matching preset or show "Custom"
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}];
const match = presets.find((p) => {
return p.format === SettingsData.lockDateFormat;
});
return match ? match.label : "Custom: " + SettingsData.lockDateFormat;
}
options: ["Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: (value) => {
const formatMap = {
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
};
if (value === "Custom...") {
customLockFormatInput.visible = true;
} else {
customLockFormatInput.visible = false;
SettingsData.setLockDateFormat(formatMap[value]);
}
}
}
DankTextField {
id: customFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom top bar format (e.g., ddd MMM d)"
text: SettingsData.clockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setClockDateFormat(text);
}
}
DankTextField {
id: customLockFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom lock screen format (e.g., dddd, MMMM d)"
text: SettingsData.lockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setLockDateFormat(text);
}
}
Rectangle {
width: parent.width
height: formatHelp.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
border.width: 1
Column {
id: formatHelp
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingXS
StyledText {
text: "Format Legend"
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
font.weight: Font.Medium
}
Row {
spacing: Theme.spacingL
Column {
spacing: 2
StyledText {
text: "• d - Day (1-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dd - Day (01-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• ddd - Day name (Mon)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dddd - Day name (Monday)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Column {
spacing: 2
StyledText {
text: "• M - Month (1-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MM - Month (01-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMM - Month (Jan)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMMM - Month (January)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Column {
spacing: 2
StyledText {
text: "• yy - Year (24)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• yyyy - Year (2024)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
}
}
}
}
}
// Weather
StyledRect {
width: parent.width
height: weatherSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: weatherSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "cloud"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Weather"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Enable Weather"
description: "Show weather information in top bar and centcom center"
checked: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setWeatherEnabled(checked);
}
}
DankToggle {
width: parent.width
text: "Fahrenheit"
description: "Use Fahrenheit instead of Celsius for temperature"
checked: SettingsData.useFahrenheit
enabled: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setTemperatureUnit(checked);
}
}
DankToggle {
width: parent.width
text: "Auto Location"
description: "Allow wttr.in to determine location based on IP address"
checked: SettingsData.useAutoLocation
enabled: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setAutoLocation(checked);
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
visible: !SettingsData.useAutoLocation && SettingsData.weatherEnabled
StyledText {
text: "Location"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
DankLocationSearch {
width: parent.width
currentLocation: SettingsData.weatherLocation
placeholderText: "New York, NY"
onLocationSelected: (displayName, coordinates) => {
SettingsData.setWeatherLocation(displayName, coordinates);
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,922 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
Item {
id: topBarTab
property var baseWidgetDefinitions: [{
"id": "launcherButton",
"text": "App Launcher",
"description": "Quick access to application launcher",
"icon": "apps",
"enabled": true
}, {
"id": "workspaceSwitcher",
"text": "Workspace Switcher",
"description": "Shows current workspace and allows switching",
"icon": "view_module",
"enabled": true
}, {
"id": "focusedWindow",
"text": "Focused Window",
"description": "Display currently focused application title",
"icon": "window",
"enabled": true
}, {
"id": "runningApps",
"text": "Running Apps",
"description": "Shows all running applications with focus indication",
"icon": "apps",
"enabled": true
}, {
"id": "clock",
"text": "Clock",
"description": "Current time and date display",
"icon": "schedule",
"enabled": true
}, {
"id": "weather",
"text": "Weather Widget",
"description": "Current weather conditions and temperature",
"icon": "wb_sunny",
"enabled": true
}, {
"id": "music",
"text": "Media Controls",
"description": "Control currently playing media",
"icon": "music_note",
"enabled": true
}, {
"id": "clipboard",
"text": "Clipboard Manager",
"description": "Access clipboard history",
"icon": "content_paste",
"enabled": true
}, {
"id": "cpuUsage",
"text": "CPU Usage",
"description": "CPU usage indicator",
"icon": "memory",
"enabled": DgopService.dgopAvailable,
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined
}, {
"id": "memUsage",
"text": "Memory Usage",
"description": "Memory usage indicator",
"icon": "storage",
"enabled": DgopService.dgopAvailable,
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined
}, {
"id": "cpuTemp",
"text": "CPU Temperature",
"description": "CPU temperature display",
"icon": "device_thermostat",
"enabled": DgopService.dgopAvailable,
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined
}, {
"id": "gpuTemp",
"text": "GPU Temperature",
"description": "GPU temperature display",
"icon": "auto_awesome_mosaic",
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.",
"enabled": DgopService.dgopAvailable
}, {
"id": "systemTray",
"text": "System Tray",
"description": "System notification area icons",
"icon": "notifications",
"enabled": true
}, {
"id": "privacyIndicator",
"text": "Privacy Indicator",
"description": "Shows when microphone, camera, or screen sharing is active",
"icon": "privacy_tip",
"enabled": true
}, {
"id": "controlCenterButton",
"text": "Control Center",
"description": "Access to system controls and settings",
"icon": "settings",
"enabled": true
}, {
"id": "notificationButton",
"text": "Notification Center",
"description": "Access to notifications and do not disturb",
"icon": "notifications",
"enabled": true
}, {
"id": "battery",
"text": "Battery",
"description": "Battery level and power management",
"icon": "battery_std",
"enabled": true
}, {
"id": "idleInhibitor",
"text": "Idle Inhibitor",
"description": "Prevent screen timeout",
"icon": "motion_sensor_active",
"enabled": true
}, {
"id": "spacer",
"text": "Spacer",
"description": "Customizable empty space",
"icon": "more_horiz",
"enabled": true
}, {
"id": "separator",
"text": "Separator",
"description": "Visual divider between widgets",
"icon": "remove",
"enabled": true
}]
property var defaultLeftWidgets: [{
"id": "launcherButton",
"enabled": true
}, {
"id": "workspaceSwitcher",
"enabled": true
}, {
"id": "focusedWindow",
"enabled": true
}]
property var defaultCenterWidgets: [{
"id": "music",
"enabled": true
}, {
"id": "clock",
"enabled": true
}, {
"id": "weather",
"enabled": true
}]
property var defaultRightWidgets: [{
"id": "privacyIndicator",
"enabled": true
}, {
"id": "systemTray",
"enabled": true
}, {
"id": "clipboard",
"enabled": true
}, {
"id": "notificationButton",
"enabled": true
}, {
"id": "battery",
"enabled": true
}, {
"id": "controlCenterButton",
"enabled": true
}]
function addWidgetToSection(widgetId, targetSection) {
var widgetObj = {
"id": widgetId,
"enabled": true
}
if (widgetId === "spacer")
widgetObj.size = 20
if (widgetId === "gpuTemp") {
widgetObj.selectedGpuIndex = 0
widgetObj.pciId = ""
}
var widgets = []
if (targetSection === "left") {
widgets = SettingsData.topBarLeftWidgets.slice()
widgets.push(widgetObj)
SettingsData.setTopBarLeftWidgets(widgets)
} else if (targetSection === "center") {
widgets = SettingsData.topBarCenterWidgets.slice()
widgets.push(widgetObj)
SettingsData.setTopBarCenterWidgets(widgets)
} else if (targetSection === "right") {
widgets = SettingsData.topBarRightWidgets.slice()
widgets.push(widgetObj)
SettingsData.setTopBarRightWidgets(widgets)
}
}
function removeWidgetFromSection(sectionId, widgetIndex) {
var widgets = []
if (sectionId === "left") {
widgets = SettingsData.topBarLeftWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets.splice(widgetIndex, 1)
}
SettingsData.setTopBarLeftWidgets(widgets)
} else if (sectionId === "center") {
widgets = SettingsData.topBarCenterWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets.splice(widgetIndex, 1)
}
SettingsData.setTopBarCenterWidgets(widgets)
} else if (sectionId === "right") {
widgets = SettingsData.topBarRightWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets.splice(widgetIndex, 1)
}
SettingsData.setTopBarRightWidgets(widgets)
}
}
function handleItemEnabledChanged(sectionId, itemId, enabled) {
var widgets = []
if (sectionId === "left")
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.topBarRightWidgets.slice()
for (var i = 0; i < widgets.length; i++) {
var widget = widgets[i]
var widgetId = typeof widget === "string" ? widget : widget.id
if (widgetId === itemId) {
if (typeof widget === "string") {
widgets[i] = {
"id": widget,
"enabled": enabled
}
} else {
var newWidget = {
"id": widget.id,
"enabled": enabled
}
if (widget.size !== undefined) newWidget.size = widget.size
if (widget.selectedGpuIndex !== undefined) newWidget.selectedGpuIndex = widget.selectedGpuIndex
else if (widget.id === "gpuTemp") newWidget.selectedGpuIndex = 0
if (widget.pciId !== undefined) newWidget.pciId = widget.pciId
else if (widget.id === "gpuTemp") newWidget.pciId = ""
widgets[i] = newWidget
}
break
}
}
if (sectionId === "left")
SettingsData.setTopBarLeftWidgets(widgets)
else if (sectionId === "center")
SettingsData.setTopBarCenterWidgets(widgets)
else if (sectionId === "right")
SettingsData.setTopBarRightWidgets(widgets)
}
function handleItemOrderChanged(sectionId, newOrder) {
if (sectionId === "left")
SettingsData.setTopBarLeftWidgets(newOrder)
else if (sectionId === "center")
SettingsData.setTopBarCenterWidgets(newOrder)
else if (sectionId === "right")
SettingsData.setTopBarRightWidgets(newOrder)
}
function handleSpacerSizeChanged(sectionId, itemId, newSize) {
var widgets = []
if (sectionId === "left")
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.topBarRightWidgets.slice()
for (var i = 0; i < widgets.length; i++) {
var widget = widgets[i]
var widgetId = typeof widget === "string" ? widget : widget.id
if (widgetId === itemId && widgetId === "spacer") {
if (typeof widget === "string") {
widgets[i] = {
"id": widget,
"enabled": true,
"size": newSize
}
} else {
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"size": newSize
}
if (widget.selectedGpuIndex !== undefined) newWidget.selectedGpuIndex = widget.selectedGpuIndex
if (widget.pciId !== undefined) newWidget.pciId = widget.pciId
widgets[i] = newWidget
}
break
}
}
if (sectionId === "left")
SettingsData.setTopBarLeftWidgets(widgets)
else if (sectionId === "center")
SettingsData.setTopBarCenterWidgets(widgets)
else if (sectionId === "right")
SettingsData.setTopBarRightWidgets(widgets)
}
function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) {
var widgets = []
if (sectionId === "left")
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.topBarRightWidgets.slice()
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex]
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"selectedGpuIndex": selectedGpuIndex,
"pciId": DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : ""
}
} else {
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"selectedGpuIndex": selectedGpuIndex,
"pciId": DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : ""
}
if (widget.size !== undefined) newWidget.size = widget.size
widgets[widgetIndex] = newWidget
}
}
if (sectionId === "left")
SettingsData.setTopBarLeftWidgets(widgets)
else if (sectionId === "center")
SettingsData.setTopBarCenterWidgets(widgets)
else if (sectionId === "right")
SettingsData.setTopBarRightWidgets(widgets)
}
function getItemsForSection(sectionId) {
var widgets = []
var widgetData = []
if (sectionId === "left")
widgetData = SettingsData.topBarLeftWidgets || []
else if (sectionId === "center")
widgetData = SettingsData.topBarCenterWidgets || []
else if (sectionId === "right")
widgetData = SettingsData.topBarRightWidgets || []
widgetData.forEach(widget => {
var widgetId = typeof widget === "string" ? widget : widget.id
var widgetEnabled = typeof widget === "string" ? true : widget.enabled
var widgetSize = typeof widget === "string" ? undefined : widget.size
var widgetSelectedGpuIndex = typeof widget
=== "string" ? undefined : widget.selectedGpuIndex
var widgetPciId = typeof widget
=== "string" ? undefined : widget.pciId
var widgetDef = baseWidgetDefinitions.find(w => {
return w.id === widgetId
})
if (widgetDef) {
var item = Object.assign({}, widgetDef)
item.enabled = widgetEnabled
if (widgetSize !== undefined)
item.size = widgetSize
if (widgetSelectedGpuIndex !== undefined)
item.selectedGpuIndex = widgetSelectedGpuIndex
if (widgetPciId !== undefined)
item.pciId = widgetPciId
widgets.push(item)
}
})
return widgets
}
Component.onCompleted: {
// Only set defaults if widgets have never been configured (null/undefined, not empty array)
if (!SettingsData.topBarLeftWidgets)
SettingsData.setTopBarLeftWidgets(defaultLeftWidgets)
if (!SettingsData.topBarCenterWidgets)
SettingsData.setTopBarCenterWidgets(defaultCenterWidgets)
if (!SettingsData.topBarRightWidgets)
SettingsData.setTopBarRightWidgets(defaultRightWidgets)
["left", "center", "right"].forEach(sectionId => {
var widgets = []
if (sectionId === "left")
widgets = SettingsData.topBarLeftWidgets.slice()
else if (sectionId === "center")
widgets = SettingsData.topBarCenterWidgets.slice()
else if (sectionId === "right")
widgets = SettingsData.topBarRightWidgets.slice()
var updated = false
for (var i = 0; i
< widgets.length; i++) {
var widget = widgets[i]
if (typeof widget === "object"
&& widget.id === "spacer"
&& !widget.size) {
widgets[i] = Object.assign(
{},
widget,
{
"size": 20
})
updated = true
}
}
if (updated) {
if (sectionId === "left")
SettingsData.setTopBarLeftWidgets(
widgets)
else if (sectionId === "center")
SettingsData.setTopBarCenterWidgets(
widgets)
else if (sectionId === "right")
SettingsData.setTopBarRightWidgets(
widgets)
}
})
}
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
anchors.bottomMargin: Theme.spacingS
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingXL
// TopBar Auto-hide Section
StyledRect {
width: parent.width
height: topBarAutoHideSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: topBarAutoHideSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "visibility_off"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - autoHideToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Auto-hide"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Automatically hide the top bar to expand screen real estate"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: autoHideToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.topBarAutoHide
onToggled: (toggled) => {
return SettingsData.setTopBarAutoHide(toggled);
}
}
}
}
}
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "widgets"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Widget Management"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - 400
height: 1
}
Rectangle {
width: 80
height: 28
radius: Theme.cornerRadius
color: resetArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariant
anchors.verticalCenter: parent.verticalCenter
border.width: 1
border.color: resetArea.containsMouse ? Theme.outline : Qt.rgba(
Theme.outline.r,
Theme.outline.g,
Theme.outline.b, 0.5)
Row {
anchors.centerIn: parent
spacing: Theme.spacingXS
DankIcon {
name: "refresh"
size: 14
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Reset"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: resetArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
SettingsData.setTopBarLeftWidgets(defaultLeftWidgets)
SettingsData.setTopBarCenterWidgets(defaultCenterWidgets)
SettingsData.setTopBarRightWidgets(defaultRightWidgets)
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on border.color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
Rectangle {
width: parent.width
height: messageText.contentHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
StyledText {
id: messageText
anchors.centerIn: parent
text: "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely."
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
width: parent.width - Theme.spacingM * 2
wrapMode: Text.WordWrap
}
}
Column {
width: parent.width
spacing: Theme.spacingL
WidgetsTabSection {
width: parent.width
title: "Left Section"
titleIcon: "format_align_left"
sectionId: "left"
allWidgets: topBarTab.baseWidgetDefinitions
items: topBarTab.getItemsForSection("left")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
topBarTab.handleItemEnabledChanged(sectionId,
itemId,
enabled)
}
onItemOrderChanged: newOrder => {
topBarTab.handleItemOrderChanged("left",
newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets = topBarTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
topBarTab.removeWidgetFromSection(sectionId,
widgetIndex)
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
topBarTab.handleSpacerSizeChanged(sectionId,
itemId,
newSize)
}
onCompactModeChanged: (widgetId, value) => {
if (widgetId === "clock") {
SettingsData.setClockCompactMode(value)
} else if (widgetId === "music") {
SettingsData.setMediaSize(value)
} else if (widgetId === "focusedWindow") {
SettingsData.setFocusedWindowCompactMode(value)
} else if (widgetId === "runningApps") {
SettingsData.setRunningAppsCompactMode(value)
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
topBarTab.handleGpuSelectionChanged(
sectionId, widgetIndex, selectedIndex)
}
}
WidgetsTabSection {
width: parent.width
title: "Center Section"
titleIcon: "format_align_center"
sectionId: "center"
allWidgets: topBarTab.baseWidgetDefinitions
items: topBarTab.getItemsForSection("center")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
topBarTab.handleItemEnabledChanged(sectionId,
itemId,
enabled)
}
onItemOrderChanged: newOrder => {
topBarTab.handleItemOrderChanged("center",
newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets = topBarTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
topBarTab.removeWidgetFromSection(sectionId,
widgetIndex)
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
topBarTab.handleSpacerSizeChanged(sectionId,
itemId,
newSize)
}
onCompactModeChanged: (widgetId, value) => {
if (widgetId === "clock") {
SettingsData.setClockCompactMode(value)
} else if (widgetId === "music") {
SettingsData.setMediaSize(value)
} else if (widgetId === "focusedWindow") {
SettingsData.setFocusedWindowCompactMode(value)
} else if (widgetId === "runningApps") {
SettingsData.setRunningAppsCompactMode(value)
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
topBarTab.handleGpuSelectionChanged(
sectionId, widgetIndex, selectedIndex)
}
}
WidgetsTabSection {
width: parent.width
title: "Right Section"
titleIcon: "format_align_right"
sectionId: "right"
allWidgets: topBarTab.baseWidgetDefinitions
items: topBarTab.getItemsForSection("right")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
topBarTab.handleItemEnabledChanged(sectionId,
itemId,
enabled)
}
onItemOrderChanged: newOrder => {
topBarTab.handleItemOrderChanged("right",
newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets = topBarTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
topBarTab.removeWidgetFromSection(sectionId,
widgetIndex)
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
topBarTab.handleSpacerSizeChanged(sectionId,
itemId,
newSize)
}
onCompactModeChanged: (widgetId, value) => {
if (widgetId === "clock") {
SettingsData.setClockCompactMode(value)
} else if (widgetId === "music") {
SettingsData.setMediaSize(value)
} else if (widgetId === "focusedWindow") {
SettingsData.setFocusedWindowCompactMode(value)
} else if (widgetId === "runningApps") {
SettingsData.setRunningAppsCompactMode(value)
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
topBarTab.handleGpuSelectionChanged(
sectionId, widgetIndex, selectedIndex)
}
}
}
// Corner Radius
StyledRect {
width: parent.width
height: cornerRadiusSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: cornerRadiusSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "rounded_corner"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Corner Radius"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Bar & Widget Corner Roundness"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: SettingsData.cornerRadius
minimum: 0
maximum: 32
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setCornerRadius(newValue);
}
}
}
}
}
// Spacing
StyledRect {
width: parent.width
height: topBarSpacingSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: topBarSpacingSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "space_bar"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Spacing"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Gap Around Top Bar (0 = edge-to-edge)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: SettingsData.topBarSpacing
minimum: 0
maximum: 32
unit: ""
showValue: true
onSliderValueChanged: (newValue) => {
SettingsData.setTopBarSpacing(newValue);
}
}
}
DankToggle {
width: parent.width
text: "Square Corners"
description: "Disable corner radius for the top bar (always square corners)"
checked: SettingsData.topBarSquareCorners
onToggled: (checked) => {
SettingsData.setTopBarSquareCorners(checked);
}
}
}
}
}
}
DankWidgetSelectionPopup {
id: widgetSelectionPopup
anchors.centerIn: parent
onWidgetSelected: (widgetId, targetSection) => {
topBarTab.addWidgetToSection(widgetId, targetSection)
}
}
}

View File

@@ -0,0 +1,269 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
Item {
id: weatherTab
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingXL
// Enable Weather
StyledRect {
width: parent.width
height: enableWeatherSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: enableWeatherSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "cloud"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - enableToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Enable Weather"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Show weather information in top bar and control center"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: enableToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setWeatherEnabled(checked);
}
}
}
}
}
// Temperature Unit
StyledRect {
width: parent.width
height: temperatureSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
visible: SettingsData.weatherEnabled
opacity: visible ? 1 : 0
Column {
id: temperatureSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "thermostat"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - temperatureToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Use Fahrenheit"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Use Fahrenheit instead of Celsius for temperature"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: temperatureToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.useFahrenheit
onToggled: (checked) => {
return SettingsData.setTemperatureUnit(checked);
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
// Location Settings
StyledRect {
width: parent.width
height: locationSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
visible: SettingsData.weatherEnabled
opacity: visible ? 1 : 0
Column {
id: locationSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "location_on"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - autoLocationToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Auto Location"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Allow wttr.in to determine location based on IP address"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: autoLocationToggle
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.useAutoLocation
onToggled: (checked) => {
return SettingsData.setAutoLocation(checked);
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
visible: !SettingsData.useAutoLocation
Rectangle {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.2
}
StyledText {
text: "Custom Location"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
DankLocationSearch {
width: parent.width
currentLocation: SettingsData.weatherLocation
placeholderText: "New York, NY"
onLocationSelected: (displayName, coordinates) => {
SettingsData.setWeatherLocation(displayName, coordinates);
}
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
}

View File

@@ -0,0 +1,377 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
Item {
id: widgetTweaksTab
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
clip: true
contentHeight: mainColumn.height
contentWidth: width
Column {
id: mainColumn
width: parent.width
spacing: Theme.spacingXL
// Launcher Button Section
StyledRect {
width: parent.width
height: launcherButtonSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: launcherButtonSection
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: "Launcher Button"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Use OS Logo"
description: "Display operating system logo instead of apps icon"
checked: SettingsData.useOSLogo
onToggled: checked => {
return SettingsData.setUseOSLogo(checked)
}
}
Row {
width: parent.width - Theme.spacingL
spacing: Theme.spacingL
visible: SettingsData.useOSLogo
opacity: visible ? 1 : 0
anchors.left: parent.left
anchors.leftMargin: Theme.spacingL
Column {
width: 120
spacing: Theme.spacingS
StyledText {
text: "Color Override"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
width: 100
height: 28
placeholderText: "#ffffff"
text: SettingsData.osLogoColorOverride
maximumLength: 7
font.pixelSize: Theme.fontSizeSmall
topPadding: Theme.spacingXS
bottomPadding: Theme.spacingXS
onEditingFinished: {
var color = text.trim()
if (color === "" || /^#[0-9A-Fa-f]{6}$/.test(color))
SettingsData.setOSLogoColorOverride(color)
else
text = SettingsData.osLogoColorOverride
}
}
}
Column {
width: 120
spacing: Theme.spacingS
StyledText {
text: "Brightness"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: 100
height: 20
minimum: 0
maximum: 100
value: Math.round(SettingsData.osLogoBrightness * 100)
unit: "%"
showValue: true
onSliderValueChanged: newValue => {
SettingsData.setOSLogoBrightness(
newValue / 100)
}
}
}
Column {
width: 120
spacing: Theme.spacingS
StyledText {
text: "Contrast"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: 100
height: 20
minimum: 0
maximum: 200
value: Math.round(SettingsData.osLogoContrast * 100)
unit: "%"
showValue: true
onSliderValueChanged: newValue => {
SettingsData.setOSLogoContrast(
newValue / 100)
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
StyledRect {
width: parent.width
height: workspaceSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
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: "Workspace Settings"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Workspace Index Numbers"
description: "Show workspace index numbers in the top bar workspace switcher"
checked: SettingsData.showWorkspaceIndex
onToggled: checked => {
return SettingsData.setShowWorkspaceIndex(checked)
}
}
DankToggle {
width: parent.width
text: "Workspace Padding"
description: "Always show a minimum of 3 workspaces, even if fewer are available"
checked: SettingsData.showWorkspacePadding
onToggled: checked => {
return SettingsData.setShowWorkspacePadding(checked)
}
}
}
}
StyledRect {
width: parent.width
height: workspaceIconsSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
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: "Named Workspace Icons"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
width: parent.width
text: "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: 1
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: 1
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
}
}
}
}
}
}
}
}
}

View File

@@ -437,7 +437,6 @@ Item {
DankFlickable {
anchors.fill: parent
anchors.topMargin: Theme.spacingL
anchors.bottomMargin: Theme.spacingXL
clip: true
contentHeight: mainColumn.height
contentWidth: width