lockscreen: Async load everything and add spinner

This improves the speed initial lockscreen load, and now loads the keypad async. Also adjust the password bar opacity to be consistent with the keys.
This commit is contained in:
Devin Lin 2024-07-22 22:22:54 -04:00
parent d60fea6bdf
commit dea468b393
2 changed files with 145 additions and 87 deletions

View file

@ -9,7 +9,7 @@ import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore import org.kde.plasma.core as PlasmaCore
import org.kde.notificationmanager as Notifications import org.kde.notificationmanager as Notifications
import org.kde.plasma.private.mobileshell.dpmsplugin as DPMS import org.kde.plasma.private.mobileshell.dpmsplugin as DPMS
import org.kde.plasma.components 3.0 as PC3
import org.kde.kirigami 2.12 as Kirigami import org.kde.kirigami 2.12 as Kirigami
@ -28,30 +28,38 @@ Item {
readonly property bool isWidescreen: root.height < 720 && (root.height < root.width * 0.75) readonly property bool isWidescreen: root.height < 720 && (root.height < root.width * 0.75)
property bool notificationsShown: false property bool notificationsShown: false
property var passwordBar: keypad.passwordBar property var passwordBar: flickableLoader.item ? flickableLoader.item.passwordBar : null
Component.onCompleted: { Component.onCompleted: {
forceActiveFocus(); forceActiveFocus();
// Go to closed position when loaded
flickable.position = 0;
flickable.goToClosePosition();
} }
// Listen for keyboard events, and focus on input area // Listen for keyboard events, and focus on input area
Keys.onPressed: { Keys.onPressed: {
root.lockScreenState.isKeyboardMode = true; if (flickableLoader.item) {
flickable.goToOpenPosition(); root.lockScreenState.isKeyboardMode = true;
passwordBar.textField.forceActiveFocus(); flickableLoader.item.goToOpenPosition();
passwordBar.textField.forceActiveFocus();
}
} }
// Wallpaper blur // Wallpaper blur
Loader { Loader {
id: wallpaperLoader
anchors.fill: parent anchors.fill: parent
active: false
asynchronous: true asynchronous: true
// This take a while to load, don't pause initial lockscreen loading for it
Timer {
running: true
repeat: false
onTriggered: wallpaperLoader.active = true
}
sourceComponent: WallpaperBlur { sourceComponent: WallpaperBlur {
source: wallpaper source: wallpaper
opacity: flickable.openFactor opacity: flickableLoader.item ? flickableLoader.item.openFactor : 0
} }
} }
@ -60,8 +68,8 @@ Item {
// Ensure keypad is opened when password is updated (ex. keyboard) // Ensure keypad is opened when password is updated (ex. keyboard)
function onPasswordChanged() { function onPasswordChanged() {
if (root.lockScreenState.password !== "") { if (root.lockScreenState.password !== "" && flickableLoader.item) {
flickable.goToOpenPosition(); flickableLoader.item.goToOpenPosition();
} }
} }
} }
@ -72,7 +80,9 @@ Item {
onDpmsTurnedOff: (screen) => { onDpmsTurnedOff: (screen) => {
if (screen.name === Screen.name) { if (screen.name === Screen.name) {
flickable.goToClosePosition(); if (flickableLoader.item) {
flickableLoader.item.goToClosePosition();
}
lockScreenState.resetPassword(); lockScreenState.resetPassword();
} }
} }
@ -88,102 +98,147 @@ Item {
z: 1 z: 1
anchors.fill: parent anchors.fill: parent
statusBarHeight: Kirigami.Units.gridUnit * 1.25 statusBarHeight: Kirigami.Units.gridUnit * 1.25
openFactor: flickable.openFactor openFactor: flickableLoader.item ? flickableLoader.item.openFactor : 0
notificationsModel: root.notifModel notificationsModel: root.notifModel
onPasswordRequested: root.askPassword() onPasswordRequested: root.askPassword()
} }
FlickContainer { // Add loading indicator when status bar has not loaded yet
id: flickable PC3.BusyIndicator {
id: flickableLoadingBusyIndicator
anchors.centerIn: parent
visible: flickableLoader.status != Loader.Ready
implicitHeight: Kirigami.Units.iconSizes.huge
implicitWidth: Kirigami.Units.iconSizes.huge
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
}
// Load flickable async
Loader {
id: flickableLoader
active: false
asynchronous: true
opacity: status == Loader.Ready ? 1 : 0
visible: opacity > 0
anchors.fill: parent anchors.fill: parent
// Speed up animation when passwordless Behavior on opacity {
animationDuration: root.lockScreenState.canBeUnlocked ? 400 : 800 NumberAnimation {}
}
// Distance to swipe to fully open keypad // This take a while to load, don't pause initial lockscreen and wallpaper loading for it
keypadHeight: Kirigami.Units.gridUnit * 20 Timer {
id: loadTimer
// Unlock lockscreen if it's already unlocked and keypad is opened running: true
onOpened: { repeat: false
if (root.lockScreenState.canBeUnlocked) { onTriggered: {
Qt.quit(); flickableLoader.active = true
} }
} }
// Unlock lockscreen if it's already unlocked and keypad is open // Container for lockscreen contents
Connections { sourceComponent: FlickContainer {
target: root.lockScreenState id: flickable
function onCanBeUnlockedChanged() { property alias passwordBar: keypad.passwordBar
if (root.lockScreenState.canBeUnlocked && flickable.openFactor > 0.8) {
// Speed up animation when passwordless
animationDuration: root.lockScreenState.canBeUnlocked ? 400 : 800
// Distance to swipe to fully open keypad
keypadHeight: Kirigami.Units.gridUnit * 20
Component.onCompleted: {
// Go to closed position when loaded
flickable.position = 0;
flickable.goToClosePosition();
}
// Unlock lockscreen if it's already unlocked and keypad is opened
onOpened: {
if (root.lockScreenState.canBeUnlocked) {
Qt.quit(); Qt.quit();
} }
} }
}
// Clear entered password after closing keypad // Unlock lockscreen if it's already unlocked and keypad is open
onOpenFactorChanged: { Connections {
if (flickable.openFactor < 0.1) { target: root.lockScreenState
root.passwordBar.clear(); function onCanBeUnlockedChanged() {
} if (root.lockScreenState.canBeUnlocked && flickable.openFactor > 0.8) {
} Qt.quit();
}
LockScreenContent {
id: lockScreenContent
isVertical: !root.isWidescreen
opacity: Math.max(0, 1 - flickable.openFactor * 2)
transform: [
Scale {
origin.x: lockScreenContent.width / 2
origin.y: lockScreenContent.height / 2
yScale: 1 - (flickable.openFactor * 2) * 0.1
xScale: 1 - (flickable.openFactor * 2) * 0.1
} }
] }
fullHeight: root.height // Clear entered password after closing keypad
onOpenFactorChanged: {
if (flickable.openFactor < 0.1) {
root.passwordBar.clear();
}
}
lockScreenState: root.lockScreenState LockScreenContent {
notificationsModel: root.notifModel id: lockScreenContent
onNotificationsShownChanged: root.notificationsShown = notificationsShown
onPasswordRequested: flickable.goToOpenPosition()
anchors.topMargin: headerBar.statusBarHeight isVertical: !root.isWidescreen
anchors.top: parent.top opacity: Math.max(0, 1 - flickable.openFactor * 2)
anchors.bottom: parent.bottom transform: [
anchors.left: parent.left Scale {
anchors.right: parent.right origin.x: lockScreenContent.width / 2
} origin.y: lockScreenContent.height / 2
yScale: 1 - (flickable.openFactor * 2) * 0.1
xScale: 1 - (flickable.openFactor * 2) * 0.1
}
]
// scroll up icon fullHeight: root.height
BottomIconIndicator {
id: scrollUpIconLoader
lockScreenState: root.lockScreenState
opacity: Math.max(0, 1 - flickable.openFactor * 2)
anchors.bottom: parent.bottom lockScreenState: root.lockScreenState
anchors.bottomMargin: Kirigami.Units.gridUnit + flickable.position * 0.1 notificationsModel: root.notifModel
anchors.horizontalCenter: parent.horizontalCenter onNotificationsShownChanged: root.notificationsShown = notificationsShown
} onPasswordRequested: flickable.goToOpenPosition()
Rectangle { anchors.topMargin: headerBar.statusBarHeight
id: keypadScrim anchors.top: parent.top
anchors.fill: parent anchors.bottom: parent.bottom
visible: opacity > 0 anchors.left: parent.left
opacity: flickable.openFactor anchors.right: parent.right
color: Qt.rgba(0, 0, 0, 0.5) }
}
Keypad { // scroll up icon
id: keypad BottomIconIndicator {
visible: !root.lockScreenState.canBeUnlocked // don't show for passwordless login id: scrollUpIconLoader
anchors.fill: parent lockScreenState: root.lockScreenState
openProgress: flickable.openFactor opacity: Math.max(0, 1 - flickable.openFactor * 2)
lockScreenState: root.lockScreenState
// only show in last 50% of anim anchors.bottom: parent.bottom
opacity: (flickable.openFactor - 0.5) * 2 anchors.bottomMargin: Kirigami.Units.gridUnit + flickable.position * 0.1
transform: Translate { y: (flickable.keypadHeight - flickable.position) * 0.1 } anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle {
id: keypadScrim
anchors.fill: parent
visible: opacity > 0
opacity: flickable.openFactor
color: Qt.rgba(0, 0, 0, 0.5)
}
Keypad {
id: keypad
visible: !root.lockScreenState.canBeUnlocked // don't show for passwordless login
anchors.fill: parent
openProgress: flickable.openFactor
lockScreenState: root.lockScreenState
// only show in last 50% of anim
opacity: (flickable.openFactor - 0.5) * 2
transform: Translate { y: (flickable.keypadHeight - flickable.position) * 0.1 }
}
} }
} }
} }

View file

@ -25,7 +25,7 @@ Rectangle {
readonly property color headerTextInactiveColor: Qt.rgba(255, 255, 255, 0.4) readonly property color headerTextInactiveColor: Qt.rgba(255, 255, 255, 0.4)
radius: Kirigami.Units.largeSpacing radius: Kirigami.Units.largeSpacing
color: Qt.rgba(255, 255, 255, 0.3) color: Qt.rgba(255, 255, 255, 0.2)
// model for shown dots // model for shown dots
// we need to use a listmodel to avoid all delegates from reloading // we need to use a listmodel to avoid all delegates from reloading
@ -164,6 +164,8 @@ Rectangle {
// toggle between showing keypad and not // toggle between showing keypad and not
ToolButton { ToolButton {
id: keyboardToggle id: keyboardToggle
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
@ -175,6 +177,7 @@ Rectangle {
implicitWidth: height implicitWidth: height
icon.name: root.lockScreenState.isKeyboardMode ? "input-dialpad-symbolic" : "input-keyboard-virtual-symbolic" icon.name: root.lockScreenState.isKeyboardMode ? "input-dialpad-symbolic" : "input-keyboard-virtual-symbolic"
icon.color: 'white'
onClicked: { onClicked: {
root.lockScreenState.isKeyboardMode = !root.lockScreenState.isKeyboardMode; root.lockScreenState.isKeyboardMode = !root.lockScreenState.isKeyboardMode;
if (root.lockScreenState.isKeyboardMode) { if (root.lockScreenState.isKeyboardMode) {