1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
// SPDX-FileCopyrightText: 2019 Nicolas Fella <nicolas.fella@gmx.de>
// SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.notificationmanager as Notifications
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.mobileshell.dpmsplugin as DPMS
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import org.kde.kirigami 2.12 as Kirigami
/**
* Lockscreen component that is loaded after the device is locked.
*
* Special attention must be paid to ensuring the GUI loads as fast as possible.
*/
Item {
id: root
readonly property var lockScreenState: LockScreenState {}
readonly property var notifModel: Notifications.WatchedNotificationsModel {}
// Only show widescreen mode for short height devices (ex. phone landscape)
readonly property bool isWidescreen: root.height < Kirigami.Units.gridUnit * 25 && (root.height < root.width * 0.75)
property bool notificationsShown: false
property var passwordBar: flickable.passwordBar
Component.onCompleted: {
forceActiveFocus();
}
// Listen for keyboard events, and focus on input area
Keys.onPressed: (event) => {
root.lockScreenState.isKeyboardMode = true;
flickable.goToOpenPosition();
passwordBar.textField.forceActiveFocus();
passwordBar.keyPress(event.text);
}
Connections {
target: MobileShellState.ShellDBusClient
function onOpenLockScreenKeypadRequested() {
flickable.goToOpenPosition();
}
}
// 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
}
}
Connections {
target: root.lockScreenState
// Ensure keypad is opened when password is updated (ex. keyboard)
function onPasswordChanged() {
if (root.lockScreenState.password !== "") {
flickable.goToOpenPosition();
}
}
}
// when screen turns off, reset state
DPMS.DPMSUtil {
id: dpms
onDpmsTurnedOff: (screen) => {
if (screen.name === Screen.name) {
flickable.goToClosePosition();
lockScreenState.resetPassword();
}
}
}
// Container for lockscreen contents
Item {
id: lockscreenContainer
anchors.fill: parent
FlickContainer {
id: flickable
anchors.fill: parent
property alias passwordBar: keypad.passwordBar
// Speed up animation when passwordless
animationDuration: Kirigami.Units.veryLongDuration
// 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();
}
}
// 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();
}
}
}
// Clear entered password after closing keypad
onOpenFactorChanged: {
if (flickable.openFactor < 0.1 && !flickable.movingUp) {
root.passwordBar.clear();
}
}
// scroll up icon
BottomIconIndicator {
id: scrollUpIconLoader
lockScreenState: root.lockScreenState
opacity: Math.max(0, 1 - flickable.openFactor * 2)
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)
}
MouseArea {
// Disable "double tap to lock" to avoid accidental locking
// when the keypad is open, and the user is typing their password.
enabled: flickable.openFactor < 0.1
anchors.fill: parent
onDoubleClicked: (mouse) => {
if (ShellSettings.KWinSettings.doubleTapWakeup) {
deviceLock.triggerLock();
}
}
MobileShell.DeviceLock {
id: deviceLock
}
}
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 }
}
}
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
}
]
lockScreenState: root.lockScreenState
notificationsModel: root.notifModel
onNotificationsShownChanged: root.notificationsShown = notificationsShown
onPasswordRequested: flickable.goToOpenPosition()
scrollLock: flickable.openFactor > 0.2
z: scrollLock ? -1 : 0
anchors.fill: parent
}
}
}
|