mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
lock: fprintd support
This commit is contained in:
@@ -173,6 +173,9 @@ Singleton {
|
|||||||
property int dankBarPosition: SettingsData.Position.Top
|
property int dankBarPosition: SettingsData.Position.Top
|
||||||
property bool dankBarIsVertical: dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right
|
property bool dankBarIsVertical: dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right
|
||||||
property bool lockScreenShowPowerActions: true
|
property bool lockScreenShowPowerActions: true
|
||||||
|
property bool enableFprint: false
|
||||||
|
property int maxFprintTries: 3
|
||||||
|
property bool fprintdAvailable: false
|
||||||
property bool hideBrightnessSlider: false
|
property bool hideBrightnessSlider: false
|
||||||
property string widgetBackgroundColor: "sch"
|
property string widgetBackgroundColor: "sch"
|
||||||
property string surfaceBase: "s"
|
property string surfaceBase: "s"
|
||||||
@@ -440,6 +443,8 @@ Singleton {
|
|||||||
popupGapsManual = settings.popupGapsManual !== undefined ? settings.popupGapsManual : 4
|
popupGapsManual = settings.popupGapsManual !== undefined ? settings.popupGapsManual : 4
|
||||||
dankBarPosition = settings.dankBarPosition !== undefined ? settings.dankBarPosition : (settings.dankBarAtBottom !== undefined ? (settings.dankBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : (settings.topBarAtBottom !== undefined ? (settings.topBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : SettingsData.Position.Top))
|
dankBarPosition = settings.dankBarPosition !== undefined ? settings.dankBarPosition : (settings.dankBarAtBottom !== undefined ? (settings.dankBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : (settings.topBarAtBottom !== undefined ? (settings.topBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : SettingsData.Position.Top))
|
||||||
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true
|
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true
|
||||||
|
enableFprint = settings.enableFprint !== undefined ? settings.enableFprint : false
|
||||||
|
maxFprintTries = settings.maxFprintTries !== undefined ? settings.maxFprintTries : 3
|
||||||
hideBrightnessSlider = settings.hideBrightnessSlider !== undefined ? settings.hideBrightnessSlider : false
|
hideBrightnessSlider = settings.hideBrightnessSlider !== undefined ? settings.hideBrightnessSlider : false
|
||||||
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
|
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
|
||||||
surfaceBase = settings.surfaceBase !== undefined ? settings.surfaceBase : "s"
|
surfaceBase = settings.surfaceBase !== undefined ? settings.surfaceBase : "s"
|
||||||
@@ -576,6 +581,8 @@ Singleton {
|
|||||||
"popupGapsManual": popupGapsManual,
|
"popupGapsManual": popupGapsManual,
|
||||||
"dankBarPosition": dankBarPosition,
|
"dankBarPosition": dankBarPosition,
|
||||||
"lockScreenShowPowerActions": lockScreenShowPowerActions,
|
"lockScreenShowPowerActions": lockScreenShowPowerActions,
|
||||||
|
"enableFprint": enableFprint,
|
||||||
|
"maxFprintTries": maxFprintTries,
|
||||||
"hideBrightnessSlider": hideBrightnessSlider,
|
"hideBrightnessSlider": hideBrightnessSlider,
|
||||||
"widgetBackgroundColor": widgetBackgroundColor,
|
"widgetBackgroundColor": widgetBackgroundColor,
|
||||||
"surfaceBase": surfaceBase,
|
"surfaceBase": surfaceBase,
|
||||||
@@ -1441,6 +1448,16 @@ Singleton {
|
|||||||
saveSettings()
|
saveSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setEnableFprint(enabled) {
|
||||||
|
enableFprint = enabled
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMaxFprintTries(tries) {
|
||||||
|
maxFprintTries = tries
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
function setHideBrightnessSlider(enabled) {
|
function setHideBrightnessSlider(enabled) {
|
||||||
hideBrightnessSlider = enabled
|
hideBrightnessSlider = enabled
|
||||||
saveSettings()
|
saveSettings()
|
||||||
@@ -1513,6 +1530,7 @@ Singleton {
|
|||||||
loadSettings()
|
loadSettings()
|
||||||
fontCheckTimer.start()
|
fontCheckTimer.start()
|
||||||
initializeListModels()
|
initializeListModels()
|
||||||
|
fprintdDetectionProcess.running = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1672,6 +1690,16 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: fprintdDetectionProcess
|
||||||
|
|
||||||
|
command: ["sh", "-c", "command -v fprintd-list >/dev/null 2>&1"]
|
||||||
|
running: false
|
||||||
|
onExited: exitCode => {
|
||||||
|
fprintdAvailable = (exitCode === 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function reveal(): string {
|
function reveal(): string {
|
||||||
root.setDankBarVisible(true)
|
root.setDankBarVisible(true)
|
||||||
|
|||||||
@@ -97,6 +97,15 @@ Item {
|
|||||||
visible: SessionService.loginctlAvailable && SessionData.loginctlLockIntegration
|
visible: SessionService.loginctlAvailable && SessionData.loginctlLockIntegration
|
||||||
onToggled: checked => SessionData.setLockBeforeSuspend(checked)
|
onToggled: checked => SessionData.setLockBeforeSuspend(checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DankToggle {
|
||||||
|
width: parent.width
|
||||||
|
text: I18n.tr("Enable fingerprint authentication")
|
||||||
|
description: "Use fingerprint reader for lock screen authentication (requires enrolled fingerprints)"
|
||||||
|
checked: SettingsData.enableFprint
|
||||||
|
visible: SettingsData.fprintdAvailable
|
||||||
|
onToggled: checked => SettingsData.setEnableFprint(checked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Common
|
import qs.Common
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import QtQuick.Effects
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Services.Pam
|
|
||||||
import Quickshell.Services.Mpris
|
import Quickshell.Services.Mpris
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -253,22 +252,50 @@ Item {
|
|||||||
border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3)
|
border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3)
|
||||||
border.width: passwordField.activeFocus ? 2 : 1
|
border.width: passwordField.activeFocus ? 2 : 1
|
||||||
|
|
||||||
DankIcon {
|
Item {
|
||||||
id: lockIcon
|
id: lockIconContainer
|
||||||
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: Theme.spacingM
|
anchors.leftMargin: Theme.spacingM
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
name: "lock"
|
width: 20
|
||||||
size: 20
|
height: 20
|
||||||
color: passwordField.activeFocus ? Theme.primary : Theme.surfaceVariantText
|
|
||||||
|
DankIcon {
|
||||||
|
id: lockIcon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: {
|
||||||
|
if (pam.fprint.tries >= SettingsData.maxFprintTries)
|
||||||
|
return "fingerprint_off";
|
||||||
|
if (pam.fprint.active)
|
||||||
|
return "fingerprint";
|
||||||
|
return "lock";
|
||||||
|
}
|
||||||
|
size: 20
|
||||||
|
color: pam.fprint.tries >= SettingsData.maxFprintTries ? Theme.error : (passwordField.activeFocus ? Theme.primary : Theme.surfaceVariantText)
|
||||||
|
opacity: pam.passwd.active ? 0 : 1
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextInput {
|
TextInput {
|
||||||
id: passwordField
|
id: passwordField
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.leftMargin: lockIcon.width + Theme.spacingM * 2
|
anchors.leftMargin: lockIconContainer.width + Theme.spacingM * 2
|
||||||
anchors.rightMargin: {
|
anchors.rightMargin: {
|
||||||
let margin = Theme.spacingM
|
let margin = Theme.spacingM
|
||||||
if (loadingSpinner.visible) {
|
if (loadingSpinner.visible) {
|
||||||
@@ -296,9 +323,9 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
if (!demoMode && !pam.active) {
|
if (!demoMode && !pam.passwd.active) {
|
||||||
console.log("Enter pressed, starting PAM authentication")
|
console.log("Enter pressed, starting PAM authentication")
|
||||||
pam.start()
|
pam.passwd.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Keys.onPressed: event => {
|
Keys.onPressed: event => {
|
||||||
@@ -306,7 +333,7 @@ Item {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pam.active) {
|
if (pam.passwd.active) {
|
||||||
console.log("PAM is active, ignoring input")
|
console.log("PAM is active, ignoring input")
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
return
|
return
|
||||||
@@ -355,7 +382,7 @@ Item {
|
|||||||
StyledText {
|
StyledText {
|
||||||
id: placeholder
|
id: placeholder
|
||||||
|
|
||||||
anchors.left: lockIcon.right
|
anchors.left: lockIconContainer.right
|
||||||
anchors.leftMargin: Theme.spacingM
|
anchors.leftMargin: Theme.spacingM
|
||||||
anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right))))
|
anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right))))
|
||||||
anchors.rightMargin: 2
|
anchors.rightMargin: 2
|
||||||
@@ -367,12 +394,12 @@ Item {
|
|||||||
if (root.unlocking) {
|
if (root.unlocking) {
|
||||||
return "Unlocking..."
|
return "Unlocking..."
|
||||||
}
|
}
|
||||||
if (pam.active) {
|
if (pam.passwd.active) {
|
||||||
return "Authenticating..."
|
return "Authenticating..."
|
||||||
}
|
}
|
||||||
return "Password..."
|
return "Password..."
|
||||||
}
|
}
|
||||||
color: root.unlocking ? Theme.primary : (pam.active ? Theme.primary : Theme.outline)
|
color: root.unlocking ? Theme.primary : (pam.passwd.active ? Theme.primary : Theme.outline)
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
opacity: (demoMode || root.passwordBuffer.length === 0) ? 1 : 0
|
opacity: (demoMode || root.passwordBuffer.length === 0) ? 1 : 0
|
||||||
|
|
||||||
@@ -392,7 +419,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
anchors.left: lockIcon.right
|
anchors.left: lockIconContainer.right
|
||||||
anchors.leftMargin: Theme.spacingM
|
anchors.leftMargin: Theme.spacingM
|
||||||
anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right))))
|
anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right))))
|
||||||
anchors.rightMargin: 2
|
anchors.rightMargin: 2
|
||||||
@@ -427,7 +454,7 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
iconName: parent.showPassword ? "visibility_off" : "visibility"
|
iconName: parent.showPassword ? "visibility_off" : "visibility"
|
||||||
buttonSize: 32
|
buttonSize: 32
|
||||||
visible: !demoMode && root.passwordBuffer.length > 0 && !pam.active && !root.unlocking
|
visible: !demoMode && root.passwordBuffer.length > 0 && !pam.passwd.active && !root.unlocking
|
||||||
enabled: visible
|
enabled: visible
|
||||||
onClicked: parent.showPassword = !parent.showPassword
|
onClicked: parent.showPassword = !parent.showPassword
|
||||||
}
|
}
|
||||||
@@ -439,7 +466,7 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
iconName: "keyboard"
|
iconName: "keyboard"
|
||||||
buttonSize: 32
|
buttonSize: 32
|
||||||
visible: !demoMode && !pam.active && !root.unlocking
|
visible: !demoMode && !pam.passwd.active && !root.unlocking
|
||||||
enabled: visible
|
enabled: visible
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (keyboardController.isKeyboardActive) {
|
if (keyboardController.isKeyboardActive) {
|
||||||
@@ -460,7 +487,7 @@ Item {
|
|||||||
height: 24
|
height: 24
|
||||||
radius: 12
|
radius: 12
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
visible: !demoMode && (pam.active || root.unlocking)
|
visible: !demoMode && (pam.passwd.active || root.unlocking)
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -492,7 +519,7 @@ Item {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: pam.active && !root.unlocking
|
visible: pam.passwd.active && !root.unlocking
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: 20
|
width: 20
|
||||||
@@ -522,7 +549,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RotationAnimation on rotation {
|
RotationAnimation on rotation {
|
||||||
running: pam.active && !root.unlocking
|
running: pam.passwd.active && !root.unlocking
|
||||||
loops: Animation.Infinite
|
loops: Animation.Infinite
|
||||||
duration: Anims.durLong
|
duration: Anims.durLong
|
||||||
from: 0
|
from: 0
|
||||||
@@ -540,12 +567,12 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
iconName: "keyboard_return"
|
iconName: "keyboard_return"
|
||||||
buttonSize: 36
|
buttonSize: 36
|
||||||
visible: (demoMode || (!pam.active && !root.unlocking))
|
visible: (demoMode || (!pam.passwd.active && !root.unlocking))
|
||||||
enabled: !demoMode
|
enabled: !demoMode
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!demoMode) {
|
if (!demoMode) {
|
||||||
console.log("Enter button clicked, starting PAM authentication")
|
console.log("Enter button clicked, starting PAM authentication")
|
||||||
pam.start()
|
pam.passwd.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1091,52 +1118,29 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileView {
|
Pam {
|
||||||
id: pamConfigWatcher
|
id: pam
|
||||||
|
lockSecured: !demoMode
|
||||||
path: "/etc/pam.d/dankshell"
|
onUnlockRequested: {
|
||||||
printErrors: false
|
root.unlocking = true
|
||||||
|
passwordField.text = ""
|
||||||
|
root.passwordBuffer = ""
|
||||||
|
root.unlockRequested()
|
||||||
|
}
|
||||||
|
onStateChanged: {
|
||||||
|
root.pamState = state
|
||||||
|
if (state !== "") {
|
||||||
|
placeholderDelay.restart()
|
||||||
|
passwordField.text = ""
|
||||||
|
root.passwordBuffer = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PamContext {
|
Binding {
|
||||||
id: pam
|
target: pam
|
||||||
|
property: "buffer"
|
||||||
config: pamConfigWatcher.loaded ? "dankshell" : "login"
|
value: root.passwordBuffer
|
||||||
onResponseRequiredChanged: {
|
|
||||||
if (demoMode)
|
|
||||||
return
|
|
||||||
|
|
||||||
console.log("PAM response required:", responseRequired)
|
|
||||||
if (!responseRequired)
|
|
||||||
return
|
|
||||||
|
|
||||||
console.log("Responding to PAM with password buffer length:", root.passwordBuffer.length)
|
|
||||||
respond(root.passwordBuffer)
|
|
||||||
}
|
|
||||||
onCompleted: res => {
|
|
||||||
if (demoMode)
|
|
||||||
return
|
|
||||||
|
|
||||||
console.log("PAM authentication completed with result:", res)
|
|
||||||
if (res === PamResult.Success) {
|
|
||||||
console.log("Authentication successful, unlocking")
|
|
||||||
root.unlocking = true
|
|
||||||
passwordField.text = ""
|
|
||||||
root.passwordBuffer = ""
|
|
||||||
root.unlockRequested()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
console.log("Authentication failed:", res)
|
|
||||||
passwordField.text = ""
|
|
||||||
root.passwordBuffer = ""
|
|
||||||
if (res === PamResult.Error)
|
|
||||||
root.pamState = "error"
|
|
||||||
else if (res === PamResult.MaxTries)
|
|
||||||
root.pamState = "max"
|
|
||||||
else if (res === PamResult.Failed)
|
|
||||||
root.pamState = "fail"
|
|
||||||
placeholderDelay.restart()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
|
|||||||
177
Modules/Lock/Pam.qml
Normal file
177
Modules/Lock/Pam.qml
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Services.Pam
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool lockSecured: false
|
||||||
|
|
||||||
|
readonly property alias passwd: passwd
|
||||||
|
readonly property alias fprint: fprint
|
||||||
|
property string lockMessage
|
||||||
|
property string state
|
||||||
|
property string fprintState
|
||||||
|
property string buffer
|
||||||
|
|
||||||
|
signal flashMsg
|
||||||
|
signal unlockRequested
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
id: pamConfigWatcher
|
||||||
|
|
||||||
|
path: "/etc/pam.d/dankshell"
|
||||||
|
printErrors: false
|
||||||
|
}
|
||||||
|
|
||||||
|
PamContext {
|
||||||
|
id: passwd
|
||||||
|
|
||||||
|
config: pamConfigWatcher.loaded ? "dankshell" : "login"
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
respond(root.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCompleted: res => {
|
||||||
|
if (res === PamResult.Success) {
|
||||||
|
root.unlockRequested();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res === PamResult.Error)
|
||||||
|
root.state = "error";
|
||||||
|
else if (res === PamResult.MaxTries)
|
||||||
|
root.state = "max";
|
||||||
|
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 || !SettingsData.enableFprint || !root.lockSecured) {
|
||||||
|
abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tries = 0;
|
||||||
|
errorTries = 0;
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
config: "fprint"
|
||||||
|
configDirectory: Quickshell.shellDir + "/assets/pam"
|
||||||
|
|
||||||
|
onCompleted: res => {
|
||||||
|
if (!available)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (res === PamResult.Success) {
|
||||||
|
root.unlockRequested();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res === PamResult.Error) {
|
||||||
|
root.fprintState = "error";
|
||||||
|
errorTries++;
|
||||||
|
if (errorTries < 5) {
|
||||||
|
abort();
|
||||||
|
errorRetry.restart();
|
||||||
|
}
|
||||||
|
} else if (res === PamResult.MaxTries) {
|
||||||
|
tries++;
|
||||||
|
if (tries < SettingsData.maxFprintTries) {
|
||||||
|
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: {
|
||||||
|
if (root.state !== "max")
|
||||||
|
root.state = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: fprintStateReset
|
||||||
|
|
||||||
|
interval: 4000
|
||||||
|
onTriggered: {
|
||||||
|
root.fprintState = "";
|
||||||
|
fprint.errorTries = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onLockSecuredChanged: {
|
||||||
|
if (lockSecured) {
|
||||||
|
availProc.running = true;
|
||||||
|
root.state = "";
|
||||||
|
root.fprintState = "";
|
||||||
|
root.lockMessage = "";
|
||||||
|
} else {
|
||||||
|
fprint.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
|
||||||
|
function onEnableFprintChanged(): void {
|
||||||
|
fprint.checkAvail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -291,7 +291,7 @@ sudo pacman -S cava wl-clipboard cliphist brightnessctl qt6-multimedia
|
|||||||
paru -S matugen-bin dgop
|
paru -S matugen-bin dgop
|
||||||
|
|
||||||
# Fedora
|
# Fedora
|
||||||
sudo dnf install cava wl-clipboard brightnessctl qt6-multimedia
|
sudo dnf install cava wl-clipboard brightnessctl qt6-qtmultimedia
|
||||||
sudo dnf copr enable wef/cliphist && sudo dnf install cliphist
|
sudo dnf copr enable wef/cliphist && sudo dnf install cliphist
|
||||||
sudo dnf copr enable heus-sueh/packages && sudo dnf install matugen
|
sudo dnf copr enable heus-sueh/packages && sudo dnf install matugen
|
||||||
```
|
```
|
||||||
|
|||||||
3
assets/pam/fprint
Normal file
3
assets/pam/fprint
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#%PAM-1.0
|
||||||
|
|
||||||
|
auth required pam_fprintd.so max-tries=1
|
||||||
Reference in New Issue
Block a user