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.notificationmanager as Notifications
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
@ -28,30 +28,38 @@ Item {
readonly property bool isWidescreen: root.height < 720 && (root.height < root.width * 0.75)
property bool notificationsShown: false
property var passwordBar: keypad.passwordBar
property var passwordBar: flickableLoader.item ? flickableLoader.item.passwordBar : null
Component.onCompleted: {
forceActiveFocus();
// Go to closed position when loaded
flickable.position = 0;
flickable.goToClosePosition();
}
// Listen for keyboard events, and focus on input area
Keys.onPressed: {
root.lockScreenState.isKeyboardMode = true;
flickable.goToOpenPosition();
passwordBar.textField.forceActiveFocus();
if (flickableLoader.item) {
root.lockScreenState.isKeyboardMode = true;
flickableLoader.item.goToOpenPosition();
passwordBar.textField.forceActiveFocus();
}
}
// Wallpaper blur
Loader {
id: wallpaperLoader
anchors.fill: parent
active: false
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 {
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)
function onPasswordChanged() {
if (root.lockScreenState.password !== "") {
flickable.goToOpenPosition();
if (root.lockScreenState.password !== "" && flickableLoader.item) {
flickableLoader.item.goToOpenPosition();
}
}
}
@ -72,7 +80,9 @@ Item {
onDpmsTurnedOff: (screen) => {
if (screen.name === Screen.name) {
flickable.goToClosePosition();
if (flickableLoader.item) {
flickableLoader.item.goToClosePosition();
}
lockScreenState.resetPassword();
}
}
@ -88,102 +98,147 @@ Item {
z: 1
anchors.fill: parent
statusBarHeight: Kirigami.Units.gridUnit * 1.25
openFactor: flickable.openFactor
openFactor: flickableLoader.item ? flickableLoader.item.openFactor : 0
notificationsModel: root.notifModel
onPasswordRequested: root.askPassword()
}
FlickContainer {
id: flickable
// Add loading indicator when status bar has not loaded yet
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
// Speed up animation when passwordless
animationDuration: root.lockScreenState.canBeUnlocked ? 400 : 800
Behavior on opacity {
NumberAnimation {}
}
// Distance to swipe to fully open keypad
keypadHeight: Kirigami.Units.gridUnit * 20
// Unlock lockscreen if it's already unlocked and keypad is opened
onOpened: {
if (root.lockScreenState.canBeUnlocked) {
Qt.quit();
// This take a while to load, don't pause initial lockscreen and wallpaper loading for it
Timer {
id: loadTimer
running: true
repeat: false
onTriggered: {
flickableLoader.active = true
}
}
// Unlock lockscreen if it's already unlocked and keypad is open
Connections {
target: root.lockScreenState
function onCanBeUnlockedChanged() {
if (root.lockScreenState.canBeUnlocked && flickable.openFactor > 0.8) {
// Container for lockscreen contents
sourceComponent: FlickContainer {
id: flickable
property alias passwordBar: keypad.passwordBar
// 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();
}
}
}
// Clear entered password after closing keypad
onOpenFactorChanged: {
if (flickable.openFactor < 0.1) {
root.passwordBar.clear();
}
}
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
// Unlock lockscreen if it's already unlocked and keypad is open
Connections {
target: root.lockScreenState
function onCanBeUnlockedChanged() {
if (root.lockScreenState.canBeUnlocked && flickable.openFactor > 0.8) {
Qt.quit();
}
}
]
}
fullHeight: root.height
// Clear entered password after closing keypad
onOpenFactorChanged: {
if (flickable.openFactor < 0.1) {
root.passwordBar.clear();
}
}
lockScreenState: root.lockScreenState
notificationsModel: root.notifModel
onNotificationsShownChanged: root.notificationsShown = notificationsShown
onPasswordRequested: flickable.goToOpenPosition()
LockScreenContent {
id: lockScreenContent
anchors.topMargin: headerBar.statusBarHeight
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
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
}
]
// scroll up icon
BottomIconIndicator {
id: scrollUpIconLoader
lockScreenState: root.lockScreenState
opacity: Math.max(0, 1 - flickable.openFactor * 2)
fullHeight: root.height
anchors.bottom: parent.bottom
anchors.bottomMargin: Kirigami.Units.gridUnit + flickable.position * 0.1
anchors.horizontalCenter: parent.horizontalCenter
}
lockScreenState: root.lockScreenState
notificationsModel: root.notifModel
onNotificationsShownChanged: root.notificationsShown = notificationsShown
onPasswordRequested: flickable.goToOpenPosition()
Rectangle {
id: keypadScrim
anchors.fill: parent
visible: opacity > 0
opacity: flickable.openFactor
color: Qt.rgba(0, 0, 0, 0.5)
}
anchors.topMargin: headerBar.statusBarHeight
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
Keypad {
id: keypad
visible: !root.lockScreenState.canBeUnlocked // don't show for passwordless login
anchors.fill: parent
openProgress: flickable.openFactor
lockScreenState: root.lockScreenState
// scroll up icon
BottomIconIndicator {
id: scrollUpIconLoader
lockScreenState: root.lockScreenState
opacity: Math.max(0, 1 - flickable.openFactor * 2)
// only show in last 50% of anim
opacity: (flickable.openFactor - 0.5) * 2
transform: Translate { y: (flickable.keypadHeight - flickable.position) * 0.1 }
anchors.bottom: parent.bottom
anchors.bottomMargin: Kirigami.Units.gridUnit + 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)
radius: Kirigami.Units.largeSpacing
color: Qt.rgba(255, 255, 255, 0.3)
color: Qt.rgba(255, 255, 255, 0.2)
// model for shown dots
// we need to use a listmodel to avoid all delegates from reloading
@ -164,6 +164,8 @@ Rectangle {
// toggle between showing keypad and not
ToolButton {
id: keyboardToggle
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
anchors.right: parent.right
anchors.top: parent.top
@ -175,6 +177,7 @@ Rectangle {
implicitWidth: height
icon.name: root.lockScreenState.isKeyboardMode ? "input-dialpad-symbolic" : "input-keyboard-virtual-symbolic"
icon.color: 'white'
onClicked: {
root.lockScreenState.isKeyboardMode = !root.lockScreenState.isKeyboardMode;
if (root.lockScreenState.isKeyboardMode) {