Settings: better horizontal dividers

This commit is contained in:
quadbyte 2025-08-06 20:03:41 -04:00
parent 7c2d2b4d66
commit 63eeb40c64
6 changed files with 980 additions and 856 deletions

View file

@ -1,26 +1,24 @@
import Quickshell
import Quickshell.Wayland
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Effects import QtQuick.Effects
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import qs.Components
import qs.Settings import qs.Settings
import qs.Widgets.SettingsWindow.Tabs import qs.Widgets.SettingsWindow.Tabs
import qs.Widgets.SettingsWindow.Tabs.Components import qs.Widgets.SettingsWindow.Tabs.Components
import qs.Components
PanelWithOverlay { PanelWithOverlay {
id: panelMain id: panelMain
property int activeTabIndex: 0 property int activeTabIndex: 0
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
// Function to show wallpaper selector // Function to show wallpaper selector
function showWallpaperSelector() { function showWallpaperSelector() {
if (wallpaperSelector) { if (wallpaperSelector)
wallpaperSelector.show(); wallpaperSelector.show();
}
} }
// Function to show settings window // Function to show settings window
@ -28,129 +26,138 @@ PanelWithOverlay {
show(); show();
} }
// Handle activeTabIndex changes
onActiveTabIndexChanged: {
if (activeTabIndex >= 0 && activeTabIndex <= 8) {
loadComponentForTab(activeTabIndex);
}
}
// Function to load component for a specific tab // Function to load component for a specific tab
function loadComponentForTab(tabIndex) { function loadComponentForTab(tabIndex) {
const componentMap = { const componentMap = {
0: generalSettings, "0": generalSettings,
1: barSettings, "1": barSettings,
2: timeWeatherSettings, "2": timeWeatherSettings,
3: recordingSettings, "3": recordingSettings,
4: networkSettings, "4": networkSettings,
5: displaySettings, "5": displaySettings,
6: wallpaperSettings, "6": wallpaperSettings,
7: miscSettings, "7": miscSettings,
8: aboutSettings "8": aboutSettings
}; };
const tabNames = ["General", "Bar", "Time & Weather", "Screen Recorder", "Network", "Display", "Wallpaper", "Misc", "About"];
const tabNames = [
"General",
"Bar",
"Time & Weather",
"Screen Recorder",
"Network",
"Display",
"Wallpaper",
"Misc",
"About"
];
if (componentMap[tabIndex]) { if (componentMap[tabIndex]) {
settingsLoader.sourceComponent = componentMap[tabIndex]; settingsLoader.sourceComponent = componentMap[tabIndex];
if (tabName) { if (tabName)
tabName.text = tabNames[tabIndex]; tabName.text = tabNames[tabIndex];
}
} }
} }
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
// Handle activeTabIndex changes
onActiveTabIndexChanged: {
if (activeTabIndex >= 0 && activeTabIndex <= 8)
loadComponentForTab(activeTabIndex);
}
// Add safety checks for component loading // Add safety checks for component loading
Component.onCompleted: { Component.onCompleted: {
// Ensure we start with a valid tab // Ensure we start with a valid tab
if (activeTabIndex < 0 || activeTabIndex > 8) { if (activeTabIndex < 0 || activeTabIndex > 8)
activeTabIndex = 0; activeTabIndex = 0;
}
}
}
// Cleanup when window is hidden // Cleanup when window is hidden
onVisibleChanged: { onVisibleChanged: {
if (!visible) { if (!visible) {
// Reset to default tab when hiding to prevent state issues // Reset to default tab when hiding to prevent state issues
activeTabIndex = 0; activeTabIndex = 0;
if (tabName) { if (tabName)
tabName.text = "General"; tabName.text = "General";
}
} }
} }
Component { Component {
id: generalSettings id: generalSettings
General {}
General {
}
} }
Component { Component {
id: barSettings id: barSettings
Bar {}
Bar {
}
} }
Component { Component {
id: timeWeatherSettings id: timeWeatherSettings
TimeWeather {}
TimeWeather {
}
} }
Component { Component {
id: recordingSettings id: recordingSettings
Recording {}
Recording {
}
} }
Component { Component {
id: networkSettings id: networkSettings
Network {}
Network {
}
} }
Component { Component {
id: miscSettings id: miscSettings
Misc {}
Misc {
}
} }
Component { Component {
id: aboutSettings id: aboutSettings
About {}
About {
}
} }
Component { Component {
id: displaySettings id: displaySettings
Display {}
Display {
}
} }
Component { Component {
id: wallpaperSettings id: wallpaperSettings
Wallpaper {}
Wallpaper {
}
} }
Rectangle { Rectangle {
id: settingsWindowRect id: settingsWindowRect
implicitWidth: Quickshell.screens.length > 0 ? Quickshell.screens[0].width / 2 : 600 implicitWidth: Quickshell.screens.length > 0 ? Quickshell.screens[0].width / 2 : 600
implicitHeight: Quickshell.screens.length > 0 ? Quickshell.screens[0].height / 2 : 400 implicitHeight: Quickshell.screens.length > 0 ? Quickshell.screens[0].height / 2 : 400
visible: parent.visible visible: parent.visible
color: "transparent" color: "transparent"
// Center the settings window on screen // Center the settings window on screen
anchors.centerIn: parent anchors.centerIn: parent
Rectangle { Rectangle {
id: background id: background
color: Theme.backgroundPrimary color: Theme.backgroundPrimary
anchors.fill: parent anchors.fill: parent
radius: 20 radius: 20
@ -167,11 +174,16 @@ PanelWithOverlay {
shadowVerticalOffset: 2 shadowVerticalOffset: 2
shadowBlur: 12 shadowBlur: 12
} }
} }
Rectangle { Rectangle {
id: settings id: settings
color: Theme.backgroundPrimary color: Theme.backgroundPrimary
topRightRadius: 20
bottomRightRadius: 20
anchors { anchors {
left: tabs.right left: tabs.right
top: parent.top top: parent.top
@ -179,151 +191,159 @@ PanelWithOverlay {
right: parent.right right: parent.right
margins: 12 margins: 12
} }
topRightRadius: 20
bottomRightRadius: 20
Rectangle { Rectangle {
id: headerArea id: headerArea
anchors {
top: parent.top
left: parent.left
right: parent.right
margins: 16
}
height: 48
color: "transparent"
RowLayout { height: 48
anchors.fill: parent color: "transparent"
spacing: 12
Text { anchors {
id: tabName top: parent.top
text: wallpaperSelector.visible ? "Select Wallpaper" : (activeTabIndex === 0 ? "General" : left: parent.left
activeTabIndex === 1 ? "Bar" : right: parent.right
activeTabIndex === 2 ? "Time & Weather" : margins: 16
activeTabIndex === 3 ? "Screen Recorder" :
activeTabIndex === 4 ? "Network" :
activeTabIndex === 5 ? "Display" :
activeTabIndex === 6 ? "Wallpaper" :
activeTabIndex === 7 ? "Misc" :
activeTabIndex === 8 ? "About" : "General")
font.pixelSize: 18
font.bold: true
color: Theme.textPrimary
Layout.fillWidth: true
} }
// Wallpaper Selection Button (only visible on Wallpaper tab) RowLayout {
Rectangle { anchors.fill: parent
width: 160 spacing: 12
height: 32
radius: 16
color: wallpaperButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Theme.accentPrimary
border.width: 1
visible: activeTabIndex === 6 // Wallpaper tab index
Row {
anchors.centerIn: parent
spacing: 6
Text {
text: "image"
font.family: wallpaperButtonArea.containsMouse ? "Material Symbols Rounded" : "Material Symbols Outlined"
font.pixelSize: 16
color: wallpaperButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: "Select Wallpaper"
font.pixelSize: 13
font.bold: true
color: wallpaperButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: wallpaperButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
// Show the wallpaper selector
wallpaperSelector.show();
}
}
}
Rectangle {
width: 32
height: 32
radius: 16
color: closeButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Theme.accentPrimary
border.width: 1
Text { Text {
anchors.centerIn: parent id: tabName
text: "close"
font.family: closeButtonArea.containsMouse ? "Material Symbols Rounded" : "Material Symbols Outlined" text: wallpaperSelector.visible ? "Select Wallpaper" : (activeTabIndex === 0 ? "General" : activeTabIndex === 1 ? "Bar" : activeTabIndex === 2 ? "Time & Weather" : activeTabIndex === 3 ? "Screen Recorder" : activeTabIndex === 4 ? "Network" : activeTabIndex === 5 ? "Display" : activeTabIndex === 6 ? "Wallpaper" : activeTabIndex === 7 ? "Misc" : activeTabIndex === 8 ? "About" : "General")
font.pixelSize: 18 font.pixelSize: 18
color: closeButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary font.bold: true
color: Theme.textPrimary
Layout.fillWidth: true
} }
MouseArea { // Wallpaper Selection Button (only visible on Wallpaper tab)
id: closeButtonArea Rectangle {
anchors.fill: parent width: 160
hoverEnabled: true height: 32
cursorShape: Qt.PointingHandCursor radius: 16
onClicked: panelMain.dismiss() color: wallpaperButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Theme.accentPrimary
border.width: 1
visible: activeTabIndex === 6 // Wallpaper tab index
Row {
anchors.centerIn: parent
spacing: 6
Text {
text: "image"
font.family: wallpaperButtonArea.containsMouse ? "Material Symbols Rounded" : "Material Symbols Outlined"
font.pixelSize: 16
color: wallpaperButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: "Select Wallpaper"
font.pixelSize: 13
font.bold: true
color: wallpaperButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: wallpaperButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
// Show the wallpaper selector
wallpaperSelector.show();
}
}
} }
Rectangle {
width: 32
height: 32
radius: 16
color: closeButtonArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Theme.accentPrimary
border.width: 1
Text {
anchors.centerIn: parent
text: "close"
font.family: closeButtonArea.containsMouse ? "Material Symbols Rounded" : "Material Symbols Outlined"
font.pixelSize: 18
color: closeButtonArea.containsMouse ? Theme.onAccent : Theme.accentPrimary
}
MouseArea {
id: closeButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: panelMain.dismiss()
}
}
} }
} }
Rectangle {
height: 1
color: Theme.outline
opacity: 0.3
anchors {
top: headerArea.bottom
left: parent.left
right: parent.right
margins: 16
}
}
Item {
id: settingsContainer
anchors {
top: headerArea.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
margins: 16
topMargin: 32
}
// Simplified single loader approach
Loader {
id: settingsLoader
anchors.fill: parent
sourceComponent: generalSettings
}
// Wallpaper Selector Component
WallpaperSelector {
id: wallpaperSelector
anchors.fill: parent
}
}
} }
Rectangle {
anchors {
top: headerArea.bottom
left: parent.left
right: parent.right
margins: 16
}
height: 1
color: Theme.outline
opacity: 0.3
}
Item {
id: settingsContainer
anchors {
top: headerArea.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
margins: 16
topMargin: 32
}
// Simplified single loader approach
Loader {
id: settingsLoader
anchors.fill: parent
sourceComponent: generalSettings
}
// Wallpaper Selector Component
WallpaperSelector {
id: wallpaperSelector
anchors.fill: parent
}
}
}
Rectangle { Rectangle {
id: tabs id: tabs
color: Theme.surface color: Theme.surface
width: Quickshell.screens.length > 0 ? Quickshell.screens[0].width / 9 : 100 width: Quickshell.screens.length > 0 ? Quickshell.screens[0].width / 9 : 100
height: settingsWindowRect.height height: settingsWindowRect.height
@ -332,101 +352,135 @@ PanelWithOverlay {
border.color: Theme.outline border.color: Theme.outline
border.width: 1 border.width: 1
Column { Column {
width: parent.width width: parent.width
spacing: 0 spacing: 0
topPadding: 8 topPadding: 8
bottomPadding: 8 bottomPadding: 8
Repeater { Repeater {
id: repeater id: repeater
model: [
{ icon: "tune", text: "General" },
{ icon: "space_dashboard", text: "Bar" },
{ icon: "schedule", text: "Time & Weather" },
{ icon: "photo_camera", text: "Screen Recorder" },
{ icon: "wifi", text: "Network" },
{ icon: "monitor", text: "Display" },
{ icon: "wallpaper", text: "Wallpaper" },
{ icon: "settings_suggest", text: "Misc" },
{ icon: "info", text: "About" }
]
delegate: Rectangle { model: [{
width: tabs.width "icon": "tune",
height: 48 "text": "General"
color: "transparent" }, {
"icon": "space_dashboard",
"text": "Bar"
}, {
"icon": "schedule",
"text": "Time & Weather"
}, {
"icon": "photo_camera",
"text": "Screen Recorder"
}, {
"icon": "wifi",
"text": "Network"
}, {
"icon": "monitor",
"text": "Display"
}, {
"icon": "wallpaper",
"text": "Wallpaper"
}, {
"icon": "settings_suggest",
"text": "Misc"
}, {
"icon": "info",
"text": "About"
}]
RowLayout { delegate: Rectangle {
anchors.fill: parent width: tabs.width
spacing: 8 height: 48
color: "transparent"
RowLayout {
anchors.fill: parent
spacing: 8
Rectangle {
id: activeIndicator
Layout.leftMargin: 8
Layout.preferredWidth: 3
Layout.preferredHeight: 24
Layout.alignment: Qt.AlignVCenter
radius: 2
color: Theme.accentPrimary
opacity: index === activeTabIndex ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
}
Label {
id: icon
text: modelData.icon
font.family: "Material Symbols Outlined"
font.pixelSize: 24
color: index === activeTabIndex ? Theme.accentPrimary : Theme.textPrimary
opacity: index === activeTabIndex ? 1 : 0.8
Layout.leftMargin: 20
Layout.preferredWidth: 24
Layout.preferredHeight: 24
Layout.alignment: Qt.AlignVCenter
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Label {
id: label
text: modelData.text
font.pixelSize: 16
color: index === activeTabIndex ? Theme.accentPrimary : (tabMouseArea.containsMouse ? Theme.accentPrimary : Theme.textSecondary)
font.weight: index === activeTabIndex ? Font.DemiBold : (tabMouseArea.containsMouse ? Font.DemiBold : Font.Normal)
Layout.fillWidth: true
Layout.preferredHeight: 24
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.leftMargin: 4
Layout.rightMargin: 16
verticalAlignment: Text.AlignVCenter
}
}
MouseArea {
id: tabMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
activeTabIndex = index;
loadComponentForTab(index);
}
}
Rectangle { Rectangle {
id: activeIndicator width: parent.width
Layout.leftMargin: 8 height: 1
Layout.preferredWidth: 3 color: Theme.outline
Layout.preferredHeight: 24 opacity: 0.6
Layout.alignment: Qt.AlignVCenter visible: index < (repeater.count - 1)
radius: 2 anchors.bottom: parent.bottom
color: Theme.accentPrimary
opacity: index === activeTabIndex ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 200 } }
} }
Label {
id: icon
text: modelData.icon
font.family: "Material Symbols Outlined"
font.pixelSize: 24
color: index === activeTabIndex ? Theme.accentPrimary : Theme.textPrimary
opacity: index === activeTabIndex ? 1 : 0.8
Layout.leftMargin: 20
Layout.preferredWidth: 24
Layout.preferredHeight: 24
Layout.alignment: Qt.AlignVCenter
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Label {
id: label
text: modelData.text
font.pixelSize: 16
color: index === activeTabIndex ? Theme.accentPrimary :
(tabMouseArea.containsMouse ? Theme.accentPrimary : Theme.textSecondary)
font.weight: index === activeTabIndex ? Font.DemiBold :
(tabMouseArea.containsMouse ? Font.DemiBold : Font.Normal)
Layout.fillWidth: true
Layout.preferredHeight: 24
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.leftMargin: 4
Layout.rightMargin: 16
verticalAlignment: Text.AlignVCenter
}
} }
MouseArea {
id: tabMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
activeTabIndex = index;
loadComponentForTab(index);
}
}
Rectangle {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.6
visible: index < (repeater.count - 1)
anchors.bottom: parent.bottom
}
} }
} }
} }
} }
}
} }

View file

@ -1,11 +1,11 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Effects import QtQuick.Effects
import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Settings
import qs.Components import qs.Components
import qs.Settings
Item { Item {
id: root id: root
@ -15,391 +15,430 @@ Item {
property var contributors: [] property var contributors: []
property string githubDataPath: Settings.settingsDir + "github_data.json" property string githubDataPath: Settings.settingsDir + "github_data.json"
function loadFromFile() {
const now = Date.now();
const data = githubData;
if (!data.timestamp || (now - data.timestamp > 3.6e+06)) {
console.log("[About] Cache expired or missing, fetching new data from GitHub...");
fetchFromGitHub();
return ;
}
console.log("[About] Loading cached GitHub data (age: " + Math.round((now - data.timestamp) / 60000) + " minutes)");
if (data.version)
root.latestVersion = data.version;
if (data.contributors)
root.contributors = data.contributors;
}
function fetchFromGitHub() {
versionProcess.running = true;
contributorsProcess.running = true;
}
function saveData() {
githubData.timestamp = Date.now();
Qt.callLater(() => {
githubDataFile.writeAdapter();
});
}
Process { Process {
id: currentVersionProcess id: currentVersionProcess
command: ["sh", "-c", "cd " + Quickshell.shellDir + " && git describe --tags --abbrev=0 2>/dev/null || echo 'Unknown'"] command: ["sh", "-c", "cd " + Quickshell.shellDir + " && git describe --tags --abbrev=0 2>/dev/null || echo 'Unknown'"]
Component.onCompleted: {
running = true;
}
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
const version = text.trim() const version = text.trim();
if (version && version !== "Unknown") { if (version && version !== "Unknown") {
root.currentVersion = version root.currentVersion = version;
} else { } else {
currentVersionProcess.command = ["sh", "-c", "cd " + Quickshell.shellDir + " && cat package.json 2>/dev/null | grep '\"version\"' | cut -d'\"' -f4 || echo 'Unknown'"];
currentVersionProcess.command = ["sh", "-c", "cd " + Quickshell.shellDir + " && cat package.json 2>/dev/null | grep '\"version\"' | cut -d'\"' -f4 || echo 'Unknown'"] currentVersionProcess.running = true;
currentVersionProcess.running = true
} }
} }
} }
Component.onCompleted: {
running = true
}
} }
FileView { FileView {
id: githubDataFile id: githubDataFile
path: root.githubDataPath path: root.githubDataPath
blockLoading: true blockLoading: true
printErrors: true printErrors: true
watchChanges: true watchChanges: true
onFileChanged: githubDataFile.reload()
onLoaded: loadFromFile()
onLoadFailed: function(error) {
console.log("GitHub data file doesn't exist yet, creating it...");
githubData.version = "Unknown";
githubData.contributors = [];
githubData.timestamp = 0;
githubDataFile.writeAdapter();
fetchFromGitHub();
}
Component.onCompleted: {
if (path)
reload();
}
JsonAdapter { JsonAdapter {
id: githubData id: githubData
property string version: "Unknown" property string version: "Unknown"
property var contributors: [] property var contributors: []
property double timestamp: 0 property double timestamp: 0
} }
onFileChanged: githubDataFile.reload()
onLoaded: loadFromFile()
onLoadFailed: function(error) {
console.log("GitHub data file doesn't exist yet, creating it...")
githubData.version = "Unknown"
githubData.contributors = []
githubData.timestamp = 0
githubDataFile.writeAdapter()
fetchFromGitHub()
}
Component.onCompleted: if (path) reload()
}
function loadFromFile() {
const now = Date.now()
const data = githubData
if (!data.timestamp || (now - data.timestamp > 3600000)) {
console.log("[About] Cache expired or missing, fetching new data from GitHub...")
fetchFromGitHub()
return
}
console.log("[About] Loading cached GitHub data (age: " + Math.round((now - data.timestamp) / 60000) + " minutes)")
if (data.version) {
root.latestVersion = data.version
}
if (data.contributors) {
root.contributors = data.contributors
}
} }
Process { Process {
id: versionProcess id: versionProcess
command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/releases/latest"] command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/releases/latest"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
try { try {
const data = JSON.parse(text) const data = JSON.parse(text);
if (data.tag_name) { if (data.tag_name) {
const version = data.tag_name const version = data.tag_name;
githubData.version = version githubData.version = version;
root.latestVersion = version root.latestVersion = version;
console.log("[About] Latest version fetched from GitHub:", version) console.log("[About] Latest version fetched from GitHub:", version);
} else { } else {
console.log("No tag_name in GitHub response") console.log("No tag_name in GitHub response");
} }
saveData() saveData();
} catch (e) { } catch (e) {
console.error("Failed to parse version:", e) console.error("Failed to parse version:", e);
} }
} }
} }
} }
Process { Process {
id: contributorsProcess id: contributorsProcess
command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/contributors?per_page=100"] command: ["curl", "-s", "https://api.github.com/repos/Ly-sec/Noctalia/contributors?per_page=100"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
try { try {
const data = JSON.parse(text) const data = JSON.parse(text);
githubData.contributors = data || [] githubData.contributors = data || [];
root.contributors = githubData.contributors root.contributors = githubData.contributors;
console.log("[About] Contributors data fetched from GitHub:", githubData.contributors.length, "contributors") console.log("[About] Contributors data fetched from GitHub:", githubData.contributors.length, "contributors");
saveData() saveData();
} catch (e) { } catch (e) {
console.error("Failed to parse contributors:", e) console.error("Failed to parse contributors:", e);
root.contributors = [] root.contributors = [];
} }
} }
} }
}
function fetchFromGitHub() {
versionProcess.running = true
contributorsProcess.running = true
}
function saveData() {
githubData.timestamp = Date.now()
Qt.callLater(() => {
githubDataFile.writeAdapter()
})
} }
Item { Item {
anchors.fill: parent anchors.fill: parent
ColumnLayout { ColumnLayout {
id: mainLayout id: mainLayout
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
spacing: 8 spacing: 8
Item { Item {
Layout.fillWidth: true
Layout.preferredHeight: 32
}
Text {
text: "Noctalia"
font.pixelSize: 24
font.bold: true
color: Theme.textPrimary
Layout.alignment: Qt.AlignCenter
}
GridLayout {
Layout.alignment: Qt.AlignCenter
columns: 2
rowSpacing: 4
columnSpacing: 8
Text {
text: "Latest Version:"
font.pixelSize: 16
color: Theme.textSecondary
Layout.alignment: Qt.AlignRight
}
Text {
text: root.latestVersion
font.pixelSize: 16
color: Theme.textPrimary
font.bold: true
}
Text {
text: "Installed Version:"
font.pixelSize: 16
color: Theme.textSecondary
Layout.alignment: Qt.AlignRight
}
Text {
text: root.currentVersion
font.pixelSize: 16
color: Theme.textPrimary
font.bold: true
}
}
Rectangle {
Layout.alignment: Qt.AlignCenter
Layout.topMargin: 8
Layout.preferredWidth: updateText.implicitWidth + 46
Layout.preferredHeight: 32
radius: 20
color: updateArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Theme.accentPrimary
border.width: 1
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 (let 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: 8
Text {
text: "system_update"
font.family: "Material Symbols Outlined"
font.pixelSize: 18
color: updateArea.containsMouse ? Theme.backgroundPrimary : Theme.accentPrimary
}
Text {
id: updateText
text: "Download latest release"
font.pixelSize: 14
color: updateArea.containsMouse ? Theme.backgroundPrimary : Theme.accentPrimary
}
}
MouseArea {
id: updateArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
Quickshell.execDetached(["xdg-open", "https://github.com/Ly-sec/Noctalia/releases/latest"])
}
}
}
Text {
text: "Description something something <.< I hate writing text..."
font.pixelSize: 14
color: Theme.textSecondary
Layout.alignment: Qt.AlignCenter
Layout.topMargin: 24
}
ColumnLayout {
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 32
Layout.rightMargin: 32
spacing: 16
RowLayout {
Layout.alignment: Qt.AlignCenter
spacing: 8
Text {
text: "Contributors"
font.pixelSize: 18
font.bold: true
color: Theme.textPrimary
}
Text {
text: "(" + root.contributors.length + ")"
font.pixelSize: 14
color: Theme.textSecondary
}
}
ScrollView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 300 Layout.preferredHeight: 16
clip: true }
Text {
text: "Noctalia"
font.pixelSize: 24
font.bold: true
color: Theme.textPrimary
Layout.alignment: Qt.AlignCenter
}
GridLayout {
Layout.alignment: Qt.AlignCenter
columns: 2
rowSpacing: 4
columnSpacing: 8
Text {
text: "Latest Version:"
font.pixelSize: 16
color: Theme.textSecondary
Layout.alignment: Qt.AlignRight
}
Text {
text: root.latestVersion
font.pixelSize: 16
color: Theme.textPrimary
font.bold: true
}
Text {
text: "Installed Version:"
font.pixelSize: 16
color: Theme.textSecondary
Layout.alignment: Qt.AlignRight
}
Text {
text: root.currentVersion
font.pixelSize: 16
color: Theme.textPrimary
font.bold: true
}
}
Rectangle {
Layout.alignment: Qt.AlignCenter
Layout.topMargin: 8
Layout.preferredWidth: updateText.implicitWidth + 46
Layout.preferredHeight: 32
radius: 20
color: updateArea.containsMouse ? Theme.accentPrimary : "transparent"
border.color: Theme.accentPrimary
border.width: 1
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 (let 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: 8
Text {
text: "system_update"
font.family: "Material Symbols Outlined"
font.pixelSize: 18
color: updateArea.containsMouse ? Theme.backgroundPrimary : Theme.accentPrimary
}
Text {
id: updateText
text: "Download latest release"
font.pixelSize: 14
color: updateArea.containsMouse ? Theme.backgroundPrimary : Theme.accentPrimary
}
}
MouseArea {
id: updateArea
Item {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
Quickshell.execDetached(["xdg-open", "https://github.com/Ly-sec/Noctalia/releases/latest"]);
}
}
GridView { }
id: contributorsGrid
anchors.centerIn: parent
width: Math.min(parent.width, Math.ceil(root.contributors.length / 3) * 200)
height: parent.height
cellWidth: 200
cellHeight: 110
model: root.contributors
delegate: Rectangle { Text {
width: contributorsGrid.cellWidth - 4 text: "Description something something <.< I hate writing text..."
height: contributorsGrid.cellHeight - 10 font.pixelSize: 14
radius: 20 color: Theme.textSecondary
color: contributorArea.containsMouse ? Theme.highlight : "transparent" Layout.alignment: Qt.AlignCenter
Layout.topMargin: 24
}
RowLayout { Rectangle {
anchors.fill: parent Layout.fillWidth: true
anchors.margins: 8 Layout.topMargin: 26
spacing: 12 Layout.bottomMargin: 18
height: 1
color: Theme.outline
opacity: 0.3
}
ColumnLayout {
Layout.fillWidth: true
Layout.leftMargin: 32
Layout.rightMargin: 32
spacing: 16
Item { RowLayout {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: 40 spacing: 8
Layout.preferredHeight: 40
Image { Text {
id: avatarImage text: "Contributors"
font.pixelSize: 18
font.bold: true
color: Theme.textPrimary
}
Text {
text: "(" + root.contributors.length + ")"
font.pixelSize: 14
color: Theme.textSecondary
}
}
ScrollView {
Layout.fillWidth: true
Layout.preferredHeight: 300
clip: true
Item {
anchors.fill: parent
GridView {
id: contributorsGrid
anchors.centerIn: parent
width: Math.min(parent.width, Math.ceil(root.contributors.length / 3) * 200)
height: parent.height
cellWidth: 200
cellHeight: 100
model: root.contributors
delegate: Rectangle {
width: contributorsGrid.cellWidth - 4
height: contributorsGrid.cellHeight - 10
radius: 20
color: contributorArea.containsMouse ? Theme.highlight : "transparent"
RowLayout {
anchors.fill: parent anchors.fill: parent
source: modelData.avatar_url || "" anchors.margins: 8
sourceSize: Qt.size(80, 80) spacing: 12
visible: false
mipmap: true Item {
smooth: true Layout.alignment: Qt.AlignVCenter
asynchronous: true Layout.preferredWidth: 40
fillMode: Image.PreserveAspectCrop Layout.preferredHeight: 40
cache: true
Image {
id: avatarImage
anchors.fill: parent
source: modelData.avatar_url || ""
sourceSize: Qt.size(80, 80)
visible: false
mipmap: true
smooth: true
asynchronous: true
fillMode: Image.PreserveAspectCrop
cache: true
}
MultiEffect {
anchors.fill: parent
source: avatarImage
maskEnabled: true
maskSource: mask
}
Item {
id: mask
anchors.fill: parent
layer.enabled: true
visible: false
Rectangle {
anchors.fill: parent
radius: avatarImage.width / 2
}
}
Text {
anchors.centerIn: parent
text: "person"
font.family: "Material Symbols Outlined"
font.pixelSize: 24
color: contributorArea.containsMouse ? Theme.backgroundPrimary : Theme.textPrimary
visible: !avatarImage.source || avatarImage.status !== Image.Ready
}
}
ColumnLayout {
spacing: 4
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
Text {
text: modelData.login || "Unknown"
font.pixelSize: 13
color: contributorArea.containsMouse ? Theme.backgroundPrimary : Theme.textPrimary
elide: Text.ElideRight
Layout.fillWidth: true
}
Text {
text: (modelData.contributions || 0) + " commits"
font.pixelSize: 11
color: contributorArea.containsMouse ? Theme.backgroundPrimary : Theme.textSecondary
}
}
} }
MultiEffect { MouseArea {
anchors.fill: parent id: contributorArea
source: avatarImage
maskEnabled: true
maskSource: mask
}
Item {
id: mask
anchors.fill: parent anchors.fill: parent
layer.enabled: true hoverEnabled: true
visible: false cursorShape: Qt.PointingHandCursor
Rectangle { onClicked: {
anchors.fill: parent if (modelData.html_url)
radius: avatarImage.width / 2 Quickshell.execDetached(["xdg-open", modelData.html_url]);
} }
} }
Text {
anchors.centerIn: parent
text: "person"
font.family: "Material Symbols Outlined"
font.pixelSize: 24
color: contributorArea.containsMouse ? Theme.backgroundPrimary : Theme.textPrimary
visible: !avatarImage.source || avatarImage.status !== Image.Ready
}
} }
ColumnLayout {
spacing: 4
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
Text {
text: modelData.login || "Unknown"
font.pixelSize: 13
color: contributorArea.containsMouse ? Theme.backgroundPrimary : Theme.textPrimary
elide: Text.ElideRight
Layout.fillWidth: true
}
Text {
text: (modelData.contributions || 0) + " commits"
font.pixelSize: 11
color: contributorArea.containsMouse ? Theme.backgroundPrimary : Theme.textSecondary
}
}
} }
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

@ -1,11 +1,12 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import qs.Settings
import qs.Components import qs.Components
import qs.Settings
ColumnLayout { ColumnLayout {
id: root id: root
spacing: 0 spacing: 0
anchors.fill: parent anchors.fill: parent
anchors.margins: 0 anchors.margins: 0
@ -15,7 +16,6 @@ ColumnLayout {
Layout.preferredHeight: 0 Layout.preferredHeight: 0
} }
ColumnLayout { ColumnLayout {
spacing: 4 spacing: 4
Layout.fillWidth: true Layout.fillWidth: true
@ -28,7 +28,6 @@ ColumnLayout {
Layout.bottomMargin: 8 Layout.bottomMargin: 8
} }
ColumnLayout { ColumnLayout {
spacing: 2 spacing: 2
Layout.fillWidth: true Layout.fillWidth: true
@ -67,7 +66,9 @@ ColumnLayout {
z: 2 z: 2
} }
Avatar {} Avatar {
}
} }
Rectangle { Rectangle {
@ -80,6 +81,7 @@ ColumnLayout {
TextInput { TextInput {
id: profileImageInput id: profileImageInput
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.rightMargin: 12 anchors.rightMargin: 12
@ -96,25 +98,27 @@ ColumnLayout {
onTextChanged: { onTextChanged: {
Settings.settings.profileImage = text; Settings.settings.profileImage = text;
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.IBeamCursor cursorShape: Qt.IBeamCursor
onClicked: profileImageInput.forceActiveFocus() onClicked: profileImageInput.forceActiveFocus()
} }
} }
} }
} }
} }
} }
Rectangle { Rectangle {
Layout.fillWidth: true
Layout.topMargin: 26 Layout.topMargin: 26
Layout.bottomMargin: 18 Layout.bottomMargin: 18
anchors {
top: headerArea.bottom
left: parent.left
right: parent.right
}
height: 1 height: 1
color: Theme.outline color: Theme.outline
opacity: 0.3 opacity: 0.3
@ -124,7 +128,6 @@ ColumnLayout {
spacing: 4 spacing: 4
Layout.fillWidth: true Layout.fillWidth: true
Text { Text {
text: "User Interface" text: "User Interface"
font.pixelSize: 18 font.pixelSize: 18
@ -133,7 +136,6 @@ ColumnLayout {
Layout.bottomMargin: 8 Layout.bottomMargin: 8
} }
ColumnLayout { ColumnLayout {
spacing: 4 spacing: 4
Layout.fillWidth: true Layout.fillWidth: true
@ -160,10 +162,12 @@ ColumnLayout {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
Rectangle { Rectangle {
id: cornersSwitch id: cornersSwitch
width: 52 width: 52
height: 32 height: 32
radius: 16 radius: 16
@ -173,6 +177,7 @@ ColumnLayout {
Rectangle { Rectangle {
id: cornersThumb id: cornersThumb
width: 28 width: 28
height: 28 height: 28
radius: 14 radius: 14
@ -187,7 +192,9 @@ ColumnLayout {
duration: 200 duration: 200
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
} }
} }
MouseArea { MouseArea {
@ -197,10 +204,12 @@ ColumnLayout {
Settings.settings.showCorners = !Settings.settings.showCorners; Settings.settings.showCorners = !Settings.settings.showCorners;
} }
} }
}
}
}
}
}
}
ColumnLayout { ColumnLayout {
spacing: 8 spacing: 8
@ -229,10 +238,12 @@ ColumnLayout {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
Rectangle { Rectangle {
id: dockSwitch id: dockSwitch
width: 52 width: 52
height: 32 height: 32
radius: 16 radius: 16
@ -242,6 +253,7 @@ ColumnLayout {
Rectangle { Rectangle {
id: dockThumb id: dockThumb
width: 28 width: 28
height: 28 height: 28
radius: 14 radius: 14
@ -256,7 +268,9 @@ ColumnLayout {
duration: 200 duration: 200
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
} }
} }
MouseArea { MouseArea {
@ -266,10 +280,12 @@ ColumnLayout {
Settings.settings.showDock = !Settings.settings.showDock; Settings.settings.showDock = !Settings.settings.showDock;
} }
} }
}
}
}
}
}
}
ColumnLayout { ColumnLayout {
spacing: 8 spacing: 8
@ -298,10 +314,12 @@ ColumnLayout {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
Rectangle { Rectangle {
id: dimSwitch id: dimSwitch
width: 52 width: 52
height: 32 height: 32
radius: 16 radius: 16
@ -311,6 +329,7 @@ ColumnLayout {
Rectangle { Rectangle {
id: dimThumb id: dimThumb
width: 28 width: 28
height: 28 height: 28
radius: 14 radius: 14
@ -325,7 +344,9 @@ ColumnLayout {
duration: 200 duration: 200
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
} }
} }
MouseArea { MouseArea {
@ -335,13 +356,18 @@ ColumnLayout {
Settings.settings.dimPanels = !Settings.settings.dimPanels; Settings.settings.dimPanels = !Settings.settings.dimPanels;
} }
} }
} }
} }
} }
} }
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
} }
} }

View file

@ -97,19 +97,14 @@ ColumnLayout {
} }
} }
Rectangle { Rectangle {
Layout.topMargin: 26 Layout.fillWidth: true
Layout.bottomMargin: 18 Layout.topMargin: 26
anchors { Layout.bottomMargin: 18
top: headerArea.bottom height: 1
left: parent.left color: Theme.outline
right: parent.right opacity: 0.3
} }
height: 1
color: Theme.outline
opacity: 0.3
}
ColumnLayout { ColumnLayout {
spacing: 16 spacing: 16

View file

@ -1,12 +1,13 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import qs.Settings
import qs.Components import qs.Components
import qs.Settings
import qs.Widgets.SettingsWindow.Tabs.Components import qs.Widgets.SettingsWindow.Tabs.Components
ColumnLayout { ColumnLayout {
id: root id: root
spacing: 0 spacing: 0
anchors.fill: parent anchors.fill: parent
anchors.margins: 0 anchors.margins: 0
@ -16,7 +17,6 @@ ColumnLayout {
Layout.preferredHeight: 0 Layout.preferredHeight: 0
} }
ColumnLayout { ColumnLayout {
spacing: 4 spacing: 4
Layout.fillWidth: true Layout.fillWidth: true
@ -29,7 +29,6 @@ ColumnLayout {
Layout.bottomMargin: 8 Layout.bottomMargin: 8
} }
ColumnLayout { ColumnLayout {
spacing: 8 spacing: 8
Layout.fillWidth: true Layout.fillWidth: true
@ -57,10 +56,12 @@ ColumnLayout {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
Rectangle { Rectangle {
id: use12HourClockSwitch id: use12HourClockSwitch
width: 52 width: 52
height: 32 height: 32
radius: 16 radius: 16
@ -70,6 +71,7 @@ ColumnLayout {
Rectangle { Rectangle {
id: use12HourClockThumb id: use12HourClockThumb
width: 28 width: 28
height: 28 height: 28
radius: 14 radius: 14
@ -84,7 +86,9 @@ ColumnLayout {
duration: 200 duration: 200
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
} }
} }
MouseArea { MouseArea {
@ -94,10 +98,12 @@ ColumnLayout {
Settings.settings.use12HourClock = !Settings.settings.use12HourClock; Settings.settings.use12HourClock = !Settings.settings.use12HourClock;
} }
} }
}
}
}
}
}
}
ColumnLayout { ColumnLayout {
spacing: 8 spacing: 8
@ -126,10 +132,12 @@ ColumnLayout {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
Rectangle { Rectangle {
id: reverseDayMonthSwitch id: reverseDayMonthSwitch
width: 52 width: 52
height: 32 height: 32
radius: 16 radius: 16
@ -139,6 +147,7 @@ ColumnLayout {
Rectangle { Rectangle {
id: reverseDayMonthThumb id: reverseDayMonthThumb
width: 28 width: 28
height: 28 height: 28
radius: 14 radius: 14
@ -153,7 +162,9 @@ ColumnLayout {
duration: 200 duration: 200
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
} }
} }
MouseArea { MouseArea {
@ -163,25 +174,24 @@ ColumnLayout {
Settings.settings.reverseDayMonth = !Settings.settings.reverseDayMonth; Settings.settings.reverseDayMonth = !Settings.settings.reverseDayMonth;
} }
} }
} }
} }
} }
} }
Rectangle { Rectangle {
Layout.fillWidth: true
Layout.topMargin: 26 Layout.topMargin: 26
Layout.bottomMargin: 18 Layout.bottomMargin: 18
anchors {
top: headerArea.bottom
left: parent.left
right: parent.right
}
height: 1 height: 1
color: Theme.outline color: Theme.outline
opacity: 0.3 opacity: 0.3
} }
ColumnLayout { ColumnLayout {
spacing: 4 spacing: 4
Layout.fillWidth: true Layout.fillWidth: true
@ -194,7 +204,6 @@ ColumnLayout {
Layout.bottomMargin: 8 Layout.bottomMargin: 8
} }
ColumnLayout { ColumnLayout {
spacing: 8 spacing: 8
Layout.fillWidth: true Layout.fillWidth: true
@ -223,6 +232,7 @@ ColumnLayout {
TextInput { TextInput {
id: cityInput id: cityInput
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.rightMargin: 12 anchors.rightMargin: 12
@ -237,7 +247,6 @@ ColumnLayout {
selectByMouse: true selectByMouse: true
activeFocusOnTab: true activeFocusOnTab: true
inputMethodHints: Qt.ImhNone inputMethodHints: Qt.ImhNone
onTextChanged: { onTextChanged: {
Settings.settings.weatherCity = text; Settings.settings.weatherCity = text;
} }
@ -249,10 +258,12 @@ ColumnLayout {
cityInput.forceActiveFocus(); cityInput.forceActiveFocus();
} }
} }
}
}
}
}
}
}
ColumnLayout { ColumnLayout {
spacing: 8 spacing: 8
@ -281,15 +292,21 @@ ColumnLayout {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
} }
}
UnitSelector {
} }
UnitSelector {}
} }
} }
} }
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
} }
} }

View file

@ -122,264 +122,101 @@ ColumnLayout {
} }
} }
} }
Rectangle { }
Layout.topMargin: 26
Layout.bottomMargin: 18 Rectangle {
anchors { Layout.fillWidth: true
top: headerArea.bottom Layout.topMargin: 26
left: parent.left Layout.bottomMargin: 18
right: parent.right height: 1
} color: Theme.outline
height: 1 opacity: 0.3
color: Theme.outline }
opacity: 0.3
ColumnLayout {
spacing: 4
Layout.fillWidth: true
Text {
text: "Automation"
font.pixelSize: 18
font.bold: true
color: Theme.textPrimary
Layout.bottomMargin: 8
} }
// Random Wallpaper
ColumnLayout { ColumnLayout {
spacing: 4 spacing: 8
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8
Text { RowLayout {
text: "Automation"
font.pixelSize: 18
font.bold: true
color: Theme.textPrimary
Layout.bottomMargin: 8
}
// Random Wallpaper
ColumnLayout {
spacing: 8 spacing: 8
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8
RowLayout { ColumnLayout {
spacing: 8 spacing: 4
Layout.fillWidth: true
ColumnLayout {
spacing: 4
Layout.fillWidth: true
Text {
text: "Random Wallpaper"
font.pixelSize: 13
font.bold: true
color: Theme.textPrimary
}
Text {
text: "Automatically select random wallpapers from the folder"
font.pixelSize: 12
color: Theme.textSecondary
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
Rectangle {
id: randomWallpaperSwitch
width: 52
height: 32
radius: 16
color: Settings.settings.randomWallpaper ? Theme.accentPrimary : Theme.surfaceVariant
border.color: Settings.settings.randomWallpaper ? Theme.accentPrimary : Theme.outline
border.width: 2
Rectangle {
id: randomWallpaperThumb
width: 28
height: 28
radius: 14
color: Theme.surface
border.color: Theme.outline
border.width: 1
y: 2
x: Settings.settings.randomWallpaper ? randomWallpaperSwitch.width - width - 2 : 2
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
Settings.settings.randomWallpaper = !Settings.settings.randomWallpaper;
}
}
}
}
}
// Use Wallpaper Theme
ColumnLayout {
spacing: 8
Layout.fillWidth: true
Layout.topMargin: 8
RowLayout {
spacing: 8
Layout.fillWidth: true
ColumnLayout {
spacing: 4
Layout.fillWidth: true
Text {
text: "Use Wallpaper Theme"
font.pixelSize: 13
font.bold: true
color: Theme.textPrimary
}
Text {
text: "Automatically adjust theme colors based on wallpaper"
font.pixelSize: 12
color: Theme.textSecondary
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
Rectangle {
id: wallpaperThemeSwitch
width: 52
height: 32
radius: 16
color: Settings.settings.useWallpaperTheme ? Theme.accentPrimary : Theme.surfaceVariant
border.color: Settings.settings.useWallpaperTheme ? Theme.accentPrimary : Theme.outline
border.width: 2
Rectangle {
id: wallpaperThemeThumb
width: 28
height: 28
radius: 14
color: Theme.surface
border.color: Theme.outline
border.width: 1
y: 2
x: Settings.settings.useWallpaperTheme ? wallpaperThemeSwitch.width - width - 2 : 2
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
Settings.settings.useWallpaperTheme = !Settings.settings.useWallpaperTheme;
}
}
}
}
}
// Wallpaper Interval
ColumnLayout {
spacing: 8
Layout.fillWidth: true
Layout.topMargin: 8
Text {
text: "Wallpaper Interval"
font.pixelSize: 13
font.bold: true
color: Theme.textPrimary
}
Text {
text: "How often to change wallpapers automatically (in seconds)"
font.pixelSize: 12
color: Theme.textSecondary
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Text { Text {
text: Settings.settings.wallpaperInterval + " seconds" text: "Random Wallpaper"
font.pixelSize: 13 font.pixelSize: 13
font.bold: true
color: Theme.textPrimary color: Theme.textPrimary
} }
Item { Text {
text: "Automatically select random wallpapers from the folder"
font.pixelSize: 12
color: Theme.textSecondary
wrapMode: Text.WordWrap
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
Slider { Rectangle {
id: intervalSlider id: randomWallpaperSwitch
Layout.fillWidth: true width: 52
from: 10 height: 32
to: 900 radius: 16
stepSize: 10 color: Settings.settings.randomWallpaper ? Theme.accentPrimary : Theme.surfaceVariant
value: Settings.settings.wallpaperInterval border.color: Settings.settings.randomWallpaper ? Theme.accentPrimary : Theme.outline
snapMode: Slider.SnapAlways border.width: 2
onMoved: {
Settings.settings.wallpaperInterval = Math.round(value);
}
background: Rectangle { Rectangle {
x: intervalSlider.leftPadding id: randomWallpaperThumb
y: intervalSlider.topPadding + intervalSlider.availableHeight / 2 - height / 2
implicitWidth: 200 width: 28
implicitHeight: 4 height: 28
width: intervalSlider.availableWidth radius: 14
height: implicitHeight color: Theme.surface
radius: 2 border.color: Theme.outline
color: Theme.surfaceVariant border.width: 1
y: 2
x: Settings.settings.randomWallpaper ? randomWallpaperSwitch.width - width - 2 : 2
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
Rectangle {
width: intervalSlider.visualPosition * parent.width
height: parent.height
color: Theme.accentPrimary
radius: 2
} }
} }
handle: Rectangle { MouseArea {
x: intervalSlider.leftPadding + intervalSlider.visualPosition * (intervalSlider.availableWidth - width) anchors.fill: parent
y: intervalSlider.topPadding + intervalSlider.availableHeight / 2 - height / 2 cursorShape: Qt.PointingHandCursor
implicitWidth: 20 onClicked: {
implicitHeight: 20 Settings.settings.randomWallpaper = !Settings.settings.randomWallpaper;
radius: 10 }
color: intervalSlider.pressed ? Theme.surfaceVariant : Theme.surface
border.color: Theme.accentPrimary
border.width: 2
} }
} }
@ -388,16 +225,172 @@ ColumnLayout {
} }
// Use Wallpaper Theme
ColumnLayout {
spacing: 8
Layout.fillWidth: true
Layout.topMargin: 8
RowLayout {
spacing: 8
Layout.fillWidth: true
ColumnLayout {
spacing: 4
Layout.fillWidth: true
Text {
text: "Use Wallpaper Theme"
font.pixelSize: 13
font.bold: true
color: Theme.textPrimary
}
Text {
text: "Automatically adjust theme colors based on wallpaper"
font.pixelSize: 12
color: Theme.textSecondary
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
Rectangle {
id: wallpaperThemeSwitch
width: 52
height: 32
radius: 16
color: Settings.settings.useWallpaperTheme ? Theme.accentPrimary : Theme.surfaceVariant
border.color: Settings.settings.useWallpaperTheme ? Theme.accentPrimary : Theme.outline
border.width: 2
Rectangle {
id: wallpaperThemeThumb
width: 28
height: 28
radius: 14
color: Theme.surface
border.color: Theme.outline
border.width: 1
y: 2
x: Settings.settings.useWallpaperTheme ? wallpaperThemeSwitch.width - width - 2 : 2
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
Settings.settings.useWallpaperTheme = !Settings.settings.useWallpaperTheme;
}
}
}
}
}
// Wallpaper Interval
ColumnLayout {
spacing: 8
Layout.fillWidth: true
Layout.topMargin: 8
Text {
text: "Wallpaper Interval"
font.pixelSize: 13
font.bold: true
color: Theme.textPrimary
}
Text {
text: "How often to change wallpapers automatically (in seconds)"
font.pixelSize: 12
color: Theme.textSecondary
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
RowLayout {
Layout.fillWidth: true
Text {
text: Settings.settings.wallpaperInterval + " seconds"
font.pixelSize: 13
color: Theme.textPrimary
}
Item {
Layout.fillWidth: true
}
}
Slider {
id: intervalSlider
Layout.fillWidth: true
from: 10
to: 900
stepSize: 10
value: Settings.settings.wallpaperInterval
snapMode: Slider.SnapAlways
onMoved: {
Settings.settings.wallpaperInterval = Math.round(value);
}
background: Rectangle {
x: intervalSlider.leftPadding
y: intervalSlider.topPadding + intervalSlider.availableHeight / 2 - height / 2
implicitWidth: 200
implicitHeight: 4
width: intervalSlider.availableWidth
height: implicitHeight
radius: 2
color: Theme.surfaceVariant
Rectangle {
width: intervalSlider.visualPosition * parent.width
height: parent.height
color: Theme.accentPrimary
radius: 2
}
}
handle: Rectangle {
x: intervalSlider.leftPadding + intervalSlider.visualPosition * (intervalSlider.availableWidth - width)
y: intervalSlider.topPadding + intervalSlider.availableHeight / 2 - height / 2
implicitWidth: 20
implicitHeight: 20
radius: 10
color: intervalSlider.pressed ? Theme.surfaceVariant : Theme.surface
border.color: Theme.accentPrimary
border.width: 2
}
}
}
} }
Rectangle { Rectangle {
Layout.fillWidth: true
Layout.topMargin: 26 Layout.topMargin: 26
Layout.bottomMargin: 18 Layout.bottomMargin: 18
anchors {
top: headerArea.bottom
left: parent.left
right: parent.right
}
height: 1 height: 1
color: Theme.outline color: Theme.outline
opacity: 0.3 opacity: 0.3