noctalia-shell/Widgets/SettingsWindow/SettingsWindow.qml

491 lines
15 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import qs.Components
import qs.Settings
import qs.Widgets.SettingsWindow.Tabs
import qs.Widgets.SettingsWindow.Tabs.Components
PanelWithOverlay {
id: panelMain
property int activeTabIndex: 0
// Function to show wallpaper selector
function showWallpaperSelector() {
if (wallpaperSelector)
wallpaperSelector.show();
}
// Function to show settings window
function showSettings() {
show();
}
// Function to load component for a specific tab
function loadComponentForTab(tabIndex) {
const componentMap = {
"0": generalSettings,
"1": barSettings,
"2": timeWeatherSettings,
"3": recordingSettings,
"4": networkSettings,
"5": displaySettings,
"6": wallpaperSettings,
"7": miscSettings,
"8": aboutSettings
};
const tabNames = ["General", "Bar", "Time & Weather", "Screen Recorder", "Network", "Display", "Wallpaper", "Misc", "About"];
if (componentMap[tabIndex]) {
settingsLoader.sourceComponent = componentMap[tabIndex];
if (tabName)
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
Component.onCompleted: {
// Ensure we start with a valid tab
if (activeTabIndex < 0 || activeTabIndex > 8)
activeTabIndex = 0;
}
// Cleanup when window is hidden
onVisibleChanged: {
if (!visible) {
// Reset to default tab when hiding to prevent state issues
activeTabIndex = 0;
if (tabName)
tabName.text = "General";
}
}
Component {
id: generalSettings
General {
}
}
Component {
id: barSettings
Bar {
}
}
Component {
id: timeWeatherSettings
TimeWeather {
}
}
Component {
id: recordingSettings
Recording {
}
}
Component {
id: networkSettings
Network {
}
}
Component {
id: miscSettings
Misc {
}
}
Component {
id: aboutSettings
About {
}
}
Component {
id: displaySettings
Display {
}
}
Component {
id: wallpaperSettings
Wallpaper {
}
}
Rectangle {
id: settingsWindowRect
implicitWidth: Quickshell.screens.length > 0 ? Quickshell.screens[0].width * 2 / 3 : 600
implicitHeight: Quickshell.screens.length > 0 ? Quickshell.screens[0].height * 2 / 3 : 400
visible: parent.visible
color: "transparent"
// Center the settings window on screen
anchors.centerIn: parent
// Prevent closing when clicking in the panel bg
MouseArea {
anchors.fill: parent
}
Rectangle {
id: background
color: Theme.backgroundPrimary
anchors.fill: parent
radius: 20
border.color: Theme.outline
border.width: 1
MultiEffect {
source: background
anchors.fill: background
shadowEnabled: true
shadowColor: Theme.shadow
shadowOpacity: 0.3
shadowHorizontalOffset: 0
shadowVerticalOffset: 2
shadowBlur: 12
}
}
Rectangle {
id: settings
color: Theme.backgroundPrimary
topRightRadius: 20
bottomRightRadius: 20
anchors {
left: tabs.right
top: parent.top
bottom: parent.bottom
right: parent.right
margins: 12
}
Rectangle {
id: headerArea
height: 48
color: "transparent"
anchors {
top: parent.top
left: parent.left
right: parent.right
margins: 16
}
RowLayout {
anchors.fill: parent
spacing: 12
Text {
id: tabName
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.bold: true
color: Theme.textPrimary
Layout.fillWidth: true
}
// Wallpaper Selection Button (only visible on Wallpaper tab)
Rectangle {
width: 160
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 {
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 {
id: tabs
color: Theme.surface
width: parent.width * 0.2
height: settingsWindowRect.height
topLeftRadius: 20
bottomLeftRadius: 20
border.color: Theme.outline
border.width: 1
Column {
width: parent.width
spacing: 0
topPadding: 8
bottomPadding: 8
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 {
width: tabs.width
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 {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.6
visible: index < (repeater.count - 1)
anchors.bottom: parent.bottom
}
}
}
}
}
}
}