Build the Panama Hyprland desktop
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
Item {
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text { text: "About Panama"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: 27; font.weight: Font.DemiBold }
|
||||
Text { text: "A curated Hyprland desktop built around focus, speed, and good taste."; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize; bottomPadding: 6 }
|
||||
|
||||
SettingsCard {
|
||||
title: "Panama Desktop"
|
||||
subtitle: "Tokyo Night Moon · Prism glass · native tiling"
|
||||
SettingRow { label: "Hyprland"; value: SystemSettings.hyprlandVersion || "Detecting…" }
|
||||
SettingRow { label: "Quickshell"; value: SystemSettings.quickshellVersion }
|
||||
SettingRow { label: "Display"; value: SystemSettings.monitorName || "Detecting…" }
|
||||
SettingRow { label: "Configuration"; detail: Quickshell.shellDir; value: "Local"; divider: false }
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Design principles"
|
||||
SettingRow { label: "Curated by default"; detail: "Strong choices instead of an incoherent matrix of switches" }
|
||||
SettingRow { label: "Quiet while idle"; detail: "No continuous decorative repaint loops" }
|
||||
SettingRow { label: "Real system boundaries"; detail: "Every control either works or clearly hands off to its owner"; divider: false }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
|
||||
Item {
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text { text: "Appearance"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: 27; font.weight: Font.DemiBold }
|
||||
Text { text: "Tokyo Night Moon, tuned for clarity and quiet motion."; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize; bottomPadding: 6 }
|
||||
|
||||
SettingsCard {
|
||||
title: "Theme"
|
||||
subtitle: "Panama has one curated visual identity rather than a matrix of partially compatible themes."
|
||||
SettingRow { label: "Color palette"; detail: "Tokyo Night Moon"; value: "Prism" }
|
||||
SettingRow { label: "Interface type"; detail: "Adwaita Sans"; value: "System"; divider: false }
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Clock"
|
||||
SettingRow {
|
||||
label: "24-hour time"
|
||||
detail: "Use 18:30 instead of 6:30 PM"
|
||||
controlWidth: 48
|
||||
SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: DesktopPreferences.use24Hour; onToggled: value => DesktopPreferences.use24Hour = value }
|
||||
}
|
||||
SettingRow {
|
||||
label: "Show seconds"
|
||||
detail: "Keep a precise clock in the center of the bar"
|
||||
controlWidth: 48
|
||||
SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: DesktopPreferences.showSeconds; onToggled: value => DesktopPreferences.showSeconds = value }
|
||||
}
|
||||
SettingRow {
|
||||
label: "Show weekday"
|
||||
detail: "Include the abbreviated weekday before the date"
|
||||
divider: false
|
||||
controlWidth: 48
|
||||
SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: DesktopPreferences.showWeekday; onToggled: value => DesktopPreferences.showWeekday = value }
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "System vitals"
|
||||
subtitle: "Choose what appears beside the workspace indicator."
|
||||
SettingRow { label: "Processor"; controlWidth: 48; SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: DesktopPreferences.showCpu; onToggled: value => DesktopPreferences.showCpu = value } }
|
||||
SettingRow { label: "Memory"; controlWidth: 48; SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: DesktopPreferences.showMemory; onToggled: value => DesktopPreferences.showMemory = value } }
|
||||
SettingRow { label: "Graphics"; divider: false; controlWidth: 48; SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: DesktopPreferences.showGpu; onToggled: value => DesktopPreferences.showGpu = value } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import QtQuick
|
||||
import Quickshell.Networking
|
||||
import Quickshell.Bluetooth
|
||||
import qs.config
|
||||
import qs.services
|
||||
import qs.modules.quicksettings
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property var wifiDevice: {
|
||||
for (const device of Networking.devices.values) {
|
||||
if (device.type === DeviceType.Wifi)
|
||||
return device;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
readonly property var bluetoothAdapter: Bluetooth.defaultAdapter
|
||||
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text { text: "Network & Devices"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: 27; font.weight: Font.DemiBold }
|
||||
Text { text: "Connect graphically—no terminal workflow required."; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize; bottomPadding: 6 }
|
||||
|
||||
SettingsCard {
|
||||
title: "Wi‑Fi"
|
||||
subtitle: Networking.wifiEnabled ? "Available networks" : "Wireless networking is off"
|
||||
SettingRow {
|
||||
label: "Wi‑Fi"
|
||||
detail: root.wifiDevice ? "Managed by NetworkManager" : "No wireless adapter found"
|
||||
controlWidth: 48
|
||||
SettingsToggle {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: Networking.wifiEnabled
|
||||
enabled: Networking.wifiHardwareEnabled
|
||||
onToggled: value => Networking.wifiEnabled = value
|
||||
}
|
||||
}
|
||||
WifiList { width: parent.width; device: root.wifiDevice; active: true; maxHeight: 240 }
|
||||
SettingRow {
|
||||
label: "Advanced network settings"
|
||||
detail: "VPN, wired profiles, DNS, and connection details"
|
||||
divider: false
|
||||
controlWidth: 104
|
||||
SettingsButton { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; text: "Open panel"; onClicked: SystemSettings.openGnomePanel("network") }
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Bluetooth"
|
||||
subtitle: root.bluetoothAdapter?.enabled ? "Nearby and paired devices" : "Bluetooth is off"
|
||||
SettingRow {
|
||||
label: "Bluetooth"
|
||||
detail: root.bluetoothAdapter ? "Pair and reconnect without leaving Settings" : "No Bluetooth adapter found"
|
||||
controlWidth: 48
|
||||
SettingsToggle {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: root.bluetoothAdapter?.enabled ?? false
|
||||
enabled: root.bluetoothAdapter !== null
|
||||
onToggled: value => { if (root.bluetoothAdapter) root.bluetoothAdapter.enabled = value; }
|
||||
}
|
||||
}
|
||||
BluetoothList { width: parent.width; active: true; maxHeight: 220 }
|
||||
SettingRow {
|
||||
label: "Advanced Bluetooth settings"
|
||||
detail: "Device details and system-level options"
|
||||
divider: false
|
||||
controlWidth: 104
|
||||
SettingsButton { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; text: "Open panel"; onClicked: SystemSettings.openGnomePanel("bluetooth") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
|
||||
Item {
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text { text: "Desktop & Dock"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: 27; font.weight: Font.DemiBold }
|
||||
Text { text: "Keep the shell instant, spatial, and out of your way."; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize; bottomPadding: 6 }
|
||||
|
||||
SettingsCard {
|
||||
title: "Dock"
|
||||
SettingRow {
|
||||
label: "Automatically hide the Dock"
|
||||
detail: "Reveal it at the bottom edge when a workspace is occupied"
|
||||
controlWidth: 48
|
||||
SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: DesktopPreferences.dockAutohide; onToggled: value => DesktopPreferences.dockAutohide = value }
|
||||
}
|
||||
SettingRow { label: "Reveal response"; detail: "The Dock appears as soon as the pointer reaches the edge"; value: DesktopPreferences.dockRevealDelayMs === 0 ? "Instant" : `${DesktopPreferences.dockRevealDelayMs} ms` }
|
||||
SettingRow { label: "Hide delay"; detail: "Prevents flicker when crossing icons"; value: `${DesktopPreferences.dockHideDelayMs} ms`; divider: false }
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Window layout"
|
||||
subtitle: "Panama follows the Forge mental model with native Hyprland tiling."
|
||||
SettingRow { label: "Layout"; detail: "Dwindle with preserved split direction"; value: "Tiling" }
|
||||
SettingRow { label: "Window corners"; detail: "Shared with Panama glass surfaces"; value: "18 px" }
|
||||
SettingRow { label: "Workspace movement"; detail: "Alt+H / Alt+L, add Shift to move a window"; value: "Dynamic"; divider: false }
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Reset"
|
||||
subtitle: "Restore Panama's curated clock, vitals, dock, focus, and display-policy defaults."
|
||||
SettingRow {
|
||||
label: "Desktop preferences"
|
||||
detail: "Your pinned applications and files are not changed"
|
||||
divider: false
|
||||
controlWidth: 122
|
||||
SettingsButton { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; text: "Restore defaults"; onClicked: DesktopPreferences.resetDesktopDefaults() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
import qs.widgets
|
||||
|
||||
Item {
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text { text: "Displays"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: 27; font.weight: Font.DemiBold }
|
||||
Text { text: SystemSettings.monitorDescription || "Reading the active display…"; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize; bottomPadding: 6 }
|
||||
|
||||
SettingsCard {
|
||||
title: SystemSettings.monitorName || "Active display"
|
||||
subtitle: `${SystemSettings.monitorWidth} × ${SystemSettings.monitorHeight} at ${SystemSettings.monitorRefreshRate.toFixed(0)} Hz · ${SystemSettings.monitorScale.toFixed(1)}× scale · ${SystemSettings.monitorFormat}`
|
||||
SettingRow { label: "Color mode"; detail: "Wide-gamut SDR desktop at 10-bit"; value: SystemSettings.colorPreset || "wide" }
|
||||
SettingRow { label: "Variable refresh"; detail: SystemSettings.monitorVrrActive ? "Active for current fullscreen content" : "Ready when game or video content requests it"; value: SystemSettings.monitorVrrActive ? "Active" : "Standby"; divider: false }
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Gaming display policy"
|
||||
subtitle: "These values apply immediately and are restored when Panama starts."
|
||||
SettingRow {
|
||||
label: "Game-aware HDR"
|
||||
detail: "Enter HDR only for fullscreen content that requests it"
|
||||
controlWidth: 48
|
||||
SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: SystemSettings.autoHdr; onToggled: value => SystemSettings.setAutoHdr(value) }
|
||||
}
|
||||
SettingRow {
|
||||
label: "Content-aware VRR"
|
||||
detail: "Enable variable refresh only for game and video content"
|
||||
controlWidth: 48
|
||||
SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: SystemSettings.vrrPolicy === 3; onToggled: value => SystemSettings.setVrrPolicy(value ? 3 : 0) }
|
||||
}
|
||||
SettingRow {
|
||||
label: "Direct scanout for games"
|
||||
detail: "Bypass compositing only for windows classified as games"
|
||||
divider: false
|
||||
controlWidth: 48
|
||||
SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: SystemSettings.directScanoutPolicy === 2; onToggled: value => SystemSettings.setDirectScanoutPolicy(value ? 2 : 0) }
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Night Light"
|
||||
SettingRow {
|
||||
label: "Warm display colors"
|
||||
detail: NightLight.automatic ? "Following the evening schedule" : "Manual control"
|
||||
controlWidth: 48
|
||||
SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: NightLight.active; onToggled: NightLight.toggle() }
|
||||
}
|
||||
SettingRow {
|
||||
label: "Color temperature"
|
||||
detail: `${NightLight.temperature} K`
|
||||
divider: false
|
||||
controlWidth: 230
|
||||
ValueSlider {
|
||||
anchors.fill: parent
|
||||
value: (6500 - NightLight.temperature) / 4000
|
||||
icon: "weather-clear-night-symbolic"
|
||||
onMoved: value => NightLight.temperature = Math.round((6500 - value * 4000) / 50) * 50
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: warningText.implicitHeight + 30
|
||||
radius: Theme.cardRadius
|
||||
color: Theme.alpha(Theme.warn, 0.085)
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(Theme.warn, 0.22)
|
||||
Text {
|
||||
id: warningText
|
||||
anchors.fill: parent
|
||||
anchors.margins: 15
|
||||
text: "Full-time desktop HDR stays unavailable here because the current compositor path can break screenshots, OBS, Sunshine, and lock-screen capture. Game-aware HDR keeps the desktop dependable without giving up HDR games."
|
||||
color: Theme.mix(Theme.fg, Theme.warn, 0.25)
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property int openedHour: new Date().getHours()
|
||||
readonly property string greeting: openedHour < 12 ? "Good morning" : (openedHour < 18 ? "Good afternoon" : "Good evening")
|
||||
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
text: `${root.greeting}, Gabriel`
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 27
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Your Panama desktop is configured and ready."
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
bottomPadding: 6
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: SystemSettings.monitorDescription || "Active display"
|
||||
subtitle: SystemSettings.monitorName || "Detecting your display…"
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 164
|
||||
spacing: 28
|
||||
|
||||
Item {
|
||||
width: parent.width * 0.47
|
||||
height: parent.height
|
||||
|
||||
Rectangle {
|
||||
width: Math.min(parent.width - 24, 260)
|
||||
height: width * 0.64
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 5
|
||||
radius: 12
|
||||
color: Theme.alpha(Theme.bgDark, 0.94)
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(Theme.accent, 0.34)
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
radius: 7
|
||||
gradient: Gradient {
|
||||
orientation: Gradient.Horizontal
|
||||
GradientStop { position: 0; color: Theme.mix(Theme.bg, Theme.accent, 0.08) }
|
||||
GradientStop { position: 1; color: Theme.mix(Theme.bg, Theme.accentSecondary, 0.08) }
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: SystemSettings.monitorName || "DISPLAY"
|
||||
color: Theme.fgMuted
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.letterSpacing: 1.5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width * 0.47
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 13
|
||||
|
||||
Text {
|
||||
text: `${SystemSettings.monitorWidth} × ${SystemSettings.monitorHeight}`
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.features: Theme.tabularFigures
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
Text {
|
||||
text: `${SystemSettings.monitorRefreshRate.toFixed(0)} Hz · ${SystemSettings.monitorScale.toFixed(1)}× scale`
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.features: Theme.tabularFigures
|
||||
font.pixelSize: Theme.fontSize
|
||||
}
|
||||
Text {
|
||||
text: `${SystemSettings.monitorFormat || "Detecting format"} · ${SystemSettings.colorPreset || "standard color"}`
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
}
|
||||
Text {
|
||||
text: SystemSettings.autoHdr ? "Game-aware HDR is ready" : "Game-aware HDR is off"
|
||||
color: SystemSettings.autoHdr ? Theme.ok : Theme.warn
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: 16
|
||||
|
||||
SettingsCard {
|
||||
width: (parent.width - parent.spacing) / 2
|
||||
title: "Quiet focus"
|
||||
subtitle: "Notifications and focused work"
|
||||
|
||||
SettingRow {
|
||||
label: "Do Not Disturb"
|
||||
detail: Notifs.doNotDisturb ? "Banners are currently quiet" : "Notification banners are visible"
|
||||
divider: false
|
||||
controlWidth: 48
|
||||
SettingsToggle {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: Notifs.doNotDisturb
|
||||
onToggled: value => Notifs.doNotDisturb = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: (parent.width - parent.spacing) / 2
|
||||
title: "Desktop services"
|
||||
subtitle: "The essentials are running"
|
||||
|
||||
SettingRow {
|
||||
label: "Sync & remote access"
|
||||
detail: `${SystemSettings.nextcloudActive ? "Nextcloud ready" : "Nextcloud stopped"} · ${SystemSettings.rustdeskActive ? "RustDesk ready" : "RustDesk stopped"}`
|
||||
divider: false
|
||||
value: SystemSettings.nextcloudActive && SystemSettings.rustdeskActive ? "Healthy" : "Review"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
Item {
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text { text: "Notifications & Focus"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: 27; font.weight: Font.DemiBold }
|
||||
Text { text: "Control interruptions without losing useful history."; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize; bottomPadding: 6 }
|
||||
|
||||
SettingsCard {
|
||||
title: "Notifications"
|
||||
SettingRow {
|
||||
label: "Do Not Disturb"
|
||||
detail: "Keep notifications in the center but suppress banners"
|
||||
controlWidth: 48
|
||||
SettingsToggle { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; checked: Notifs.doNotDisturb; onToggled: value => Notifs.doNotDisturb = value }
|
||||
}
|
||||
SettingRow { label: "Notification history"; detail: "Live notifications retained by Panama"; value: `${Notifs.history.length} items` }
|
||||
SettingRow {
|
||||
label: "Clear notification history"
|
||||
detail: "Dismiss every item currently in the notification center"
|
||||
divider: false
|
||||
controlWidth: 94
|
||||
SettingsButton { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; text: "Clear all"; enabled: Notifs.history.length > 0; onClicked: Notifs.dismissAll() }
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Focus sessions"
|
||||
subtitle: "A focus session binds quiet mode and Caffeine to the current workspace."
|
||||
SettingRow {
|
||||
label: "Default duration"
|
||||
detail: "Used by Super+Shift+F and Quick Settings"
|
||||
controlWidth: 264
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 6
|
||||
Repeater {
|
||||
model: [25, 45, 60, 90]
|
||||
SettingsButton {
|
||||
required property int modelData
|
||||
text: `${modelData}m`
|
||||
tone: DesktopPreferences.focusDurationMinutes === modelData ? "accent" : "normal"
|
||||
onClicked: DesktopPreferences.focusDurationMinutes = modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SettingRow {
|
||||
label: FocusSession.active ? `Active on ${FocusSession.workspaceLabel}` : "No active focus session"
|
||||
detail: FocusSession.active ? `${FocusSession.remainingText} remaining` : "Start one without leaving Settings"
|
||||
divider: false
|
||||
controlWidth: 120
|
||||
SettingsButton {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: FocusSession.active ? "Show controls" : "Start focus"
|
||||
tone: FocusSession.active ? "normal" : "accent"
|
||||
onClicked: FocusSession.reveal()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
Component.onCompleted: ScreenIntelligence.refresh()
|
||||
|
||||
Timer {
|
||||
id: launchDelay
|
||||
interval: 180
|
||||
onTriggered: Capture.openIntelligence()
|
||||
}
|
||||
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
text: "Screen Intelligence"
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 27
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
Text {
|
||||
text: "Turn text and codes on screen into content you can use."
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
bottomPadding: 6
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Read anything on screen"
|
||||
subtitle: "Select a region, window, or display. Panama recognizes it locally and gives you clean follow-up actions."
|
||||
|
||||
SettingRow {
|
||||
icon: ""
|
||||
label: "Read screen text"
|
||||
detail: "Copy, search, translate, or open detected links"
|
||||
controlWidth: 160
|
||||
divider: false
|
||||
SettingsButton {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "Start reading"
|
||||
tone: "accent"
|
||||
enabled: ScreenIntelligence.ocrReady && ScreenIntelligence.englishReady
|
||||
onClicked: {
|
||||
ShellState.closeSettings();
|
||||
launchDelay.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Local recognition"
|
||||
subtitle: "The screen image stays in Panama's cache and is deleted when you dismiss the result."
|
||||
|
||||
SettingRow {
|
||||
label: "Text recognition"
|
||||
detail: "Tesseract with the English language model"
|
||||
value: ScreenIntelligence.ocrReady && ScreenIntelligence.englishReady ? "Ready" : "Needs install"
|
||||
}
|
||||
SettingRow {
|
||||
label: "QR & barcodes"
|
||||
detail: "ZBar recognizes codes alongside ordinary text"
|
||||
value: ScreenIntelligence.codeReady ? "Ready" : "Needs install"
|
||||
}
|
||||
SettingRow {
|
||||
label: "Privacy"
|
||||
detail: "Only Search, Translate, and Open send the selected result to another application or service"
|
||||
value: "Local first"
|
||||
divider: false
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Shortcut"
|
||||
SettingRow {
|
||||
label: "Read a screen selection"
|
||||
detail: "Also available as Read in the Print-screen picker"
|
||||
value: "Super + Shift + S"
|
||||
controlWidth: 190
|
||||
divider: ScreenIntelligence.ocrReady && ScreenIntelligence.codeReady && ScreenIntelligence.englishReady
|
||||
}
|
||||
SettingRow {
|
||||
visible: !ScreenIntelligence.ocrReady || !ScreenIntelligence.codeReady || !ScreenIntelligence.englishReady
|
||||
label: "Install recognition engines"
|
||||
detail: "sudo dnf install -y tesseract zbar"
|
||||
value: "Required once"
|
||||
divider: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
Item {
|
||||
function status(active: bool): string { return active ? "Running" : "Stopped"; }
|
||||
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
Text { width: parent.width - refresh.width; text: "Startup & Services"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: 27; font.weight: Font.DemiBold }
|
||||
SettingsButton { id: refresh; text: SystemSettings.busy ? "Refreshing…" : "Refresh"; enabled: !SystemSettings.busy; onClicked: SystemSettings.refresh() }
|
||||
}
|
||||
Text { text: "A clear view of the background tools that make the desktop feel complete."; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize; bottomPadding: 6 }
|
||||
|
||||
SettingsCard {
|
||||
title: "Your services"
|
||||
SettingRow {
|
||||
label: "Nextcloud"
|
||||
detail: "File synchronization and tray status"
|
||||
controlWidth: 190
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 10
|
||||
Text { anchors.verticalCenter: parent.verticalCenter; text: status(SystemSettings.nextcloudActive); color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize }
|
||||
SettingsButton { text: "Open"; onClicked: SystemSettings.openApplication("nextcloud") }
|
||||
}
|
||||
}
|
||||
SettingRow {
|
||||
label: "RustDesk"
|
||||
detail: "Remote access through the enabled system service"
|
||||
controlWidth: 190
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 10
|
||||
Text { anchors.verticalCenter: parent.verticalCenter; text: status(SystemSettings.rustdeskActive); color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize }
|
||||
SettingsButton { text: "Open"; onClicked: SystemSettings.openApplication("rustdesk") }
|
||||
}
|
||||
}
|
||||
SettingRow {
|
||||
label: "KDE Connect"
|
||||
detail: "Phone pairing, clipboard, files, and remote controls"
|
||||
divider: false
|
||||
controlWidth: 190
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 10
|
||||
Text { anchors.verticalCenter: parent.verticalCenter; text: status(SystemSettings.kdeconnectActive); color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize }
|
||||
SettingsButton { text: "Open"; onClicked: SystemSettings.openApplication("kdeconnect") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Desktop foundation"
|
||||
SettingRow { label: "Hyprpaper"; detail: "Wallpaper service"; value: status(SystemSettings.hyprpaperActive) }
|
||||
SettingRow { label: "Hypridle"; detail: "Idle and lock policy"; value: status(SystemSettings.hypridleActive) }
|
||||
SettingRow { label: "Vicinae"; detail: "Spotlight-style launcher daemon"; value: status(SystemSettings.vicinaeActive); divider: false }
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Fedora system settings"
|
||||
subtitle: "These remain owned by trusted system services and GNOME's mature panels."
|
||||
SettingRow {
|
||||
label: "Network, Bluetooth, printers, users, and accounts"
|
||||
detail: "GNOME Settings remains searchable from the launcher too"
|
||||
divider: false
|
||||
controlWidth: 122
|
||||
SettingsButton { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; text: "Open network"; onClicked: SystemSettings.openGnomePanel("network") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
default property alias trailingData: trailing.data
|
||||
property string icon: ""
|
||||
property string label: ""
|
||||
property string detail: ""
|
||||
property string value: ""
|
||||
property bool divider: true
|
||||
property int controlWidth: 150
|
||||
|
||||
width: parent ? parent.width : 620
|
||||
implicitHeight: Math.max(56, copy.implicitHeight + 20)
|
||||
|
||||
Text {
|
||||
id: iconLabel
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: root.icon === "" ? 0 : 28
|
||||
visible: root.icon !== ""
|
||||
text: root.icon
|
||||
color: Theme.accent
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 17
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
id: copy
|
||||
anchors.left: iconLabel.visible ? iconLabel.right : parent.left
|
||||
anchors.leftMargin: iconLabel.visible ? 10 : 0
|
||||
anchors.right: trailing.left
|
||||
anchors.rightMargin: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 3
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: root.label
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
font.weight: Font.Medium
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
visible: root.detail !== ""
|
||||
text: root.detail
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: trailing
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: root.controlWidth
|
||||
height: 32
|
||||
|
||||
Text {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.value !== ""
|
||||
text: root.value
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.features: Theme.tabularFigures
|
||||
font.pixelSize: Theme.fontSize
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: copy.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
height: 1
|
||||
visible: root.divider
|
||||
color: Theme.alpha(Theme.fg, 0.065)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string text: ""
|
||||
property string tone: "normal"
|
||||
property bool enabled: true
|
||||
signal clicked
|
||||
|
||||
implicitWidth: label.implicitWidth + 22
|
||||
implicitHeight: 31
|
||||
radius: 9
|
||||
opacity: enabled ? 1 : 0.45
|
||||
color: {
|
||||
if (tone === "accent")
|
||||
return mouse.containsMouse ? Theme.mix(Theme.accent, Theme.fg, 0.12) : Theme.accent;
|
||||
return mouse.containsMouse ? Theme.alpha(Theme.fg, 0.13) : Theme.alpha(Theme.fg, 0.075);
|
||||
}
|
||||
border.width: tone === "accent" ? 0 : 1
|
||||
border.color: Theme.alpha(Theme.fg, 0.08)
|
||||
|
||||
Text {
|
||||
id: label
|
||||
anchors.centerIn: parent
|
||||
text: root.text
|
||||
color: root.tone === "accent" ? Theme.bgDark : Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
anchors.fill: parent
|
||||
enabled: root.enabled
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
default property alias contentData: body.data
|
||||
property string title: ""
|
||||
property string subtitle: ""
|
||||
|
||||
width: parent ? parent.width : 680
|
||||
implicitHeight: body.implicitHeight + 30
|
||||
radius: Theme.cardRadius + 2
|
||||
color: Theme.alpha(Theme.bgPanel, 0.72)
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(Theme.fg, 0.07)
|
||||
|
||||
PrismEdge {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
inset: root.radius
|
||||
opacity: 0.36
|
||||
}
|
||||
|
||||
Column {
|
||||
id: body
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 15
|
||||
spacing: 0
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
visible: root.title !== ""
|
||||
text: root.title
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
bottomPadding: root.subtitle === "" ? 10 : 3
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
visible: root.subtitle !== ""
|
||||
text: root.subtitle
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
wrapMode: Text.WordWrap
|
||||
bottomPadding: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var hostWindow: null
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: titlebar
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
height: 48
|
||||
color: Theme.alpha(Theme.bgDark, 0.97)
|
||||
border.width: 0
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 18
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "Panama Settings"
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 7
|
||||
|
||||
Rectangle {
|
||||
width: 28; height: 28; radius: 9
|
||||
color: minMouse.containsMouse ? Theme.alpha(Theme.fg, 0.12) : Theme.alpha(Theme.fg, 0)
|
||||
Text { anchors.centerIn: parent; text: "—"; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize }
|
||||
MouseArea { id: minMouse; anchors.fill: parent; hoverEnabled: true; cursorShape: Qt.PointingHandCursor; onClicked: if (root.hostWindow) root.hostWindow.minimized = true }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 28; height: 28; radius: 9
|
||||
color: closeMouse.containsMouse ? Theme.alpha(Theme.danger, 0.17) : Theme.alpha(Theme.fg, 0)
|
||||
Text { anchors.centerIn: parent; text: "×"; color: closeMouse.containsMouse ? 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)
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: pageLoader
|
||||
anchors.left: sidebar.right
|
||||
anchors.right: parent.right
|
||||
anchors.top: titlebar.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
sourceComponent: {
|
||||
switch (ShellState.settingsPage) {
|
||||
case "appearance": return appearancePage;
|
||||
case "displays": return displaysPage;
|
||||
case "connectivity": return connectivityPage;
|
||||
case "desktop": return desktopPage;
|
||||
case "sound": return soundPage;
|
||||
case "notifications": return notificationsPage;
|
||||
case "screen-intelligence": return screenIntelligencePage;
|
||||
case "shortcuts": return shortcutsPage;
|
||||
case "services": return servicesPage;
|
||||
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: appearancePage; AppearancePage {} }
|
||||
Component { id: displaysPage; DisplaysPage {} }
|
||||
Component { id: connectivityPage; ConnectivityPage {} }
|
||||
Component { id: desktopPage; DesktopPage {} }
|
||||
Component { id: soundPage; SoundPage {} }
|
||||
Component { id: notificationsPage; NotificationsPage {} }
|
||||
Component { id: screenIntelligencePage; ScreenIntelligencePage {} }
|
||||
Component { id: shortcutsPage; ShortcutsPage {} }
|
||||
Component { id: servicesPage; ServicesPage {} }
|
||||
Component { id: aboutPage; AboutPage {} }
|
||||
|
||||
Shortcut {
|
||||
sequence: "Escape"
|
||||
onActivated: ShellState.closeSettings()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string selectedPage: "home"
|
||||
property string query: searchInput.text.trim().toLowerCase()
|
||||
signal pageRequested(string page)
|
||||
|
||||
readonly property var destinations: [
|
||||
{ page: "home", label: "Home", icon: "\u{F02DC}" },
|
||||
{ page: "appearance", label: "Appearance", icon: "\u{F0E0D}" },
|
||||
{ page: "displays", label: "Displays", icon: "\u{F0379}" },
|
||||
{ page: "connectivity", label: "Network & Devices", icon: "\u{F08D4}" },
|
||||
{ page: "desktop", label: "Desktop & Dock", icon: "\u{F04A4}" },
|
||||
{ page: "sound", label: "Sound", icon: "\u{F057E}" },
|
||||
{ page: "notifications", label: "Notifications & Focus", icon: "\u{F009A}" },
|
||||
{ page: "screen-intelligence", label: "Screen Intelligence", icon: "\u{F05A8}" },
|
||||
{ page: "shortcuts", label: "Input & Shortcuts", icon: "\u{F030C}" },
|
||||
{ page: "services", label: "Startup & Services", icon: "\u{F0493}" },
|
||||
{ page: "about", label: "About Panama", icon: "\u{F02FD}" }
|
||||
]
|
||||
|
||||
width: 272
|
||||
color: Theme.alpha(Theme.bgDark, 0.96)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 18
|
||||
spacing: 12
|
||||
|
||||
Text {
|
||||
text: "PANAMA"
|
||||
color: Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: 2.2
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 36
|
||||
radius: 10
|
||||
color: Theme.alpha(Theme.fg, searchArea.containsMouse || searchInput.activeFocus ? 0.105 : 0.065)
|
||||
border.width: 1
|
||||
border.color: searchInput.activeFocus ? Theme.alpha(Theme.accent, 0.5) : Theme.alpha(Theme.fg, 0.055)
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 11
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "\u{F0349}"
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 14
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: searchInput
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 35
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Theme.fg
|
||||
selectionColor: Theme.accent
|
||||
selectedTextColor: Theme.bgDark
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
clip: true
|
||||
|
||||
Text {
|
||||
anchors.fill: parent
|
||||
visible: !searchInput.text && !searchInput.activeFocus
|
||||
text: "Search settings"
|
||||
color: Theme.fgMuted
|
||||
font: searchInput.font
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: searchArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.IBeamCursor
|
||||
onClicked: searchInput.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 4
|
||||
|
||||
Repeater {
|
||||
model: root.destinations.filter(item => root.query === "" || item.label.toLowerCase().includes(root.query))
|
||||
|
||||
Rectangle {
|
||||
id: navItem
|
||||
required property var modelData
|
||||
width: parent.width
|
||||
height: 40
|
||||
radius: 10
|
||||
color: modelData.page === root.selectedPage
|
||||
? Theme.alpha(Theme.accent, 0.17)
|
||||
: (navMouse.containsMouse ? Theme.alpha(Theme.fg, Theme.hoverAlpha * 0.55) : Theme.alpha(Theme.fg, 0))
|
||||
border.width: modelData.page === root.selectedPage ? 1 : 0
|
||||
border.color: Theme.alpha(Theme.accent, 0.26)
|
||||
|
||||
Rectangle {
|
||||
width: 2
|
||||
height: 18
|
||||
radius: 1
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: navItem.modelData.page === root.selectedPage
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0; color: Theme.accent }
|
||||
GradientStop { position: 1; color: Theme.accentSecondary }
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 13
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 25
|
||||
text: navItem.modelData.icon
|
||||
color: navItem.modelData.page === root.selectedPage ? Theme.accent : Theme.fgDim
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 15
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 47
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 9
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: navItem.modelData.label
|
||||
color: navItem.modelData.page === root.selectedPage ? Theme.fg : Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
font.weight: navItem.modelData.page === root.selectedPage ? Font.Medium : Font.Normal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: navMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.pageRequested(navItem.modelData.page)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
height: 54
|
||||
color: Theme.alpha(Theme.bg, 0.35)
|
||||
border.width: 0
|
||||
|
||||
Rectangle {
|
||||
width: 7
|
||||
height: 7
|
||||
radius: 4
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 19
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Theme.ok
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 36
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "Panama desktop is healthy"
|
||||
color: Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property bool checked: false
|
||||
property bool enabled: true
|
||||
signal toggled(bool checked)
|
||||
|
||||
implicitWidth: 42
|
||||
implicitHeight: 24
|
||||
radius: height / 2
|
||||
color: checked ? Theme.accent : Theme.alpha(Theme.fg, 0.13)
|
||||
opacity: enabled ? 1 : 0.45
|
||||
border.width: 1
|
||||
border.color: checked ? Theme.alpha(Theme.accentAlt, 0.55) : Theme.alpha(Theme.fg, 0.08)
|
||||
|
||||
Behavior on color { ColorAnimation { duration: Theme.durFast } }
|
||||
|
||||
Rectangle {
|
||||
width: 18
|
||||
height: 18
|
||||
radius: 9
|
||||
x: root.checked ? root.width - width - 3 : 3
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: root.checked ? Theme.bgDark : Theme.fgDim
|
||||
border.width: 0
|
||||
Behavior on x {
|
||||
NumberAnimation { duration: Theme.durFast; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: root.enabled
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.toggled(!root.checked)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
FloatingWindow {
|
||||
id: root
|
||||
|
||||
title: "Panama Settings"
|
||||
visible: ShellState.settingsOpen
|
||||
implicitWidth: 1120
|
||||
implicitHeight: 760
|
||||
minimumSize: Qt.size(900, 620)
|
||||
color: Theme.alpha(Theme.bg, 0)
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
SystemSettings.refresh();
|
||||
} else if (ShellState.settingsOpen) {
|
||||
// Keep Super+I deterministic after compositor close/Alt+F4.
|
||||
ShellState.closeSettings();
|
||||
}
|
||||
}
|
||||
|
||||
SettingsShell {
|
||||
anchors.fill: parent
|
||||
hostWindow: root
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var shortcuts: [
|
||||
{ key: "Super + T", action: "Terminal" },
|
||||
{ key: "Super + N", action: "Neovim in the current directory" },
|
||||
{ key: "Super + W", action: "Web browser" },
|
||||
{ key: "Super + F", action: "Files" },
|
||||
{ key: "Super + I", action: "Panama Settings" },
|
||||
{ key: "Super + Space", action: "Launcher" },
|
||||
{ key: "Super + Grave", action: "Continuum overview" },
|
||||
{ key: "Super + V", action: "Clipboard history" },
|
||||
{ key: "Super + S", action: "Quick Settings" },
|
||||
{ key: "Super + B", action: "Notifications" },
|
||||
{ key: "Super + Shift + S", action: "Screen Intelligence" },
|
||||
{ key: "Super + Shift + F", action: "Focus session" },
|
||||
{ key: "Alt + H / L", action: "Previous / next workspace" },
|
||||
{ key: "Alt + Shift + H / L", action: "Move window between workspaces" },
|
||||
{ key: "Super + H / J / K / L", action: "Focus a tiled window" },
|
||||
{ key: "Super + Shift + H / J / K / L", action: "Move a tiled window" },
|
||||
{ key: "Super + Shift + X", action: "Send window to scratchpad" },
|
||||
{ key: "Super + X", action: "Toggle scratchpad" },
|
||||
{ key: "Print", action: "Capture, record, or read" }
|
||||
]
|
||||
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text { text: "Input & Shortcuts"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: 27; font.weight: Font.DemiBold }
|
||||
Text { text: "The Forge mental model, carried forward into native tiling."; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize; bottomPadding: 6 }
|
||||
|
||||
SettingsCard {
|
||||
title: "Panama shortcuts"
|
||||
Repeater {
|
||||
model: root.shortcuts
|
||||
SettingRow {
|
||||
required property var modelData
|
||||
required property int index
|
||||
label: modelData.action
|
||||
value: modelData.key
|
||||
controlWidth: 210
|
||||
divider: index < root.shortcuts.length - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Hardware input"
|
||||
SettingRow {
|
||||
label: "Mouse, touchpad, and keyboard devices"
|
||||
detail: "Use Fedora's hardware-backed input panels"
|
||||
divider: false
|
||||
controlWidth: 126
|
||||
SettingsButton { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; text: "Open keyboard"; onClicked: SystemSettings.openGnomePanel("keyboard") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import QtQuick
|
||||
import Quickshell.Services.Pipewire
|
||||
import qs.config
|
||||
import qs.services
|
||||
import qs.modules.quicksettings
|
||||
|
||||
Item {
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: content.implicitHeight + 64
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Column {
|
||||
id: content
|
||||
width: parent.width - 68
|
||||
x: 34
|
||||
y: 30
|
||||
spacing: 16
|
||||
|
||||
Text { text: "Sound"; color: Theme.fg; font.family: Theme.fontFamily; font.pixelSize: 27; font.weight: Font.DemiBold }
|
||||
Text { text: "Live PipeWire output, input, and device selection."; color: Theme.fgDim; font.family: Theme.fontFamily; font.pixelSize: Theme.fontSize; bottomPadding: 6 }
|
||||
|
||||
SettingsCard {
|
||||
title: "Output"
|
||||
subtitle: Pipewire.defaultAudioSink?.description ?? "No output device"
|
||||
AudioSlider { width: parent.width; node: Pipewire.defaultAudioSink; output: true }
|
||||
Rectangle { width: parent.width; height: 1; color: Theme.alpha(Theme.fg, 0.06) }
|
||||
AudioDeviceList { width: parent.width; output: true; maxHeight: 190 }
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Input"
|
||||
subtitle: Pipewire.defaultAudioSource?.description ?? "No input device"
|
||||
AudioSlider { width: parent.width; node: Pipewire.defaultAudioSource; output: false }
|
||||
Rectangle { width: parent.width; height: 1; color: Theme.alpha(Theme.fg, 0.06) }
|
||||
AudioDeviceList { width: parent.width; output: false; maxHeight: 160 }
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Advanced sound"
|
||||
SettingRow {
|
||||
label: "Application volumes and profiles"
|
||||
detail: "Open Fedora's complete sound panel"
|
||||
divider: false
|
||||
controlWidth: 104
|
||||
SettingsButton { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; text: "Open panel"; onClicked: SystemSettings.openGnomePanel("sound") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
module qs.modules.settings
|
||||
AboutPage 1.0 AboutPage.qml
|
||||
AppearancePage 1.0 AppearancePage.qml
|
||||
ConnectivityPage 1.0 ConnectivityPage.qml
|
||||
DesktopPage 1.0 DesktopPage.qml
|
||||
DisplaysPage 1.0 DisplaysPage.qml
|
||||
HomePage 1.0 HomePage.qml
|
||||
NotificationsPage 1.0 NotificationsPage.qml
|
||||
ScreenIntelligencePage 1.0 ScreenIntelligencePage.qml
|
||||
ServicesPage 1.0 ServicesPage.qml
|
||||
SettingRow 1.0 SettingRow.qml
|
||||
SettingsCard 1.0 SettingsCard.qml
|
||||
SettingsButton 1.0 SettingsButton.qml
|
||||
SettingsShell 1.0 SettingsShell.qml
|
||||
SettingsSidebar 1.0 SettingsSidebar.qml
|
||||
SettingsToggle 1.0 SettingsToggle.qml
|
||||
SettingsWindow 1.0 SettingsWindow.qml
|
||||
ShortcutsPage 1.0 ShortcutsPage.qml
|
||||
SoundPage 1.0 SoundPage.qml
|
||||
Reference in New Issue
Block a user