Add keyboard option to lockscreen #72

This commit is contained in:
Devin Lin 2021-04-11 00:26:30 -04:00
parent 8852ad01a9
commit 07142481bf
3 changed files with 185 additions and 118 deletions

View file

@ -1,5 +1,5 @@
/* /*
SPDX-FileCopyrightText: 2020 Devin Lin <espidev@gmail.com> SPDX-FileCopyrightText: 2020-2021 Devin Lin <espidev@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later
*/ */
@ -24,7 +24,7 @@ Rectangle {
property string pinLabel: qsTr("Enter PIN") property string pinLabel: qsTr("Enter PIN")
// for displaying temporary number in pin dot display // for displaying temporary number in pin dot display
property int indexWithNumber: -2 property int previewCharIndex: -2
// if waiting for result of auth // if waiting for result of auth
property bool waitingForAuth: false property bool waitingForAuth: false
@ -35,11 +35,17 @@ Rectangle {
property color buttonTextColor: PlasmaCore.Theme.textColor property color buttonTextColor: PlasmaCore.Theme.textColor
property color dropShadowColor: Qt.darker(PlasmaCore.Theme.backgroundColor, 1.2) property color dropShadowColor: Qt.darker(PlasmaCore.Theme.backgroundColor, 1.2)
property color headerBackgroundColor: Qt.lighter(PlasmaCore.Theme.backgroundColor, 1.3) 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 opacity: Math.sin((Math.PI / 2) * swipeProgress + 1.5 * Math.PI) + 1
implicitHeight: passwordBar.isPinMode ? PlasmaCore.Units.gridUnit * 17 : passwordBar.implicitHeight
Behavior on implicitHeight {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
signal passwordChanged() signal passwordChanged()
// keypad functions // keypad functions
@ -52,7 +58,7 @@ Rectangle {
function backspace() { function backspace() {
if (!keypadRoot.waitingForAuth) { if (!keypadRoot.waitingForAuth) {
keypadRoot.indexWithNumber = -2; keypadRoot.previewCharIndex = -2;
root.password = root.password.substr(0, root.password.length - 1); root.password = root.password.substr(0, root.password.length - 1);
passwordChanged(); passwordChanged();
} }
@ -60,7 +66,7 @@ Rectangle {
function clear() { function clear() {
if (!keypadRoot.waitingForAuth) { if (!keypadRoot.waitingForAuth) {
keypadRoot.indexWithNumber = -2; keypadRoot.previewCharIndex = -2;
root.password = ""; root.password = "";
passwordChanged(); passwordChanged();
} }
@ -82,7 +88,7 @@ Rectangle {
if (keypadRoot.pinLabel !== qsTr("Enter PIN")) { if (keypadRoot.pinLabel !== qsTr("Enter PIN")) {
keypadRoot.pinLabel = qsTr("Enter PIN"); keypadRoot.pinLabel = qsTr("Enter PIN");
} }
keypadRoot.indexWithNumber = root.password.length; keypadRoot.previewCharIndex = root.password.length;
root.password += data root.password += data
passwordChanged(); passwordChanged();
@ -131,13 +137,13 @@ Rectangle {
running: false running: false
repeat: false repeat: false
onTriggered: { onTriggered: {
keypadRoot.indexWithNumber = -2; keypadRoot.previewCharIndex = -2;
} }
} }
RectangularGlow { RectangularGlow {
anchors.topMargin: 1 anchors.topMargin: 1
anchors.fill: topTextDisplay anchors.fill: passwordBar
cached: true cached: true
glowRadius: 4 glowRadius: 4
spread: 0.2 spread: 0.2
@ -145,126 +151,36 @@ Rectangle {
opacity: (Math.sin(2*((Math.PI / 2) * keypadRoot.swipeProgress + 1.5 * Math.PI)) + 1) opacity: (Math.sin(2*((Math.PI / 2) * keypadRoot.swipeProgress + 1.5 * Math.PI)) + 1)
} }
// rectangle "bar" on the top of the keypad // pin display and bar
Rectangle { PasswordBar {
id: topTextDisplay id: passwordBar
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
color: keypadRoot.headerBackgroundColor color: keypadRoot.headerBackgroundColor
implicitHeight: units.gridUnit * 2.5
opacity: (Math.sin(2*((Math.PI / 2) * keypadRoot.swipeProgress + 1.5 * Math.PI)) + 1) opacity: (Math.sin(2*((Math.PI / 2) * keypadRoot.swipeProgress + 1.5 * Math.PI)) + 1)
// label ("wrong pin", "enter pin") keypadOpen: swipeProgress === 1
Label { password: root.password
opacity: root.password.length === 0 ? 1 : 0 previewCharIndex: keypadRoot.previewCharIndex
anchors.centerIn: parent pinLabel: keypadRoot.pinLabel
text: keypadRoot.pinLabel
font.pointSize: 12
color: keypadRoot.headerTextColor
Behavior on opacity {
NumberAnimation { duration: 200 }
}
}
}
// we need to use a listmodel to avoid all delegates from reloading
ListModel {
id: dotDisplayModel
}
onPasswordChanged: {
while (root.password.length < dotDisplayModel.count) {
dotDisplayModel.remove(dotDisplayModel.count - 1);
}
while (root.password.length > dotDisplayModel.count) {
dotDisplayModel.append({"char": root.password.charAt(dotDisplayModel.count)});
}
}
// pin dot display
ColumnLayout {
anchors.fill: topTextDisplay
ListView {
id: dotDisplay
property int dotWidth: Math.round(units.gridUnit * 0.35)
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.bottomMargin: Math.round(dotWidth / 2)
orientation: ListView.Horizontal
implicitWidth: count * dotWidth + spacing * (count - 1)
spacing: 8
model: dotDisplayModel
Behavior on implicitWidth {
NumberAnimation { duration: 50 }
}
delegate: Item {
implicitWidth: dotDisplay.dotWidth
implicitHeight: dotDisplay.dotWidth
property bool showChar: index === indexWithNumber
Component.onCompleted: {
if (showChar) {
charAnimation.to = 1;
charAnimation.duration = 75;
charAnimation.restart();
} else {
dotAnimation.to = 1;
dotAnimation.restart();
}
}
onShowCharChanged: {
if (!showChar) {
charAnimation.to = 0;
charAnimation.duration = 50;
charAnimation.restart();
dotAnimation.to = 1;
dotAnimation.start();
}
}
Rectangle { // dot
id: dot
scale: 0
anchors.fill: parent
radius: width
color: keypadRoot.waitingForAuth ? keypadRoot.headerTextInactiveColor : keypadRoot.headerTextColor // dim when waiting for auth
PropertyAnimation {
id: dotAnimation
target: dot;
property: "scale";
duration: 50
}
}
Label { // number/letter
id: charLabel
scale: 0
anchors.centerIn: parent
color: keypadRoot.waitingForAuth ? keypadRoot.headerTextInactiveColor : keypadRoot.headerTextColor // dim when waiting for auth
text: model.char
font.pointSize: 12
PropertyAnimation {
id: charAnimation
target: charLabel;
property: "scale";
}
}
}
}
} }
// actual number keys // actual number keys
ColumnLayout { ColumnLayout {
visible: opacity > 0
opacity: passwordBar.isPinMode ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
top: topTextDisplay.bottom top: passwordBar.bottom
bottom: parent.bottom bottom: parent.bottom
topMargin: units.gridUnit topMargin: units.gridUnit
bottomMargin: units.gridUnit bottomMargin: units.gridUnit

View file

@ -278,8 +278,6 @@ PlasmaCore.ColorScope {
focus: passwordFlickable.contentY === passwordFlickable.columnHeight focus: passwordFlickable.contentY === passwordFlickable.columnHeight
swipeProgress: passwordFlickable.contentY / passwordFlickable.columnHeight swipeProgress: passwordFlickable.contentY / passwordFlickable.columnHeight
Layout.fillWidth: true Layout.fillWidth: true
Layout.minimumHeight: units.gridUnit * 17
Layout.maximumWidth: root.width
} }
} }
} }

View file

@ -0,0 +1,153 @@
/*
SPDX-FileCopyrightText: 2020-2021 Devin Lin <espidev@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.12
import QtQuick.Controls 2.1
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
import org.kde.kirigami 2.12 as Kirigami
Rectangle {
id: root
implicitHeight: units.gridUnit * 2.5
// toggle between pin and password mode
property bool isPinMode: true
property string password
property int previewCharIndex
property string pinLabel
property bool keypadOpen
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})
// we need to use a listmodel to avoid all delegates from reloading
ListModel {
id: dotDisplayModel
}
onPasswordChanged: {
while (password.length < dotDisplayModel.count) {
dotDisplayModel.remove(dotDisplayModel.count - 1);
}
while (password.length > dotDisplayModel.count) {
dotDisplayModel.append({"char": password.charAt(dotDisplayModel.count)});
}
}
// hidden textfield so that the virtual keyboard shows up
TextField {
visible: false
id: textField
focus: keypadOpen && !isPinMode
z: 1
}
// toggle between showing keypad and not
ToolButton {
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: units.smallSpacing
implicitWidth: height
icon.name: "input-keyboard-virtual-symbolic"
onClicked: root.isPinMode = !root.isPinMode
}
// label ("wrong pin", "enter pin")
Label {
opacity: password.length === 0 ? 1 : 0
anchors.centerIn: parent
text: root.pinLabel
font.pointSize: 12
color: root.headerTextColor
Behavior on opacity {
NumberAnimation { duration: 200 }
}
}
// pin dot display
ColumnLayout {
anchors.fill: parent
ListView {
id: dotDisplay
property int dotWidth: Math.round(units.gridUnit * 0.35)
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.bottomMargin: Math.round(dotWidth / 2)
orientation: ListView.Horizontal
implicitWidth: count * dotWidth + spacing * (count - 1)
spacing: 8
model: dotDisplayModel
Behavior on implicitWidth {
NumberAnimation { duration: 50 }
}
delegate: Item {
implicitWidth: dotDisplay.dotWidth
implicitHeight: dotDisplay.dotWidth
property bool showChar: index === root.previewCharIndex
Component.onCompleted: {
if (showChar) {
charAnimation.to = 1;
charAnimation.duration = 75;
charAnimation.restart();
} else {
dotAnimation.to = 1;
dotAnimation.restart();
}
}
onShowCharChanged: {
if (!showChar) {
charAnimation.to = 0;
charAnimation.duration = 50;
charAnimation.restart();
dotAnimation.to = 1;
dotAnimation.start();
}
}
Rectangle { // dot
id: dot
scale: 0
anchors.fill: parent
radius: width
color: keypadRoot.waitingForAuth ? root.headerTextInactiveColor : root.headerTextColor // dim when waiting for auth
PropertyAnimation {
id: dotAnimation
target: dot;
property: "scale";
duration: 50
}
}
Label { // number/letter
id: charLabel
scale: 0
anchors.centerIn: parent
color: keypadRoot.waitingForAuth ? root.headerTextInactiveColor : root.headerTextColor // dim when waiting for auth
text: model.char
font.pointSize: 12
PropertyAnimation {
id: charAnimation
target: charLabel;
property: "scale";
}
}
}
}
}
}