diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-08-23 20:43:04 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-23 20:43:04 +1000 |
| commit | aea57958326360a1dc15509c02397594da20538e (patch) | |
| tree | d3a4626e7246f93ae420f500a8b189ee0342b074 /modules/lock/Pam.qml | |
| parent | bar: add idle inhibitor (#459) (diff) | |
| download | caelestia-shell-aea57958326360a1dc15509c02397594da20538e.tar.gz caelestia-shell-aea57958326360a1dc15509c02397594da20538e.tar.bz2 caelestia-shell-aea57958326360a1dc15509c02397594da20538e.zip | |
lock: add fprint support (#429)
* lock: add fprint support
* lock: better fprint detection
* lock: cap error retries
* nix: fix fprint pam for nix
* lock: reset fprint tries
* lock: minor pam fixes
Delay fprint error retries
Reset fprint error retries on lock
* lock: loading indicator passwd state
Instead of fprint state cause no way of detecting that
* dashboard: better visualiser
* lock: better fprint availability check
* lock: better in/out anim
Animating layout sizes is a bad idea :woe:
Use scale instead
* lock: add better error/fail messages
* lock: less fprint icon states
Already shown by message
* lock: fix fprint reset
* lock: include passwd pam
* lock: flash message on change
* lock: fix message anim
Also wrap message instead of eliding
* lock: better messages for no fprint
Diffstat (limited to 'modules/lock/Pam.qml')
| -rw-r--r-- | modules/lock/Pam.qml | 127 |
1 files changed, 123 insertions, 4 deletions
diff --git a/modules/lock/Pam.qml b/modules/lock/Pam.qml index 2675405..0186c2f 100644 --- a/modules/lock/Pam.qml +++ b/modules/lock/Pam.qml @@ -1,4 +1,6 @@ +import qs.config import Quickshell +import Quickshell.Io import Quickshell.Wayland import Quickshell.Services.Pam import QtQuick @@ -9,12 +11,16 @@ Scope { required property WlSessionLock lock readonly property alias passwd: passwd - readonly property bool active: passwd.active + readonly property alias fprint: fprint + property string lockMessage property string state + property string fprintState property string buffer + signal flashMsg + function handleKey(event: KeyEvent): void { - if (passwd.active) + if (passwd.active || state === "max") return; if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { @@ -34,6 +40,16 @@ Scope { PamContext { id: passwd + config: "passwd" + configDirectory: Quickshell.shellDir + "/assets/pam.d" + + onMessageChanged: { + if (message.startsWith("The account is locked")) + root.lockMessage = message; + else if (root.lockMessage && message.endsWith(" left to unlock)")) + root.lockMessage += "\n" + message; + } + onResponseRequiredChanged: { if (!responseRequired) return; @@ -53,22 +69,125 @@ Scope { else if (res === PamResult.Failed) root.state = "fail"; + root.flashMsg(); stateReset.restart(); } } + PamContext { + id: fprint + + property bool available + property int tries + property int errorTries + + function checkAvail(): void { + if (!available || !Config.lock.enableFprint || !root.lock.secure) { + abort(); + return; + } + + tries = 0; + errorTries = 0; + start(); + } + + config: "fprint" + configDirectory: Quickshell.shellDir + "/assets/pam.d" + + onCompleted: res => { + if (!available) + return; + + if (res === PamResult.Success) + return root.lock.unlock(); + + if (res === PamResult.Error) { + root.fprintState = "error"; + errorTries++; + if (errorTries < 5) { + abort(); + errorRetry.restart(); + } + } else if (res === PamResult.MaxTries) { + // Isn't actually the real max tries as pam only reports completed + // when max tries is reached. + tries++; + if (tries < Config.lock.maxFprintTries) { + // Restart if not actually real max tries + root.fprintState = "fail"; + start(); + } else { + root.fprintState = "max"; + abort(); + } + } + + root.flashMsg(); + fprintStateReset.start(); + } + } + + Process { + id: availProc + + command: ["sh", "-c", "fprintd-list $USER"] + onExited: code => { + fprint.available = code === 0; + fprint.checkAvail(); + } + } + + Timer { + id: errorRetry + + interval: 800 + onTriggered: fprint.start() + } + Timer { id: stateReset interval: 4000 - onTriggered: root.state = "" + onTriggered: { + if (root.state !== "max") + root.state = ""; + } + } + + Timer { + id: fprintStateReset + + interval: 4000 + onTriggered: { + root.fprintState = ""; + fprint.errorTries = 0; + } } Connections { target: root.lock + function onSecureChanged(): void { + if (root.lock.secure) { + availProc.running = true; + root.buffer = ""; + root.state = ""; + root.fprintState = ""; + root.lockMessage = ""; + } + } + function onUnlock(): void { - root.buffer = ""; + fprint.abort(); + } + } + + Connections { + target: Config.lock + + function onEnableFprintChanged(): void { + fprint.checkAvail(); } } } |