Watch
1
0
Fork
You've already forked souveraine
0

lock: glance-first touch surface, keypad behind swipe-to-unlock

PIN pad hidden until swipe up / tap hint / hardware key; retreats after
25s idle with nothing typed. shouldReFocus no longer implies reveal --
hypridle fires it on every wake and wake must land on glance.
This commit is contained in:
Fimeg 2026-07-17 06:46:49 -04:00
commit 401a6609ea

View file

@ -29,9 +29,19 @@ MouseArea {
readonly property int keySize: 96
readonly property int keySpacing: 18
// Two-stage lock: glance (ambient cards + swipe hint) and PIN. The pad
// is not always up a swipe up (or any hardware key) reveals it, and it
// retreats after sitting idle with nothing typed. Credentials machinery
// is untouched; this is purely which stage is presented.
property bool pinRevealed: false
property real pressY: 0
function forceFieldFocus() {
root.forceActiveFocus();
}
// Note: shouldReFocus does NOT reveal the pad hypridle's after_sleep_cmd
// fires it on every wake to fix Hyprland's keyboard-focus loss, and wake
// must land on glance, not the keypad. Typing reveals via Keys below.
Connections {
target: root.context
function onShouldReFocus() {
@ -39,7 +49,26 @@ MouseArea {
}
}
Component.onCompleted: forceFieldFocus()
onPressed: forceFieldFocus()
onPressed: mouse => {
root.pressY = mouse.y;
forceFieldFocus();
}
onPositionChanged: mouse => {
if (!root.pinRevealed && root.pressY - mouse.y > 60)
root.pinRevealed = true;
else if (root.pinRevealed && mouse.y - root.pressY > 80
&& root.context.currentText.length === 0
&& !root.context.unlockInProgress)
root.pinRevealed = false;
}
// Retreat to glance when the pad sits unused and empty.
Timer {
interval: 25000
running: root.pinRevealed && root.context.currentText.length === 0
&& !root.context.unlockInProgress
onTriggered: root.pinRevealed = false
}
// Souveraine-owned ambient content. Credentials stay below this host, so
// phone, laptop, and desktop can rearrange the same cards later without
@ -59,9 +88,11 @@ MouseArea {
root.context.currentText += d;
}
// Hardware keyboard entry (USB-C keyboard); mirrors the desktop surface
// Hardware keyboard entry (USB-C keyboard); mirrors the desktop surface.
// Any key is also a reveal gesture, so typing works from glance.
focus: true
Keys.onPressed: event => {
root.pinRevealed = true;
root.context.resetClearTimer();
if (event.key === Qt.Key_Backspace) {
root.context.currentText = (event.modifiers & Qt.ControlModifier)
@ -75,6 +106,40 @@ MouseArea {
}
}
// Glance-stage hint; tapping it is an alternative to the swipe.
ColumnLayout {
id: swipeHint
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 64
}
z: 2
spacing: 2
visible: opacity > 0
opacity: root.pinRevealed ? 0 : 1
Behavior on opacity {
NumberAnimation { duration: 180 }
}
MaterialSymbol {
Layout.alignment: Qt.AlignHCenter
text: "keyboard_arrow_up"
iconSize: 34
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
Layout.alignment: Qt.AlignHCenter
text: Translation.tr("Swipe up to unlock")
color: Appearance.colors.colSubtext
font.pixelSize: Appearance.font.pixelSize.normal
}
TapHandler {
onTapped: root.pinRevealed = true
}
}
ColumnLayout {
id: padColumn
anchors {
@ -84,6 +149,21 @@ MouseArea {
}
z: 2
spacing: 20
visible: opacity > 0
opacity: root.pinRevealed ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: 200 }
}
// Slide up from below the screen edge as it reveals.
transform: Translate {
y: root.pinRevealed ? 0 : padColumn.height + 48
Behavior on y {
NumberAnimation {
duration: 260
easing.type: Easing.OutCubic
}
}
}
// Entered-PIN dots, with the empty-state hint behind them.
// In a ColumnLayout so ErrorShakeAnimation's Layout.leftMargin works.