Dotfiles_ArchAP/quickshell/.config/quickshell/labfy-sway/controlcenter/ControlCenter.qml

244 lines
9.8 KiB
QML

import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Networking
import Quickshell.Bluetooth
import "../components"
import "../theme"
PopupWindow {
id: popup
required property var barWindow
// CONTRACT: indices externes historiques conservés ; tout nouveau routage
// passe par ces noms afin de ne pas multiplier les indices StackLayout.
readonly property var pages: ({ main: 0, wifi: 1, bluetooth: 2, session: 3,
confirmation: 4, battery: 5, appearance: 6, wallpaper: 7, theme: 8,
nightLight: 9, sunMode: 10, locationTime: 11, sessionManager: 12 })
property int currentPage: pages.main
function openPage(name) { if (pages[name] !== undefined) currentPage = pages[name]; }
signal thresholdApplied()
property var pendingAction: null
// Une seule table associe les libellés, confirmations et commandes de session.
readonly property var sessionActions: [
{ id: "lock", label: "Verrouiller", icon: "", accent: Theme.accent, command: ["swaylock"] },
{ id: "suspend", label: "Veille", icon: "", accent: Theme.accent,
confirmTitle: "Mettre l'ordinateur en veille ?",
description: "La session sera verrouillée avant la veille.",
command: ["systemctl", "suspend"] },
{ id: "logout", label: "Déconnexion", icon: "", accent: Theme.urgent,
confirmTitle: "Se déconnecter ?",
description: "La session SwayFX en cours sera fermée.",
command: ["uwsm", "stop"] },
{ id: "reboot", label: "Redémarrer", icon: "", accent: Theme.warning,
confirmTitle: "Redémarrer l'ordinateur ?",
description: "La session en cours sera fermée.",
command: ["systemctl", "reboot"] },
{ id: "poweroff", label: "Éteindre", icon: "", accent: Theme.danger,
confirmTitle: "Éteindre l'ordinateur ?",
description: "La session en cours sera fermée.",
command: ["systemctl", "poweroff"] }
]
readonly property var wifiDevice: Networking.devices.values.find(device => device.type === DeviceType.Wifi) || null
readonly property var adapter: Bluetooth.defaultAdapter
// Une nouvelle ouverture recommence sur MAIN ; les pages libèrent leurs scans à la fermeture.
onVisibleChanged: if (!visible) {
openPage("main");
pendingAction = null;
}
function requestSessionAction(id) {
const selected = sessionActions.find(item => item.id === id);
if (!selected) return;
if (id === "lock") {
executeSessionAction(id);
return;
}
pendingAction = selected;
openPage("confirmation");
}
function executeSessionAction(id) {
const selected = sessionActions.find(item => item.id === id);
if (!selected) return;
// Fermer le popup avant toute commande qui peut verrouiller ou terminer la session.
visible = false;
// CONTRACT: UWSM possède le cycle de vie de Sway ; son arrêt doit donc
// passer par la commande déclarée, comme les autres actions de session.
if (selected.command) Quickshell.execDetached(selected.command);
}
anchor.window: barWindow
anchor.rect.x: barWindow.width - implicitWidth - 8
anchor.rect.y: barWindow.height + 6
anchor.edges: Edges.Top | Edges.Left
anchor.gravity: Edges.Bottom | Edges.Right
implicitWidth: 400
implicitHeight: currentPage === 0 ? mainPage.implicitHeight + 32
: currentPage === 3 ? sessionPage.implicitHeight + 32
: currentPage === 4 ? confirmationPage.implicitHeight + 32
: currentPage === 5 ? batteryPage.implicitHeight + 32
: currentPage === pages.wallpaper ? 550
: currentPage === pages.appearance ? 520
: currentPage === pages.locationTime || currentPage === pages.sessionManager ? 650 : 440
visible: false
// CONTRACT: PopupWindow n'applique un changement de grabFocus qu'après
// fermeture/réouverture ; le prendre dès MAIN garde le clavier disponible
// pour le mot de passe Wi-Fi et l'alias Bluetooth après navigation interne.
grabFocus: true
color: "transparent"
Rectangle {
anchors.fill: parent
radius: 4
color: Theme.popupBackground
border.color: Theme.outline
StackLayout {
anchors.fill: parent
anchors.margins: 16
currentIndex: popup.currentPage
Column {
id: mainPage
spacing: 18
Text {
text: "Réglages rapides"
color: Theme.foreground
font.pixelSize: 16
font.bold: true
}
Row {
width: parent.width
spacing: 8
WifiTile {
width: (parent.width - parent.spacing) / 2
wifiDevice: popup.wifiDevice
onDetailsRequested: popup.openPage("wifi")
}
BluetoothTile {
width: (parent.width - parent.spacing) / 2
adapter: popup.adapter
onDetailsRequested: popup.openPage("bluetooth")
}
}
VolumeSlider { width: parent.width }
BrightnessSlider { width: parent.width }
PowerProfile { width: parent.width }
Rectangle {
width: parent.width; height: 38; radius: 4
color: appearancePointer.containsMouse ? Theme.buttonHover : Theme.buttonBackground
NerdIcon { anchors.left: parent.left; anchors.leftMargin: 10; anchors.verticalCenter: parent.verticalCenter; text: "󰸉"; color: Theme.accent; font.pixelSize: 18 }
Text { anchors.left: parent.left; anchors.leftMargin: 42; anchors.verticalCenter: parent.verticalCenter; text: "Apparence"; color: Theme.foreground; font.pixelSize: 13 }
MouseArea { id: appearancePointer; anchors.fill: parent; hoverEnabled: true; onClicked: popup.openPage("appearance") }
}
Item {
width: parent.width
height: 30
Rectangle {
anchors.right: parent.right
width: 40
height: 30
radius: 4
color: powerPointer.containsMouse ? Theme.border : Theme.buttonBackground
NerdIcon {
anchors.centerIn: parent
text: ""
}
MouseArea {
id: powerPointer
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton
onClicked: popup.openPage("session")
}
}
}
}
WifiPage {
id: wifiPage
wifiDevice: popup.wifiDevice
activePage: popup.visible && popup.currentPage === 1
onBackRequested: popup.openPage("main")
}
BluetoothPage {
id: bluetoothPage
adapter: popup.adapter
activePage: popup.visible && popup.currentPage === 2
onBackRequested: popup.openPage("main")
}
SessionPage {
id: sessionPage
actions: popup.sessionActions
onBackRequested: popup.openPage("main")
onManagerRequested: popup.openPage("sessionManager")
onActionRequested: id => popup.requestSessionAction(id)
}
ConfirmAction {
id: confirmationPage
actionInfo: popup.pendingAction || ({ id: "", label: "", confirmTitle: "",
description: "", accent: Theme.foreground })
onCancelled: {
popup.pendingAction = null;
popup.openPage("session");
}
onConfirmed: id => {
if (popup.pendingAction && popup.pendingAction.id === id)
popup.executeSessionAction(id);
}
}
BatterySettings {
id: batteryPage
activePage: popup.visible && popup.currentPage === 5
onBackRequested: popup.openPage("main")
onThresholdApplied: popup.thresholdApplied()
}
AppearancePage {
onBackRequested: popup.openPage("main")
onWallpaperRequested: popup.openPage("wallpaper")
onThemeRequested: popup.openPage("theme")
onNightLightRequested: popup.openPage("nightLight")
onSunModeRequested: popup.openPage("sunMode")
onLocationTimeRequested: popup.openPage("locationTime")
}
WallpaperPage {
activePage: popup.visible && popup.currentPage === popup.pages.wallpaper
onBackRequested: popup.openPage("appearance")
}
ThemePage {
onBackRequested: popup.openPage("appearance")
}
NightLightPage {
onBackRequested: popup.openPage("appearance")
}
SunModePage {
onBackRequested: popup.openPage("appearance")
}
LocationTimePage {
onBackRequested: popup.openPage("appearance")
}
SessionManager {
activePage: popup.visible && popup.currentPage === popup.pages.sessionManager
onBackRequested: popup.openPage("session")
}
}
}
}