feat: add an animation speed setting
This commit is contained in:
1 parent
dc0f680652
commit
71d01cd710
11 files changed
+156
-100
No files matched your search
@@ -16,8 +16,9 @@ instead of a password. Before a face counts, it has to show a sign of life, so
|
||||
holding up a photo of somebody is not enough.
|
||||
|
||||
A bubble at the top of the screen shows what is going on: it drops down when
|
||||
the camera starts looking, the face in it looks around, and it turns into a
|
||||
tick when it recognises somebody. It shows above the lock screen too.
|
||||
the camera starts looking, the face in it looks around, and when it recognises
|
||||
somebody two green rings spin and land around a tick. It shows above the lock
|
||||
screen too. *Animation speed* makes all of it faster or slower.
|
||||
|
||||
Run without a command it shows an interactive menu. Everything it can be told
|
||||
is reachable from there; the settings files behind it do not need to be edited
|
||||
@@ -228,7 +229,8 @@ A laptop with its lid shut is not scanned (*Not while the lid is closed*).
|
||||
# FILES
|
||||
|
||||
_~/.config/plasma-face-unlock/config_
|
||||
This user's settings: the lock screen, the bubble. Written by the menu.
|
||||
This user's settings: the lock screen, the bubble and its animation
|
||||
speed. Written by the menu.
|
||||
|
||||
_/etc/plasma-face-unlock/config_
|
||||
The system settings: camera, photo check, strictness, attention, scan
|
||||
|
||||
@@ -763,3 +763,15 @@ msgstr "Los geht's"
|
||||
msgid "Done"
|
||||
msgstr "Fertig"
|
||||
|
||||
|
||||
#: src/lib/menu.sh
|
||||
msgid "Animation speed"
|
||||
msgstr "Animationsgeschwindigkeit"
|
||||
|
||||
#: src/lib/menu.sh
|
||||
msgid "fast"
|
||||
msgstr "schnell"
|
||||
|
||||
#: src/lib/menu.sh
|
||||
msgid "slow"
|
||||
msgstr "langsam"
|
||||
+63
-51
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: plasma-face-unlock 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/LoonixTools/plasma-face-unlock/"
|
||||
"issues\n"
|
||||
"POT-Creation-Date: 2026-09-22 23:06+0200\n"
|
||||
"POT-Creation-Date: 2026-09-22 23:12+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -55,8 +55,8 @@ msgstr ""
|
||||
msgid "First, set up your face."
|
||||
msgstr ""
|
||||
|
||||
#: src/plasma-face-unlock:100 src/plasma-face-unlock:120 src/lib/menu.sh:348
|
||||
#: src/lib/menu.sh:352 src/lib/menu.sh:358 src/lib/menu.sh:360
|
||||
#: src/plasma-face-unlock:100 src/plasma-face-unlock:120 src/lib/menu.sh:352
|
||||
#: src/lib/menu.sh:356 src/lib/menu.sh:362 src/lib/menu.sh:364
|
||||
msgid "Could not save the setting."
|
||||
msgstr ""
|
||||
|
||||
@@ -84,16 +84,16 @@ msgstr ""
|
||||
msgid "No face is set up yet."
|
||||
msgstr ""
|
||||
|
||||
#: src/plasma-face-unlock:148 src/lib/menu.sh:167 src/lib/menu.sh:472
|
||||
#: src/plasma-face-unlock:148 src/lib/menu.sh:167 src/lib/menu.sh:476
|
||||
msgid "on"
|
||||
msgstr ""
|
||||
|
||||
#: src/plasma-face-unlock:148 src/lib/menu.sh:169 src/lib/menu.sh:179
|
||||
#: src/lib/menu.sh:473
|
||||
#: src/lib/menu.sh:477
|
||||
msgid "off"
|
||||
msgstr ""
|
||||
|
||||
#: src/plasma-face-unlock:150 src/lib/menu.sh:490
|
||||
#: src/plasma-face-unlock:150 src/lib/menu.sh:494
|
||||
#, sh-printf-format
|
||||
msgid "%s samples, %s learned"
|
||||
msgstr ""
|
||||
@@ -123,7 +123,7 @@ msgstr ""
|
||||
msgid "Turn it off (faces are kept)"
|
||||
msgstr ""
|
||||
|
||||
#: src/plasma-face-unlock:176 src/lib/menu.sh:555
|
||||
#: src/plasma-face-unlock:176 src/lib/menu.sh:559
|
||||
msgid "Add a face"
|
||||
msgstr ""
|
||||
|
||||
@@ -222,7 +222,7 @@ msgstr ""
|
||||
msgid "The camera could not be used."
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/daemon.sh:111 src/lib/menu.sh:243
|
||||
#: src/lib/daemon.sh:111 src/lib/menu.sh:246
|
||||
msgid "The recognition models are missing. Reinstall the package."
|
||||
msgstr ""
|
||||
|
||||
@@ -323,11 +323,11 @@ msgstr ""
|
||||
msgid "[y/N]"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:159 src/lib/menu.sh:392
|
||||
#: src/lib/menu.sh:159 src/lib/menu.sh:396
|
||||
msgid "ON"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:161 src/lib/menu.sh:393
|
||||
#: src/lib/menu.sh:161 src/lib/menu.sh:397
|
||||
msgid "OFF"
|
||||
msgstr ""
|
||||
|
||||
@@ -339,7 +339,7 @@ msgstr ""
|
||||
msgid "basic (screens and phone edges)"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:180
|
||||
#: src/lib/menu.sh:180 src/lib/menu.sh:185
|
||||
msgid "normal"
|
||||
msgstr ""
|
||||
|
||||
@@ -359,132 +359,140 @@ msgstr ""
|
||||
msgid "small pill with a lock"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:185
|
||||
#: src/lib/menu.sh:186
|
||||
msgid "fast"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:187
|
||||
msgid "slow"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:188
|
||||
#, sh-printf-format
|
||||
msgid "%s seconds"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:186 src/lib/menu.sh:323
|
||||
#: src/lib/menu.sh:189 src/lib/menu.sh:327
|
||||
msgid "automatic"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:203
|
||||
#: src/lib/menu.sh:206
|
||||
msgid "Face unlock"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:207
|
||||
#: src/lib/menu.sh:210
|
||||
msgid "Service"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:207
|
||||
#: src/lib/menu.sh:210
|
||||
msgid "not running"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:209
|
||||
#: src/lib/menu.sh:212
|
||||
msgid "Turning face unlock on again starts it."
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:220 src/lib/menu.sh:222 src/lib/menu.sh:469
|
||||
#: src/lib/menu.sh:556
|
||||
#: src/lib/menu.sh:223 src/lib/menu.sh:225 src/lib/menu.sh:473
|
||||
#: src/lib/menu.sh:560
|
||||
msgid "Faces"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:220
|
||||
#: src/lib/menu.sh:223
|
||||
msgid "none set up yet"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:222
|
||||
#: src/lib/menu.sh:225
|
||||
msgid "all turned off"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:228
|
||||
#: src/lib/menu.sh:231
|
||||
msgid "none found"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:230 /tmp/tmp.FOzKaHKE4a/settings.sh:9
|
||||
#: src/lib/menu.sh:233 /tmp/tmp.PgsbSPb4Sv/settings.sh:9
|
||||
msgid "Camera"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:232
|
||||
#: src/lib/menu.sh:235
|
||||
msgid "Lock screen"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:233
|
||||
#: src/lib/menu.sh:236
|
||||
msgid "sudo"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:234
|
||||
#: src/lib/menu.sh:237
|
||||
msgid "Admin prompts"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:235 /tmp/tmp.FOzKaHKE4a/settings.sh:6
|
||||
#: src/lib/menu.sh:238 /tmp/tmp.PgsbSPb4Sv/settings.sh:6
|
||||
msgid "Photo check"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:238
|
||||
#: src/lib/menu.sh:241
|
||||
msgid "Paused"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:238
|
||||
#: src/lib/menu.sh:241
|
||||
#, sh-printf-format
|
||||
msgid "for %d more minutes, or until the password is used"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:240
|
||||
#: src/lib/menu.sh:243
|
||||
msgid "Last unlock"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:319
|
||||
#: src/lib/menu.sh:323
|
||||
#, sh-printf-format
|
||||
msgid "automatic (%s)"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:329
|
||||
#: src/lib/menu.sh:333
|
||||
msgid "(infrared)"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:333
|
||||
#: src/lib/menu.sh:337
|
||||
msgid "(not connected)"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:389 src/lib/menu.sh:557
|
||||
#: src/lib/menu.sh:393 src/lib/menu.sh:561
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:390
|
||||
#: src/lib/menu.sh:394
|
||||
msgid "Up/Down: select, Space or Right: change, q: back"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:391
|
||||
#: src/lib/menu.sh:395
|
||||
msgid "Settings marked * are for the whole computer and ask for your password."
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:470
|
||||
#: src/lib/menu.sh:474
|
||||
msgid "Up/Down: select, Space: on/off, r: rename, d: delete, a: add, q: back"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:471
|
||||
#: src/lib/menu.sh:475
|
||||
msgid "No face is set up yet. Press a to add one."
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:516
|
||||
#: src/lib/menu.sh:520
|
||||
msgid "New name:"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:523
|
||||
#: src/lib/menu.sh:527
|
||||
#, sh-printf-format
|
||||
msgid "Delete \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:554
|
||||
#: src/lib/menu.sh:558
|
||||
msgid "Turn face unlock on or off"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:558
|
||||
#: src/lib/menu.sh:562
|
||||
msgid "Try it"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh:559
|
||||
#: src/lib/menu.sh:563
|
||||
msgid "Quit"
|
||||
msgstr ""
|
||||
|
||||
@@ -564,39 +572,43 @@ msgstr ""
|
||||
msgid "Bubble style"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh
|
||||
msgid "Animation speed"
|
||||
msgstr ""
|
||||
|
||||
#: src/lib/menu.sh
|
||||
msgid "Bubble for sudo and admin prompts too"
|
||||
msgstr ""
|
||||
|
||||
#: src/agent/bubblecontroller.cpp:92
|
||||
#: src/agent/bubblecontroller.cpp:98
|
||||
msgid "Blink once"
|
||||
msgstr ""
|
||||
|
||||
#: src/agent/bubblecontroller.cpp:94
|
||||
#: src/agent/bubblecontroller.cpp:100
|
||||
msgid "Look at the screen"
|
||||
msgstr ""
|
||||
|
||||
#: src/agent/bubblecontroller.cpp:96
|
||||
#: src/agent/bubblecontroller.cpp:102
|
||||
msgid "Move closer"
|
||||
msgstr ""
|
||||
|
||||
#: src/agent/bubblecontroller.cpp:98
|
||||
#: src/agent/bubblecontroller.cpp:104
|
||||
msgid "Too dark"
|
||||
msgstr ""
|
||||
|
||||
#: src/agent/bubblecontroller.cpp:118
|
||||
#: src/agent/bubblecontroller.cpp:124
|
||||
msgid "Use your password"
|
||||
msgstr ""
|
||||
|
||||
#: src/agent/bubblecontroller.cpp:124
|
||||
#: src/agent/bubblecontroller.cpp:130
|
||||
msgid "Not recognized"
|
||||
msgstr ""
|
||||
|
||||
#: src/agent/bubblecontroller.cpp:126
|
||||
#: src/agent/bubblecontroller.cpp:132
|
||||
msgid "Try again and blink"
|
||||
msgstr ""
|
||||
|
||||
#: src/agent/bubblecontroller.cpp:128
|
||||
#: src/agent/bubblecontroller.cpp:134
|
||||
msgid "Camera unavailable"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -28,6 +28,12 @@ BubbleController::BubbleController(UserConfig *config, QObject *parent)
|
||||
m_hide.setSingleShot(true);
|
||||
connect(&m_hide, &QTimer::timeout, this, &BubbleController::dismiss);
|
||||
connect(m_config, &UserConfig::changed, this, &BubbleController::styleChanged);
|
||||
connect(m_config, &UserConfig::changed, this, &BubbleController::paceChanged);
|
||||
}
|
||||
|
||||
qreal BubbleController::pace() const
|
||||
{
|
||||
return m_config->pace();
|
||||
}
|
||||
|
||||
QString BubbleController::style() const
|
||||
@@ -106,7 +112,7 @@ void BubbleController::succeeded()
|
||||
}
|
||||
setMessage({});
|
||||
setPhase(QStringLiteral("success"));
|
||||
m_hide.start(SuccessHoldMs);
|
||||
m_hide.start(int(SuccessHoldMs * pace()));
|
||||
}
|
||||
|
||||
void BubbleController::failed(const QString &reason, qint64 lockout)
|
||||
@@ -117,7 +123,7 @@ void BubbleController::failed(const QString &reason, qint64 lockout)
|
||||
if (lockout > 0 || reason == u"lockout") {
|
||||
setMessage(i18n("Use your password"));
|
||||
setPhase(QStringLiteral("lockout"));
|
||||
m_hide.start(LockoutHoldMs);
|
||||
m_hide.start(int(LockoutHoldMs * pace()));
|
||||
return;
|
||||
}
|
||||
if (reason == u"mismatch" || reason == u"spoof") {
|
||||
@@ -135,7 +141,7 @@ void BubbleController::failed(const QString &reason, qint64 lockout)
|
||||
return;
|
||||
}
|
||||
setPhase(QStringLiteral("failure"));
|
||||
m_hide.start(FailureHoldMs);
|
||||
m_hide.start(int(FailureHoldMs * pace()));
|
||||
}
|
||||
|
||||
void BubbleController::dismiss()
|
||||
|
||||
@@ -27,6 +27,8 @@ class BubbleController : public QObject
|
||||
// Whether the window should be on screen. Stays true after the phase
|
||||
// goes back to hidden until the bubble has finished closing.
|
||||
Q_PROPERTY(bool shown READ shown NOTIFY shownChanged)
|
||||
// The animation speed setting, as a multiple of each animation's length.
|
||||
Q_PROPERTY(qreal pace READ pace NOTIFY paceChanged)
|
||||
public:
|
||||
explicit BubbleController(UserConfig *config, QObject *parent = nullptr);
|
||||
|
||||
@@ -47,6 +49,7 @@ public:
|
||||
{
|
||||
return m_shown;
|
||||
}
|
||||
qreal pace() const;
|
||||
|
||||
void scanStarted();
|
||||
void faceFound();
|
||||
@@ -68,6 +71,7 @@ Q_SIGNALS:
|
||||
void faceSeenChanged();
|
||||
void styleChanged();
|
||||
void shownChanged();
|
||||
void paceChanged();
|
||||
|
||||
private:
|
||||
void setPhase(const QString &phase);
|
||||
|
||||
@@ -189,7 +189,7 @@ void LockController::onScanFinished(const QJsonObject &result)
|
||||
const QString reason = result.value(u"reason").toString();
|
||||
if (result.value(u"ok").toBool()) {
|
||||
m_bubble->succeeded();
|
||||
QTimer::singleShot(UnlockAfterSuccessMs, this, &LockController::unlock);
|
||||
QTimer::singleShot(int(UnlockAfterSuccessMs * m_config->pace()), this, &LockController::unlock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+26
-22
@@ -26,6 +26,8 @@ Item {
|
||||
readonly property string phase: bubble ? bubble.phase : "hidden"
|
||||
readonly property bool minimal: bubble && bubble.style === "minimal"
|
||||
readonly property bool wantOpen: phase !== "hidden"
|
||||
// The animation speed setting: how long everything takes, 1 normal.
|
||||
readonly property real pace: bubble ? bubble.pace : 1
|
||||
|
||||
property bool positioned: false
|
||||
property bool expanded: false
|
||||
@@ -54,12 +56,12 @@ Item {
|
||||
|
||||
Timer {
|
||||
id: expandLater
|
||||
interval: Theme.expandDelay
|
||||
interval: Theme.expandDelay * root.pace
|
||||
onTriggered: root.expanded = true
|
||||
}
|
||||
Timer {
|
||||
id: slideOut
|
||||
interval: Theme.slideOutDelay
|
||||
interval: Theme.slideOutDelay * root.pace
|
||||
onTriggered: {
|
||||
root.positioned = false
|
||||
closeDone.restart()
|
||||
@@ -67,7 +69,7 @@ Item {
|
||||
}
|
||||
Timer {
|
||||
id: closeDone
|
||||
interval: Theme.slideOutDuration + 60
|
||||
interval: Theme.slideOutDuration * root.pace + 60
|
||||
onTriggered: if (root.bubble) root.bubble.closed()
|
||||
}
|
||||
|
||||
@@ -85,11 +87,11 @@ Item {
|
||||
id: pulseAnimation
|
||||
running: root.phase === "scanning" && root.expanded
|
||||
loops: Animation.Infinite
|
||||
PauseAnimation { duration: 600 }
|
||||
NumberAnimation { from: 0; to: 1; duration: 400; easing.type: Easing.InOutQuad }
|
||||
PauseAnimation { duration: 50 }
|
||||
NumberAnimation { from: 1; to: 0; duration: 400; easing.type: Easing.InOutQuad }
|
||||
PauseAnimation { duration: 50 }
|
||||
PauseAnimation { duration: 600 * root.pace }
|
||||
NumberAnimation { from: 0; to: 1; duration: 400 * root.pace; easing.type: Easing.InOutQuad }
|
||||
PauseAnimation { duration: 50 * root.pace }
|
||||
NumberAnimation { from: 1; to: 0; duration: 400 * root.pace; easing.type: Easing.InOutQuad }
|
||||
PauseAnimation { duration: 50 * root.pace }
|
||||
onRunningChanged: if (!running) settle.restart()
|
||||
}
|
||||
NumberAnimation {
|
||||
@@ -97,7 +99,7 @@ Item {
|
||||
target: root
|
||||
property: "pulse"
|
||||
to: 0
|
||||
duration: 200
|
||||
duration: 200 * root.pace
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
|
||||
@@ -105,11 +107,11 @@ Item {
|
||||
property real shake: 0
|
||||
SequentialAnimation {
|
||||
id: pillShake
|
||||
NumberAnimation { target: root; property: "shake"; to: -10; duration: 55; easing.type: Easing.OutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: 9; duration: 70 }
|
||||
NumberAnimation { target: root; property: "shake"; to: -6; duration: 65 }
|
||||
NumberAnimation { target: root; property: "shake"; to: 4; duration: 60 }
|
||||
NumberAnimation { target: root; property: "shake"; to: 0; duration: 55; easing.type: Easing.OutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: -10; duration: 55 * root.pace; easing.type: Easing.OutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: 9; duration: 70 * root.pace }
|
||||
NumberAnimation { target: root; property: "shake"; to: -6; duration: 65 * root.pace }
|
||||
NumberAnimation { target: root; property: "shake"; to: 4; duration: 60 * root.pace }
|
||||
NumberAnimation { target: root; property: "shake"; to: 0; duration: 55 * root.pace; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -126,14 +128,14 @@ Item {
|
||||
// not sag.
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: root.opening ? Theme.growDuration : Theme.shrinkDuration
|
||||
duration: (root.opening ? Theme.growDuration : Theme.shrinkDuration) * root.pace
|
||||
easing.type: root.opening ? Easing.OutBack : Easing.OutCubic
|
||||
easing.overshoot: 1.6
|
||||
}
|
||||
}
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: root.opening ? Theme.growDuration : Theme.shrinkDuration
|
||||
duration: (root.opening ? Theme.growDuration : Theme.shrinkDuration) * root.pace
|
||||
easing.type: root.opening ? Easing.OutBack : Easing.OutCubic
|
||||
easing.overshoot: 0.9
|
||||
}
|
||||
@@ -145,7 +147,7 @@ Item {
|
||||
y: root.positioned ? Theme.topGap : -Theme.closedHeight - 20
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: root.opening ? Theme.slideInDuration : Theme.slideOutDuration
|
||||
duration: (root.opening ? Theme.slideInDuration : Theme.slideOutDuration) * root.pace
|
||||
easing.type: root.opening ? Easing.OutCubic : Easing.InCubic
|
||||
}
|
||||
}
|
||||
@@ -164,7 +166,7 @@ Item {
|
||||
shadowOpacity: root.expanded ? 0.35 : 0
|
||||
shadowBlur: 0.7
|
||||
shadowVerticalOffset: 3
|
||||
Behavior on shadowOpacity { NumberAnimation { duration: 200 } }
|
||||
Behavior on shadowOpacity { NumberAnimation { duration: 200 * root.pace } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +180,7 @@ Item {
|
||||
visible: !root.minimal
|
||||
scale: island.fit
|
||||
opacity: root.expanded ? 1 : 0
|
||||
Behavior on opacity { NumberAnimation { duration: root.opening ? 260 : 120 } }
|
||||
Behavior on opacity { NumberAnimation { duration: (root.opening ? 260 : 120) * root.pace } }
|
||||
|
||||
readonly property bool hasMessage: root.bubble && root.bubble.message.length > 0
|
||||
|
||||
@@ -193,8 +195,9 @@ Item {
|
||||
height: 100
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: full.hasMessage ? 28 : 40
|
||||
Behavior on y { NumberAnimation { duration: 220; easing.type: Easing.OutCubic } }
|
||||
Behavior on y { NumberAnimation { duration: 220 * root.pace; easing.type: Easing.OutCubic } }
|
||||
mode: root.glyphMode
|
||||
pace: root.pace
|
||||
}
|
||||
|
||||
Text {
|
||||
@@ -209,7 +212,7 @@ Item {
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
opacity: full.hasMessage ? 1 : 0
|
||||
Behavior on opacity { NumberAnimation { duration: 200 } }
|
||||
Behavior on opacity { NumberAnimation { duration: 200 * root.pace } }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,7 +223,7 @@ Item {
|
||||
anchors.fill: parent
|
||||
visible: root.minimal
|
||||
opacity: root.expanded ? 1 : 0
|
||||
Behavior on opacity { NumberAnimation { duration: root.opening ? 200 : 120 } }
|
||||
Behavior on opacity { NumberAnimation { duration: (root.opening ? 200 : 120) * root.pace } }
|
||||
|
||||
LockGlyph {
|
||||
width: 18
|
||||
@@ -239,6 +242,7 @@ Item {
|
||||
anchors.rightMargin: 14
|
||||
lineWidth: 2.4
|
||||
mode: root.glyphMode === "lockout" ? "failure" : root.glyphMode
|
||||
pace: root.pace
|
||||
onSettled: ok => {
|
||||
if (!ok) {
|
||||
pillShake.restart()
|
||||
|
||||
+22
-20
@@ -26,6 +26,8 @@ Item {
|
||||
property string mode: "idle"
|
||||
property color color: Theme.textPrimary
|
||||
property real lineWidth: width * 0.055
|
||||
// How long everything takes, 1 normal (the animation speed setting).
|
||||
property real pace: 1
|
||||
|
||||
// The verdict is showing: after the rings on success, at once on failure.
|
||||
signal settled(bool success)
|
||||
@@ -45,11 +47,11 @@ Item {
|
||||
running: root.looking
|
||||
from: 0
|
||||
to: 2 * Math.PI
|
||||
duration: 2000
|
||||
duration: 2000 * root.pace
|
||||
loops: Animation.Infinite
|
||||
}
|
||||
property real lookAmount: root.looking ? 1 : 0
|
||||
Behavior on lookAmount { NumberAnimation { duration: 350; easing.type: Easing.InOutQuad } }
|
||||
Behavior on lookAmount { NumberAnimation { duration: 350 * root.pace; easing.type: Easing.InOutQuad } }
|
||||
readonly property real yaw: 0.34 * Math.cos(lookAngle) * lookAmount
|
||||
readonly property real pitch: 0.2 * Math.sin(lookAngle) * lookAmount
|
||||
|
||||
@@ -65,15 +67,15 @@ Item {
|
||||
|
||||
// -- the smile, flat on failure
|
||||
property real smile: mode === "failure" ? 0 : 1
|
||||
Behavior on smile { NumberAnimation { duration: 220; easing.type: Easing.OutQuad } }
|
||||
Behavior on smile { NumberAnimation { duration: 220 * root.pace; easing.type: Easing.OutQuad } }
|
||||
|
||||
// -- the brackets breathe while scanning and close in on a face
|
||||
property real breathe: 0
|
||||
SequentialAnimation on breathe {
|
||||
running: root.looking
|
||||
loops: Animation.Infinite
|
||||
NumberAnimation { from: 0; to: 1; duration: 700; easing.type: Easing.InOutSine }
|
||||
NumberAnimation { from: 1; to: 0; duration: 700; easing.type: Easing.InOutSine }
|
||||
NumberAnimation { from: 0; to: 1; duration: 700 * root.pace; easing.type: Easing.InOutSine }
|
||||
NumberAnimation { from: 1; to: 0; duration: 700 * root.pace; easing.type: Easing.InOutSine }
|
||||
onRunningChanged: if (!running) root.breathe = 0
|
||||
}
|
||||
readonly property real bracketScale: mode === "tracking" ? 0.9 : 1 - 0.04 * breathe
|
||||
@@ -126,11 +128,11 @@ Item {
|
||||
SequentialAnimation {
|
||||
id: succeed
|
||||
ParallelAnimation {
|
||||
NumberAnimation { target: root; property: "t"; from: 0; to: 1; duration: 850 }
|
||||
NumberAnimation { target: root; property: "t"; from: 0; to: 1; duration: 850 * root.pace }
|
||||
// The tick starts as the ring comes to rest, so the one motion
|
||||
// runs on into the other.
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: 470 }
|
||||
PauseAnimation { duration: 470 * root.pace }
|
||||
ScriptAction { script: drawTick.start() }
|
||||
}
|
||||
}
|
||||
@@ -141,7 +143,7 @@ Item {
|
||||
target: root
|
||||
property: "tick"
|
||||
to: 1
|
||||
duration: 260
|
||||
duration: 260 * root.pace
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
|
||||
@@ -222,12 +224,12 @@ Item {
|
||||
property real shake: 0
|
||||
SequentialAnimation {
|
||||
id: shakeAnimation
|
||||
NumberAnimation { target: root; property: "shake"; to: -9; duration: 55; easing.type: Easing.OutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: 8; duration: 70; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: -6; duration: 65; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: 4; duration: 60; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: -2; duration: 55; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: 0; duration: 50; easing.type: Easing.OutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: -9; duration: 55 * root.pace; easing.type: Easing.OutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: 8; duration: 70 * root.pace; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: -6; duration: 65 * root.pace; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: 4; duration: 60 * root.pace; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: -2; duration: 55 * root.pace; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { target: root; property: "shake"; to: 0; duration: 50 * root.pace; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -246,7 +248,7 @@ Item {
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
scale: root.bracketScale
|
||||
Behavior on scale { NumberAnimation { duration: 260; easing.type: Easing.OutBack } }
|
||||
Behavior on scale { NumberAnimation { duration: 260 * root.pace; easing.type: Easing.OutBack } }
|
||||
|
||||
component Bracket: ShapePath {
|
||||
strokeColor: root.bracketColor
|
||||
@@ -254,7 +256,7 @@ Item {
|
||||
fillColor: "transparent"
|
||||
capStyle: ShapePath.RoundCap
|
||||
joinStyle: ShapePath.RoundJoin
|
||||
Behavior on strokeColor { ColorAnimation { duration: 220 } }
|
||||
Behavior on strokeColor { ColorAnimation { duration: 220 * root.pace } }
|
||||
}
|
||||
|
||||
Bracket {
|
||||
@@ -352,7 +354,7 @@ Item {
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
// Gives way to the rings, and to the lock.
|
||||
property real shown: root.mode === "lockout" ? 0 : 1
|
||||
Behavior on shown { NumberAnimation { duration: 180 } }
|
||||
Behavior on shown { NumberAnimation { duration: 180 * root.pace } }
|
||||
opacity: shown * (1 - root.faceGone)
|
||||
scale: 1 - 0.2 * root.faceGone
|
||||
|
||||
@@ -362,7 +364,7 @@ Item {
|
||||
fillColor: "transparent"
|
||||
capStyle: ShapePath.RoundCap
|
||||
joinStyle: ShapePath.RoundJoin
|
||||
Behavior on strokeColor { ColorAnimation { duration: 220 } }
|
||||
Behavior on strokeColor { ColorAnimation { duration: 220 * root.pace } }
|
||||
}
|
||||
|
||||
// Eyes
|
||||
@@ -412,8 +414,8 @@ Item {
|
||||
color: root.color
|
||||
opacity: root.mode === "lockout" ? 1 : 0
|
||||
scale: root.mode === "lockout" ? 1 : 0.7
|
||||
Behavior on opacity { NumberAnimation { duration: 200 } }
|
||||
Behavior on scale { NumberAnimation { duration: 260; easing.type: Easing.OutBack } }
|
||||
Behavior on opacity { NumberAnimation { duration: 200 * root.pace } }
|
||||
Behavior on scale { NumberAnimation { duration: 260 * root.pace; easing.type: Easing.OutBack } }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,8 @@ void UserConfig::load()
|
||||
m_bubble = kv.boolean(QStringLiteral("Bubble"), true);
|
||||
m_bubbleStyle = kv.value(QStringLiteral("BubbleStyle"), QStringLiteral("full")) == u"minimal" ? QStringLiteral("minimal") : QStringLiteral("full");
|
||||
m_bubbleForPrompts = kv.boolean(QStringLiteral("BubbleForPrompts"), true);
|
||||
const QString speed = kv.value(QStringLiteral("AnimationSpeed"), QStringLiteral("normal"));
|
||||
m_pace = speed == u"fast" ? 0.6 : speed == u"slow" ? 1.5 : 1.0;
|
||||
|
||||
if (QFileInfo::exists(path()) && !m_watcher.files().contains(path())) {
|
||||
m_watcher.addPath(path());
|
||||
|
||||
@@ -13,6 +13,7 @@ class UserConfig : public QObject
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool bubble READ bubble NOTIFY changed)
|
||||
Q_PROPERTY(QString bubbleStyle READ bubbleStyle NOTIFY changed)
|
||||
Q_PROPERTY(qreal pace READ pace NOTIFY changed)
|
||||
public:
|
||||
explicit UserConfig(QObject *parent = nullptr);
|
||||
|
||||
@@ -54,6 +55,12 @@ public:
|
||||
{
|
||||
return m_bubbleForPrompts;
|
||||
}
|
||||
// How long the bubble's animations take, as a multiple of normal: the
|
||||
// animation speed setting (fast 0.6, normal 1, slow 1.5).
|
||||
qreal pace() const
|
||||
{
|
||||
return m_pace;
|
||||
}
|
||||
|
||||
static QString path();
|
||||
|
||||
@@ -70,5 +77,6 @@ private:
|
||||
bool m_bubble = true;
|
||||
QString m_bubbleStyle = QStringLiteral("full");
|
||||
bool m_bubbleForPrompts = true;
|
||||
qreal m_pace = 1;
|
||||
QString m_styleOverride;
|
||||
};
|
||||
@@ -182,6 +182,9 @@ pfu_value_label() {
|
||||
Strictness:relaxed) pfu_msg "relaxed" ;;
|
||||
BubbleStyle:full) pfu_msg "island with the face" ;;
|
||||
BubbleStyle:minimal) pfu_msg "small pill with a lock" ;;
|
||||
AnimationSpeed:normal) pfu_msg "normal" ;;
|
||||
AnimationSpeed:fast) pfu_msg "fast" ;;
|
||||
AnimationSpeed:slow) pfu_msg "slow" ;;
|
||||
ScanSeconds:*) pfu_msg "%s seconds" "$2" ;;
|
||||
Camera:auto) pfu_msg "automatic" ;;
|
||||
*) printf '%s' "$2" ;;
|
||||
@@ -266,6 +269,7 @@ PFU_SETTINGS=(
|
||||
"sys|SkipLidClosed|bool|yes|Not while the lid is closed"
|
||||
"user|Bubble|bool|yes|Show the bubble at the top"
|
||||
"user|BubbleStyle|choice|full|Bubble style|full,minimal"
|
||||
"user|AnimationSpeed|choice|normal|Animation speed|normal,fast,slow"
|
||||
"user|BubbleForPrompts|bool|yes|Bubble for sudo and admin prompts too"
|
||||
)
|
||||
|
||||
|
||||
Reference in new issue
Block a user