Settings: large cleanup and factorization. Should look much better.

This commit is contained in:
LemmyCook 2025-08-27 20:39:50 -04:00
parent 1206be34dc
commit 8302285388
21 changed files with 2434 additions and 2937 deletions

View file

@ -175,7 +175,7 @@ NPanel {
// Action buttons // Action buttons
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: Style.marginS * scaling spacing: Style.marginL * scaling
NIconButton { NIconButton {
icon: "refresh" icon: "refresh"
@ -187,7 +187,6 @@ NPanel {
colorBg: Color.mSurfaceVariant colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface colorFg: Color.mOnSurface
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 35 * scaling
} }
NIconButton { NIconButton {
@ -201,7 +200,6 @@ NPanel {
colorBg: ArchUpdaterService.updateInProgress ? Color.mSurfaceVariant : Color.mPrimary colorBg: ArchUpdaterService.updateInProgress ? Color.mSurfaceVariant : Color.mPrimary
colorFg: ArchUpdaterService.updateInProgress ? Color.mOnSurfaceVariant : Color.mOnPrimary colorFg: ArchUpdaterService.updateInProgress ? Color.mOnSurfaceVariant : Color.mOnPrimary
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 35 * scaling
} }
NIconButton { NIconButton {
@ -219,7 +217,6 @@ NPanel {
colorFg: ArchUpdaterService.updateInProgress ? Color.mOnSurfaceVariant : (ArchUpdaterService.selectedPackagesCount colorFg: ArchUpdaterService.updateInProgress ? Color.mOnSurfaceVariant : (ArchUpdaterService.selectedPackagesCount
> 0 ? Color.mOnSecondary : Color.mOnSurfaceVariant) > 0 ? Color.mOnSecondary : Color.mOnSurfaceVariant)
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 35 * scaling
} }
} }
} }

View file

@ -267,7 +267,7 @@ NPanel {
// Tab label on the main right side // Tab label on the main right side
NText { NText {
text: root.tabsModel[currentTabIndex].label text: root.tabsModel[currentTabIndex].label
font.pointSize: Style.fontSizeL * scaling font.pointSize: Style.fontSizeXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mPrimary color: Color.mPrimary
Layout.fillWidth: true Layout.fillWidth: true
@ -287,21 +287,28 @@ NPanel {
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
clip: true
Repeater { Repeater {
model: root.tabsModel model: root.tabsModel
onItemAdded: function (index, item) {
item.sourceComponent = root.tabsModel[index].source
}
delegate: Loader { delegate: Loader {
// All loaders will occupy the same space, stacked on top of each other.
anchors.fill: parent anchors.fill: parent
visible: index === root.currentTabIndex active: index === root.currentTabIndex
// The loader is only active (and uses memory) when its page is visible. sourceComponent: ColumnLayout {
active: visible ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
padding: Style.marginL * scaling
Loader {
active: true
sourceComponent: root.tabsModel[index].source
width: scrollView.availableWidth
}
}
}
} }
} }
} }

View file

@ -15,10 +15,6 @@ ColumnLayout {
property string currentVersion: "Unknown" // Fallback version property string currentVersion: "Unknown" // Fallback version
property var contributors: GitHubService.contributors property var contributors: GitHubService.contributors
spacing: 0
Layout.fillWidth: true
Layout.fillHeight: true
Process { Process {
id: currentVersionProcess id: currentVersionProcess
@ -41,23 +37,9 @@ ColumnLayout {
} }
} }
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginL * scaling
rightPadding: Style.marginM * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: scrollView.availableWidth
spacing: 0
NText { NText {
text: "Noctalia: quiet by design" text: "Noctalia Shell"
font.pointSize: Style.fontSizeXXXL * scaling font.pointSize: Style.fontSizeXXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mOnSurface
@ -65,14 +47,6 @@ ColumnLayout {
Layout.bottomMargin: Style.marginS * scaling Layout.bottomMargin: Style.marginS * scaling
} }
NText {
text: "It may just be another quickshell setup but it won't get in your way."
font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurface
Layout.alignment: Qt.AlignCenter
Layout.bottomMargin: Style.marginL * scaling
}
GridLayout { GridLayout {
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
columns: 2 columns: 2
@ -163,8 +137,8 @@ ColumnLayout {
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * 2 * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginxL * scaling
} }
NText { NText {
@ -258,5 +232,4 @@ ColumnLayout {
} }
} }
} }
}
}

View file

@ -7,11 +7,8 @@ import qs.Commons
import qs.Services import qs.Services
ColumnLayout { ColumnLayout {
id: root
property real localVolume: AudioService.volume property real localVolume: AudioService.volume
// Connection used to open the pill when volume changes
Connections { Connections {
target: AudioService.sink?.audio ? AudioService.sink?.audio : null target: AudioService.sink?.audio ? AudioService.sink?.audio : null
function onVolumeChanged() { function onVolumeChanged() {
@ -19,52 +16,13 @@ ColumnLayout {
} }
} }
spacing: 0
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginM * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: scrollView.availableWidth
spacing: 0
Item {
Layout.fillWidth: true
Layout.preferredHeight: 0
}
ColumnLayout {
spacing: Style.marginXS * scaling
Layout.fillWidth: true
NText {
text: "Audio Output Volume"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
}
// Volume Controls
ColumnLayout {
spacing: Style.marginS * scaling
Layout.fillWidth: true
Layout.topMargin: Style.marginS * scaling
// Master Volume // Master Volume
ColumnLayout { ColumnLayout {
spacing: Style.marginS * scaling spacing: Style.marginS * scaling
Layout.fillWidth: true Layout.fillWidth: true
NLabel { NLabel {
label: "Master Volume" label: "Output Volume"
description: "System-wide volume level." description: "System-wide volume level."
} }
@ -141,24 +99,22 @@ ColumnLayout {
} }
} }
} }
}
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * 2 * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// AudioService Devices // AudioService Devices
ColumnLayout { ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginS * scaling
Layout.fillWidth: true
NText { NText {
text: "Audio Devices" text: "Audio Devices"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling Layout.bottomMargin: Style.marginS * scaling
} }
@ -189,7 +145,6 @@ ColumnLayout {
} }
} }
} }
}
// ------------------------------- // -------------------------------
// Input Devices // Input Devices
@ -223,25 +178,44 @@ ColumnLayout {
// Divider // Divider
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// MPRIS Player Preferences // Media Player Preferences
ColumnLayout { ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true
NText { NText {
text: "MPRIS Player Preferences" text: "Media Player"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling Layout.bottomMargin: Style.marginS * scaling
} }
// Miniplayer section
NToggle {
label: "Show Album Art In Bar Media Player"
description: "Show the album art of the currently playing song next to the title."
checked: Settings.data.audio.showMiniplayerAlbumArt
onToggled: checked => {
Settings.data.audio.showMiniplayerAlbumArt = checked
}
}
NToggle {
label: "Show Audio Visualizer In Bar Media Player"
description: "Shows an audio visualizer in the background of the miniplayer."
checked: Settings.data.audio.showMiniplayerCava
onToggled: checked => {
Settings.data.audio.showMiniplayerCava = checked
}
}
// Preferred player (persistent) // Preferred player (persistent)
NTextInput { NTextInput {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
label: "Preferred Player" label: "Preferred Player"
description: "Substring to match MPRIS player (identity/bus/desktop)." description: "Substring to match MPRIS player (identity/bus/desktop)."
placeholderText: "e.g. spotify, vlc, mpv" placeholderText: "e.g. spotify, vlc, mpv"
@ -266,7 +240,7 @@ ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
label: "Blacklist player" label: "Blacklist player"
description: "Substring, e.g. plex, shim, mpv" description: "Substring, e.g. plex, shim, mpv."
placeholderText: "type substring and press +" placeholderText: "type substring and press +"
} }
@ -355,46 +329,6 @@ ColumnLayout {
Layout.bottomMargin: Style.marginXL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// Bar Mini Media player
ColumnLayout {
spacing: Style.marginL * scaling
Layout.fillWidth: true
NText {
text: "Bar Media Player"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
}
// Miniplayer section
NToggle {
label: "Show Album Art In Bar Media Player"
description: "Show the album art of the currently playing song next to the title."
checked: Settings.data.audio.showMiniplayerAlbumArt
onToggled: checked => {
Settings.data.audio.showMiniplayerAlbumArt = checked
}
}
NToggle {
label: "Show Audio Visualizer In Bar Media Player"
description: "Shows an audio visualizer in the background of the miniplayer."
checked: Settings.data.audio.showMiniplayerCava
onToggled: checked => {
Settings.data.audio.showMiniplayerCava = checked
}
}
}
// Divider
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
}
// AudioService Visualizer Category // AudioService Visualizer Category
ColumnLayout { ColumnLayout {
spacing: Style.marginS * scaling spacing: Style.marginS * scaling
@ -404,7 +338,7 @@ ColumnLayout {
text: "Audio Visualizer" text: "Audio Visualizer"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling Layout.bottomMargin: Style.marginS * scaling
} }
@ -439,7 +373,7 @@ ColumnLayout {
NComboBox { NComboBox {
label: "Frame Rate" label: "Frame Rate"
description: "Target frame rate for audio visualizer. (default: 60)" description: "Target frame rate for audio visualizer."
model: ListModel { model: ListModel {
ListElement { ListElement {
key: "30" key: "30"
@ -476,6 +410,10 @@ ColumnLayout {
} }
} }
} }
} // Divider
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
} }
} }

View file

@ -6,54 +6,15 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
spacing: 0
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginM * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: scrollView.availableWidth
spacing: 0
Item {
Layout.fillWidth: true
Layout.preferredHeight: 0
}
ColumnLayout { ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true
ColumnLayout {
spacing: Style.marginXXS * scaling
Layout.fillWidth: true
NText {
text: "Bar Position"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: "Choose where to place the bar on the screen"
font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
RowLayout {
NComboBox { NComboBox {
Layout.fillWidth: true Layout.fillWidth: true
label: "Bar Position"
description: "Choose where to place the bar on the screen."
model: ListModel { model: ListModel {
ListElement { ListElement {
key: "top" key: "top"
@ -65,9 +26,7 @@ ColumnLayout {
} }
} }
currentKey: Settings.data.bar.position currentKey: Settings.data.bar.position
onSelected: key => { onSelected: key => Settings.data.bar.position = key
Settings.data.bar.position = key
}
} }
} }
@ -150,11 +109,12 @@ ColumnLayout {
Settings.data.bar.showWorkspaceLabel = key Settings.data.bar.showWorkspaceLabel = key
} }
} }
}
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// Widgets Management Section // Widgets Management Section
@ -190,7 +150,6 @@ ColumnLayout {
sectionName: "Left" sectionName: "Left"
widgetModel: Settings.data.bar.widgets.left widgetModel: Settings.data.bar.widgets.left
availableWidgets: availableWidgets availableWidgets: availableWidgets
scrollView: scrollView
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section) onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index) onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex) onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
@ -201,7 +160,6 @@ ColumnLayout {
sectionName: "Center" sectionName: "Center"
widgetModel: Settings.data.bar.widgets.center widgetModel: Settings.data.bar.widgets.center
availableWidgets: availableWidgets availableWidgets: availableWidgets
scrollView: scrollView
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section) onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index) onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex) onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
@ -212,15 +170,17 @@ ColumnLayout {
sectionName: "Right" sectionName: "Right"
widgetModel: Settings.data.bar.widgets.right widgetModel: Settings.data.bar.widgets.right
availableWidgets: availableWidgets availableWidgets: availableWidgets
scrollView: scrollView
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section) onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index) onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex) onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
} }
} }
} }
}
} NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
} }
// Helper functions // Helper functions

View file

@ -6,33 +6,11 @@ import qs.Commons
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
Item { ColumnLayout {
readonly property real scaling: ScalingService.scale(screen) readonly property real scaling: ScalingService.scale(screen)
readonly property string tabIcon: "brightness_6" readonly property string tabIcon: "brightness_6"
readonly property string tabLabel: "Brightness" readonly property string tabLabel: "Brightness"
Layout.fillWidth: true
Layout.fillHeight: true
ScrollView {
anchors.fill: parent
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
contentWidth: parent.width
ColumnLayout {
width: parent.width
ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.margins: Style.marginL * scaling
Layout.fillWidth: true
NText {
text: "Brightness Settings"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
// Brightness Step Section // Brightness Step Section
ColumnLayout { ColumnLayout {
@ -54,16 +32,9 @@ Item {
} }
} }
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL * scaling
Layout.bottomMargin: Style.marginL * scaling
}
// Monitor Overview Section // Monitor Overview Section
ColumnLayout { ColumnLayout {
spacing: Style.marginS * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true
NLabel { NLabel {
label: "Monitors Brightness Control" label: "Monitors Brightness Control"
@ -147,10 +118,9 @@ Item {
} }
} }
Item { NDivider {
Layout.fillHeight: true Layout.fillWidth: true
} Layout.topMargin: Style.marginXL * scaling
} Layout.bottomMargin: Style.marginXL * scaling
}
} }
} }

View file

@ -9,8 +9,6 @@ import qs.Widgets
ColumnLayout { ColumnLayout {
id: root id: root
spacing: 0
// Helper function to get color from scheme file (supports dark/light variants) // Helper function to get color from scheme file (supports dark/light variants)
function getSchemeColor(schemePath, colorKey) { function getSchemeColor(schemePath, colorKey) {
// Extract scheme name from path // Extract scheme name from path
@ -55,6 +53,28 @@ ColumnLayout {
} }
} }
// Simple process to check if matugen exists
Process {
id: matugenCheck
command: ["which", "matugen"]
running: false
onExited: function (exitCode) {
if (exitCode === 0) {
// Matugen exists, enable it
Settings.data.colorSchemes.useWallpaperColors = true
ColorSchemeService.changedWallpaper()
ToastService.showNotice("Matugen", "Enabled!")
} else {
// Matugen not found
ToastService.showWarning("Matugen", "Not installed!")
}
}
stdout: StdioCollector {}
stderr: StdioCollector {}
}
// A non-visual Item to host the Repeater that loads the color scheme files. // A non-visual Item to host the Repeater that loads the color scheme files.
Item { Item {
visible: false visible: false
@ -83,17 +103,6 @@ ColumnLayout {
} }
} }
// UI Code
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginM * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout { ColumnLayout {
width: scrollView.availableWidth width: scrollView.availableWidth
spacing: 0 spacing: 0
@ -159,36 +168,30 @@ ColumnLayout {
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
ColumnLayout { ColumnLayout {
spacing: Style.marginXXS * scaling spacing: Style.marginS * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText { NText {
text: "Predefined Color Schemes" text: "Predefined Color Schemes"
font.pointSize: Style.fontSizeL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.fillWidth: true
} }
NText { NText {
text: "These color schemes only apply when 'Use Matugen' is disabled. When enabled, Matugen will generate colors based on your wallpaper instead. You can toggle between light and dark themes when using Matugen." text: "These color schemes are only active when 'Use Matugen' is turned off. With Matugen enabled, colors will be automatically generated from your wallpaper. You can still switch between light and dark themes while using Matugen."
font.pointSize: Style.fontSizeXS * scaling font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurface color: Color.mOnSurfaceVariant
Layout.fillWidth: true Layout.fillWidth: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }
} }
ColumnLayout {
spacing: Style.marginXS * scaling
Layout.fillWidth: true
Layout.topMargin: Style.marginL * scaling
// Color Schemes Grid // Color Schemes Grid
GridLayout { GridLayout {
columns: 4 columns: 4
@ -340,28 +343,10 @@ ColumnLayout {
} }
} }
} }
}
}
// Simple process to check if matugen exists NDivider {
Process { Layout.fillWidth: true
id: matugenCheck Layout.topMargin: Style.marginXL * scaling
command: ["which", "matugen"] Layout.bottomMargin: Style.marginXL * scaling
running: false
onExited: function (exitCode) {
if (exitCode === 0) {
// Matugen exists, enable it
Settings.data.colorSchemes.useWallpaperColors = true
ColorSchemeService.changedWallpaper()
ToastService.showNotice("Matugen", "Enabled!")
} else {
// Matugen not found
ToastService.showWarning("Matugen", "Not installed!")
}
}
stdout: StdioCollector {}
stderr: StdioCollector {}
} }
} }

View file

@ -6,13 +6,11 @@ import qs.Commons
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
Item { ColumnLayout {
readonly property real scaling: ScalingService.scale(screen) readonly property real scaling: ScalingService.scale(screen)
readonly property string tabIcon: "monitor" readonly property string tabIcon: "monitor"
readonly property string tabLabel: "Display" readonly property string tabLabel: "Display"
readonly property int tabIndex: 5 readonly property int tabIndex: 5
Layout.fillWidth: true
Layout.fillHeight: true
// Time dropdown options (00:00 .. 23:30) // Time dropdown options (00:00 .. 23:30)
ListModel { ListModel {
@ -45,38 +43,26 @@ Item {
}) })
} }
ScrollView {
anchors.fill: parent
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
contentWidth: Math.max(parent.width, 600 * scaling)
ColumnLayout {
id: contentColumn
width: Math.max(parent.width, 600 * scaling)
ColumnLayout {
spacing: Style.marginL * scaling
Layout.margins: Style.marginL * scaling
Layout.fillWidth: true
NText { NText {
text: "Permonitor configuration" text: "Monitor-specific configuration"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface
} }
NText { NText {
text: "By default, bars and notifications are shown on all displays. Select one or more below to narrow your view." text: "Bars and notifications appear on all displays by default. Choose specific displays below to limit where they're shown."
font.pointSize: Style.fontSize * scaling font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurfaceVariant color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling) Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling)
} }
ColumnLayout {
spacing: Style.marginL * scaling
Layout.topMargin: Style.marginL * scaling
Repeater { Repeater {
model: Quickshell.screens || [] model: Quickshell.screens || []
delegate: Rectangle { delegate: Rectangle {
@ -134,8 +120,8 @@ Item {
checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1 checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1
onToggled: checked => { onToggled: checked => {
if (checked) { if (checked) {
Settings.data.notifications.monitors = addMonitor( Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors,
Settings.data.notifications.monitors, modelData.name) modelData.name)
} else { } else {
Settings.data.notifications.monitors = removeMonitor( Settings.data.notifications.monitors = removeMonitor(
Settings.data.notifications.monitors, modelData.name) Settings.data.notifications.monitors, modelData.name)
@ -152,8 +138,7 @@ Item {
if (checked) { if (checked) {
Settings.data.dock.monitors = addMonitor(Settings.data.dock.monitors, modelData.name) Settings.data.dock.monitors = addMonitor(Settings.data.dock.monitors, modelData.name)
} else { } else {
Settings.data.dock.monitors = removeMonitor(Settings.data.dock.monitors, Settings.data.dock.monitors = removeMonitor(Settings.data.dock.monitors, modelData.name)
modelData.name)
} }
} }
} }
@ -228,67 +213,54 @@ Item {
} }
} }
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
}
// Night Light Section // Night Light Section
ColumnLayout {
spacing: Style.marginXS * scaling
NText { NText {
text: "Night Light" text: "Night Light"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.topMargin: Style.marginXL * scaling
} }
NText { NText {
text: "Reduce blue light emission to help you sleep better and reduce eye strain." text: "Reduce blue light emission to help you sleep better and reduce eye strain."
font.pointSize: Style.fontSize * scaling font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurfaceVariant color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling) Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling)
} }
}
NToggle { NToggle {
label: "Enable Night Light" label: "Enable Night Light"
description: "Apply a warm color filter to reduce blue light emission." description: "Apply a warm color filter to reduce blue light emission."
checked: Settings.data.nightLight.enabled checked: Settings.data.nightLight.enabled
onToggled: checked => { onToggled: checked => Settings.data.nightLight.enabled = checked
Settings.data.nightLight.enabled = checked
}
} }
NToggle { NToggle {
label: "Auto Schedule" label: "Auto Schedule"
description: "Automatically enable night light based on time schedule." description: "Automatically enable night light based on time schedule."
checked: Settings.data.nightLight.autoSchedule checked: Settings.data.nightLight.autoSchedule
enabled: Settings.data.nightLight.enabled
onToggled: checked => Settings.data.nightLight.autoSchedule = checked onToggled: checked => Settings.data.nightLight.autoSchedule = checked
} }
// Intensity settings // Intensity settings
ColumnLayout { ColumnLayout {
spacing: Style.marginXS * scaling NLabel {
label: "Intensity"
NText { description: "Higher values create warmer light."
text: "Intensity"
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
enabled: Settings.data.nightLight.enabled
} }
NText {
text: "Higher values create warmer (more orange) light, lower values create cooler (more blue) light."
font.pointSize: Style.fontSizeS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
enabled: Settings.data.nightLight.enabled
}
}
RowLayout { RowLayout {
spacing: Style.marginS * scaling spacing: Style.marginS * scaling
Layout.fillWidth: true
enabled: Settings.data.nightLight.enabled
NSlider { NSlider {
from: 0 from: 0
@ -307,31 +279,24 @@ Item {
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
} }
} }
}
// Schedule settings // Schedule settings
ColumnLayout { ColumnLayout {
spacing: Style.marginXS * scaling spacing: Style.marginXS * scaling
NText { NLabel {
text: "Schedule" label: "Schedule"
font.pointSize: Style.fontSizeM * scaling description: "Set a start and end time for automatic schedule."
font.weight: Style.fontWeightBold
color: Color.mOnSurface
enabled: Settings.data.nightLight.enabled
} }
RowLayout { RowLayout {
spacing: Style.marginL * scaling Layout.fillWidth: false
Layout.fillWidth: true spacing: Style.marginM * scaling
enabled: Settings.data.nightLight.enabled
ColumnLayout {
spacing: Style.marginXXS * scaling
Layout.fillWidth: true
NText { NText {
text: "Start Time" text: "Start Time"
font.pointSize: Style.fontSizeS * scaling font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurfaceVariant color: Color.mOnSurfaceVariant
} }
@ -340,33 +305,32 @@ Item {
currentKey: Settings.data.nightLight.startTime currentKey: Settings.data.nightLight.startTime
placeholder: "Select start time" placeholder: "Select start time"
onSelected: key => Settings.data.nightLight.startTime = key onSelected: key => Settings.data.nightLight.startTime = key
} preferredWidth: 120 * scaling
} }
ColumnLayout { Item {// add a little more spacing
spacing: Style.marginXXS * scaling }
Layout.fillWidth: true
NText { NText {
text: "Stop Time" text: "Stop Time"
font.pointSize: Style.fontSizeS * scaling font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurfaceVariant color: Color.mOnSurfaceVariant
} }
NComboBox { NComboBox {
model: timeOptions model: timeOptions
currentKey: Settings.data.nightLight.stopTime currentKey: Settings.data.nightLight.stopTime
placeholder: "Select stop time" placeholder: "Select stop time"
onSelected: key => Settings.data.nightLight.stopTime = key onSelected: key => Settings.data.nightLight.stopTime = key
preferredWidth: 120 * scaling
} }
} }
} }
} }
Item {
Layout.fillHeight: true NDivider {
} Layout.fillWidth: true
} Layout.topMargin: Style.marginXL * scaling
} Layout.bottomMargin: Style.marginXL * scaling
} }
} }

View file

@ -6,46 +6,8 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
spacing: 0
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginM * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: scrollView.availableWidth
spacing: 0
Item {
Layout.fillWidth: true
Layout.preferredHeight: 0
}
ColumnLayout {
spacing: Style.marginL * scaling
Layout.fillWidth: true
NText {
text: "General Settings"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
// Profile section // Profile section
ColumnLayout {
spacing: Style.marginS * scaling
Layout.fillWidth: true
Layout.topMargin: Style.marginS * scaling
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
@ -71,8 +33,6 @@ ColumnLayout {
} }
} }
} }
}
}
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
@ -80,6 +40,7 @@ ColumnLayout {
Layout.bottomMargin: Style.marginXL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// User Interface
ColumnLayout { ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true Layout.fillWidth: true
@ -88,7 +49,7 @@ ColumnLayout {
text: "User Interface" text: "User Interface"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling Layout.bottomMargin: Style.marginS * scaling
} }
@ -123,19 +84,9 @@ ColumnLayout {
spacing: Style.marginXXS * scaling spacing: Style.marginXXS * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText { NLabel {
text: "Border radius" label: "Border radius"
font.pointSize: Style.fontSizeL * scaling description: "Adjust the rounded border of all UI elements."
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: "Adjust the rounded border of all UI elements"
font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
} }
RowLayout { RowLayout {
@ -158,30 +109,14 @@ ColumnLayout {
} }
} }
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling
}
// Animation Speed // Animation Speed
ColumnLayout { ColumnLayout {
spacing: Style.marginXXS * scaling spacing: Style.marginXXS * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText { NLabel {
text: "Animation Speed" label: "Animation Speed"
font.pointSize: Style.fontSizeL * scaling description: "Adjust global animation speed."
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: "Adjust global animation speed (0.1× to 2.0×)"
font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
} }
RowLayout { RowLayout {
@ -203,18 +138,29 @@ ColumnLayout {
} }
} }
} }
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
}
// Fonts
ColumnLayout {
spacing: Style.marginL * scaling
Layout.fillWidth: true
NText { NText {
text: "Fonts" text: "Fonts"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling Layout.bottomMargin: Style.marginS * scaling
} }
// Font configuration section // Font configuration section
ColumnLayout { ColumnLayout {
spacing: Style.marginS * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true Layout.fillWidth: true
NTextInput { NTextInput {
@ -251,6 +197,10 @@ ColumnLayout {
} }
} }
} }
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
} }
} }

View file

@ -6,62 +6,9 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
spacing: 0
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginM * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: scrollView.availableWidth
spacing: 0
Item {
Layout.fillWidth: true
Layout.preferredHeight: 0
}
ColumnLayout { ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true
NText {
text: "Launcher"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NToggle {
label: "Enable Clipboard History"
description: "Show clipboard history in the Launcher (command >clip)."
checked: Settings.data.appLauncher.enableClipboardHistory
onToggled: checked => {
Settings.data.appLauncher.enableClipboardHistory = checked
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL * scaling
Layout.bottomMargin: Style.marginS * scaling
}
NText {
text: "Launcher Position"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
}
NComboBox { NComboBox {
id: launcherPosition id: launcherPosition
@ -104,18 +51,32 @@ ColumnLayout {
} }
} }
NDivider { NToggle {
label: "Enable Clipboard History"
description: "Show clipboard history in the launcher."
checked: Settings.data.appLauncher.enableClipboardHistory
onToggled: checked => {
Settings.data.appLauncher.enableClipboardHistory = checked
}
}
ColumnLayout {
spacing: Style.marginXXS * scaling
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * scaling
Layout.bottomMargin: Style.marginS * scaling NText {
text: "Background Opacity"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
} }
NText { NText {
text: "Launcher Background" text: "Adjust the background opacity of the launcher."
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXS * scaling
font.weight: Style.fontWeightBold color: Color.mOnSurfaceVariant
color: Color.mOnSurface wrapMode: Text.WordWrap
Layout.bottomMargin: Style.marginS * scaling Layout.fillWidth: true
} }
RowLayout { RowLayout {
@ -139,5 +100,10 @@ ColumnLayout {
} }
} }
} }
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
} }
} }

View file

@ -8,38 +8,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
spacing: 0
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginM * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: scrollView.availableWidth
spacing: 0
Item {
Layout.fillWidth: true
Layout.preferredHeight: 0
}
ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true
NText {
text: "Interfaces"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NToggle { NToggle {
label: "WiFi Enabled" label: "WiFi Enabled"
@ -70,7 +39,10 @@ ColumnLayout {
} }
} }
} }
}
} NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
} }
} }

View file

@ -6,40 +6,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root spacing: Style.marginL * scaling
spacing: 0
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginM * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: scrollView.availableWidth
spacing: 0
Item {
Layout.fillWidth: true
Layout.preferredHeight: 0
}
ColumnLayout {
spacing: Style.marginXS * scaling
Layout.fillWidth: true
NText {
text: "Recordings"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
}
// Output Directory // Output Directory
ColumnLayout { ColumnLayout {
@ -55,6 +22,7 @@ ColumnLayout {
onEditingFinished: { onEditingFinished: {
Settings.data.screenRecorder.directory = text Settings.data.screenRecorder.directory = text
} }
Layout.fillWidth: true
} }
ColumnLayout { ColumnLayout {
@ -75,8 +43,8 @@ ColumnLayout {
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * 2 * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// Video Settings // Video Settings
@ -88,7 +56,7 @@ ColumnLayout {
text: "Video Settings" text: "Video Settings"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling Layout.bottomMargin: Style.marginS * scaling
} }
@ -115,7 +83,7 @@ ColumnLayout {
// Frame Rate // Frame Rate
NComboBox { NComboBox {
label: "Frame Rate" label: "Frame Rate"
description: "Target frame rate for screen recordings. (default: 60)" description: "Target frame rate for screen recordings."
model: ListModel { model: ListModel {
ListElement { ListElement {
key: "30" key: "30"
@ -248,7 +216,7 @@ ColumnLayout {
text: "Audio Settings" text: "Audio Settings"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling Layout.bottomMargin: Style.marginS * scaling
} }
@ -296,7 +264,10 @@ ColumnLayout {
} }
} }
} }
}
} NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
} }
} }

View file

@ -6,47 +6,8 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
spacing: 0
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
padding: Style.marginM * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: scrollView.availableWidth
spacing: 0
Item {
Layout.fillWidth: true
Layout.preferredHeight: 0
}
ColumnLayout {
spacing: Style.marginXS * scaling
Layout.fillWidth: true
NText {
text: "Location"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
}
// Location section // Location section
ColumnLayout {
spacing: Style.marginM * scaling
Layout.fillWidth: true
Layout.topMargin: Style.marginS * scaling
NTextInput { NTextInput {
label: "Location name" label: "Location name"
description: "Choose a known location near you." description: "Choose a known location near you."
@ -58,12 +19,11 @@ ColumnLayout {
LocationService.resetWeather() LocationService.resetWeather()
} }
} }
}
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * 2 * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// Time section // Time section
@ -75,8 +35,7 @@ ColumnLayout {
text: "Time Format" text: "Time Format"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling
} }
NToggle { NToggle {
@ -109,8 +68,8 @@ ColumnLayout {
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * 2 * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// Weather section // Weather section
@ -122,8 +81,7 @@ ColumnLayout {
text: "Weather" text: "Weather"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling
} }
NToggle { NToggle {
@ -135,7 +93,10 @@ ColumnLayout {
} }
} }
} }
}
} NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
} }
} }

View file

@ -6,34 +6,20 @@ import qs.Commons
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
Item { ColumnLayout {
readonly property real scaling: ScalingService.scale(screen) readonly property real scaling: ScalingService.scale(screen)
readonly property string tabIcon: "photo_library" readonly property string tabIcon: "photo_library"
readonly property string tabLabel: "Wallpaper Selector" readonly property string tabLabel: "Wallpaper Selector"
readonly property int tabIndex: 7 readonly property int tabIndex: 7
Layout.fillWidth: true
Layout.fillHeight: true
ScrollView {
anchors.fill: parent
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
contentWidth: parent.width
ColumnLayout {
width: parent.width
ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.margins: Style.marginL * scaling
Layout.fillWidth: true
// Current wallpaper display // Current wallpaper display
NText { NText {
text: "Current Wallpaper" text: "Current Wallpaper"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
} }
Rectangle { Rectangle {
@ -54,10 +40,11 @@ Item {
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// Wallpaper selector
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
@ -69,12 +56,12 @@ Item {
text: "Wallpaper Selector" text: "Wallpaper Selector"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
} }
NText { NText {
text: "Click on a wallpaper to set it as your current wallpaper." text: "Click on a wallpaper to set it as your current wallpaper."
color: Color.mOnSurface color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
} }
@ -102,8 +89,7 @@ Item {
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: { Layout.preferredHeight: {
return Math.ceil( return Math.ceil(WallpaperService.wallpaperList.length / wallpaperGridView.columns) * wallpaperGridView.cellHeight
WallpaperService.wallpaperList.length / wallpaperGridView.columns) * wallpaperGridView.cellHeight
} }
GridView { GridView {
@ -117,8 +103,7 @@ Item {
interactive: false interactive: false
property int columns: 5 property int columns: 5
property int itemSize: Math.floor( property int itemSize: Math.floor((width - leftMargin - rightMargin - (4 * Style.marginS * scaling)) / columns)
(width - leftMargin - rightMargin - (4 * Style.marginS * scaling)) / columns)
cellWidth: Math.floor((width - leftMargin - rightMargin) / columns) cellWidth: Math.floor((width - leftMargin - rightMargin) / columns)
cellHeight: Math.floor(itemSize * 0.67) + Style.marginS * scaling cellHeight: Math.floor(itemSize * 0.67) + Style.marginS * scaling
@ -151,19 +136,19 @@ Item {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: Color.transparent color: Color.transparent
border.color: isSelected ? Color.mPrimary : Color.mSurface border.color: isSelected ? Color.mSecondary : Color.mSurface
border.width: Math.max(1, Style.borderL * scaling) border.width: Math.max(1, Style.borderL * 1.5 * scaling)
} }
// Selection tick-mark // Selection tick-mark
Rectangle { Rectangle {
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.margins: Style.marginXS * scaling anchors.margins: Style.marginS * scaling
width: 28 * scaling width: 28 * scaling
height: 28 * scaling height: 28 * scaling
radius: width / 2 radius: width / 2
color: Color.mPrimary color: Color.mSecondary
border.color: Color.mOutline border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling) border.width: Math.max(1, Style.borderS * scaling)
visible: isSelected visible: isSelected
@ -172,7 +157,7 @@ Item {
text: "check" text: "check"
font.pointSize: Style.fontSizeM * scaling font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnPrimary color: Color.mOnSecondary
anchors.centerIn: parent anchors.centerIn: parent
} }
} }
@ -180,8 +165,8 @@ Item {
// Hover effect // Hover effect
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: Color.mOnSurface color: Color.mSurface
opacity: mouseArea.containsMouse ? 0.1 : 0 opacity: (mouseArea.containsMouse || isSelected) ? 0 : 0.4
radius: parent.radius radius: parent.radius
Behavior on opacity { Behavior on opacity {
@ -240,7 +225,10 @@ Item {
} }
} }
} }
}
} NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
} }
} }

View file

@ -7,52 +7,29 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
spacing: 0 // Process to check if swww is installed
Process {
id: swwwCheck
command: ["which", "swww"]
running: false
ScrollView { onExited: function (exitCode) {
id: scrollView if (exitCode === 0) {
// SWWW exists, enable it
Layout.fillWidth: true Settings.data.wallpaper.swww.enabled = true
Layout.fillHeight: true WallpaperService.startSWWWDaemon()
padding: Style.marginM * scaling ToastService.showNotice("SWWW", "Enabled!")
clip: true } else {
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff // SWWW not found
ScrollBar.vertical.policy: ScrollBar.AsNeeded ToastService.showWarning("SWWW", "Not installed!")
}
ColumnLayout {
width: scrollView.availableWidth
spacing: 0
Item {
Layout.fillWidth: true
Layout.preferredHeight: 0
} }
ColumnLayout { stdout: StdioCollector {}
spacing: Style.marginL * scaling stderr: StdioCollector {}
Layout.fillWidth: true
NText {
text: "Directory"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.bottomMargin: Style.marginS * scaling
} }
// Wallpaper Settings Category
ColumnLayout {
spacing: Style.marginS * scaling
Layout.fillWidth: true
Layout.topMargin: Style.marginS * scaling
// Wallpaper Folder
ColumnLayout {
spacing: Style.marginS * scaling
Layout.fillWidth: true
NTextInput { NTextInput {
label: "Wallpaper Directory" label: "Wallpaper Directory"
description: "Path to your wallpaper directory." description: "Path to your wallpaper directory."
@ -62,14 +39,11 @@ ColumnLayout {
Settings.data.wallpaper.directory = text Settings.data.wallpaper.directory = text
} }
} }
}
}
}
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * 2 * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
ColumnLayout { ColumnLayout {
@ -80,8 +54,7 @@ ColumnLayout {
text: "Automation" text: "Automation"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling
} }
// Random Wallpaper // Random Wallpaper
@ -306,10 +279,11 @@ ColumnLayout {
id: customRow id: customRow
visible: presetRow.customForcedVisible || !presetRow.isCurrentPreset visible: presetRow.customForcedVisible || !presetRow.isCurrentPreset
spacing: Style.marginS * scaling spacing: Style.marginS * scaling
Layout.topMargin: Style.marginS * scaling
NTextInput { NTextInput {
label: "Custom Interval" label: "Custom Interval"
description: "Enter time as HH:MM (e.g., 1:30)" description: "Enter time as HH:MM (e.g., 1:30)."
text: { text: {
const s = Settings.data.wallpaper.randomInterval const s = Settings.data.wallpaper.randomInterval
const h = Math.floor(s / 3600) const h = Math.floor(s / 3600)
@ -339,28 +313,27 @@ ColumnLayout {
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginL * 2 * scaling Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginL * scaling Layout.bottomMargin: Style.marginXL * scaling
} }
// ------------------------------- // -------------------------------
// SWWW // Swww
ColumnLayout { ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
Layout.fillWidth: true Layout.fillWidth: true
NText { NText {
text: "SWWW" text: "Swww"
font.pointSize: Style.fontSizeXXL * scaling font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mSecondary
Layout.bottomMargin: Style.marginS * scaling
} }
// Use SWWW // Use SWWW
NToggle { NToggle {
label: "Use SWWW" label: "Use Swww"
description: "Use SWWW daemon for advanced wallpaper management." description: "Use Swww daemon for advanced wallpaper management."
checked: Settings.data.wallpaper.swww.enabled checked: Settings.data.wallpaper.swww.enabled
onToggled: checked => { onToggled: checked => {
if (checked) { if (checked) {
@ -368,7 +341,7 @@ ColumnLayout {
swwwCheck.running = true swwwCheck.running = true
} else { } else {
Settings.data.wallpaper.swww.enabled = false Settings.data.wallpaper.swww.enabled = false
ToastService.showNotice("SWWW", "Disabled") ToastService.showNotice("Swww", "Disabled")
} }
} }
} }
@ -383,7 +356,7 @@ ColumnLayout {
// Resize Mode // Resize Mode
NComboBox { NComboBox {
label: "Resize Mode" label: "Resize Mode"
description: "How SWWW should resize wallpapers to fit the screen." description: "How Swww should resize wallpapers to fit the screen."
model: ListModel { model: ListModel {
ListElement { ListElement {
key: "no" key: "no"
@ -478,32 +451,14 @@ ColumnLayout {
// Transition FPS // Transition FPS
ColumnLayout { ColumnLayout {
NLabel {
label: "Transition FPS"
description: "Frames per second for transition animations."
}
RowLayout { RowLayout {
Layout.fillWidth: true spacing: Style.marginL * scaling
ColumnLayout {
NText {
text: "Transition FPS"
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: "Frames per second for transition animations."
font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurface
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
NText {
text: sliderWpTransitionFps.value + " FPS"
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
}
}
NSlider { NSlider {
id: sliderWpTransitionFps
Layout.fillWidth: true Layout.fillWidth: true
from: 30 from: 30
to: 500 to: 500
@ -512,36 +467,23 @@ ColumnLayout {
onMoved: Settings.data.wallpaper.swww.transitionFps = Math.round(value) onMoved: Settings.data.wallpaper.swww.transitionFps = Math.round(value)
cutoutColor: Color.mSurface cutoutColor: Color.mSurface
} }
NText {
text: Settings.data.wallpaper.swww.transitionFps + " FPS"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
}
}
} }
// Transition Duration // Transition Duration
ColumnLayout { ColumnLayout {
NLabel {
label: "Transition Duration"
description: "Duration of transition animations in seconds."
}
RowLayout { RowLayout {
Layout.fillWidth: true spacing: Style.marginL * scaling
ColumnLayout {
NText {
text: "Transition Duration"
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: "Duration of transition animations in seconds."
font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurface
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
NText {
text: sliderWpTransitionDuration.value.toFixed(2) + "s"
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
}
}
NSlider { NSlider {
id: sliderWpTransitionDuration
Layout.fillWidth: true Layout.fillWidth: true
from: 0.25 from: 0.25
to: 10 to: 10
@ -550,31 +492,18 @@ ColumnLayout {
onMoved: Settings.data.wallpaper.swww.transitionDuration = value onMoved: Settings.data.wallpaper.swww.transitionDuration = value
cutoutColor: Color.mSurface cutoutColor: Color.mSurface
} }
NText {
text: Settings.data.wallpaper.swww.transitionDuration.toFixed(2) + "s"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
} }
} }
} }
} }
} }
// Process to check if swww is installed NDivider {
Process { Layout.fillWidth: true
id: swwwCheck Layout.topMargin: Style.marginXL * scaling
command: ["which", "swww"] Layout.bottomMargin: Style.marginXL * scaling
running: false
onExited: function (exitCode) {
if (exitCode === 0) {
// SWWW exists, enable it
Settings.data.wallpaper.swww.enabled = true
WallpaperService.startSWWWDaemon()
ToastService.showNotice("SWWW", "Enabled!")
} else {
// SWWW not found
ToastService.showWarning("SWWW", "Not installed!")
}
}
stdout: StdioCollector {}
stderr: StdioCollector {}
} }
} }

View file

@ -5,10 +5,11 @@ import qs.Commons
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { RowLayout {
id: root id: root
readonly property real preferredHeight: Style.baseWidgetSize * 1.35 * scaling readonly property real preferredHeight: Style.baseWidgetSize * 1.1 * scaling
property real preferredWidth: 320 * scaling
property string label: "" property string label: ""
property string description: "" property string description: ""
@ -23,11 +24,6 @@ ColumnLayout {
spacing: Style.marginS * scaling spacing: Style.marginS * scaling
Layout.fillWidth: true Layout.fillWidth: true
NLabel {
label: root.label
description: root.description
}
function findIndexByKey(key) { function findIndexByKey(key) {
for (var i = 0; i < root.model.count; i++) { for (var i = 0; i < root.model.count; i++) {
if (root.model.get(i).key === key) { if (root.model.get(i).key === key) {
@ -37,10 +33,15 @@ ColumnLayout {
return -1 return -1
} }
NLabel {
label: root.label
description: root.description
}
ComboBox { ComboBox {
id: combo id: combo
Layout.preferredWidth: 320 * scaling Layout.preferredWidth: root.preferredWidth
Layout.preferredHeight: height Layout.preferredHeight: height
model: model model: model
currentIndex: findIndexByKey(currentKey) currentIndex: findIndexByKey(currentKey)

View file

@ -11,7 +11,7 @@ ColumnLayout {
NText { NText {
text: label text: label
font.pointSize: Style.fontSizeM * scaling font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
color: Color.mOnSurface color: Color.mOnSurface
visible: label !== "" visible: label !== ""

View file

@ -10,7 +10,6 @@ NBox {
property string sectionName: "" property string sectionName: ""
property var widgetModel: [] property var widgetModel: []
property var availableWidgets: [] property var availableWidgets: []
property var scrollView: null
signal addWidget(string widgetName, string section) signal addWidget(string widgetName, string section)
signal removeWidget(string section, int index) signal removeWidget(string section, int index)
@ -23,7 +22,7 @@ NBox {
if (widgetCount === 0) if (widgetCount === 0)
return 140 * scaling return 140 * scaling
var availableWidth = scrollView ? scrollView.availableWidth - (Style.marginM * scaling * 2) : 400 * scaling var availableWidth = parent.width
var avgWidgetWidth = 150 * scaling var avgWidgetWidth = 150 * scaling
var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth)) var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth))
var rows = Math.ceil(widgetCount / widgetsPerRow) var rows = Math.ceil(widgetCount / widgetsPerRow)
@ -52,7 +51,7 @@ NBox {
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: Style.marginM * scaling anchors.margins: Style.marginL * scaling
spacing: Style.marginM * scaling spacing: Style.marginM * scaling
RowLayout { RowLayout {
@ -189,13 +188,13 @@ NBox {
return return
} }
Logger.log("NSectionEditor", `Started dragging widget: ${modelData} at index ${index}`) //Logger.log("NSectionEditor", `Started dragging widget: ${modelData} at index ${index}`)
// Bring to front when starting drag // Bring to front when starting drag
widgetItem.z = 1000 widgetItem.z = 1000
} }
onReleased: { onReleased: {
Logger.log("NSectionEditor", `Released widget: ${modelData} at index ${index}`) //Logger.log("NSectionEditor", `Released widget: ${modelData} at index ${index}`)
// Reset z-index when drag ends // Reset z-index when drag ends
widgetItem.z = 0 widgetItem.z = 0
@ -232,13 +231,13 @@ NBox {
if (targetIndex !== -1 && targetIndex !== index) { if (targetIndex !== -1 && targetIndex !== index) {
const fromIndex = index const fromIndex = index
const toIndex = targetIndex const toIndex = targetIndex
Logger.log( // Logger.log(
"NSectionEditor", // "NSectionEditor",
`Dropped widget from index ${fromIndex} to position ${toIndex} (distance: ${minDistance.toFixed( // `Dropped widget from index ${fromIndex} to position ${toIndex} (distance: ${minDistance.toFixed(
2)})`) // 2)})`)
reorderWidget(sectionName.toLowerCase(), fromIndex, toIndex) reorderWidget(sectionName.toLowerCase(), fromIndex, toIndex)
} else { } else {
Logger.log("NSectionEditor", `No valid drop target found for widget at index ${index}`) Logger.warn("NSectionEditor", `No valid drop target found for widget at index ${index}`)
} }
} }
} }
@ -264,17 +263,16 @@ NBox {
radius: Style.radiusS * scaling radius: Style.radiusS * scaling
} }
onEntered: function (drag) { onEntered: function (drag) {//Logger.log("NSectionEditor", "Entered start drop zone")
Logger.log("NSectionEditor", "Entered start drop zone")
} }
onDropped: function (drop) { onDropped: function (drop) {
Logger.log("NSectionEditor", "Dropped on start zone") //Logger.log("NSectionEditor", "Dropped on start zone")
if (drop.source && drop.source.widgetIndex !== undefined) { if (drop.source && drop.source.widgetIndex !== undefined) {
const fromIndex = drop.source.widgetIndex const fromIndex = drop.source.widgetIndex
const toIndex = 0 // Insert at the beginning const toIndex = 0 // Insert at the beginning
if (fromIndex !== toIndex) { if (fromIndex !== toIndex) {
Logger.log("NSectionEditor", `Dropped widget from index ${fromIndex} to beginning`) //Logger.log("NSectionEditor", `Dropped widget from index ${fromIndex} to beginning`)
reorderWidget(sectionName.toLowerCase(), fromIndex, toIndex) reorderWidget(sectionName.toLowerCase(), fromIndex, toIndex)
} }
} }
@ -299,17 +297,16 @@ NBox {
radius: Style.radiusS * scaling radius: Style.radiusS * scaling
} }
onEntered: function (drag) { onEntered: function (drag) {//Logger.log("NSectionEditor", "Entered end drop zone")
Logger.log("NSectionEditor", "Entered end drop zone")
} }
onDropped: function (drop) { onDropped: function (drop) {
Logger.log("NSectionEditor", "Dropped on end zone") //Logger.log("NSectionEditor", "Dropped on end zone")
if (drop.source && drop.source.widgetIndex !== undefined) { if (drop.source && drop.source.widgetIndex !== undefined) {
const fromIndex = drop.source.widgetIndex const fromIndex = drop.source.widgetIndex
const toIndex = widgetModel.length // Insert at the end const toIndex = widgetModel.length // Insert at the end
if (fromIndex !== toIndex) { if (fromIndex !== toIndex) {
Logger.log("NSectionEditor", `Dropped widget from index ${fromIndex} to end`) //Logger.log("NSectionEditor", `Dropped widget from index ${fromIndex} to end`)
reorderWidget(sectionName.toLowerCase(), fromIndex, toIndex) reorderWidget(sectionName.toLowerCase(), fromIndex, toIndex)
} }
} }

View file

@ -30,26 +30,9 @@ RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
ColumnLayout { NLabel {
spacing: Style.marginXXS * scaling label: root.label
Layout.fillWidth: true description: root.description
NText {
text: label
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
visible: label !== ""
}
NText {
text: description
font.pointSize: Style.fontSizeS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
visible: description !== ""
}
} }
// Value // Value

View file

@ -150,7 +150,7 @@ Item {
id: labelText id: labelText
text: root.label text: root.label
color: Color.mOnSurface color: Color.mOnSurface
font.pointSize: Style.fontSize * scaling font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold font.weight: Style.fontWeightBold
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
width: parent.width width: parent.width
@ -161,7 +161,7 @@ Item {
id: descriptionText id: descriptionText
text: root.description text: root.description
color: Color.mOnSurface color: Color.mOnSurface
font.pointSize: Style.fontSize * scaling font.pointSize: Style.fontSizeM * scaling
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
width: parent.width width: parent.width
visible: text.length > 0 visible: text.length > 0
@ -176,7 +176,7 @@ Item {
color: Color.mOnSurface color: Color.mOnSurface
fontPointSize: Style.fontSize * scaling fontPointSize: Style.fontSizeM * scaling
sizeRatio: 0.8 sizeRatio: 0.8
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop

View file

@ -19,24 +19,9 @@ RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
ColumnLayout { NLabel {
spacing: Style.marginXXS * scaling label: root.label
Layout.fillWidth: true description: root.description
NText {
text: label
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: description
font.pointSize: Style.fontSizeS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
} }
Rectangle { Rectangle {