281 lines
10 KiB
QML
281 lines
10 KiB
QML
import QtQuick
|
||
import qs.config
|
||
import qs.services
|
||
|
||
Rectangle {
|
||
id: root
|
||
|
||
property var hostWindow: null
|
||
readonly property var myHomeDiagnostics: pageLoader.status === Loader.Ready
|
||
&& pageLoader.item
|
||
&& pageLoader.item.objectName === "my-home-page"
|
||
? pageLoader.item.pageDiagnostics
|
||
: ({})
|
||
readonly property var healthDiagnostics: pageLoader.status === Loader.Ready
|
||
&& pageLoader.item
|
||
&& pageLoader.item.objectName === "system-health-page"
|
||
? pageLoader.item.uiDiagnostics()
|
||
: ({})
|
||
|
||
function requestHealthAction(id: string): bool {
|
||
if (pageLoader.status !== Loader.Ready
|
||
|| !pageLoader.item
|
||
|| pageLoader.item.objectName !== "system-health-page")
|
||
return false;
|
||
return pageLoader.item.activateRenderedAction(id);
|
||
}
|
||
|
||
color: Theme.bg
|
||
radius: 18
|
||
border.width: 1
|
||
border.color: Theme.alpha(Theme.fg, 0.08)
|
||
clip: true
|
||
|
||
SettingsSidebar {
|
||
id: sidebar
|
||
anchors.left: parent.left
|
||
anchors.top: titlebar.bottom
|
||
anchors.bottom: parent.bottom
|
||
selectedPage: ShellState.settingsPage
|
||
onPageRequested: page => ShellState.openSettings(page)
|
||
}
|
||
|
||
// The one titlebar Panama draws, so it follows Panama's own titlebar
|
||
// rules: the close button sits on the configured side, there is no
|
||
// minimize (Hyprland has no minimize — the button this bar used to show
|
||
// was a lie), and turning the titlebar off leaves the window pure
|
||
// Hyprland: Super+Q closes, Super+drag moves, Escape still works.
|
||
Rectangle {
|
||
id: titlebar
|
||
|
||
readonly property bool shown: DesktopPreferences.get("panamaTitlebar") !== false
|
||
readonly property bool buttonsLeft: DesktopPreferences.get("titlebarButtonSide") === "left"
|
||
|
||
anchors.left: parent.left
|
||
anchors.right: parent.right
|
||
anchors.top: parent.top
|
||
height: shown ? 48 : 0
|
||
visible: shown
|
||
color: Theme.alpha(Theme.bgDark, 0.97)
|
||
border.width: 0
|
||
|
||
Text {
|
||
anchors.left: titlebar.buttonsLeft ? undefined : parent.left
|
||
anchors.right: titlebar.buttonsLeft ? parent.right : undefined
|
||
anchors.leftMargin: 18
|
||
anchors.rightMargin: 18
|
||
anchors.verticalCenter: parent.verticalCenter
|
||
text: "Settings"
|
||
color: Theme.fg
|
||
font.family: Theme.fontFamily
|
||
font.pixelSize: Theme.fontSize
|
||
font.weight: Font.DemiBold
|
||
}
|
||
|
||
Rectangle {
|
||
id: closeButton
|
||
|
||
anchors.left: titlebar.buttonsLeft ? parent.left : undefined
|
||
anchors.right: titlebar.buttonsLeft ? undefined : parent.right
|
||
anchors.leftMargin: 12
|
||
anchors.rightMargin: 12
|
||
anchors.verticalCenter: parent.verticalCenter
|
||
width: 28
|
||
height: 28
|
||
radius: 9
|
||
color: closeMouse.containsMouse || activeFocus
|
||
? Theme.alpha(Theme.danger, 0.17) : Theme.alpha(Theme.fg, 0)
|
||
border.width: activeFocus ? 2 : 0
|
||
border.color: Theme.alpha(Theme.danger, 0.6)
|
||
activeFocusOnTab: true
|
||
|
||
Accessible.role: Accessible.Button
|
||
Accessible.name: "Close Settings"
|
||
Keys.onReturnPressed: ShellState.closeSettings()
|
||
Keys.onSpacePressed: ShellState.closeSettings()
|
||
|
||
Text {
|
||
anchors.centerIn: parent
|
||
text: "×"
|
||
color: closeMouse.containsMouse || closeButton.activeFocus ? Theme.danger : Theme.fgDim
|
||
font.family: Theme.fontFamily
|
||
font.pixelSize: 18
|
||
}
|
||
|
||
MouseArea {
|
||
id: closeMouse
|
||
anchors.fill: parent
|
||
hoverEnabled: true
|
||
cursorShape: Qt.PointingHandCursor
|
||
onClicked: ShellState.closeSettings()
|
||
}
|
||
}
|
||
|
||
DragHandler {
|
||
target: null
|
||
onActiveChanged: if (active && root.hostWindow) root.hostWindow.startSystemMove()
|
||
}
|
||
}
|
||
|
||
Rectangle {
|
||
anchors.left: sidebar.right
|
||
anchors.top: titlebar.bottom
|
||
anchors.bottom: parent.bottom
|
||
width: 1
|
||
color: Theme.alpha(Theme.fg, 0.06)
|
||
}
|
||
|
||
// The tab strip for the current category, rendered above the page so the
|
||
// leaf pages themselves stay untouched by the grouping. A category with a
|
||
// single subject earns no strip.
|
||
readonly property var categoryTabs: SettingsRoutes.tabsFor(ShellState.settingsPage)
|
||
|
||
Item {
|
||
id: categoryStrip
|
||
|
||
readonly property bool shown: root.categoryTabs.length > 1
|
||
|
||
anchors.left: sidebar.right
|
||
anchors.right: parent.right
|
||
anchors.top: titlebar.bottom
|
||
anchors.leftMargin: 34
|
||
anchors.rightMargin: 34
|
||
height: shown ? 48 : 0
|
||
visible: shown
|
||
|
||
SettingsTabs {
|
||
anchors.left: parent.left
|
||
anchors.right: parent.right
|
||
anchors.bottom: parent.bottom
|
||
tabs: root.categoryTabs.map(tab => ({ value: tab.page, label: tab.label }))
|
||
current: ShellState.settingsPage
|
||
onSelected: value => ShellState.openSettings(value)
|
||
}
|
||
}
|
||
|
||
Loader {
|
||
id: pageLoader
|
||
anchors.left: sidebar.right
|
||
anchors.right: parent.right
|
||
anchors.top: categoryStrip.bottom
|
||
anchors.bottom: parent.bottom
|
||
sourceComponent: {
|
||
switch (ShellState.settingsPage) {
|
||
case "appearance": return appearancePage;
|
||
case "displays": return displaysPage;
|
||
case "connectivity": return connectivityPage;
|
||
case "my-home": return myHomePage;
|
||
case "phone": return phonePage;
|
||
case "bar": return barPage;
|
||
case "dock": return dockPage;
|
||
case "control-center": return controlCenterPage;
|
||
case "tiling": return tilingPage;
|
||
case "workspaces": return workspacesPage;
|
||
case "sync": return syncPage;
|
||
case "sound": return soundPage;
|
||
case "gaming": return gamingPage;
|
||
case "notifications": return notificationsPage;
|
||
case "focus": return focusPage;
|
||
case "screen-intelligence": return screenIntelligencePage;
|
||
case "shortcuts": return shortcutsPage;
|
||
case "mouse": return mousePage;
|
||
case "dictation": return dictationPage;
|
||
case "privacy": return privacyPage;
|
||
case "region": return regionPage;
|
||
case "accounts": return onlineAccountsPage;
|
||
case "accessibility": return accessibilityPage;
|
||
case "power": return powerPage;
|
||
case "datetime": return dateTimePage;
|
||
case "applications": return applicationsPage;
|
||
case "storage": return storagePage;
|
||
case "snapshots": return snapshotsPage;
|
||
case "updates": return updatesPage;
|
||
case "users": return usersPage;
|
||
case "sharing": return sharingPage;
|
||
case "firewall": return firewallPage;
|
||
case "printers": return printersPage;
|
||
case "containers": return containersPage;
|
||
case "ssh-keys": return sshKeysPage;
|
||
case "services": return healthPage;
|
||
case "manual": return manualPage;
|
||
case "about": return aboutPage;
|
||
default: return homePage;
|
||
}
|
||
}
|
||
}
|
||
|
||
Rectangle {
|
||
anchors.right: parent.right
|
||
anchors.rightMargin: 22
|
||
anchors.bottom: parent.bottom
|
||
anchors.bottomMargin: 20
|
||
width: Math.min(460, errorCopy.implicitWidth + 34)
|
||
height: 42
|
||
radius: 12
|
||
visible: SystemSettings.lastError !== ""
|
||
color: Theme.mix(Theme.bgPopover, Theme.danger, 0.1)
|
||
border.width: 1
|
||
border.color: Theme.alpha(Theme.danger, 0.28)
|
||
|
||
Text {
|
||
id: errorCopy
|
||
anchors.centerIn: parent
|
||
text: SystemSettings.lastError
|
||
color: Theme.fg
|
||
font.family: Theme.fontFamily
|
||
font.pixelSize: Theme.fontSizeSmall
|
||
}
|
||
|
||
MouseArea {
|
||
anchors.fill: parent
|
||
cursorShape: Qt.PointingHandCursor
|
||
onClicked: SystemSettings.lastError = ""
|
||
}
|
||
}
|
||
|
||
Component { id: homePage; HomePage {} }
|
||
Component { id: applicationsPage; ApplicationsPage {} }
|
||
Component { id: storagePage; StoragePage {} }
|
||
Component { id: snapshotsPage; SnapshotsPage {} }
|
||
Component { id: updatesPage; UpdatesPage {} }
|
||
Component { id: usersPage; UsersPage {} }
|
||
Component { id: sharingPage; SharingPage {} }
|
||
Component { id: firewallPage; FirewallPage {} }
|
||
Component { id: containersPage; ContainersPage {} }
|
||
Component { id: sshKeysPage; SshKeysPage {} }
|
||
Component { id: printersPage; PrintersPage {} }
|
||
Component { id: accessibilityPage; AccessibilityPage {} }
|
||
Component { id: powerPage; PowerPage {} }
|
||
Component { id: dateTimePage; DateTimePage {} }
|
||
Component { id: appearancePage; AppearancePage {} }
|
||
Component { id: displaysPage; DisplaysPage {} }
|
||
Component { id: connectivityPage; ConnectivityPage {} }
|
||
Component { id: myHomePage; MyHomePage {} }
|
||
Component { id: phonePage; PhonePage {} }
|
||
Component { id: barPage; BarPage {} }
|
||
Component { id: dockPage; DockPage {} }
|
||
Component { id: controlCenterPage; ControlCenterPage {} }
|
||
Component { id: tilingPage; TilingPage {} }
|
||
Component { id: workspacesPage; WorkspacesPage {} }
|
||
Component { id: syncPage; SyncPage {} }
|
||
Component { id: soundPage; SoundPage {} }
|
||
Component { id: gamingPage; GamingPage {} }
|
||
Component { id: notificationsPage; NotificationsPage {} }
|
||
Component { id: focusPage; FocusPage {} }
|
||
Component { id: screenIntelligencePage; ScreenIntelligencePage {} }
|
||
Component { id: shortcutsPage; ShortcutsPage {} }
|
||
Component { id: mousePage; MousePage {} }
|
||
Component { id: dictationPage; DictationPage {} }
|
||
Component { id: privacyPage; PrivacyPage {} }
|
||
Component { id: regionPage; RegionPage {} }
|
||
Component { id: onlineAccountsPage; OnlineAccountsPage {} }
|
||
Component { id: healthPage; HealthPage {} }
|
||
Component { id: manualPage; ManualPage {} }
|
||
Component { id: aboutPage; AboutPage {} }
|
||
|
||
Shortcut {
|
||
sequence: "Escape"
|
||
onActivated: ShellState.closeSettings()
|
||
}
|
||
}
|