import QtQuick import Quickshell import "../services" as S import NovaStats as NS // NOT safe for lock screen - executes system commands (shutdown, reboot, logout, suspend) Column { id: root required property color accentColor signal runCommand(var cmd) signal dismiss readonly property bool _isNiri: Quickshell.env("NIRI_SOCKET") !== "" property var _confirmItem: null function _run(cmd) { runCommand(cmd); dismiss(); } function _requestAction(item) { if (item.confirm) { _confirmItem = item; } else { _run(item.cmd); } } function _cancelConfirm() { _confirmItem = null; } // Normal menu entries Column { visible: !root._confirmItem width: root.width Repeater { model: [ { label: "Lock", icon: "\uF023", cmd: ["loginctl", "lock-session"], color: NS.ThemeService.base0D, confirm: false }, { label: "Suspend", icon: "\uF186", cmd: ["systemctl", "suspend"], color: NS.ThemeService.base0E, confirm: false }, { label: "Logout", icon: "\uF2F5", cmd: root._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""], color: NS.ThemeService.base0A, confirm: false }, { label: "Reboot", icon: "\uF021", cmd: ["systemctl", "reboot"], color: NS.ThemeService.base09, confirm: true }, { label: "Shutdown", icon: "\uF011", cmd: ["systemctl", "poweroff"], color: NS.ThemeService.base08, confirm: true } ] delegate: Item { id: entry required property var modelData required property int index width: root.width height: 32 Rectangle { anchors.fill: parent anchors.leftMargin: 4 anchors.rightMargin: 4 color: entryHover.hovered ? NS.ThemeService.base02 : "transparent" radius: NS.ThemeService.radius } Text { id: entryIcon anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 12 text: entry.modelData.icon color: entry.modelData.color font.pixelSize: NS.ThemeService.fontSize + 1 font.family: NS.ThemeService.iconFontFamily } Text { anchors.verticalCenter: parent.verticalCenter anchors.left: entryIcon.right anchors.leftMargin: 10 text: entry.modelData.label color: NS.ThemeService.base05 font.pixelSize: NS.ThemeService.fontSize font.family: NS.ThemeService.fontFamily } HoverHandler { id: entryHover cursorShape: Qt.PointingHandCursor } TapHandler { onTapped: root._requestAction(entry.modelData) } } } } // Confirmation view Column { visible: !!root._confirmItem width: root.width spacing: 4 Item { width: parent.width height: 28 Text { anchors.centerIn: parent text: root._confirmItem ? root._confirmItem.label + "?" : "" color: root._confirmItem ? root._confirmItem.color : NS.ThemeService.base05 font.pixelSize: NS.ThemeService.fontSize font.family: NS.ThemeService.fontFamily font.bold: true } } Row { anchors.horizontalCenter: parent.horizontalCenter spacing: 8 Item { width: 72 height: 28 Rectangle { anchors.fill: parent color: cancelHover.hovered ? NS.ThemeService.base02 : NS.ThemeService.base01 radius: NS.ThemeService.radius border.width: 1 border.color: NS.ThemeService.base03 } Text { anchors.centerIn: parent text: "Cancel" color: NS.ThemeService.base05 font.pixelSize: NS.ThemeService.fontSize font.family: NS.ThemeService.fontFamily } HoverHandler { id: cancelHover cursorShape: Qt.PointingHandCursor } TapHandler { onTapped: root._cancelConfirm() } } Item { width: 72 height: 28 Rectangle { anchors.fill: parent color: { if (!root._confirmItem) return NS.ThemeService.base02; const c = root._confirmItem.color; return confirmHover.hovered ? Qt.rgba(c.r, c.g, c.b, 0.3) : Qt.rgba(c.r, c.g, c.b, 0.15); } radius: NS.ThemeService.radius border.width: 1 border.color: root._confirmItem ? root._confirmItem.color : NS.ThemeService.base03 } Text { anchors.centerIn: parent text: "Confirm" color: root._confirmItem ? root._confirmItem.color : NS.ThemeService.base05 font.pixelSize: NS.ThemeService.fontSize font.family: NS.ThemeService.fontFamily font.bold: true } HoverHandler { id: confirmHover cursorShape: Qt.PointingHandCursor } TapHandler { onTapped: { if (root._confirmItem) root._run(root._confirmItem.cmd); } } } } Item { width: 1 height: 4 } } }