// SPDX-FileCopyrightText: 2020-2024 Devin Lin // SPDX-License-Identifier: GPL-2.0-or-later import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Effects import org.kde.plasma.components 3.0 as PlasmaComponents import org.kde.plasma.core as PlasmaCore import org.kde.plasma.workspace.keyboardlayout 1.0 import org.kde.plasma.private.mobileshell as MobileShell import org.kde.kirigami as Kirigami Item { id: root required property real openProgress required property var lockScreenState property alias passwordBar: passwordBar MobileShell.HapticsEffect { id: haptics } // Column layout - most cases ColumnLayout { id: keypadVerticalContainer visible: root.height > Kirigami.Units.gridUnit * 25 anchors.centerIn: parent spacing: Kirigami.Units.gridUnit * 2 LayoutItemProxy { id: verticalHeaderProxy target: header } LayoutItemProxy { target: keypadGrid } states: [ State { name: "keypad" when: !lockScreenState.isKeyboardMode AnchorChanges { target: verticalHeaderProxy; anchors.top: keypadVerticalContainer.top } PropertyChanges { target: verticalHeaderProxy; anchors.verticalCenterOffset: 0 } }, State { name: "keyboard" when: lockScreenState.isKeyboardMode AnchorChanges { target: verticalHeaderProxy; anchors.verticalCenter: keypadVerticalContainer.verticalCenter } PropertyChanges { target: verticalHeaderProxy; anchors.verticalCenterOffset: -Kirigami.Units.gridUnit * 3 } } ] transitions: Transition { AnchorAnimation { easing.type: Easing.OutCirc duration: openProgress > 0.5 ? 300 : 0 } } } // Row layout - used when there is restricted height RowLayout { id: keypadHorizontalContainer visible: !keypadVerticalContainer.visible anchors.centerIn: parent spacing: Kirigami.Units.gridUnit * 2 LayoutItemProxy { id: horizontalHeaderProxy target: header } LayoutItemProxy { target: keypadGrid } states: [ State { name: "keypad" when: !lockScreenState.isKeyboardMode AnchorChanges { target: horizontalHeaderProxy; anchors.left: keypadHorizontalContainer.left } }, State { name: "keyboard" when: lockScreenState.isKeyboardMode AnchorChanges { target: horizontalHeaderProxy; anchors.horizontalCenter: keypadHorizontalContainer.horizontalCenter } } ] transitions: Transition { AnchorAnimation { easing.type: Easing.OutCirc duration: openProgress > 0.5 ? 300 : 0 } } } ColumnLayout { id: header spacing: Kirigami.Units.gridUnit // label ("wrong pin", "enter pin") Label { id: descriptionLabel Layout.alignment: Qt.AlignHCenter opacity: root.lockScreenState.password.length === 0 ? 1 : 0 text: root.lockScreenState.pinLabel font.pointSize: 12 font.bold: true color: 'white' // Enforce extra margin at top of vertical container Layout.topMargin: keypadVerticalContainer.visible ? Kirigami.Units.gridUnit * 3 : 0 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration } } } // pin display and bar PasswordBar { id: passwordBar Layout.preferredWidth: Kirigami.Units.gridUnit * 14 Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5 lockScreenState: root.lockScreenState isKeypadOpen: root.openProgress >= 0.9 enabled: root.openProgress >= 0.8 } } GridLayout { id: keypadGrid columnSpacing: Kirigami.Units.gridUnit rowSpacing: Kirigami.Units.gridUnit uniformCellHeights: true uniformCellWidths: true readonly property real intendedWidth: Kirigami.Units.gridUnit * 14 Layout.preferredWidth: Kirigami.Units.gridUnit * 14 Layout.preferredHeight: Kirigami.Units.gridUnit * 22 readonly property real cellLength: (intendedWidth - columnSpacing * 2) / 3 columns: 3 // numpad keys Repeater { model: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "R", "0", "E"] delegate: AbstractButton { id: button implicitWidth: keypadGrid.cellLength implicitHeight: keypadGrid.cellLength visible: modelData.length > 0 enabled: root.openProgress >= 0.8 && !lockScreenState.isKeyboardMode // Only enable after a certain point in animation opacity: enabled Behavior on opacity { SequentialAnimation { PauseAnimation { duration: 20 * index } NumberAnimation { duration: 300 } } } background: Rectangle { readonly property real restingOpacity: (modelData !== "R" && modelData !== "E") ? 0.2 : 0.0 radius: width color: Qt.rgba(255, 255, 255, button.pressed ? 0.5 : restingOpacity) } onPressedChanged: { if (pressed) { haptics.buttonVibrate(); } } onClicked: { if (modelData === "R") { passwordBar.backspace(); } else if (modelData === "E") { passwordBar.enter(); } else { passwordBar.keyPress(modelData); } } onPressAndHold: { if (modelData === "R") { haptics.buttonVibrate(); passwordBar.clear(); } } contentItem: Item { PlasmaComponents.Label { visible: modelData !== "R" && modelData !== "E" text: modelData anchors.centerIn: parent font.pointSize: 18 color: 'white' } Kirigami.Icon { visible: modelData === "R" || modelData === "E" anchors.centerIn: parent width: Kirigami.Units.iconSizes.small height: Kirigami.Units.iconSizes.small source: modelData === "R" ? "edit-clear" : "go-next" Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.Complementary } } } } } }