aerothemeplasma/plasma/shells/org.kde.plasma.desktop/contents/lockscreen_old/LockScreenUi.qml

422 lines
14 KiB
QML
Raw Normal View History

2024-08-09 01:20:25 +00:00
/*
SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQml 2.15
import QtQuick 2.8
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.1
import Qt5Compat.GraphicalEffects
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.workspace.components 2.0 as PW
import org.kde.plasma.private.keyboardindicator as KeyboardIndicator
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kscreenlocker 1.0 as ScreenLocker
import org.kde.plasma.private.sessions 2.0
import org.kde.breeze.components
Item {
id: lockScreenUi
// If we're using software rendering, draw outlines instead of shadows
// See https://bugs.kde.org/show_bug.cgi?id=398317
readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software
property bool hadPrompt: false
function handleMessage(msg) {
if (!root.notification) {
root.notification += msg;
} else if (root.notification.includes(msg)) {
root.notificationRepeated();
} else {
root.notification += "\n" + msg
}
}
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
Connections {
target: authenticator
function onFailed(kind) {
if (kind != 0) { // if this is coming from the noninteractive authenticators
return;
}
const msg = i18nd("plasma_shell_org.kde.plasma.desktop", "Unlocking failed");
lockScreenUi.handleMessage(msg);
graceLockTimer.restart();
notificationRemoveTimer.restart();
rejectPasswordAnimation.start();
lockScreenUi.hadPrompt = false;
}
function onSucceeded() {
if (lockScreenUi.hadPrompt) {
Qt.quit();
} else {
mainStack.replace(null, Qt.resolvedUrl("NoPasswordUnlock.qml"),
{
userListModel: users
},
StackView.Immediate,
);
mainStack.forceActiveFocus();
}
}
function onInfoMessageChanged() {
lockScreenUi.handleMessage(authenticator.infoMessage);
lockScreenUi.hadPrompt = true;
}
function onErrorMessageChanged() {
lockScreenUi.handleMessage(authenticator.errorMessage);
}
function onPromptChanged(msg) {
lockScreenUi.handleMessage(authenticator.prompt);
}
function onPromptForSecretChanged(msg) {
mainBlock.showPassword = false;
mainBlock.mainPasswordBox.forceActiveFocus();
lockScreenUi.hadPrompt = true;
}
}
SessionManagement {
id: sessionManagement
}
KeyboardIndicator.KeyState {
id: capsLockState
key: Qt.Key_CapsLock
}
Connections {
target: sessionManagement
function onAboutToSuspend() {
root.clearPassword();
}
}
RejectPasswordAnimation {
id: rejectPasswordAnimation
target: mainBlock
}
MouseArea {
id: lockScreenRoot
property bool uiVisible: false
property bool blockUI: mainStack.depth > 1 || mainBlock.mainPasswordBox.text.length > 0 || inputPanel.keyboardActive
x: parent.x
y: parent.y
width: parent.width
height: parent.height
hoverEnabled: true
cursorShape: uiVisible ? Qt.ArrowCursor : Qt.BlankCursor
drag.filterChildren: true
onPressed: uiVisible = true;
onPositionChanged: uiVisible = true;
onUiVisibleChanged: {
if (blockUI) {
fadeoutTimer.running = false;
} else if (uiVisible) {
fadeoutTimer.restart();
}
authenticator.startAuthenticating();
}
onBlockUIChanged: {
if (blockUI) {
fadeoutTimer.running = false;
uiVisible = true;
} else {
fadeoutTimer.restart();
}
}
Keys.onEscapePressed: {
// If the escape key is pressed, kscreenlocker will turn off the screen.
// We do not want to show the password prompt in this case.
if (uiVisible) {
uiVisible = false;
if (inputPanel.keyboardActive) {
inputPanel.showHide();
}
root.clearPassword();
}
}
Keys.onPressed: event => {
uiVisible = true;
event.accepted = false;
}
Timer {
id: fadeoutTimer
interval: 10000
onTriggered: {
if (!lockScreenRoot.blockUI) {
mainBlock.mainPasswordBox.showPassword = false;
lockScreenRoot.uiVisible = false;
}
}
}
Timer {
id: notificationRemoveTimer
interval: 3000
onTriggered: root.notification = ""
}
Timer {
id: graceLockTimer
interval: 3000
onTriggered: {
root.clearPassword();
authenticator.startAuthenticating();
}
}
PropertyAnimation {
id: launchAnimation
target: lockScreenRoot
property: "opacity"
from: 0
to: 1
duration: Kirigami.Units.veryLongDuration * 2
}
Component.onCompleted: launchAnimation.start();
WallpaperFader {
anchors.fill: parent
state: lockScreenRoot.uiVisible ? "on" : "off"
source: wallpaper
mainStack: mainStack
footer: footer
clock: clock
}
DropShadow {
id: clockShadow
anchors.fill: clock
source: clock
visible: !softwareRendering
radius: 6
samples: 14
spread: 0.3
color : "black" // shadows should always be black
Behavior on opacity {
OpacityAnimator {
duration: Kirigami.Units.veryLongDuration * 2
easing.type: Easing.InOutQuad
}
}
}
Clock {
id: clock
property Item shadow: clockShadow
visible: y > 0
anchors.horizontalCenter: parent.horizontalCenter
y: (mainBlock.userList.y + mainStack.y)/2 - height/2
Layout.alignment: Qt.AlignBaseline
}
ListModel {
id: users
Component.onCompleted: {
users.append({
name: kscreenlocker_userName,
realName: kscreenlocker_userName,
icon: kscreenlocker_userImage !== ""
? "file://" + kscreenlocker_userImage.split("/").map(encodeURIComponent).join("/")
: "",
})
}
}
StackView {
id: mainStack
anchors {
left: parent.left
right: parent.right
}
height: lockScreenRoot.height + Kirigami.Units.gridUnit * 3
focus: true //StackView is an implicit focus scope, so we need to give this focus so the item inside will have it
// this isn't implicit, otherwise items still get processed for the scenegraph
visible: opacity > 0
initialItem: MainBlock {
id: mainBlock
lockScreenUiVisible: lockScreenRoot.uiVisible
showUserList: userList.y + mainStack.y > 0
enabled: !graceLockTimer.running
StackView.onStatusChanged: {
// prepare for presenting again to the user
if (StackView.status === StackView.Activating) {
mainPasswordBox.clear();
mainPasswordBox.focus = true;
root.notification = "";
}
}
userListModel: users
notificationMessage: {
const parts = [];
if (capsLockState.locked) {
console.log(authenticator);
console.log(JSON.stringify(authenticator));
parts.push(i18nd("plasma_shell_org.kde.plasma.desktop", "Caps Lock is on"));
}
if (root.notification) {
parts.push(root.notification);
}
return parts.join(" • ");
}
onPasswordResult: password => {
authenticator.respond(password)
}
actionItems: [
ActionButton {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Eepy")
iconSource: "system-suspend"
onClicked: root.suspendToRam()
visible: root.suspendToRamSupported
},
ActionButton {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Hibernate")
iconSource: "system-suspend-hibernate"
onClicked: root.suspendToDisk()
visible: root.suspendToDiskSupported
},
ActionButton {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Switch User")
iconSource: "system-switch-user"
onClicked: {
sessionManagement.switchUser();
}
visible: sessionManagement.canSwitchUser
}
]
Loader {
Layout.topMargin: Kirigami.Units.smallSpacing // some distance to the password field
Layout.fillWidth: true
Layout.preferredHeight: item ? item.implicitHeight : 0
active: config.showMediaControls
source: "MediaControls.qml"
}
}
}
VirtualKeyboardLoader {
id: inputPanel
z: 1
screenRoot: lockScreenRoot
mainStack: mainStack
mainBlock: mainBlock
passwordField: mainBlock.mainPasswordBox
}
Loader {
z: 2
active: root.viewVisible
source: "LockOsd.qml"
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: Kirigami.Units.gridUnit
}
}
// Note: Containment masks stretch clickable area of their buttons to
// the screen edges, essentially making them adhere to Fitts's law.
// Due to virtual keyboard button having an icon, buttons may have
// different heights, so fillHeight is required.
//
// Note for contributors: Keep this in sync with SDDM Main.qml footer.
RowLayout {
id: footer
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
margins: Kirigami.Units.smallSpacing
}
spacing: Kirigami.Units.smallSpacing
PlasmaComponents3.ToolButton {
id: virtualKeyboardButton
focusPolicy: Qt.TabFocus
text: i18ndc("plasma_shell_org.kde.plasma.desktop", "Button to show/hide virtual keyboard", "Virtual Keyboard")
icon.name: inputPanel.keyboardActive ? "input-keyboard-virtual-on" : "input-keyboard-virtual-off"
onClicked: {
// Otherwise the password field loses focus and virtual keyboard
// keystrokes get eaten
mainBlock.mainPasswordBox.forceActiveFocus();
inputPanel.showHide()
}
visible: inputPanel.status === Loader.Ready
Layout.fillHeight: true
containmentMask: Item {
parent: virtualKeyboardButton
anchors.fill: parent
anchors.leftMargin: -footer.anchors.margins
anchors.bottomMargin: -footer.anchors.margins
}
}
PlasmaComponents3.ToolButton {
id: keyboardButton
focusPolicy: Qt.TabFocus
Accessible.description: i18ndc("plasma_shell_org.kde.plasma.desktop", "Button to change keyboard layout", "Switch layout")
icon.name: "input-keyboard"
PW.KeyboardLayoutSwitcher {
id: keyboardLayoutSwitcher
anchors.fill: parent
acceptedButtons: Qt.NoButton
}
text: keyboardLayoutSwitcher.layoutNames.longName
onClicked: keyboardLayoutSwitcher.keyboardLayout.switchToNextLayout()
visible: keyboardLayoutSwitcher.hasMultipleKeyboardLayouts
Layout.fillHeight: true
containmentMask: Item {
parent: keyboardButton
anchors.fill: parent
anchors.leftMargin: virtualKeyboardButton.visible ? 0 : -footer.anchors.margins
anchors.bottomMargin: -footer.anchors.margins
}
}
Item {
Layout.fillWidth: true
}
Battery {}
}
}
}