Settings: more cleanup and conditionnal controls (NightLight)

+ Auto formatting
This commit is contained in:
LemmyCook 2025-08-28 06:57:37 -04:00
parent 85b92d9c6f
commit 0562dbbbf9
14 changed files with 434 additions and 431 deletions

View file

@ -25,8 +25,10 @@ Variants {
property var removingNotifications: ({}) property var removingNotifications: ({})
// If no notification display activated in settings, then show them all // If no notification display activated in settings, then show them all
active: Settings.isLoaded && modelData && (NotificationService.notificationModel.count > 0) ? (Settings.data.notifications.monitors.includes(modelData.name) active: Settings.isLoaded && modelData
|| (Settings.data.notifications.monitors.length === 0)) : false && (NotificationService.notificationModel.count > 0) ? (Settings.data.notifications.monitors.includes(
modelData.name)
|| (Settings.data.notifications.monitors.length === 0)) : false
visible: (NotificationService.notificationModel.count > 0) visible: (NotificationService.notificationModel.count > 0)

View file

@ -37,199 +37,196 @@ ColumnLayout {
} }
} }
NText {
text: "Noctalia Shell"
font.pointSize: Style.fontSizeXXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.alignment: Qt.AlignCenter
Layout.bottomMargin: Style.marginS * scaling
}
GridLayout {
Layout.alignment: Qt.AlignCenter
columns: 2
rowSpacing: Style.marginXS * scaling
columnSpacing: Style.marginS * scaling
NText {
text: "Latest Version:"
color: Color.mOnSurface
Layout.alignment: Qt.AlignRight
}
NText {
text: root.latestVersion
color: Color.mOnSurface
font.weight: Style.fontWeightBold
}
NText {
text: "Installed Version:"
color: Color.mOnSurface
Layout.alignment: Qt.AlignRight
}
NText {
text: root.currentVersion
color: Color.mOnSurface
font.weight: Style.fontWeightBold
}
}
Rectangle {
Layout.alignment: Qt.AlignCenter
Layout.topMargin: Style.marginS * scaling
Layout.preferredWidth: updateText.implicitWidth + 46 * scaling
Layout.preferredHeight: Style.barHeight * scaling
radius: Style.radiusL * scaling
color: updateArea.containsMouse ? Color.mPrimary : Color.transparent
border.color: Color.mPrimary
border.width: Math.max(1, Style.borderS * scaling)
visible: {
if (root.currentVersion === "Unknown" || root.latestVersion === "Unknown")
return false
const latest = root.latestVersion.replace("v", "").split(".")
const current = root.currentVersion.replace("v", "").split(".")
for (var i = 0; i < Math.max(latest.length, current.length); i++) {
const l = parseInt(latest[i] || "0")
const c = parseInt(current[i] || "0")
if (l > c)
return true
if (l < c)
return false
}
return false
}
RowLayout {
anchors.centerIn: parent
spacing: Style.marginS * scaling
NIcon {
text: "system_update"
font.pointSize: Style.fontSizeXXL * scaling
color: updateArea.containsMouse ? Color.mSurface : Color.mPrimary
}
NText { NText {
text: "Noctalia Shell" id: updateText
font.pointSize: Style.fontSizeXXXL * scaling text: "Download latest release"
font.weight: Style.fontWeightBold font.pointSize: Style.fontSizeL * scaling
color: Color.mOnSurface color: updateArea.containsMouse ? Color.mSurface : Color.mPrimary
Layout.alignment: Qt.AlignCenter
Layout.bottomMargin: Style.marginS * scaling
} }
}
GridLayout { MouseArea {
Layout.alignment: Qt.AlignCenter id: updateArea
columns: 2
rowSpacing: Style.marginXS * scaling
columnSpacing: Style.marginS * scaling
NText { anchors.fill: parent
text: "Latest Version:" hoverEnabled: true
color: Color.mOnSurface cursorShape: Qt.PointingHandCursor
Layout.alignment: Qt.AlignRight onClicked: {
} Quickshell.execDetached(["xdg-open", "https://github.com/Ly-sec/Noctalia/releases/latest"])
NText {
text: root.latestVersion
color: Color.mOnSurface
font.weight: Style.fontWeightBold
}
NText {
text: "Installed Version:"
color: Color.mOnSurface
Layout.alignment: Qt.AlignRight
}
NText {
text: root.currentVersion
color: Color.mOnSurface
font.weight: Style.fontWeightBold
}
} }
}
}
Rectangle { NDivider {
Layout.alignment: Qt.AlignCenter Layout.fillWidth: true
Layout.topMargin: Style.marginS * scaling Layout.topMargin: Style.marginXL * scaling
Layout.preferredWidth: updateText.implicitWidth + 46 * scaling Layout.bottomMargin: Style.marginxL * scaling
Layout.preferredHeight: Style.barHeight * scaling }
NText {
text: `Shout-out to our ${root.contributors.length} awesome contributors!`
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.alignment: Qt.AlignCenter
Layout.topMargin: Style.marginL * 2
}
ScrollView {
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 200 * Style.marginXS * scaling
Layout.fillHeight: true
Layout.topMargin: Style.marginL * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
GridView {
id: contributorsGrid
anchors.fill: parent
width: 200 * 4 * scaling
height: Math.ceil(root.contributors.length / 4) * 100
cellWidth: Style.baseWidgetSize * 6.25 * scaling
cellHeight: Style.baseWidgetSize * 3.125 * scaling
model: root.contributors
delegate: Rectangle {
width: contributorsGrid.cellWidth - Style.marginL * scaling
height: contributorsGrid.cellHeight - Style.marginXS * scaling
radius: Style.radiusL * scaling radius: Style.radiusL * scaling
color: updateArea.containsMouse ? Color.mPrimary : Color.transparent color: contributorArea.containsMouse ? Color.mSecondary : Color.transparent
border.color: Color.mPrimary
border.width: Math.max(1, Style.borderS * scaling)
visible: {
if (root.currentVersion === "Unknown" || root.latestVersion === "Unknown")
return false
const latest = root.latestVersion.replace("v", "").split(".")
const current = root.currentVersion.replace("v", "").split(".")
for (var i = 0; i < Math.max(latest.length, current.length); i++) {
const l = parseInt(latest[i] || "0")
const c = parseInt(current[i] || "0")
if (l > c)
return true
if (l < c)
return false
}
return false
}
RowLayout { RowLayout {
anchors.centerIn: parent anchors.fill: parent
spacing: Style.marginS * scaling anchors.margins: Style.marginS * scaling
spacing: Style.marginM * scaling
NIcon { Item {
text: "system_update" Layout.alignment: Qt.AlignVCenter
font.pointSize: Style.fontSizeXXL * scaling Layout.preferredWidth: Style.baseWidgetSize * 2 * scaling
color: updateArea.containsMouse ? Color.mSurface : Color.mPrimary Layout.preferredHeight: Style.baseWidgetSize * 2 * scaling
NImageCircled {
imagePath: modelData.avatar_url || ""
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
fallbackIcon: "person"
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
}
} }
NText { ColumnLayout {
id: updateText spacing: Style.marginXS * scaling
text: "Download latest release" Layout.alignment: Qt.AlignVCenter
font.pointSize: Style.fontSizeL * scaling Layout.fillWidth: true
color: updateArea.containsMouse ? Color.mSurface : Color.mPrimary
NText {
text: modelData.login || "Unknown"
font.weight: Style.fontWeightBold
color: contributorArea.containsMouse ? Color.mSurface : Color.mOnSurface
elide: Text.ElideRight
Layout.fillWidth: true
}
NText {
text: (modelData.contributions || 0) + " " + ((modelData.contributions || 0) === 1 ? "commit" : "commits")
font.pointSize: Style.fontSizeXS * scaling
color: contributorArea.containsMouse ? Color.mSurface : Color.mOnSurface
}
} }
} }
MouseArea { MouseArea {
id: updateArea id: contributorArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
Quickshell.execDetached(["xdg-open", "https://github.com/Ly-sec/Noctalia/releases/latest"]) if (modelData.html_url)
} Quickshell.execDetached(["xdg-open", modelData.html_url])
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginxL * scaling
}
NText {
text: `Shout-out to our ${root.contributors.length} awesome contributors!`
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.alignment: Qt.AlignCenter
Layout.topMargin: Style.marginL * 2
}
ScrollView {
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 200 * Style.marginXS * scaling
Layout.fillHeight: true
Layout.topMargin: Style.marginL * scaling
clip: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
GridView {
id: contributorsGrid
anchors.fill: parent
width: 200 * 4 * scaling
height: Math.ceil(root.contributors.length / 4) * 100
cellWidth: Style.baseWidgetSize * 6.25 * scaling
cellHeight: Style.baseWidgetSize * 3.125 * scaling
model: root.contributors
delegate: Rectangle {
width: contributorsGrid.cellWidth - Style.marginL * scaling
height: contributorsGrid.cellHeight - Style.marginXS * scaling
radius: Style.radiusL * scaling
color: contributorArea.containsMouse ? Color.mSecondary : Color.transparent
RowLayout {
anchors.fill: parent
anchors.margins: Style.marginS * scaling
spacing: Style.marginM * scaling
Item {
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: Style.baseWidgetSize * 2 * scaling
Layout.preferredHeight: Style.baseWidgetSize * 2 * scaling
NImageCircled {
imagePath: modelData.avatar_url || ""
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
fallbackIcon: "person"
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
}
}
ColumnLayout {
spacing: Style.marginXS * scaling
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
NText {
text: modelData.login || "Unknown"
font.weight: Style.fontWeightBold
color: contributorArea.containsMouse ? Color.mSurface : Color.mOnSurface
elide: Text.ElideRight
Layout.fillWidth: true
}
NText {
text: (modelData.contributions || 0) + " " + ((modelData.contributions
|| 0) === 1 ? "commit" : "commits")
font.pointSize: Style.fontSizeXS * scaling
color: contributorArea.containsMouse ? Color.mSurface : Color.mOnSurface
}
}
}
MouseArea {
id: contributorArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (modelData.html_url)
Quickshell.execDetached(["xdg-open", modelData.html_url])
}
}
} }
} }
} }
} }
}
}

View file

@ -7,6 +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
Connections { Connections {

View file

@ -6,6 +6,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
ColumnLayout { ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling

View file

@ -7,9 +7,8 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
readonly property real scaling: ScalingService.scale(screen) id: root
readonly property string tabIcon: "brightness_6"
readonly property string tabLabel: "Brightness"
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
// Brightness Step Section // Brightness Step Section

View file

@ -9,6 +9,13 @@ import qs.Widgets
ColumnLayout { ColumnLayout {
id: root id: root
// Cache for scheme JSON (can be flat or {dark, light})
property var schemeColorsCache: ({})
// Scale properties for card animations
property real cardScaleLow: 0.95
property real cardScaleHigh: 1.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
@ -29,13 +36,6 @@ ColumnLayout {
return "#000000" return "#000000"
} }
// Cache for scheme JSON (can be flat or {dark, light})
property var schemeColorsCache: ({})
// Scale properties for card animations
property real cardScaleLow: 0.95
property real cardScaleHigh: 1.0
// This function is called by the FileView Repeater when a scheme file is loaded // This function is called by the FileView Repeater when a scheme file is loaded
function schemeLoaded(schemeName, jsonData) { function schemeLoaded(schemeName, jsonData) {
var value = jsonData || {} var value = jsonData || {}

View file

@ -7,10 +7,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
readonly property real scaling: ScalingService.scale(screen) id: root
readonly property string tabIcon: "monitor"
readonly property string tabLabel: "Display"
readonly property int tabIndex: 5
// Time dropdown options (00:00 .. 23:30) // Time dropdown options (00:00 .. 23:30)
ListModel { ListModel {
@ -43,168 +40,166 @@ ColumnLayout {
}) })
} }
NText {
text: "Monitor-specific configuration"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
}
NText { NText {
text: "Monitor-specific configuration" text: "Bars and notifications appear on all displays by default. Choose specific displays below to limit where they're shown."
font.pointSize: Style.fontSizeL * scaling font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold color: Color.mOnSurfaceVariant
} wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling)
}
NText { ColumnLayout {
text: "Bars and notifications appear on all displays by default. Choose specific displays below to limit where they're shown." spacing: Style.marginL * scaling
font.pointSize: Style.fontSizeM * scaling Layout.topMargin: Style.marginL * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling)
}
ColumnLayout { Repeater {
spacing: Style.marginL * scaling model: Quickshell.screens || []
Layout.topMargin: Style.marginL * scaling delegate: Rectangle {
Layout.fillWidth: true
Layout.minimumWidth: 550 * scaling
radius: Style.radiusM * scaling
color: Color.mSurface
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
implicitHeight: contentCol.implicitHeight + Style.marginXL * 2 * scaling
Repeater { ColumnLayout {
model: Quickshell.screens || [] id: contentCol
delegate: Rectangle { anchors.fill: parent
Layout.fillWidth: true anchors.margins: Style.marginL * scaling
Layout.minimumWidth: 550 * scaling spacing: Style.marginXXS * scaling
radius: Style.radiusM * scaling
color: Color.mSurface NText {
border.color: Color.mOutline text: (modelData.name || "Unknown")
border.width: Math.max(1, Style.borderS * scaling) font.pointSize: Style.fontSizeXL * scaling
implicitHeight: contentCol.implicitHeight + Style.marginXL * 2 * scaling font.weight: Style.fontWeightBold
color: Color.mSecondary
}
NText {
text: `Resolution: ${modelData.width}x${modelData.height} - Position: (${modelData.x}, ${modelData.y})`
font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
ColumnLayout { ColumnLayout {
id: contentCol spacing: Style.marginL * scaling
anchors.fill: parent Layout.fillWidth: true
anchors.margins: Style.marginL * scaling
spacing: Style.marginXXS * scaling
NText { NToggle {
text: (modelData.name || "Unknown") Layout.fillWidth: true
font.pointSize: Style.fontSizeXL * scaling label: "Bar"
font.weight: Style.fontWeightBold description: "Enable the bar on this monitor."
color: Color.mSecondary checked: (Settings.data.bar.monitors || []).indexOf(modelData.name) !== -1
onToggled: checked => {
if (checked) {
Settings.data.bar.monitors = addMonitor(Settings.data.bar.monitors, modelData.name)
} else {
Settings.data.bar.monitors = removeMonitor(Settings.data.bar.monitors, modelData.name)
}
}
} }
NText { NToggle {
text: `Resolution: ${modelData.width}x${modelData.height} - Position: (${modelData.x}, ${modelData.y})`
font.pointSize: Style.fontSizeXS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
label: "Notifications"
description: "Enable notifications on this monitor."
checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1
onToggled: checked => {
if (checked) {
Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors,
modelData.name)
} else {
Settings.data.notifications.monitors = removeMonitor(Settings.data.notifications.monitors,
modelData.name)
}
}
}
NToggle {
Layout.fillWidth: true
label: "Dock"
description: "Enable the dock on this monitor."
checked: (Settings.data.dock.monitors || []).indexOf(modelData.name) !== -1
onToggled: checked => {
if (checked) {
Settings.data.dock.monitors = addMonitor(Settings.data.dock.monitors, modelData.name)
} else {
Settings.data.dock.monitors = removeMonitor(Settings.data.dock.monitors, modelData.name)
}
}
} }
ColumnLayout { ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginS * scaling
Layout.fillWidth: true Layout.fillWidth: true
NToggle { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
label: "Bar" spacing: Style.marginL * scaling
description: "Enable the bar on this monitor."
checked: (Settings.data.bar.monitors || []).indexOf(modelData.name) !== -1
onToggled: checked => {
if (checked) {
Settings.data.bar.monitors = addMonitor(Settings.data.bar.monitors, modelData.name)
} else {
Settings.data.bar.monitors = removeMonitor(Settings.data.bar.monitors, modelData.name)
}
}
}
NToggle { ColumnLayout {
Layout.fillWidth: true spacing: Style.marginXXS * scaling
label: "Notifications"
description: "Enable notifications on this monitor."
checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1
onToggled: checked => {
if (checked) {
Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors,
modelData.name)
} else {
Settings.data.notifications.monitors = removeMonitor(
Settings.data.notifications.monitors, modelData.name)
}
}
}
NToggle {
Layout.fillWidth: true
label: "Dock"
description: "Enable the dock on this monitor."
checked: (Settings.data.dock.monitors || []).indexOf(modelData.name) !== -1
onToggled: checked => {
if (checked) {
Settings.data.dock.monitors = addMonitor(Settings.data.dock.monitors, modelData.name)
} else {
Settings.data.dock.monitors = removeMonitor(Settings.data.dock.monitors, modelData.name)
}
}
}
ColumnLayout {
spacing: Style.marginS * scaling
Layout.fillWidth: true
RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: Style.marginL * scaling
ColumnLayout {
spacing: Style.marginXXS * scaling
Layout.fillWidth: true
NText {
text: "Scale"
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: "Scale the user interface on this monitor."
font.pointSize: Style.fontSizeS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
NText { NText {
text: `${Math.round(ScalingService.scaleByName(modelData.name) * 100)}%` text: "Scale"
Layout.alignment: Qt.AlignVCenter font.pointSize: Style.fontSizeM * scaling
Layout.minimumWidth: 50 * scaling font.weight: Style.fontWeightBold
horizontalAlignment: Text.AlignRight color: Color.mOnSurface
}
NText {
text: "Scale the user interface on this monitor."
font.pointSize: Style.fontSizeS * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
} }
} }
RowLayout { NText {
spacing: Style.marginS * scaling text: `${Math.round(ScalingService.scaleByName(modelData.name) * 100)}%`
Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter
Layout.minimumWidth: 50 * scaling
horizontalAlignment: Text.AlignRight
}
}
NSlider { RowLayout {
id: scaleSlider spacing: Style.marginS * scaling
from: 0.7 Layout.fillWidth: true
to: 1.8
stepSize: 0.01 NSlider {
value: ScalingService.scaleByName(modelData.name) id: scaleSlider
onPressedChanged: { from: 0.7
var data = Settings.data.monitorsScaling || {} to: 1.8
data[modelData.name] = value stepSize: 0.01
Settings.data.monitorsScaling = data value: ScalingService.scaleByName(modelData.name)
} onPressedChanged: {
Layout.fillWidth: true var data = Settings.data.monitorsScaling || {}
Layout.minimumWidth: 150 * scaling data[modelData.name] = value
Settings.data.monitorsScaling = data
} }
Layout.fillWidth: true
Layout.minimumWidth: 150 * scaling
}
NIconButton { NIconButton {
icon: "refresh" icon: "refresh"
tooltipText: "Reset Scaling" tooltipText: "Reset Scaling"
onClicked: { onClicked: {
var data = Settings.data.monitorsScaling || {} var data = Settings.data.monitorsScaling || {}
data[modelData.name] = 1.0 data[modelData.name] = 1.0
Settings.data.monitorsScaling = data Settings.data.monitorsScaling = data
}
} }
} }
} }
@ -212,121 +207,124 @@ ColumnLayout {
} }
} }
} }
}
NDivider { NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
}
// Night Light Section
ColumnLayout {
spacing: Style.marginXS * scaling
NText {
text: "Night Light"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mSecondary
}
NText {
text: "Reduce blue light emission to help you sleep better and reduce eye strain."
font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling)
Layout.bottomMargin: Style.marginXL * scaling
} }
}
// Night Light Section NToggle {
ColumnLayout { label: "Enable Night Light"
spacing: Style.marginXS * scaling description: "Apply a warm color filter to reduce blue light emission."
NText { checked: Settings.data.nightLight.enabled
text: "Night Light" onToggled: checked => Settings.data.nightLight.enabled = checked
font.pointSize: Style.fontSizeXXL * scaling }
font.weight: Style.fontWeightBold
color: Color.mSecondary
}
NText { // Intensity settings
text: "Reduce blue light emission to help you sleep better and reduce eye strain." ColumnLayout {
font.pointSize: Style.fontSizeM * scaling visible: Settings.data.nightLight.enabled
color: Color.mOnSurfaceVariant NLabel {
wrapMode: Text.WordWrap label: "Intensity"
description: "Higher values create warmer light."
}
RowLayout {
spacing: Style.marginS * scaling
NSlider {
from: 0
to: 1
stepSize: 0.01
value: Settings.data.nightLight.intensity
onMoved: Settings.data.nightLight.intensity = value
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling) Layout.minimumWidth: 150 * scaling
}
}
NToggle {
label: "Enable Night Light"
description: "Apply a warm color filter to reduce blue light emission."
checked: Settings.data.nightLight.enabled
onToggled: checked => Settings.data.nightLight.enabled = checked
}
NToggle {
label: "Auto Schedule"
description: "Automatically enable night light based on time schedule."
checked: Settings.data.nightLight.autoSchedule
onToggled: checked => Settings.data.nightLight.autoSchedule = checked
}
// Intensity settings
ColumnLayout {
NLabel {
label: "Intensity"
description: "Higher values create warmer light."
}
RowLayout {
spacing: Style.marginS * scaling
NSlider {
from: 0
to: 1
stepSize: 0.01
value: Settings.data.nightLight.intensity
onMoved: Settings.data.nightLight.intensity = value
Layout.fillWidth: true
Layout.minimumWidth: 150 * scaling
}
NText {
text: `${Math.round(Settings.data.nightLight.intensity * 100)}%`
Layout.alignment: Qt.AlignVCenter
Layout.minimumWidth: 60 * scaling
horizontalAlignment: Text.AlignRight
}
}
}
// Schedule settings
ColumnLayout {
spacing: Style.marginXS * scaling
NLabel {
label: "Schedule"
description: "Set a start and end time for automatic schedule."
} }
RowLayout { NText {
Layout.fillWidth: false text: `${Math.round(Settings.data.nightLight.intensity * 100)}%`
spacing: Style.marginM * scaling Layout.alignment: Qt.AlignVCenter
Layout.minimumWidth: 60 * scaling
NText { horizontalAlignment: Text.AlignRight
text: "Start Time"
font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurfaceVariant
}
NComboBox {
model: timeOptions
currentKey: Settings.data.nightLight.startTime
placeholder: "Select start time"
onSelected: key => Settings.data.nightLight.startTime = key
preferredWidth: 120 * scaling
}
Item {// add a little more spacing
}
NText {
text: "Stop Time"
font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurfaceVariant
}
NComboBox {
model: timeOptions
currentKey: Settings.data.nightLight.stopTime
placeholder: "Select stop time"
onSelected: key => Settings.data.nightLight.stopTime = key
preferredWidth: 120 * scaling
}
} }
} }
} }
NToggle {
label: "Auto Schedule"
description: "Automatically enable night light based on time schedule."
checked: Settings.data.nightLight.autoSchedule
onToggled: checked => Settings.data.nightLight.autoSchedule = checked
visible: Settings.data.nightLight.enabled
}
// Schedule settings
ColumnLayout {
spacing: Style.marginXS * scaling
visible: Settings.data.nightLight.enabled && Settings.data.nightLight.autoSchedule
NLabel {
label: "Schedule"
description: "Set a start and end time for automatic schedule."
}
RowLayout {
Layout.fillWidth: false
spacing: Style.marginM * scaling
NText {
text: "Start Time"
font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurfaceVariant
}
NComboBox {
model: timeOptions
currentKey: Settings.data.nightLight.startTime
placeholder: "Select start time"
onSelected: key => Settings.data.nightLight.startTime = key
preferredWidth: 120 * scaling
}
Item {// add a little more spacing
}
NText {
text: "Stop Time"
font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurfaceVariant
}
NComboBox {
model: timeOptions
currentKey: Settings.data.nightLight.stopTime
placeholder: "Select stop time"
onSelected: key => Settings.data.nightLight.stopTime = key
preferredWidth: 120 * scaling
}
}
}
}
NDivider { NDivider {
Layout.fillWidth: true Layout.fillWidth: true

View file

@ -6,6 +6,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
// Profile section // Profile section
RowLayout { RowLayout {

View file

@ -6,6 +6,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
ColumnLayout { ColumnLayout {
spacing: Style.marginL * scaling spacing: Style.marginL * scaling

View file

@ -8,6 +8,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
NToggle { NToggle {

View file

@ -6,6 +6,8 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
spacing: Style.marginL * scaling spacing: Style.marginL * scaling
// Output Directory // Output Directory

View file

@ -6,6 +6,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
// Location section // Location section
NTextInput { NTextInput {

View file

@ -7,10 +7,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
readonly property real scaling: ScalingService.scale(screen) id: root
readonly property string tabIcon: "photo_library"
readonly property string tabLabel: "Wallpaper Selector"
readonly property int tabIndex: 7
spacing: Style.marginL * scaling spacing: Style.marginL * scaling

View file

@ -7,6 +7,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
ColumnLayout { ColumnLayout {
id: root
// Process to check if swww is installed // Process to check if swww is installed
Process { Process {