Files
monoshell/Lock.qml
2026-02-13 17:17:29 -08:00

170 lines
5.2 KiB
QML

import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets
import Quickshell.Io
import Quickshell.Services.Pam
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
WlSessionLock {
id: lock
locked: false
required property bool animate
WlSessionLockSurface {
id: surface
color: "transparent"
Rectangle {
id: content
anchors.fill: parent
visible: content.ready
readonly property bool ready:
lock.animate &&
lock.secure &&
capture.hasContent
color: "#181818"
Text {
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: surface.height/12
}
color: "white"
font.pixelSize: 160
font.family: "Sriracha"
property var clock: SystemClock {}
text: `${clock.hours}:${clock.minutes}`
}
Rectangle {
anchors {
bottom: parent.bottom
horizontalCenter: parent.horizontalCenter
bottomMargin: surface.height/6
}
width: 300
height: 40
radius: height/2
color: "#222222"
TextInput {
id: input
x: (parent.width - this.width)/2
Behavior on x { NumberAnimation {
duration: 300
easing.type: Easing.OutQuint
}}
anchors.verticalCenter: parent.verticalCenter
focus: true
color: "white"
font.pixelSize: 20
echoMode: TextInput.Password
cursorDelegate: Item {}
Keys.onReturnPressed: pam.start()
}
Text {
anchors {
horizontalCenter: input.horizontalCenter
top: parent.bottom
topMargin: 10
}
color: "white"
font.pixelSize: 14
text: pam.message
}
}
}
ClippingRectangle {
anchors.fill: parent
color: "transparent"
radius: 0
RectangularShadow {
visible: content.ready
anchors.fill: parent
spread: 2
blur: 10
}
ScreencopyView {
id: capture
anchors.fill: parent
captureSource: surface.screen
Connections {
target: lock
function onLockedChanged() {capture.captureFrame()}
}
}
transform: Scale {
origin { x: width/2; y: height/2 }
xScale: 1
yScale: xScale
NumberAnimation on xScale {
running: content.ready
to: 0.85
duration: 800
easing.type: Easing.InQuint
}
NumberAnimation on xScale {
id: exit
running: false
from: 0.85
to: 1
duration: 800
easing.type: Easing.OutQuint
onFinished: {
content.visible = false
fadeOut.start()
}
}
}
SequentialAnimation on opacity {
running: content.ready
PauseAnimation {duration: 500}
NumberAnimation {
duration: 300
to: 0
}
}
NumberAnimation on opacity {
duration: 300
running: exit.running
from: 0
to: 1
}
NumberAnimation on radius {
running: content.ready
duration: 800
to: 32
}
NumberAnimation on radius {
running: exit.running
to: 0
duration: 800
}
NumberAnimation on opacity {
id: fadeOut
running: false
to: 0
duration: 150
onFinished: lock.locked = false
}
}
PamContext {
id: pam
config: "pam.conf"
configDirectory: "."
onPamMessage: if (this.responseRequired) this.respond(input.text)
onCompleted: result => {
switch (result) {
case PamResult.Success:
exit.start()
break;
case PamResult.Failed:
case PamResult.Error:
case PamResult.MaxTries:
input.clear()
fail.start();
break;
}}
}
}
}