added three new modules (Crypto.qml, Battery.qml, Network.qml), improved Stats.qml, improved Tray.qml, optimized code in general, added a polkit agent, configurations change (check configs)
This commit is contained in:
544
polkit/Polkit.qml
Normal file
544
polkit/Polkit.qml
Normal file
@@ -0,0 +1,544 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Services.Polkit
|
||||
|
||||
import "../config" as Cfg
|
||||
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property var t: Cfg.Config.theme
|
||||
readonly property var cfg: Cfg.Config
|
||||
|
||||
property bool interactionAvailable: false
|
||||
property bool windowShouldExist: false
|
||||
|
||||
PolkitAgent {
|
||||
id: agent
|
||||
|
||||
onAuthenticationRequestStarted: {
|
||||
root.windowShouldExist = true
|
||||
root.interactionAvailable = true
|
||||
resetInput()
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var flow: agent.flow ?? null
|
||||
|
||||
Connections {
|
||||
target: flow
|
||||
function onAuthenticationFailed() {
|
||||
root.interactionAvailable = true
|
||||
resetInput()
|
||||
}
|
||||
}
|
||||
|
||||
function submitAuth() {
|
||||
if (!root.interactionAvailable) return
|
||||
if (flow?.isResponseRequired) {
|
||||
root.interactionAvailable = false
|
||||
flow.submit(windowLoader.item?.passwordText ?? "")
|
||||
windowLoader.item?.clearPassword()
|
||||
}
|
||||
}
|
||||
|
||||
function resetInput() {
|
||||
windowLoader.item?.resetInput()
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: windowLoader
|
||||
active: root.windowShouldExist
|
||||
|
||||
sourceComponent: Component {
|
||||
PanelWindow {
|
||||
id: overlay
|
||||
|
||||
property bool exiting: false
|
||||
property bool authFailed: false
|
||||
property var displayFlow: null
|
||||
|
||||
function captureFlowSnapshot(flow) {
|
||||
if (!flow) return null
|
||||
return {
|
||||
message: flow.message,
|
||||
actionId: flow.actionId,
|
||||
supplementaryMessage: flow.supplementaryMessage,
|
||||
supplementaryIsError: flow.supplementaryIsError,
|
||||
identities: flow.identities?.slice() ?? [],
|
||||
selectedIdentity: flow.selectedIdentity,
|
||||
isResponseRequired: flow.isResponseRequired,
|
||||
inputPrompt: flow.inputPrompt,
|
||||
responseVisible: flow.responseVisible
|
||||
}
|
||||
}
|
||||
|
||||
readonly property string passwordText: passwordInput.text
|
||||
function clearPassword() { passwordInput.clear() }
|
||||
function resetInput() {
|
||||
passwordInput.clear()
|
||||
passwordInput.forceActiveFocus()
|
||||
}
|
||||
|
||||
visible: true
|
||||
|
||||
anchors { top: true; bottom: true; left: true; right: true }
|
||||
color: "transparent"
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||
WlrLayershell.namespace: "main-shell-polkit"
|
||||
|
||||
Timer {
|
||||
id: exitDebounce
|
||||
interval: 250
|
||||
onTriggered: {
|
||||
if (!agent.isActive && !overlay.exiting) {
|
||||
overlay.exiting = true
|
||||
exitAnim.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cancelAndClose() {
|
||||
if (overlay.exiting) return
|
||||
overlay.exiting = true
|
||||
exitAnim.start()
|
||||
root.flow?.cancelAuthenticationRequest()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: t.polkitOverlayBg
|
||||
}
|
||||
|
||||
component DialogButton: Rectangle {
|
||||
property string label
|
||||
property int labelWeight: Font.Normal
|
||||
property color bgColor
|
||||
property color bgHoverColor
|
||||
property color borderColor
|
||||
property color borderHoverColor
|
||||
property color labelColor
|
||||
signal tapped()
|
||||
|
||||
width: (parent.width - 12) / 2
|
||||
height: 44
|
||||
radius: 10
|
||||
|
||||
HoverHandler { id: hover }
|
||||
|
||||
color: hover.hovered ? bgHoverColor : bgColor
|
||||
border.color: hover.hovered ? borderHoverColor : borderColor
|
||||
border.width: 1
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 200 } }
|
||||
Behavior on border.color { ColorAnimation { duration: 200 } }
|
||||
|
||||
scale: pressHandler.pressed ? 0.97 : 1.0
|
||||
Behavior on scale { NumberAnimation { duration: 100; easing.type: Easing.OutQuad } }
|
||||
|
||||
TapHandler {
|
||||
id: pressHandler
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onTapped: parent.tapped()
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: label
|
||||
color: labelColor
|
||||
font.pixelSize: 13
|
||||
font.weight: labelWeight
|
||||
font.letterSpacing: 0.2
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: card
|
||||
|
||||
property real shakeX: 0
|
||||
|
||||
x: Math.round((parent.width - width) / 2) + shakeX
|
||||
y: Math.round((parent.height - height) / 2)
|
||||
|
||||
width: 440
|
||||
height: content.implicitHeight + 64
|
||||
|
||||
radius: cfg.popupRadius
|
||||
color: t.polkitCardBg
|
||||
border.color: t.polkitCardBorder
|
||||
border.width: 1
|
||||
|
||||
opacity: 0
|
||||
scale: 0.86
|
||||
|
||||
Component.onCompleted: {
|
||||
overlay.displayFlow = agent.flow
|
||||
enterAnim.start()
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: enterAnim
|
||||
NumberAnimation {
|
||||
target: card; property: "opacity"
|
||||
from: 0; to: 1
|
||||
duration: 260; easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
target: card; property: "scale"
|
||||
from: 0.86; to: 1.0
|
||||
duration: 360; easing.type: Easing.OutBack; easing.overshoot: 0.6
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: exitAnim
|
||||
NumberAnimation {
|
||||
target: card; property: "opacity"
|
||||
from: 1; to: 0
|
||||
duration: 200; easing.type: Easing.InCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
target: card; property: "scale"
|
||||
from: 1.0; to: 0.88
|
||||
duration: 260; easing.type: Easing.InBack
|
||||
}
|
||||
onFinished: {
|
||||
overlay.exiting = false
|
||||
root.windowShouldExist = false
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: agent
|
||||
function onIsActiveChanged() {
|
||||
if (agent.isActive) {
|
||||
overlay.authFailed = false
|
||||
overlay.displayFlow = agent.flow
|
||||
exitDebounce.stop()
|
||||
if (overlay.exiting) {
|
||||
exitAnim.stop()
|
||||
overlay.exiting = false
|
||||
}
|
||||
card.opacity = 0
|
||||
card.scale = 0.86
|
||||
enterAnim.restart()
|
||||
} else {
|
||||
if (overlay.displayFlow)
|
||||
overlay.displayFlow = captureFlowSnapshot(overlay.displayFlow)
|
||||
exitDebounce.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: flow
|
||||
function onAuthenticationFailed() {
|
||||
overlay.authFailed = true
|
||||
shakeAnim.restart()
|
||||
}
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: shakeAnim
|
||||
NumberAnimation { target: card; property: "shakeX"; to: 12; duration: 45; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { target: card; property: "shakeX"; to: -10; duration: 45 }
|
||||
NumberAnimation { target: card; property: "shakeX"; to: 8; duration: 45 }
|
||||
NumberAnimation { target: card; property: "shakeX"; to: -5; duration: 45 }
|
||||
NumberAnimation { target: card; property: "shakeX"; to: 3; duration: 45 }
|
||||
NumberAnimation { target: card; property: "shakeX"; to: 0; duration: 45 }
|
||||
}
|
||||
|
||||
Column {
|
||||
id: content
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
topMargin: 32
|
||||
leftMargin: 32
|
||||
rightMargin: 32
|
||||
}
|
||||
spacing: 16
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 72
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 66
|
||||
height: 66
|
||||
radius: 33
|
||||
color: t.polkitIconBg
|
||||
border.color: t.polkitIconBorder
|
||||
border.width: 1
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: ""
|
||||
font.pixelSize: 28
|
||||
color: t.polkitIconColor
|
||||
Component.onCompleted: {
|
||||
if (implicitWidth < 4) text = "🔒"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: "Authentication Required"
|
||||
color: t.polkitTitle
|
||||
font.pixelSize: 17
|
||||
font.weight: Font.DemiBold
|
||||
font.letterSpacing: 0.3
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: !!displayFlow?.message
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: displayFlow?.message ?? ""
|
||||
color: t.polkitMessage
|
||||
font.pixelSize: 13
|
||||
lineHeight: 1.50
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: !!displayFlow?.actionId
|
||||
width: parent.width
|
||||
height: pillBg.height
|
||||
|
||||
Rectangle {
|
||||
id: pillBg
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: Math.min(pillText.implicitWidth + 22, parent.width)
|
||||
height: pillText.implicitHeight + 10
|
||||
radius: 6
|
||||
color: t.polkitPillBg
|
||||
|
||||
Text {
|
||||
id: pillText
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - 22
|
||||
elide: Text.ElideMiddle
|
||||
text: displayFlow?.actionId ?? ""
|
||||
color: t.polkitPillText
|
||||
font.pixelSize: 11
|
||||
font.family: "monospace"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: t.polkitDivider
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: overlay.authFailed || !!displayFlow?.supplementaryMessage
|
||||
width: parent.width
|
||||
height: suppRow.implicitHeight + 20
|
||||
radius: 10
|
||||
color: overlay.authFailed || displayFlow?.supplementaryIsError ? t.polkitSuppErrBg : t.polkitSuppOkBg
|
||||
border.color: overlay.authFailed || displayFlow?.supplementaryIsError ? t.polkitSuppErrBorder : t.polkitSuppOkBorder
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
id: suppRow
|
||||
anchors {
|
||||
top: parent.top; topMargin: 10
|
||||
bottom: parent.bottom; bottomMargin: 10
|
||||
left: parent.left; leftMargin: 14
|
||||
right: parent.right; rightMargin: 14
|
||||
}
|
||||
spacing: 9
|
||||
|
||||
Text {
|
||||
anchors.top: parent.top
|
||||
text: "✕"
|
||||
font.pixelSize: 12
|
||||
font.weight: Font.Medium
|
||||
lineHeight: 1.8
|
||||
color: t.polkitSuppErrText
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width - 22
|
||||
wrapMode: Text.WordWrap
|
||||
text: overlay.authFailed ? "Authentication failed, please try again." : (displayFlow?.supplementaryMessage ?? "")
|
||||
font.pixelSize: 12
|
||||
lineHeight: 1.45
|
||||
color: overlay.authFailed || displayFlow?.supplementaryIsError ? t.polkitSuppErrText : t.polkitSuppOkText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: true
|
||||
width: parent.width
|
||||
text: displayFlow?.inputPrompt ?? "Password"
|
||||
color: t.polkitInputPrompt
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: true
|
||||
width: parent.width
|
||||
height: 46
|
||||
radius: 10
|
||||
color: t.polkitFieldBg
|
||||
border.color: passwordInput.activeFocus ? t.polkitFieldBorderFocus : t.polkitFieldBorder
|
||||
border.width: passwordInput.activeFocus ? 1.5 : 1
|
||||
|
||||
Behavior on border.color { ColorAnimation { duration: 120 } }
|
||||
Behavior on border.width { NumberAnimation { duration: 120 } }
|
||||
|
||||
TextInput {
|
||||
id: passwordInput
|
||||
|
||||
enabled: root.interactionAvailable
|
||||
|
||||
anchors {
|
||||
left: parent.left; leftMargin: 16
|
||||
right: eyeBtn.left; rightMargin: 8
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
property bool showPassword: false
|
||||
|
||||
echoMode: (displayFlow?.responseVisible || showPassword)
|
||||
? TextInput.Normal : TextInput.Password
|
||||
|
||||
color: t.polkitInputText
|
||||
selectionColor: t.polkitInputSelection
|
||||
selectedTextColor: t.polkitInputSelectedText
|
||||
font.pixelSize: 14
|
||||
passwordCharacter: "•"
|
||||
clip: true
|
||||
|
||||
Keys.onReturnPressed: root.submitAuth()
|
||||
Keys.onEnterPressed: root.submitAuth()
|
||||
Keys.onEscapePressed: overlay.cancelAndClose()
|
||||
}
|
||||
|
||||
Text {
|
||||
id: eyeBtn
|
||||
anchors {
|
||||
right: parent.right; rightMargin: 14
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
text: passwordInput.showPassword ? "🙈" : "👁"
|
||||
font.pixelSize: 20
|
||||
color: eyeHover.hovered ? t.polkitEyeIconHover : t.polkitEyeIcon
|
||||
|
||||
Behavior on color { ColorAnimation { duration: 120 } }
|
||||
|
||||
HoverHandler { id: eyeHover }
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors.margins: -8
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: passwordInput.showPassword = !passwordInput.showPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { width: 1; height: 2 }
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: 12
|
||||
layoutDirection: Qt.RightToLeft
|
||||
|
||||
DialogButton {
|
||||
label: "Authenticate"
|
||||
labelWeight: Font.Medium
|
||||
labelColor: t.polkitAuthText
|
||||
bgColor: t.polkitAuthBg
|
||||
bgHoverColor: t.polkitAuthBgHover
|
||||
borderColor: t.polkitAuthBg
|
||||
borderHoverColor: t.polkitAuthBgHover
|
||||
onTapped: root.submitAuth()
|
||||
}
|
||||
|
||||
DialogButton {
|
||||
label: "Cancel"
|
||||
labelColor: t.polkitCancelText
|
||||
bgColor: t.polkitCancelBg
|
||||
bgHoverColor: t.polkitCancelBgHover
|
||||
borderColor: t.polkitCancelBorder
|
||||
borderHoverColor: t.polkitCancelBgHover
|
||||
onTapped: overlay.cancelAndClose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: cfg.popupRadius
|
||||
color: Qt.rgba(
|
||||
t.polkitCardBg.r,
|
||||
t.polkitCardBg.g,
|
||||
t.polkitCardBg.b, 0.78)
|
||||
opacity: root.interactionAvailable ? 0 : 1
|
||||
visible: opacity > 0
|
||||
|
||||
Behavior on opacity { NumberAnimation { duration: 180; easing.type: Easing.InOutSine } }
|
||||
|
||||
Canvas {
|
||||
id: spinnerCanvas
|
||||
anchors.centerIn: parent
|
||||
width: 40
|
||||
height: 40
|
||||
|
||||
property real angle: 0
|
||||
|
||||
NumberAnimation on angle {
|
||||
running: !root.interactionAvailable
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 700
|
||||
loops: Animation.Infinite
|
||||
}
|
||||
|
||||
onAngleChanged: requestPaint()
|
||||
|
||||
onPaint: {
|
||||
const ctx = getContext("2d")
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
const cx = width / 2, cy = height / 2
|
||||
const r = width / 2 - 3
|
||||
|
||||
ctx.strokeStyle = Qt.rgba(
|
||||
t.polkitTitle.r, t.polkitTitle.g, t.polkitTitle.b, 0.12)
|
||||
ctx.lineWidth = 3.5
|
||||
ctx.beginPath()
|
||||
ctx.arc(cx, cy, r, 0, 2 * Math.PI)
|
||||
ctx.stroke()
|
||||
|
||||
const start = (angle - 90) * Math.PI / 180
|
||||
ctx.strokeStyle = Qt.rgba(
|
||||
t.polkitTitle.r, t.polkitTitle.g, t.polkitTitle.b, 0.88)
|
||||
ctx.lineCap = "round"
|
||||
ctx.beginPath()
|
||||
ctx.arc(cx, cy, r, start, start + 1.3 * Math.PI)
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user