diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-08-10 19:22:27 +1000 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-08-10 19:22:27 +1000 |
| commit | 56ca1632c5ecd6e1c3124154e689608c359fab1e (patch) | |
| tree | e374308f1927a545db79dcb22a791eb667bd8719 /modules | |
| parent | lock: add content + better unlock anim (diff) | |
| download | caelestia-shell-56ca1632c5ecd6e1c3124154e689608c359fab1e.tar.gz caelestia-shell-56ca1632c5ecd6e1c3124154e689608c359fab1e.tar.bz2 caelestia-shell-56ca1632c5ecd6e1c3124154e689608c359fab1e.zip | |
lock: input field + separate pam
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/lock/Center.qml | 214 | ||||
| -rw-r--r-- | modules/lock/Content.qml | 97 | ||||
| -rw-r--r-- | modules/lock/Lock.qml | 7 | ||||
| -rw-r--r-- | modules/lock/LockSurface.qml | 1 | ||||
| -rw-r--r-- | modules/lock/Pam.qml | 50 |
5 files changed, 302 insertions, 67 deletions
diff --git a/modules/lock/Center.qml b/modules/lock/Center.qml new file mode 100644 index 0000000..9610da2 --- /dev/null +++ b/modules/lock/Center.qml @@ -0,0 +1,214 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.images +import qs.services +import qs.config +import qs.utils +import Quickshell +import QtQuick +import QtQuick.Layouts + +ColumnLayout { + id: root + + required property var lock + readonly property list<string> timeComponents: Time.format(Config.services.useTwelveHourClock ? "hh:mm:A" : "hh:mm").split(":") + + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumWidth: Config.lock.sizes.centerWidth + + spacing: Appearance.spacing.large * 2 + + RowLayout { + Layout.alignment: Qt.AlignHCenter + Layout.bottomMargin: Appearance.spacing.large + spacing: Appearance.spacing.small + + StyledText { + Layout.alignment: Qt.AlignVCenter + text: root.timeComponents[0] + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.extraLarge * 3 + font.bold: true + } + + StyledText { + Layout.alignment: Qt.AlignVCenter + text: ":" + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.extraLarge * 3 + font.bold: true + } + + StyledText { + Layout.alignment: Qt.AlignVCenter + text: root.timeComponents[1] + color: Colours.palette.m3secondary + font.pointSize: Appearance.font.size.extraLarge * 3 + font.bold: true + } + + Loader { + Layout.leftMargin: Appearance.spacing.normal + Layout.alignment: Qt.AlignVCenter + + asynchronous: true + active: Config.services.useTwelveHourClock + visible: active + + sourceComponent: StyledText { + text: root.timeComponents[2] ?? "" + color: Colours.palette.m3primary + font.pointSize: Appearance.font.size.extraLarge * 2 + font.bold: true + } + } + } + + StyledClippingRect { + Layout.alignment: Qt.AlignHCenter + + implicitWidth: Config.lock.sizes.centerWidth / 2 + implicitHeight: Config.lock.sizes.centerWidth / 2 + + color: Colours.tPalette.m3surfaceContainer + radius: Appearance.rounding.full + + MaterialIcon { + anchors.centerIn: parent + + text: "person" + fill: 1 + grade: 200 + font.pointSize: Math.floor(Config.lock.sizes.centerWidth / 4) + } + + CachingImage { + id: pfp + + anchors.fill: parent + path: `${Paths.stringify(Paths.home)}/.face` + } + } + + StyledRect { + Layout.alignment: Qt.AlignHCenter + + implicitWidth: Config.lock.sizes.centerWidth * 0.8 + implicitHeight: input.implicitHeight + Appearance.padding.small * 2 + + color: Colours.palette.m3surfaceContainer + radius: Appearance.rounding.full + + focus: true + onActiveFocusChanged: { + if (!activeFocus) + forceActiveFocus(); + } + + Keys.onPressed: event => root.lock.pam.handleKey(event) + + RowLayout { + id: input + + anchors.fill: parent + anchors.margins: Appearance.padding.small + spacing: Appearance.spacing.normal + + MaterialIcon { + Layout.leftMargin: Appearance.padding.smaller + text: "lock" + } + + ListView { + id: passwordList + + Layout.fillWidth: true + implicitHeight: Appearance.font.size.normal + + orientation: Qt.Horizontal + clip: true + spacing: Appearance.spacing.small / 2 + highlightRangeMode: ListView.StrictlyEnforceRange + preferredHighlightBegin: 0 + preferredHighlightEnd: count ? width - implicitHeight * 2 : 0 + currentIndex: count - 1 + + model: ScriptModel { + values: root.lock.pam.buffer + } + + delegate: StyledRect { + implicitWidth: implicitHeight + implicitHeight: passwordList.implicitHeight + + color: Colours.palette.m3onSurface + radius: Appearance.rounding.small / 2 + } + + add: Transition { + Anim { + property: "scale" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + remove: Transition { + Anim { + property: "scale" + to: 0.5 + } + Anim { + property: "opacity" + to: 0 + } + } + + highlightFollowsCurrentItem: false + highlight: Item { + x: passwordList.currentItem?.x ?? 0 + + Behavior on x { + Anim {} + } + } + } + + StyledRect { + implicitWidth: implicitHeight + implicitHeight: enterIcon.implicitHeight + Appearance.padding.small * 2 + + color: root.lock.pam.buffer ? Colours.palette.m3primary : Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + radius: Appearance.rounding.full + + StateLayer { + color: root.lock.pam.buffer ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + + function onClicked(): void { + root.lock.pam.start(); + } + } + + MaterialIcon { + id: enterIcon + + anchors.centerIn: parent + text: "arrow_forward" + color: root.lock.pam.buffer ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface + font.weight: 500 + } + } + } + } + + component Anim: NumberAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } +} diff --git a/modules/lock/Content.qml b/modules/lock/Content.qml index 15e1425..43cf871 100644 --- a/modules/lock/Content.qml +++ b/modules/lock/Content.qml @@ -1,14 +1,10 @@ -pragma ComponentBehavior: Bound - import qs.components -import qs.components.images import qs.services import qs.config -import qs.utils import QtQuick import QtQuick.Layouts -GridLayout { +RowLayout { id: root required property var lock @@ -16,85 +12,52 @@ GridLayout { anchors.fill: parent anchors.margins: Appearance.padding.large - rowSpacing: Appearance.spacing.large - columnSpacing: Appearance.spacing.large - - rows: 2 - columns: 3 + spacing: Appearance.spacing.large - StyledRect { - Layout.row: 0 - Layout.column: 0 + ColumnLayout { Layout.fillWidth: true - Layout.fillHeight: true - - radius: Appearance.rounding.small - color: Colours.tPalette.m3surfaceContainer - } - - StyledRect { - Layout.row: 1 - Layout.column: 0 - Layout.fillWidth: true - Layout.fillHeight: true - - radius: Appearance.rounding.small - color: Colours.tPalette.m3surfaceContainer - } - - StyledClippingRect { - Layout.row: 0 - Layout.column: 1 - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + spacing: Appearance.spacing.normal - implicitWidth: Config.lock.sizes.faceSize - implicitHeight: Config.lock.sizes.faceSize + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true - radius: Appearance.rounding.large - color: Colours.tPalette.m3surfaceContainer - - MaterialIcon { - anchors.centerIn: parent - - text: "person" - fill: 1 - grade: 200 - font.pointSize: Math.floor(Config.lock.sizes.faceSize / 2) + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer } - CachingImage { - id: pfp + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true - anchors.fill: parent - path: `${Paths.stringify(Paths.home)}/.face` + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer } } - Input { - Layout.row: 1 - Layout.column: 1 - + Center { lock: root.lock } - StyledRect { - Layout.row: 0 - Layout.column: 2 + ColumnLayout { Layout.fillWidth: true - Layout.fillHeight: true + spacing: Appearance.spacing.normal - radius: Appearance.rounding.small - color: Colours.tPalette.m3surfaceContainer - } + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true - StyledRect { - Layout.row: 1 - Layout.column: 2 - Layout.fillWidth: true - Layout.fillHeight: true + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer + } - radius: Appearance.rounding.small - color: Colours.tPalette.m3surfaceContainer + StyledRect { + Layout.fillWidth: true + Layout.fillHeight: true + + radius: Appearance.rounding.small + color: Colours.tPalette.m3surfaceContainer + } } component Anim: NumberAnimation { diff --git a/modules/lock/Lock.qml b/modules/lock/Lock.qml index 0017086..fc0bff8 100644 --- a/modules/lock/Lock.qml +++ b/modules/lock/Lock.qml @@ -14,9 +14,16 @@ Scope { LockSurface { lock: lock + pam: pam } } + Pam { + id: pam + + lock: lock + } + CustomShortcut { name: "lock" description: "Lock the current session" diff --git a/modules/lock/LockSurface.qml b/modules/lock/LockSurface.qml index 3b6b86c..8dec866 100644 --- a/modules/lock/LockSurface.qml +++ b/modules/lock/LockSurface.qml @@ -12,6 +12,7 @@ WlSessionLockSurface { id: root required property WlSessionLock lock + required property Pam pam property bool locked diff --git a/modules/lock/Pam.qml b/modules/lock/Pam.qml new file mode 100644 index 0000000..44e8671 --- /dev/null +++ b/modules/lock/Pam.qml @@ -0,0 +1,50 @@ +import Quickshell.Wayland +import Quickshell.Services.Pam +import QtQuick + +PamContext { + id: root + + required property WlSessionLock lock + + property string state: "none" + property string buffer: "" + + function handleKey(event: KeyEvent): void { + if (active) + return; + + if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { + start(); + } else if (event.key === Qt.Key_Backspace) { + if (event.modifiers & Qt.ControlModifier) { + buffer = ""; + } else { + buffer = buffer.slice(0, -1); + } + } else if (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) { + // No illegal characters (you are insane if you use unicode in your password) + buffer += event.text; + } + } + + onResponseRequiredChanged: { + if (!responseRequired) + return; + + respond(buffer); + buffer = ""; + } + + onCompleted: res => { + if (res === PamResult.Success) + return lock.unlock(); + + if (res === PamResult.Error) + state = "error"; + else if (res === PamResult.MaxTries) + state = "max"; + else if (res === PamResult.Failed) + state = "fail"; + } +} |