feat: init quickshell

This commit is contained in:
2025-07-13 22:10:17 +08:00
parent a63be876f7
commit 237a62ea8a
103 changed files with 14997 additions and 498 deletions

View File

@@ -0,0 +1,758 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "root:/Data" as Data
// Appearance settings content
Column {
width: parent.width
spacing: 20
// Theme Setting in Collapsible Section
SettingsCategory {
width: parent.width
title: "Theme Setting"
icon: "palette"
content: Component {
Column {
width: parent.width
spacing: 30 // Increased spacing between major sections
// Dark/Light Mode Switch
Column {
width: parent.width
spacing: 12
Text {
text: "Theme Mode"
color: Data.ThemeManager.fgColor
font.pixelSize: 15
font.bold: true
font.family: "monospace"
}
Row {
spacing: 16
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: "Light"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
}
// Toggle switch - enhanced design
Rectangle {
width: 64
height: 32
radius: 16
color: Data.ThemeManager.currentTheme.type === "dark" ? Qt.lighter(Data.ThemeManager.accentColor, 0.8) : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.2)
border.width: 2
border.color: Data.ThemeManager.currentTheme.type === "dark" ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.4)
anchors.verticalCenter: parent.verticalCenter
// Inner track shadow
Rectangle {
anchors.fill: parent
anchors.margins: 2
radius: parent.radius - 2
color: "transparent"
border.width: 1
border.color: Qt.rgba(0, 0, 0, 0.1)
}
// Toggle handle
Rectangle {
id: toggleHandle
width: 26
height: 26
radius: 13
color: Data.ThemeManager.currentTheme.type === "dark" ? Data.ThemeManager.bgColor : Data.ThemeManager.panelBackground
border.width: 2
border.color: Data.ThemeManager.currentTheme.type === "dark" ? Data.ThemeManager.accentColor : Data.ThemeManager.fgColor
anchors.verticalCenter: parent.verticalCenter
x: Data.ThemeManager.currentTheme.type === "dark" ? parent.width - width - 3 : 3
// Handle shadow
Rectangle {
anchors.centerIn: parent
anchors.verticalCenterOffset: 1
width: parent.width - 2
height: parent.height - 2
radius: parent.radius - 1
color: Qt.rgba(0, 0, 0, 0.1)
z: -1
}
// Handle highlight
Rectangle {
anchors.centerIn: parent
width: parent.width - 6
height: parent.height - 6
radius: parent.radius - 3
color: Qt.rgba(255, 255, 255, 0.15)
}
Behavior on x {
NumberAnimation {
duration: 250
easing.type: Easing.OutBack
easing.overshoot: 0.3
}
}
Behavior on border.color {
ColorAnimation {
duration: 200
}
}
}
// Background color transition
Behavior on color {
ColorAnimation {
duration: 200
}
}
Behavior on border.color {
ColorAnimation {
duration: 200
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: {
console.log("Theme switch clicked, current:", Data.ThemeManager.currentThemeId);
var currentFamily = Data.ThemeManager.currentThemeId.replace(/_dark$|_light$/, "");
var newType = Data.ThemeManager.currentTheme.type === "dark" ? "light" : "dark";
var newThemeId = currentFamily + "_" + newType;
console.log("Switching to:", newThemeId);
Data.ThemeManager.setTheme(newThemeId);
// Force update the settings if currentTheme isn't being saved properly
if (!Data.Settings.currentTheme) {
Data.Settings.currentTheme = newThemeId;
Data.Settings.saveSettings();
}
}
onEntered: {
parent.scale = 1.05;
}
onExited: {
parent.scale = 1.0;
}
}
Behavior on scale {
NumberAnimation {
duration: 150
easing.type: Easing.OutQuad
}
}
}
Text {
text: "Dark"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
}
}
}
// Separator
Rectangle {
width: parent.width - 40
height: 1
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.1)
anchors.horizontalCenter: parent.horizontalCenter
}
// Theme Selection
Column {
width: parent.width
spacing: 12
Text {
text: "Theme Family"
color: Data.ThemeManager.fgColor
font.pixelSize: 15
font.bold: true
font.family: "monospace"
}
Text {
text: "Choose your preferred theme family"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
anchors.horizontalCenter: parent.horizontalCenter
}
// Compact 2x2 grid for themes
GridLayout {
columns: 2
columnSpacing: 8
rowSpacing: 8
anchors.horizontalCenter: parent.horizontalCenter
property var themeFamily: {
var currentFamily = Data.ThemeManager.currentThemeId.replace(/_dark$|_light$/, "");
return currentFamily;
}
property var themeFamilies: [
{
id: "oxocarbon",
name: "Oxocarbon",
description: "IBM Carbon"
},
{
id: "dracula",
name: "Dracula",
description: "Vibrant"
},
{
id: "gruvbox",
name: "Gruvbox",
description: "Retro"
},
{
id: "catppuccin",
name: "Catppuccin",
description: "Pastel"
},
{
id: "matugen",
name: "Matugen",
description: "Generated"
}
]
Repeater {
model: parent.themeFamilies
delegate: Rectangle {
Layout.preferredWidth: 140
Layout.preferredHeight: 50
radius: 10
color: parent.themeFamily === modelData.id ? Data.ThemeManager.accentColor : Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: parent.themeFamily === modelData.id ? 2 : 1
border.color: parent.themeFamily === modelData.id ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Row {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 10
spacing: 6
// Compact theme preview colors
Row {
spacing: 1
property var previewTheme: Data.ThemeManager.themes[modelData.id + "_" + Data.ThemeManager.currentTheme.type] || Data.ThemeManager.themes[modelData.id + "_dark"]
Rectangle {
width: 4
height: 14
radius: 1
color: parent.previewTheme.base00
}
Rectangle {
width: 4
height: 14
radius: 1
color: parent.previewTheme.base0E
}
Rectangle {
width: 4
height: 14
radius: 1
color: parent.previewTheme.base0D
}
Rectangle {
width: 4
height: 14
radius: 1
color: parent.previewTheme.base0B
}
}
Column {
spacing: 1
anchors.verticalCenter: parent.verticalCenter
Text {
text: modelData.name
color: parent.parent.parent.parent.themeFamily === modelData.id ? Data.ThemeManager.bgColor : Data.ThemeManager.fgColor
font.pixelSize: 12
font.bold: parent.parent.parent.parent.themeFamily === modelData.id
font.family: "monospace"
}
Text {
text: modelData.description
color: parent.parent.parent.parent.themeFamily === modelData.id ? Qt.rgba(Data.ThemeManager.bgColor.r, Data.ThemeManager.bgColor.g, Data.ThemeManager.bgColor.b, 0.8) : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.6)
font.pixelSize: 9
font.family: "monospace"
}
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: {
var themeType = Data.ThemeManager.currentTheme.type;
var newThemeId = modelData.id + "_" + themeType;
console.log("Theme card clicked:", newThemeId);
Data.ThemeManager.setTheme(newThemeId);
}
onEntered: {
parent.scale = 1.02;
}
onExited: {
parent.scale = 1.0;
}
}
Behavior on scale {
NumberAnimation {
duration: 150
easing.type: Easing.OutQuad
}
}
}
}
}
}
// Separator
Rectangle {
width: parent.width - 40
height: 1
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.1)
anchors.horizontalCenter: parent.horizontalCenter
}
// Accent Colors
Column {
width: parent.width
spacing: 12
Text {
text: "Accent Colors"
color: Data.ThemeManager.fgColor
font.pixelSize: 15
font.bold: true
font.family: "monospace"
}
Text {
text: "Choose your preferred accent color for " + Data.ThemeManager.currentTheme.name
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
wrapMode: Text.Wrap
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
}
// Compact flow layout for accent colors
Flow {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 20 // Margins to prevent clipping
spacing: 8
property var accentColors: {
var currentFamily = Data.ThemeManager.currentThemeId.replace(/_dark$|_light$/, "");
var themeColors = [];
// Theme-specific accent colors - reduced to 5 per theme for compactness
if (currentFamily === "dracula") {
themeColors.push({
name: "Magenta",
dark: "#ff79c6",
light: "#e91e63"
}, {
name: "Purple",
dark: "#bd93f9",
light: "#6c7ce0"
}, {
name: "Cyan",
dark: "#8be9fd",
light: "#17a2b8"
}, {
name: "Green",
dark: "#50fa7b",
light: "#27ae60"
}, {
name: "Orange",
dark: "#ffb86c",
light: "#f39c12"
});
} else if (currentFamily === "gruvbox") {
themeColors.push({
name: "Orange",
dark: "#fe8019",
light: "#d65d0e"
}, {
name: "Red",
dark: "#fb4934",
light: "#cc241d"
}, {
name: "Yellow",
dark: "#fabd2f",
light: "#d79921"
}, {
name: "Green",
dark: "#b8bb26",
light: "#98971a"
}, {
name: "Purple",
dark: "#d3869b",
light: "#b16286"
});
} else if (currentFamily === "catppuccin") {
themeColors.push({
name: "Mauve",
dark: "#cba6f7",
light: "#8839ef"
}, {
name: "Blue",
dark: "#89b4fa",
light: "#1e66f5"
}, {
name: "Teal",
dark: "#94e2d5",
light: "#179299"
}, {
name: "Green",
dark: "#a6e3a1",
light: "#40a02b"
}, {
name: "Peach",
dark: "#fab387",
light: "#fe640b"
});
} else if (currentFamily === "matugen") {
// Use dynamic matugen colors if available
if (Data.ThemeManager.matugen && Data.ThemeManager.matugen.isMatugenActive()) {
themeColors.push({
name: "Primary",
dark: Data.ThemeManager.matugen.getMatugenColor("primary") || "#adc6ff",
light: Data.ThemeManager.matugen.getMatugenColor("primary") || "#0f62fe"
}, {
name: "Secondary",
dark: Data.ThemeManager.matugen.getMatugenColor("secondary") || "#bfc6dc",
light: Data.ThemeManager.matugen.getMatugenColor("secondary") || "#6272a4"
}, {
name: "Tertiary",
dark: Data.ThemeManager.matugen.getMatugenColor("tertiary") || "#debcdf",
light: Data.ThemeManager.matugen.getMatugenColor("tertiary") || "#b16286"
}, {
name: "Surface",
dark: Data.ThemeManager.matugen.getMatugenColor("surface_tint") || "#adc6ff",
light: Data.ThemeManager.matugen.getMatugenColor("surface_tint") || "#0f62fe"
}, {
name: "Error",
dark: Data.ThemeManager.matugen.getMatugenColor("error") || "#ffb4ab",
light: Data.ThemeManager.matugen.getMatugenColor("error") || "#ba1a1a"
});
} else {
// Fallback matugen colors
themeColors.push({
name: "Primary",
dark: "#adc6ff",
light: "#0f62fe"
}, {
name: "Secondary",
dark: "#bfc6dc",
light: "#6272a4"
}, {
name: "Tertiary",
dark: "#debcdf",
light: "#b16286"
}, {
name: "Surface",
dark: "#adc6ff",
light: "#0f62fe"
}, {
name: "Error",
dark: "#ffb4ab",
light: "#ba1a1a"
});
}
} else {
// oxocarbon and fallback
themeColors.push({
name: "Purple",
dark: "#be95ff",
light: "#8a3ffc"
}, {
name: "Blue",
dark: "#78a9ff",
light: "#0f62fe"
}, {
name: "Cyan",
dark: "#3ddbd9",
light: "#007d79"
}, {
name: "Green",
dark: "#42be65",
light: "#198038"
}, {
name: "Pink",
dark: "#ff7eb6",
light: "#d12771"
});
}
return themeColors;
}
Repeater {
model: parent.accentColors
delegate: Rectangle {
width: 60
height: 50
radius: 10
color: Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: Data.ThemeManager.accentColor.toString() === (Data.ThemeManager.currentTheme.type === "dark" ? modelData.dark : modelData.light) ? 3 : 1
border.color: Data.ThemeManager.accentColor.toString() === (Data.ThemeManager.currentTheme.type === "dark" ? modelData.dark : modelData.light) ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Column {
anchors.centerIn: parent
spacing: 4
Rectangle {
width: 20
height: 20
radius: 10
color: Data.ThemeManager.currentTheme.type === "dark" ? modelData.dark : modelData.light
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: modelData.name
color: Data.ThemeManager.fgColor
font.pixelSize: 9
font.family: "monospace"
font.bold: true
anchors.horizontalCenter: parent.horizontalCenter
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: {
// Set custom accent
Data.Settings.useCustomAccent = true;
Data.ThemeManager.setCustomAccent(modelData.dark, modelData.light);
}
onEntered: {
parent.scale = 1.05;
}
onExited: {
parent.scale = 1.0;
}
}
Behavior on scale {
NumberAnimation {
duration: 150
easing.type: Easing.OutQuad
}
}
}
}
}
}
}
}
}
// Animation Settings in Collapsible Section
SettingsCategory {
width: parent.width
title: "Animation Settings"
icon: "animation"
content: Component {
Column {
width: parent.width
spacing: 20
Text {
text: "Configure workspace change animations"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
anchors.horizontalCenter: parent.horizontalCenter
}
// Workspace Burst Toggle
Row {
width: parent.width
height: 40
Column {
anchors.verticalCenter: parent.verticalCenter
width: parent.width - 80
Text {
text: "Workspace Burst Effect"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
}
Text {
text: "Expanding rings when switching workspaces"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.6)
font.pixelSize: 11
font.family: "monospace"
}
}
// Toggle switch for burst
Rectangle {
width: 50
height: 25
radius: 12.5
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
color: Data.Settings.workspaceBurstEnabled ? Qt.lighter(Data.ThemeManager.accentColor, 0.8) : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.2)
border.width: 1
border.color: Data.Settings.workspaceBurstEnabled ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.4)
Rectangle {
width: 20
height: 20
radius: 10
color: Data.ThemeManager.bgColor
border.width: 1.5
border.color: Data.Settings.workspaceBurstEnabled ? Data.ThemeManager.accentColor : Data.ThemeManager.fgColor
anchors.verticalCenter: parent.verticalCenter
x: Data.Settings.workspaceBurstEnabled ? parent.width - width - 2.5 : 2.5
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutQuad
}
}
}
Behavior on color {
ColorAnimation {
duration: 200
}
}
Behavior on border.color {
ColorAnimation {
duration: 200
}
}
MouseArea {
anchors.fill: parent
onClicked: {
Data.Settings.workspaceBurstEnabled = !Data.Settings.workspaceBurstEnabled;
}
}
}
}
// Workspace Glow Toggle
Row {
width: parent.width
height: 40
Column {
anchors.verticalCenter: parent.verticalCenter
width: parent.width - 80
Text {
text: "Workspace Shadow Glow"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
}
Text {
text: "Accent color glow in workspace shadow"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.6)
font.pixelSize: 11
font.family: "monospace"
}
}
// Toggle switch for glow
Rectangle {
width: 50
height: 25
radius: 12.5
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
color: Data.Settings.workspaceGlowEnabled ? Qt.lighter(Data.ThemeManager.accentColor, 0.8) : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.2)
border.width: 1
border.color: Data.Settings.workspaceGlowEnabled ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.4)
Rectangle {
width: 20
height: 20
radius: 10
color: Data.ThemeManager.bgColor
border.width: 1.5
border.color: Data.Settings.workspaceGlowEnabled ? Data.ThemeManager.accentColor : Data.ThemeManager.fgColor
anchors.verticalCenter: parent.verticalCenter
x: Data.Settings.workspaceGlowEnabled ? parent.width - width - 2.5 : 2.5
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutQuad
}
}
}
Behavior on color {
ColorAnimation {
duration: 200
}
}
Behavior on border.color {
ColorAnimation {
duration: 200
}
}
MouseArea {
anchors.fill: parent
onClicked: {
Data.Settings.workspaceGlowEnabled = !Data.Settings.workspaceGlowEnabled;
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,129 @@
import QtQuick
import QtQuick.Controls
import "root:/Data" as Data
// Music Player settings content
Column {
width: parent.width
spacing: 20
// Auto-switch to active player
Column {
width: parent.width
spacing: 12
Text {
text: "Auto-switch to Active Player"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Text {
text: "Automatically switch to the player that starts playing music"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
wrapMode: Text.Wrap
width: parent.width
}
Rectangle {
width: 200
height: 35
radius: 18
color: Data.Settings.autoSwitchPlayer ? Data.ThemeManager.accentColor : Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: 1
border.color: Data.ThemeManager.accentColor
Behavior on color {
ColorAnimation {
duration: 200
}
}
Text {
anchors.centerIn: parent
text: Data.Settings.autoSwitchPlayer ? "Enabled" : "Disabled"
color: Data.Settings.autoSwitchPlayer ? Data.ThemeManager.bgColor : Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
Behavior on color {
ColorAnimation {
duration: 200
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
Data.Settings.autoSwitchPlayer = !Data.Settings.autoSwitchPlayer;
}
}
}
}
// Always show player dropdown
Column {
width: parent.width
spacing: 12
Text {
text: "Always Show Player Dropdown"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Text {
text: "Show the player selection dropdown even with only one player"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
wrapMode: Text.Wrap
width: parent.width
}
Rectangle {
width: 200
height: 35
radius: 18
color: Data.Settings.alwaysShowPlayerDropdown ? Data.ThemeManager.accentColor : Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: 1
border.color: Data.ThemeManager.accentColor
Behavior on color {
ColorAnimation {
duration: 200
}
}
Text {
anchors.centerIn: parent
text: Data.Settings.alwaysShowPlayerDropdown ? "Enabled" : "Disabled"
color: Data.Settings.alwaysShowPlayerDropdown ? Data.ThemeManager.bgColor : Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
Behavior on color {
ColorAnimation {
duration: 200
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
Data.Settings.alwaysShowPlayerDropdown = !Data.Settings.alwaysShowPlayerDropdown;
}
}
}
}
}

View File

@@ -0,0 +1,531 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "root:/Data" as Data
// Night Light settings content
Item {
id: nightLightSettings
width: parent.width
height: contentColumn.height
Column {
id: contentColumn
width: parent.width
spacing: 20
// Night Light Enable Toggle
Row {
width: parent.width
spacing: 16
Column {
width: parent.width - nightLightToggle.width - 16
spacing: 4
Text {
text: "Enable Night Light"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Text {
text: "Reduces blue light to help protect your eyes and improve sleep"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
wrapMode: Text.Wrap
}
}
Rectangle {
id: nightLightToggle
width: 50
height: 28
radius: 14
color: Data.Settings.nightLightEnabled ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Behavior on color {
ColorAnimation {
duration: 200
}
}
Rectangle {
width: 20
height: 20
radius: 10
color: Data.ThemeManager.bgColor
x: Data.Settings.nightLightEnabled ? parent.width - width - 4 : 4
anchors.verticalCenter: parent.verticalCenter
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: {
Data.Settings.nightLightEnabled = !Data.Settings.nightLightEnabled;
}
onEntered: {
parent.scale = 1.05;
}
onExited: {
parent.scale = 1.0;
}
}
Behavior on scale {
NumberAnimation {
duration: 150
easing.type: Easing.OutQuad
}
}
}
}
// Warmth Level Slider
Column {
width: parent.width
spacing: 12
Text {
text: "Warmth Level"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Text {
text: "Adjust how warm the screen filter appears"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
wrapMode: Text.Wrap
width: parent.width
}
Row {
width: parent.width
spacing: 12
Text {
anchors.verticalCenter: parent.verticalCenter
text: "Cool"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.6)
font.pixelSize: 12
font.family: "monospace"
}
Slider {
id: warmthSlider
width: parent.width - 120
height: 30
from: 0.1
to: 1.0
value: Data.Settings.nightLightWarmth || 0.4
stepSize: 0.1
onValueChanged: {
Data.Settings.nightLightWarmth = value;
}
background: Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: parent.width
height: 6
radius: 3
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.2)
Rectangle {
width: warmthSlider.visualPosition * parent.width
height: parent.height
radius: parent.radius
color: Qt.rgba(1.0, 0.8 - warmthSlider.value * 0.3, 0.4, 1.0)
}
}
handle: Rectangle {
x: warmthSlider.leftPadding + warmthSlider.visualPosition * (warmthSlider.availableWidth - width)
y: warmthSlider.topPadding + warmthSlider.availableHeight / 2 - height / 2
width: 20
height: 20
radius: 10
color: Data.ThemeManager.accentColor
border.color: Qt.lighter(Data.ThemeManager.accentColor, 1.2)
border.width: 2
}
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: "Warm"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.6)
font.pixelSize: 12
font.family: "monospace"
}
}
}
// Auto-enable Toggle
Row {
width: parent.width
spacing: 16
Column {
width: parent.width - autoToggle.width - 16
spacing: 4
Text {
text: "Auto-enable Schedule"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Text {
text: "Automatically turn on night light at sunset/bedtime"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
wrapMode: Text.Wrap
}
}
Rectangle {
id: autoToggle
width: 50
height: 28
radius: 14
color: Data.Settings.nightLightAuto ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Behavior on color {
ColorAnimation {
duration: 200
}
}
Rectangle {
width: 20
height: 20
radius: 10
color: Data.ThemeManager.bgColor
x: Data.Settings.nightLightAuto ? parent.width - width - 4 : 4
anchors.verticalCenter: parent.verticalCenter
Behavior on x {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onClicked: {
Data.Settings.nightLightAuto = !Data.Settings.nightLightAuto;
}
onEntered: {
parent.scale = 1.05;
}
onExited: {
parent.scale = 1.0;
}
}
Behavior on scale {
NumberAnimation {
duration: 150
easing.type: Easing.OutQuad
}
}
}
}
// Schedule Time Controls - visible when auto-enable is on
Column {
width: parent.width
spacing: 16
visible: Data.Settings.nightLightAuto
opacity: Data.Settings.nightLightAuto ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
Text {
text: "Schedule Times"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
// Start and End Time Row
Row {
width: parent.width
spacing: 20
// Start Time
Column {
id: startTimeColumn
width: (parent.width - parent.spacing) / 2
spacing: 8
Text {
text: "Start Time"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
}
Text {
text: "Night light turns on"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 12
font.family: "monospace"
}
Rectangle {
id: startTimeButton
width: parent.width
height: 40
radius: 8
color: Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: 1
border.color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Row {
anchors.centerIn: parent
spacing: 8
Text {
text: (Data.Settings.nightLightStartHour || 20).toString().padStart(2, '0') + ":00"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
anchors.fill: parent
onClicked: {
startTimePopup.open();
}
}
}
// Start Time Popup
Popup {
id: startTimePopup
width: startTimeButton.width
height: 170
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
y: startTimeButton.y - height - 10
x: startTimeButton.x
dim: false
background: Rectangle {
color: Data.ThemeManager.bgColor
radius: 12
border.width: 2
border.color: Data.ThemeManager.accentColor
}
Column {
anchors.centerIn: parent
spacing: 12
Text {
text: "Select Start Hour"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
anchors.horizontalCenter: parent.horizontalCenter
}
GridLayout {
columns: 6
columnSpacing: 6
rowSpacing: 6
anchors.horizontalCenter: parent.horizontalCenter
Repeater {
model: 24
delegate: Rectangle {
width: 24
height: 24
radius: 4
color: (Data.Settings.nightLightStartHour || 20) === modelData ? Data.ThemeManager.accentColor : Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: 1
border.color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Text {
anchors.centerIn: parent
text: modelData.toString().padStart(2, '0')
color: (Data.Settings.nightLightStartHour || 20) === modelData ? Data.ThemeManager.bgColor : Data.ThemeManager.fgColor
font.pixelSize: 10
font.bold: true
font.family: "monospace"
}
MouseArea {
anchors.fill: parent
onClicked: {
Data.Settings.nightLightStartHour = modelData;
startTimePopup.close();
}
}
}
}
}
}
}
}
// End Time
Column {
id: endTimeColumn
width: (parent.width - parent.spacing) / 2
spacing: 8
Text {
text: "End Time"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
}
Text {
text: "Night light turns off"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 12
font.family: "monospace"
}
Rectangle {
id: endTimeButton
width: parent.width
height: 40
radius: 8
color: Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: 1
border.color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Row {
anchors.centerIn: parent
spacing: 8
Text {
text: (Data.Settings.nightLightEndHour || 6).toString().padStart(2, '0') + ":00"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
anchors.fill: parent
onClicked: {
endTimePopup.open();
}
}
}
// End Time Popup
Popup {
id: endTimePopup
width: endTimeButton.width
height: 170
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
y: endTimeButton.y - height - 10
x: endTimeButton.x
dim: false
background: Rectangle {
color: Data.ThemeManager.bgColor
radius: 12
border.width: 2
border.color: Data.ThemeManager.accentColor
}
Column {
anchors.centerIn: parent
spacing: 12
Text {
text: "Select End Hour"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
anchors.horizontalCenter: parent.horizontalCenter
}
GridLayout {
columns: 6
columnSpacing: 6
rowSpacing: 6
anchors.horizontalCenter: parent.horizontalCenter
Repeater {
model: 24
delegate: Rectangle {
width: 24
height: 24
radius: 4
color: (Data.Settings.nightLightEndHour || 6) === modelData ? Data.ThemeManager.accentColor : Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: 1
border.color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Text {
anchors.centerIn: parent
text: modelData.toString().padStart(2, '0')
color: (Data.Settings.nightLightEndHour || 6) === modelData ? Data.ThemeManager.bgColor : Data.ThemeManager.fgColor
font.pixelSize: 10
font.bold: true
font.family: "monospace"
}
MouseArea {
anchors.fill: parent
onClicked: {
Data.Settings.nightLightEndHour = modelData;
endTimePopup.close();
}
}
}
}
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,536 @@
import QtQuick
import QtQuick.Controls
import "root:/Data" as Data
// Notification settings content
Item {
id: notificationSettings
width: parent.width
height: contentColumn.height
// Expose the text input focus for parent keyboard management
property bool anyTextInputFocused: appNameInput.activeFocus
Column {
id: contentColumn
width: parent.width
spacing: 20
// Display Time Setting
Column {
width: parent.width
spacing: 12
Text {
text: "Display Time"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Text {
text: "How long notifications stay visible on screen"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
wrapMode: Text.Wrap
width: parent.width
}
Row {
spacing: 16
width: parent.width
Slider {
id: displayTimeSlider
width: parent.width - timeLabel.width - 16
height: 30
from: 2000
to: 15000
stepSize: 1000
value: Data.Settings.displayTime
onValueChanged: {
Data.Settings.displayTime = value;
}
background: Rectangle {
width: displayTimeSlider.availableWidth
height: 6
radius: 3
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
anchors.verticalCenter: parent.verticalCenter
Rectangle {
width: displayTimeSlider.visualPosition * parent.width
height: parent.height
radius: parent.radius
color: Data.ThemeManager.accentColor
}
}
handle: Rectangle {
x: displayTimeSlider.leftPadding + displayTimeSlider.visualPosition * (displayTimeSlider.availableWidth - width)
y: displayTimeSlider.topPadding + displayTimeSlider.availableHeight / 2 - height / 2
width: 20
height: 20
radius: 10
color: Data.ThemeManager.accentColor
border.color: Qt.lighter(Data.ThemeManager.accentColor, 1.2)
border.width: 2
scale: displayTimeSlider.pressed ? 1.2 : 1.0
Behavior on scale {
NumberAnimation {
duration: 150
}
}
}
}
Text {
id: timeLabel
text: (displayTimeSlider.value / 1000).toFixed(1) + "s"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
width: 40
}
}
}
// Max History Items
Column {
width: parent.width
spacing: 12
Text {
text: "History Limit"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Text {
text: "Maximum number of notifications to keep in history"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
wrapMode: Text.Wrap
width: parent.width
}
Row {
spacing: 16
width: parent.width
Slider {
id: historySlider
width: parent.width - historyLabel.width - 16
height: 30
from: 10
to: 100
stepSize: 5
value: Data.Settings.historyLimit
onValueChanged: {
Data.Settings.historyLimit = value;
}
background: Rectangle {
width: historySlider.availableWidth
height: 6
radius: 3
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
anchors.verticalCenter: parent.verticalCenter
Rectangle {
width: historySlider.visualPosition * parent.width
height: parent.height
radius: parent.radius
color: Data.ThemeManager.accentColor
}
}
handle: Rectangle {
x: historySlider.leftPadding + historySlider.visualPosition * (historySlider.availableWidth - width)
y: historySlider.topPadding + historySlider.availableHeight / 2 - height / 2
width: 20
height: 20
radius: 10
color: Data.ThemeManager.accentColor
border.color: Qt.lighter(Data.ThemeManager.accentColor, 1.2)
border.width: 2
scale: historySlider.pressed ? 1.2 : 1.0
Behavior on scale {
NumberAnimation {
duration: 150
}
}
}
}
Text {
id: historyLabel
text: historySlider.value + " items"
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
width: 60
}
}
}
// Ignored Apps Setting
Column {
width: parent.width
spacing: 12
Text {
text: "Ignored Applications"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Text {
text: "Applications that won't show notifications"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 13
font.family: "monospace"
wrapMode: Text.Wrap
width: parent.width
}
// Current ignored apps list
Rectangle {
width: parent.width
height: Math.max(100, ignoredAppsFlow.height + 16)
radius: 12
color: Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: 1
border.color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Flow {
id: ignoredAppsFlow
anchors.fill: parent
anchors.margins: 8
spacing: 6
Repeater {
model: Data.Settings.ignoredApps
delegate: Rectangle {
width: appNameText.width + removeButton.width + 16
height: 28
radius: 14
color: Qt.rgba(Data.ThemeManager.accentColor.r, Data.ThemeManager.accentColor.g, Data.ThemeManager.accentColor.b, 0.15)
border.width: 1
border.color: Qt.rgba(Data.ThemeManager.accentColor.r, Data.ThemeManager.accentColor.g, Data.ThemeManager.accentColor.b, 0.3)
Row {
anchors.centerIn: parent
spacing: 4
Text {
id: appNameText
anchors.verticalCenter: parent.verticalCenter
text: modelData
color: Data.ThemeManager.fgColor
font.pixelSize: 12
font.family: "monospace"
}
Rectangle {
id: removeButton
width: 18
height: 18
radius: 9
color: removeMouseArea.containsMouse ? Qt.rgba(1, 0.3, 0.3, 0.8) : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.5)
Behavior on color {
ColorAnimation {
duration: 150
}
}
Text {
anchors.centerIn: parent
text: "×"
color: "white"
font.pixelSize: 12
font.bold: true
}
MouseArea {
id: removeMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
Data.Settings.removeIgnoredApp(modelData);
}
}
}
}
}
}
// Add new app button
Rectangle {
width: addAppText.width + 36
height: 28
radius: 14
color: addAppMouseArea.containsMouse ? Qt.rgba(Data.ThemeManager.accentColor.r, Data.ThemeManager.accentColor.g, Data.ThemeManager.accentColor.b, 0.2) : Qt.lighter(Data.ThemeManager.bgColor, 1.2)
border.width: 2
border.color: Data.ThemeManager.accentColor
Behavior on color {
ColorAnimation {
duration: 150
}
}
Row {
anchors.centerIn: parent
spacing: 6
Text {
anchors.verticalCenter: parent.verticalCenter
text: "add"
font.family: "Material Symbols Outlined"
font.pixelSize: 14
color: Data.ThemeManager.accentColor
}
Text {
id: addAppText
anchors.verticalCenter: parent.verticalCenter
text: "Add App"
color: Data.ThemeManager.accentColor
font.pixelSize: 12
font.bold: true
font.family: "monospace"
}
}
MouseArea {
id: addAppMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: addAppPopup.open()
}
}
}
}
// Quick suggestions
Column {
width: parent.width
spacing: 8
Text {
text: "Common Apps"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 12
font.family: "monospace"
}
Flow {
width: parent.width
spacing: 6
Repeater {
model: ["Discord", "Spotify", "Steam", "Firefox", "Chrome", "VSCode", "Slack"]
delegate: Rectangle {
width: suggestedAppText.width + 16
height: 24
radius: 12
color: suggestionMouseArea.containsMouse ? Qt.rgba(Data.ThemeManager.accentColor.r, Data.ThemeManager.accentColor.g, Data.ThemeManager.accentColor.b, 0.1) : "transparent"
border.width: 1
border.color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Text {
id: suggestedAppText
anchors.centerIn: parent
text: modelData
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.7)
font.pixelSize: 11
font.family: "monospace"
}
MouseArea {
id: suggestionMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
Data.Settings.addIgnoredApp(modelData);
}
}
}
}
}
}
}
}
// Add app popup
Popup {
id: addAppPopup
parent: notificationSettings
width: 280
height: 160
x: (parent.width - width) / 2
y: (parent.height - height) / 2
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
background: Rectangle {
color: Data.ThemeManager.bgColor
border.color: Data.ThemeManager.accentColor
border.width: 2
radius: 20
}
Column {
anchors.centerIn: parent
spacing: 16
width: parent.width - 40
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: "Add Ignored App"
color: Data.ThemeManager.accentColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Rectangle {
width: parent.width
height: 40
radius: 20
color: Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: appNameInput.activeFocus ? 2 : 1
border.color: appNameInput.activeFocus ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Behavior on border.color {
ColorAnimation {
duration: 150
}
}
TextInput {
id: appNameInput
anchors.fill: parent
anchors.margins: 12
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.family: "monospace"
selectByMouse: true
clip: true
verticalAlignment: TextInput.AlignVCenter
focus: true
activeFocusOnTab: true
inputMethodHints: Qt.ImhNone
Keys.onPressed: function (event) {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
addAppButton.clicked();
event.accepted = true;
}
}
// Placeholder text implementation
Text {
anchors.fill: parent
anchors.margins: 12
text: "App name (e.g. Discord)"
color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.5)
font.pixelSize: 14
font.family: "monospace"
verticalAlignment: Text.AlignVCenter
visible: appNameInput.text === ""
}
}
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: 12
Rectangle {
width: 80
height: 32
radius: 16
color: cancelMouseArea.containsMouse ? Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.1) : "transparent"
border.width: 1
border.color: Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Text {
anchors.centerIn: parent
text: "Cancel"
color: Data.ThemeManager.fgColor
font.pixelSize: 12
font.family: "monospace"
}
MouseArea {
id: cancelMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
appNameInput.text = "";
addAppPopup.close();
}
}
}
Rectangle {
id: addAppButton
width: 80
height: 32
radius: 16
color: addMouseArea.containsMouse ? Qt.lighter(Data.ThemeManager.accentColor, 1.1) : Data.ThemeManager.accentColor
signal clicked
onClicked: {
if (appNameInput.text.trim() !== "") {
if (Data.Settings.addIgnoredApp(appNameInput.text.trim())) {
appNameInput.text = "";
addAppPopup.close();
}
}
}
Text {
anchors.centerIn: parent
text: "Add"
color: Data.ThemeManager.bgColor
font.pixelSize: 12
font.bold: true
font.family: "monospace"
}
MouseArea {
id: addMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: parent.clicked()
}
}
}
}
onOpened: {
appNameInput.forceActiveFocus();
}
}
}

View File

@@ -0,0 +1,103 @@
import QtQuick
import QtQuick.Controls
import "root:/Data" as Data
// Reusable collapsible settings category component
Item {
id: categoryRoot
property string title: ""
property string icon: ""
property bool expanded: false
property alias content: contentLoader.sourceComponent
height: headerRect.height + (expanded ? contentLoader.height + 20 : 0)
Behavior on height {
NumberAnimation {
duration: 250
easing.type: Easing.OutCubic
}
}
// Category header
Rectangle {
id: headerRect
width: parent.width
height: 50
radius: 12
color: expanded ? Qt.rgba(Data.ThemeManager.accentColor.r, Data.ThemeManager.accentColor.g, Data.ThemeManager.accentColor.b, 0.1) : Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: expanded ? 2 : 1
border.color: expanded ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Row {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 16
spacing: 12
Text {
anchors.verticalCenter: parent.verticalCenter
text: categoryRoot.icon
font.family: "Material Symbols Outlined"
font.pixelSize: 20
color: expanded ? Data.ThemeManager.accentColor : Data.ThemeManager.fgColor
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: categoryRoot.title
color: expanded ? Data.ThemeManager.accentColor : Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
}
// Expand/collapse arrow
Text {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 16
text: expanded ? "expand_less" : "expand_more"
font.family: "Material Symbols Outlined"
font.pixelSize: 20
color: expanded ? Data.ThemeManager.accentColor : Data.ThemeManager.fgColor
Behavior on rotation {
NumberAnimation {
duration: 250
easing.type: Easing.OutCubic
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
categoryRoot.expanded = !categoryRoot.expanded;
}
}
}
// Category content
Loader {
id: contentLoader
anchors.top: headerRect.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: expanded ? 20 : 0
anchors.leftMargin: 16
anchors.rightMargin: 16
visible: expanded
opacity: expanded ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: 250
easing.type: Easing.OutCubic
}
}
}
}

View File

@@ -0,0 +1,77 @@
import QtQuick
import QtQuick.Controls
import "root:/Data" as Data
// System settings content
Item {
id: systemSettings
width: parent.width
height: contentColumn.height
// Expose the text input focus for parent keyboard management
property bool anyTextInputFocused: videoPathInput.activeFocus
Column {
id: contentColumn
width: parent.width
spacing: 20
// Video Recording Path
Column {
width: parent.width
spacing: 8
Text {
text: "Video Recording Path"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Rectangle {
width: parent.width
height: 40
radius: 8
color: Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: videoPathInput.activeFocus ? 2 : 1
border.color: videoPathInput.activeFocus ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Behavior on border.color {
ColorAnimation {
duration: 150
}
}
TextInput {
id: videoPathInput
anchors.fill: parent
anchors.margins: 12
text: Data.Settings.videoPath
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.family: "monospace"
selectByMouse: true
clip: true
verticalAlignment: TextInput.AlignVCenter
focus: true
activeFocusOnTab: true
inputMethodHints: Qt.ImhNone
onTextChanged: {
Data.Settings.videoPath = text;
}
Keys.onPressed: function (event) {}
}
MouseArea {
anchors.fill: parent
onClicked: {
videoPathInput.forceActiveFocus();
}
}
}
}
}
}

View File

@@ -0,0 +1,207 @@
import QtQuick
import QtQuick.Controls
import "root:/Data" as Data
// Weather settings content
Item {
id: weatherSettings
width: parent.width
height: contentColumn.height
required property var shell
// Expose the text input focus for parent keyboard management
property bool anyTextInputFocused: locationInput.activeFocus
Column {
id: contentColumn
width: parent.width
spacing: 20
// Location Setting
Column {
width: parent.width
spacing: 8
Text {
text: "Location"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Row {
width: parent.width
spacing: 12
Rectangle {
width: parent.width - applyButton.width - 12
height: 40
radius: 8
color: Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: locationInput.activeFocus ? 2 : 1
border.color: locationInput.activeFocus ? Data.ThemeManager.accentColor : Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.3)
Behavior on border.color {
ColorAnimation {
duration: 150
}
}
TextInput {
id: locationInput
anchors.fill: parent
anchors.margins: 12
text: Data.Settings.weatherLocation
color: Data.ThemeManager.fgColor
font.pixelSize: 14
font.family: "monospace"
selectByMouse: true
clip: true
verticalAlignment: TextInput.AlignVCenter
focus: true
activeFocusOnTab: true
inputMethodHints: Qt.ImhNone
Keys.onPressed: function (event) {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
applyButton.clicked();
event.accepted = true;
}
}
MouseArea {
anchors.fill: parent
onClicked: {
locationInput.forceActiveFocus();
}
}
}
}
Rectangle {
id: applyButton
width: 80
height: 40
radius: 8
color: applyMouseArea.containsMouse ? Qt.lighter(Data.ThemeManager.accentColor, 1.1) : Data.ThemeManager.accentColor
signal clicked
onClicked: {
Data.Settings.weatherLocation = locationInput.text;
weatherSettings.shell.weatherService.loadWeather();
}
Text {
anchors.centerIn: parent
text: "Apply"
color: Data.ThemeManager.bgColor
font.pixelSize: 12
font.bold: true
font.family: "monospace"
}
MouseArea {
id: applyMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: parent.clicked()
}
}
}
}
// Temperature Units
Column {
width: parent.width
spacing: 12
Text {
text: "Temperature Units"
color: Data.ThemeManager.fgColor
font.pixelSize: 16
font.bold: true
font.family: "monospace"
}
Row {
spacing: 12
Rectangle {
width: 80
height: 35
radius: 18
color: !Data.Settings.useFahrenheit ? Data.ThemeManager.accentColor : Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: 1
border.color: Data.ThemeManager.accentColor
Behavior on color {
ColorAnimation {
duration: 200
}
}
Text {
anchors.centerIn: parent
text: "°C"
color: !Data.Settings.useFahrenheit ? Data.ThemeManager.bgColor : Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
Behavior on color {
ColorAnimation {
duration: 200
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
Data.Settings.useFahrenheit = false;
}
}
}
Rectangle {
width: 80
height: 35
radius: 18
color: Data.Settings.useFahrenheit ? Data.ThemeManager.accentColor : Qt.lighter(Data.ThemeManager.bgColor, 1.15)
border.width: 1
border.color: Data.ThemeManager.accentColor
Behavior on color {
ColorAnimation {
duration: 200
}
}
Text {
anchors.centerIn: parent
text: "°F"
color: Data.Settings.useFahrenheit ? Data.ThemeManager.bgColor : Data.ThemeManager.fgColor
font.pixelSize: 14
font.bold: true
font.family: "monospace"
Behavior on color {
ColorAnimation {
duration: 200
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
Data.Settings.useFahrenheit = true;
}
}
}
}
}
}
}