From dea468b393cf83cbbfdc7f66ed791372d6789ef8 Mon Sep 17 00:00:00 2001 From: Devin Lin Date: Mon, 22 Jul 2024 22:22:54 -0400 Subject: [PATCH] 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. --- shell/contents/lockscreen/LockScreen.qml | 227 ++++++++++++++-------- shell/contents/lockscreen/PasswordBar.qml | 5 +- 2 files changed, 145 insertions(+), 87 deletions(-) diff --git a/shell/contents/lockscreen/LockScreen.qml b/shell/contents/lockscreen/LockScreen.qml index 66300249..aed6a40c 100644 --- a/shell/contents/lockscreen/LockScreen.qml +++ b/shell/contents/lockscreen/LockScreen.qml @@ -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 } + } } } } diff --git a/shell/contents/lockscreen/PasswordBar.qml b/shell/contents/lockscreen/PasswordBar.qml index 300258e0..ea0052a9 100644 --- a/shell/contents/lockscreen/PasswordBar.qml +++ b/shell/contents/lockscreen/PasswordBar.qml @@ -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) {