repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
quickshell/nuguland/PrivilegeSurface.qml
Rawpragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Window
import "privilege.js" as PrivilegeUi
Rectangle {
id: root
required property Theme theme
required property Privilege privilegeService
property var panelState: privilegeService ? parseJson(privilegeService.stateJson(), {
"request": {},
"privilegeSurfacePanelContract": {},
"buttons": [],
"confirming": false
}) : ({
"request": {},
"privilegeSurfacePanelContract": {},
"buttons": [],
"confirming": false
})
readonly property var request: panelState.request || ({})
property bool secretVisible: false
property bool promptWasActive: false
readonly property bool secretPromptField: true
readonly property bool denyCancelConfirmRow: true
readonly property bool failureShakeSlot: true
function parseJson(text, valueWhenInvalid) {
try {
return JSON.parse(String(text));
} catch (error) {
return valueWhenInvalid;
}
}
function refreshFrom(text) {
const wasActive = promptWasActive;
panelState = parseJson(text, panelState);
promptWasActive = !!panelState.active;
if (!wasActive && promptWasActive)
Qt.callLater(root.focusSecret);
}
function submitSecret(secret) {
if (privilegeService)
refreshFrom(privilegeService.submit(secret));
}
function deny() {
if (privilegeService)
refreshFrom(privilegeService.deny());
}
function cancel() {
if (privilegeService)
refreshFrom(privilegeService.cancel());
}
function focusSecret() {
if (root.visible && root.panelState.active) {
root.forceActiveFocus();
secretInput.forceActiveFocus();
}
}
color: theme ? theme.withAlpha(theme.ui.backdrop, 0.94) : "black"
visible: panelState.active || panelState.error.length > 0 || panelState.confirming
focus: visible
onVisibleChanged: {
if (visible && panelState.active)
Qt.callLater(root.focusSecret);
}
Component.onCompleted: {
promptWasActive = !!panelState.active;
Qt.callLater(root.focusSecret);
}
Connections {
target: root.privilegeService
function onActiveChanged() {
root.refreshFrom(root.privilegeService.stateJson());
}
function onConfirmingChanged() {
root.refreshFrom(root.privilegeService.stateJson());
}
function onErrorChanged() {
root.refreshFrom(root.privilegeService.stateJson());
}
}
Connections {
target: root.Window.window
function onActiveChanged() {
if (root.Window.window.active && root.visible && root.panelState.active)
Qt.callLater(root.focusSecret);
}
}
Keys.onEscapePressed: event => {
event.accepted = true;
root.cancel();
}
Rectangle {
anchors.centerIn: parent
width: Math.min(parent.width - 48, 680)
height: cardColumn.implicitHeight + 44
radius: 24
color: root.theme ? root.theme.withAlpha(root.theme.ui.backdrop, 0.98) : "#181818"
border.width: 1
border.color: root.theme ? root.theme.withAlpha(root.panelState.error ? root.theme.error : root.theme.ui.accent, 0.32) : "transparent"
Column {
id: cardColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 22
spacing: 16
Column {
width: parent.width
spacing: 10
NuguText {
theme: root.theme
variant: "title"
text: root.panelState.confirming ? "authorization granted" : (root.panelState.error && !root.panelState.active ? "authentication unavailable" : "authorization required")
width: parent.width
elide: Text.ElideRight
}
Rectangle {
width: parent.width
height: commandText.implicitHeight + 20
radius: 16
color: root.theme ? root.theme.withAlpha(root.theme.ui.minor, 0.08) : "transparent"
Text {
id: commandText
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 10
text: PrivilegeUi.commandMarkdown(root.request.message || "A system change needs your password.")
color: root.theme ? root.theme.content.normal : "white"
textFormat: Text.RichText
wrapMode: Text.WordWrap
elide: Text.ElideNone
}
}
}
Rectangle {
id: successBanner
visible: root.panelState.confirming
width: parent.width
height: visible ? 58 : 0
radius: 16
color: root.theme ? root.theme.withAlpha(root.theme.info, 0.16) : "transparent"
border.width: 1
border.color: root.theme ? root.theme.withAlpha(root.theme.info, 0.62) : "transparent"
opacity: visible ? 1 : 0
scale: visible ? 1 : 0.96
Behavior on opacity {
NumberAnimation {
duration: root.theme && root.theme.lowPowerMode ? 0 : 150
easing.type: Easing.OutCubic
}
}
Behavior on scale {
NumberAnimation {
duration: root.theme && root.theme.lowPowerMode ? 0 : 180
easing.type: Easing.OutBack
}
}
Row {
anchors.centerIn: parent
spacing: 12
Text {
anchors.verticalCenter: parent.verticalCenter
text: "✓"
color: root.theme ? root.theme.info : "white"
font.family: "IBM Plex Mono"
font.pixelSize: 20
font.bold: true
}
NuguText {
anchors.verticalCenter: parent.verticalCenter
theme: root.theme
variant: "title"
text: "authorized"
color: root.theme ? root.theme.info : "white"
}
}
}
PrivilegeFailureShake {
theme: root.theme
objectName: "failureShakeSlot"
visible: !root.panelState.confirming
active: root.panelState.error && root.panelState.error.length > 0
width: parent.width
height: inputColumn.implicitHeight
Column {
id: inputColumn
width: parent.width
spacing: 7
Rectangle {
id: secretBox
objectName: "secretPromptField"
width: parent.width
height: 48
radius: 16
color: root.theme ? root.theme.withAlpha(root.panelState.error ? root.theme.error : root.theme.ui.focus, root.panelState.error ? 0.12 : (secretInput.activeFocus ? 0.16 : 0.1)) : "transparent"
border.width: 1
border.color: root.theme ? root.theme.withAlpha(root.panelState.error ? root.theme.error : root.theme.ui.focus, root.panelState.error ? 0.72 : (secretInput.activeFocus ? 0.82 : 0.32)) : "transparent"
Behavior on color {
ColorAnimation {
duration: root.theme && root.theme.lowPowerMode ? 0 : 120
}
}
Behavior on border.color {
ColorAnimation {
duration: root.theme && root.theme.lowPowerMode ? 0 : 120
}
}
NuguText {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
theme: root.theme
variant: "meta"
text: root.request.prompt || "password"
visible: secretInput.text.length === 0
opacity: secretInput.activeFocus ? 0.42 : 0.68
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.IBeamCursor
onClicked: secretInput.forceActiveFocus()
}
TextInput {
id: secretInput
anchors.fill: parent
anchors.leftMargin: 14
anchors.rightMargin: 58
verticalAlignment: TextInput.AlignVCenter
color: root.theme ? root.theme.content.normal : "white"
selectionColor: root.theme ? root.theme.ui.focus : "white"
selectedTextColor: root.theme ? root.theme.content.backdrop : "black"
font.family: "IBM Plex Mono"
echoMode: root.secretVisible || root.request.responseVisible ? TextInput.Normal : TextInput.Password
inputMethodHints: Qt.ImhSensitiveData
activeFocusOnTab: true
KeyNavigation.tab: revealButton
KeyNavigation.backtab: authorizeButton
Keys.onReturnPressed: event => {
event.accepted = true;
root.submitSecret(text);
text = "";
}
Keys.onEnterPressed: event => {
event.accepted = true;
root.submitSecret(text);
text = "";
}
Keys.onEscapePressed: event => {
event.accepted = true;
root.cancel();
text = "";
}
}
PopupButton {
id: revealButton
anchors.right: parent.right
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
theme: root.theme
width: 38
height: 32
icon: root.secretVisible ? "" : ""
text: root.secretVisible ? "hide password" : "show password"
accessibleName: text
tooltip: text
showText: false
checked: root.secretVisible
KeyNavigation.tab: cancelButton
KeyNavigation.backtab: secretInput
onClicked: root.secretVisible = !root.secretVisible
}
}
NuguText {
visible: root.panelState.error && root.panelState.error.length > 0
theme: root.theme
variant: "meta"
text: root.panelState.error === "Authentication failed" ? "password rejected" : (root.panelState.error === "no-active-polkit-flow" ? "no active authentication request" : root.panelState.error)
width: parent.width
color: root.theme ? root.theme.error : "white"
elide: Text.ElideRight
}
}
}
Row {
objectName: "denyCancelConfirmRow"
visible: !root.panelState.confirming
width: parent.width
spacing: 10
PopupButton {
id: cancelButton
theme: root.theme
width: Math.floor((parent.width - 10) * 0.38)
height: 40
icon: ""
text: "cancel"
accessibleName: text
tooltip: text
role: "ghost"
KeyNavigation.tab: authorizeButton
KeyNavigation.backtab: revealButton
onClicked: {
root.cancel();
secretInput.text = "";
}
}
PopupButton {
id: authorizeButton
theme: root.theme
width: parent.width - Math.floor((parent.width - 10) * 0.38) - 10
height: 40
icon: ""
text: "authorize"
accessibleName: text
tooltip: text
role: "primary"
enabled: root.panelState.active
KeyNavigation.tab: secretInput
KeyNavigation.backtab: cancelButton
onClicked: {
root.submitSecret(secretInput.text);
secretInput.text = "";
}
}
}
}
}
component PrivilegeFailureShake: Item {
id: shakeRoot
required property Theme theme
default property alias content: contentItem.data
property bool active: false
property real boundedDistance: 12
readonly property var shakeOffsets: [0, -boundedDistance, boundedDistance, -boundedDistance / 2, boundedDistance / 2, 0]
// The caller supplies width and height; content only fills that frame.
onActiveChanged: {
if (active)
shake.restart();
}
Item {
id: contentItem
anchors.fill: parent
}
SequentialAnimation {
id: shake
running: false
alwaysRunToEnd: true
ScriptAction {
script: translation.x = shakeRoot.shakeOffsets[0]
}
NumberAnimation {
target: translation
property: "x"
to: shakeRoot.shakeOffsets[1]
duration: shakeRoot.theme.lowPowerMode ? 0 : 50
easing.type: Easing.OutCubic
}
NumberAnimation {
target: translation
property: "x"
to: shakeRoot.shakeOffsets[2]
duration: shakeRoot.theme.lowPowerMode ? 0 : 50
easing.type: Easing.OutCubic
}
NumberAnimation {
target: translation
property: "x"
to: shakeRoot.shakeOffsets[3]
duration: shakeRoot.theme.lowPowerMode ? 0 : 40
easing.type: Easing.OutCubic
}
NumberAnimation {
target: translation
property: "x"
to: shakeRoot.shakeOffsets[4]
duration: shakeRoot.theme.lowPowerMode ? 0 : 40
easing.type: Easing.OutCubic
}
NumberAnimation {
target: translation
property: "x"
to: shakeRoot.shakeOffsets[5]
duration: shakeRoot.theme.lowPowerMode ? 0 : 30
easing.type: Easing.OutCubic
}
}
transform: Translate {
id: translation
x: 0
}
}
}