shift-shell/look-and-feel/contents/lockscreen/Keypad.qml

315 lines
11 KiB
QML
Raw Normal View History

2020-08-31 01:38:46 +00:00
/*
Copyright (C) 2020 Devin Lin <espidev@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.12
2020-11-13 15:24:01 +00:00
import QtQuick.Controls 2.1
2020-08-31 01:38:46 +00:00
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.12
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.workspace.keyboardlayout 1.0
2020-11-21 19:49:08 +00:00
import org.kde.kirigami 2.12 as Kirigami
2020-08-31 01:38:46 +00:00
Rectangle {
id: keypadRoot
2020-11-21 19:49:08 +00:00
// 0 - keypad is not shown, 1 - keypad is shown
property double swipeProgress
// slightly translucent background, for key contrast
color: Kirigami.ColorUtils.adjustColor(PlasmaCore.Theme.backgroundColor, {"alpha": 0.9*255})
2020-08-31 01:38:46 +00:00
property string pinLabel: qsTr("Enter PIN")
// for displaying temporary number in pin dot display
property string lastKeyPressValue: "0"
property int indexWithNumber: -2
// if waiting for result of auth
property bool waitingForAuth: false
2020-11-21 19:49:08 +00:00
// colour calculations
property color buttonColor: Qt.lighter(PlasmaCore.Theme.backgroundColor, 1.3)
property color buttonPressedColor: Qt.darker(PlasmaCore.Theme.backgroundColor, 1.08)
property color buttonTextColor: PlasmaCore.Theme.textColor
property color dropShadowColor: Qt.darker(PlasmaCore.Theme.backgroundColor, 1.2)
2020-11-21 19:49:08 +00:00
property color headerBackgroundColor: Qt.lighter(PlasmaCore.Theme.backgroundColor, 1.3)
property color headerTextColor: Kirigami.ColorUtils.adjustColor(PlasmaCore.Theme.textColor, {"alpha": 0.75*255})
property color headerTextInactiveColor: Kirigami.ColorUtils.adjustColor(PlasmaCore.Theme.textColor, {"alpha": 0.4*255})
opacity: Math.sin((Math.PI / 2) * swipeProgress + 1.5 * Math.PI) + 1
// keypad functions
function reset() {
waitingForAuth = false;
root.password = "";
keypadRoot.pinLabel = qsTr("Enter PIN");
}
2020-08-31 01:38:46 +00:00
function backspace() {
if (!keypadRoot.waitingForAuth) {
keypadRoot.lastKeyPressValue = "0";
keypadRoot.indexWithNumber = -2;
root.password = root.password.substr(0, root.password.length - 1);
}
2020-08-31 01:38:46 +00:00
}
function clear() {
if (!keypadRoot.waitingForAuth) {
keypadRoot.lastKeyPressValue = "0";
keypadRoot.indexWithNumber = -2;
root.password = "";
}
}
2020-08-31 01:38:46 +00:00
function enter() {
2020-10-03 21:27:14 +00:00
if (root.password !== "") { // prevent typing lock when password is empty
keypadRoot.waitingForAuth = true;
}
// don't try to unlock if there is a timeout (unlock once unlocked)
if (!authenticator.graceLocked) {
authenticator.tryUnlock(root.password);
}
2020-08-31 01:38:46 +00:00
}
function keyPress(data) {
if (!keypadRoot.waitingForAuth) {
if (keypadRoot.pinLabel !== qsTr("Enter PIN")) {
keypadRoot.pinLabel = qsTr("Enter PIN");
}
keypadRoot.lastKeyPressValue = data;
keypadRoot.indexWithNumber = root.password.length;
root.password += data
// trigger turning letter into dot later
letterTimer.restart();
2020-08-31 01:38:46 +00:00
}
}
Connections {
target: authenticator
function onSucceeded() {
pinLabel = qsTr("Logging in...");
keypadRoot.waitingForAuth = false;
}
2020-08-31 01:38:46 +00:00
function onFailed() {
root.password = "";
pinLabel = qsTr("Wrong PIN");
keypadRoot.waitingForAuth = false;
}
function onGraceLockedChanged() {
// try authenticating if it was waiting for grace lock to stop and it has stopped
if (!authenticator.graceLocked && keypadRoot.waitingForAuth) {
authenticator.tryUnlock(root.password);
}
2020-08-31 01:38:46 +00:00
}
}
// listen for keyboard events
Keys.onPressed: {
if (event.modifiers === Qt.NoModifier) {
if (event.key === Qt.Key_Backspace) {
keypadRoot.backspace();
2020-08-31 01:38:46 +00:00
} else if (event.key === Qt.Key_Return) {
keypadRoot.enter();
2020-08-31 01:38:46 +00:00
} else if (event.text != "") {
keypadRoot.keyPress(event.text);
2020-08-31 01:38:46 +00:00
}
}
}
// trigger turning letter into dot after 500 milliseconds
Timer {
id: letterTimer
interval: 500
running: false
repeat: false
onTriggered: {
keypadRoot.lastKeyPressValue = 0;
keypadRoot.indexWithNumber = -2;
2020-08-31 01:38:46 +00:00
}
}
// rectangle "bar" on the top of the keypad
2020-11-21 19:49:08 +00:00
Rectangle {
id: topTextDisplay
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
color: keypadRoot.headerBackgroundColor
implicitHeight: units.gridUnit * 2.5
opacity: (Math.sin(2*((Math.PI / 2) * keypadRoot.swipeProgress + 1.5 * Math.PI)) + 1)
}
DropShadow {
anchors.fill: topTextDisplay
source: topTextDisplay
cached: true
horizontalOffset: 0
verticalOffset: 1
radius: 4
samples: 6
color: keypadRoot.dropShadowColor
opacity: (Math.sin(2*((Math.PI / 2) * keypadRoot.swipeProgress + 1.5 * Math.PI)) + 1)
}
// pin dot display
Item {
anchors.verticalCenter: topTextDisplay.verticalCenter
anchors.horizontalCenter: topTextDisplay.horizontalCenter
// label ("wrong pin", "enter pin")
Label {
visible: root.password.length === 0
anchors.centerIn: parent
text: keypadRoot.pinLabel
font.pointSize: 12
color: keypadRoot.headerTextColor
2020-11-21 19:49:08 +00:00
}
// dot display and letter
RowLayout {
id: dotDisplay
anchors.centerIn: parent
height: units.gridUnit * 1.5 // maintain height when letter is shown
spacing: 6
Repeater {
model: root.password.length
delegate: Rectangle { // dot
visible: index !== indexWithNumber // hide dot if number is shown
Layout.preferredWidth: units.gridUnit * 0.35
Layout.preferredHeight: Layout.preferredWidth
Layout.alignment: Qt.AlignVCenter
radius: width
color: keypadRoot.waitingForAuth ? keypadRoot.headerTextInactiveColor : keypadRoot.headerTextColor // dim when waiting for auth
}
}
Label { // number/letter
visible: root.password.length-1 === indexWithNumber // hide label if no label needed
Layout.alignment: Qt.AlignHCenter
color: keypadRoot.waitingForAuth ? keypadRoot.headerTextInactiveColor : keypadRoot.headerTextColor // dim when waiting for auth
text: lastKeyPressValue
font.pointSize: 12
}
}
}
// actual number keys
2020-08-31 01:38:46 +00:00
ColumnLayout {
anchors {
left: parent.left
right: parent.right
2020-11-21 19:49:08 +00:00
top: topTextDisplay.bottom
2020-08-31 01:38:46 +00:00
bottom: parent.bottom
topMargin: units.gridUnit
bottomMargin: units.gridUnit
}
spacing: units.gridUnit
2020-08-31 01:38:46 +00:00
GridLayout {
property string thePw
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.leftMargin: units.gridUnit * 0.5
Layout.rightMargin: units.gridUnit * 0.5
Layout.maximumWidth: units.gridUnit * 22
Layout.maximumHeight: units.gridUnit * 12.5
columns: 4
2020-08-31 01:38:46 +00:00
// numpad keys
Repeater {
model: ["1", "2", "3", "R", "4", "5", "6", "0", "7", "8", "9", "E"]
2020-08-31 01:38:46 +00:00
delegate: Item {
Layout.fillWidth: true
Layout.fillHeight: true
2020-08-31 01:38:46 +00:00
Rectangle {
id: keyRect
anchors.centerIn: parent
width: parent.width
height: parent.height
radius: 5
2020-11-21 19:49:08 +00:00
color: keypadRoot.buttonColor
2020-08-31 01:38:46 +00:00
visible: modelData.length > 0
2020-11-21 19:49:08 +00:00
opacity: (Math.sin(2*((Math.PI / 2) * keypadRoot.swipeProgress + 1.5 * Math.PI)) + 1)
2020-08-31 01:38:46 +00:00
2020-11-13 15:24:01 +00:00
AbstractButton {
2020-08-31 01:38:46 +00:00
anchors.fill: parent
2020-11-20 09:58:43 +00:00
onPressedChanged: {
2020-11-21 19:49:08 +00:00
if (pressed) {
parent.color = keypadRoot.buttonPressedColor;
} else {
parent.color = keypadRoot.buttonColor;
}
2020-11-20 09:58:43 +00:00
}
2020-08-31 01:38:46 +00:00
onClicked: {
if (modelData === "R") {
keypadRoot.backspace();
2020-08-31 01:38:46 +00:00
} else if (modelData === "E") {
keypadRoot.enter();
2020-08-31 01:38:46 +00:00
} else {
keypadRoot.keyPress(modelData);
2020-08-31 01:38:46 +00:00
}
}
onPressAndHold: {
if (modelData === "R") {
clear();
}
}
2020-08-31 01:38:46 +00:00
}
}
2020-08-31 01:38:46 +00:00
DropShadow {
anchors.fill: keyRect
source: keyRect
cached: true
horizontalOffset: 0
verticalOffset: 1
radius: 4
samples: 6
2020-11-21 19:49:08 +00:00
color: keypadRoot.dropShadowColor
opacity: (Math.sin(2*((Math.PI / 2) * keypadRoot.swipeProgress + 1.5 * Math.PI)) + 1)
2020-08-31 01:38:46 +00:00
}
PlasmaComponents.Label {
visible: modelData !== "R" && modelData !== "E"
text: modelData
anchors.centerIn: parent
font.pointSize: 18
2020-11-21 19:49:08 +00:00
color: keypadRoot.buttonTextColor
2020-08-31 01:38:46 +00:00
}
PlasmaCore.IconItem {
visible: modelData === "R"
anchors.centerIn: parent
source: "edit-clear"
}
PlasmaCore.IconItem {
visible: modelData === "E"
anchors.centerIn: parent
source: "go-next"
}
}
}
}
}
}