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
*/
@ -24,7 +24,7 @@ Rectangle {
property string pinLabel: qsTr("Enter PIN")
// for displaying temporary number in pin dot display
property int indexWithNumber: -2
property int previewCharIndex: -2
// if waiting for result of auth
property bool waitingForAuth: false
@ -35,11 +35,17 @@ Rectangle {
property color buttonTextColor: PlasmaCore.Theme.textColor
property color dropShadowColor: Qt.darker(PlasmaCore.Theme.backgroundColor, 1.2)
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
implicitHeight: passwordBar.isPinMode ? PlasmaCore.Units.gridUnit * 17 : passwordBar.implicitHeight
Behavior on implicitHeight {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
signal passwordChanged()
// keypad functions
@ -52,7 +58,7 @@ Rectangle {
function backspace() {
if (!keypadRoot.waitingForAuth) {
keypadRoot.indexWithNumber = -2;
keypadRoot.previewCharIndex = -2;
root.password = root.password.substr(0, root.password.length - 1);
passwordChanged();
}
@ -60,7 +66,7 @@ Rectangle {
function clear() {
if (!keypadRoot.waitingForAuth) {
keypadRoot.indexWithNumber = -2;
keypadRoot.previewCharIndex = -2;
root.password = "";
passwordChanged();
}
@ -82,7 +88,7 @@ Rectangle {
if (keypadRoot.pinLabel !== qsTr("Enter PIN")) {
keypadRoot.pinLabel = qsTr("Enter PIN");
}
keypadRoot.indexWithNumber = root.password.length;
keypadRoot.previewCharIndex = root.password.length;
root.password += data
passwordChanged();
@ -131,13 +137,13 @@ Rectangle {
running: false
repeat: false
onTriggered: {
keypadRoot.indexWithNumber = -2;
keypadRoot.previewCharIndex = -2;
}
}
RectangularGlow {
anchors.topMargin: 1
anchors.fill: topTextDisplay
anchors.fill: passwordBar
cached: true
glowRadius: 4
spread: 0.2
@ -145,126 +151,36 @@ Rectangle {
opacity: (Math.sin(2*((Math.PI / 2) * keypadRoot.swipeProgress + 1.5 * Math.PI)) + 1)
}
// rectangle "bar" on the top of the keypad
Rectangle {
id: topTextDisplay
// pin display and bar
PasswordBar {
id: passwordBar
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)
// label ("wrong pin", "enter pin")
Label {
opacity: root.password.length === 0 ? 1 : 0
anchors.centerIn: parent
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";
}
}
}
}
keypadOpen: swipeProgress === 1
password: root.password
previewCharIndex: keypadRoot.previewCharIndex
pinLabel: keypadRoot.pinLabel
}
// actual number keys
ColumnLayout {
visible: opacity > 0
opacity: passwordBar.isPinMode ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
anchors {
left: parent.left
right: parent.right
top: topTextDisplay.bottom
top: passwordBar.bottom
bottom: parent.bottom
topMargin: units.gridUnit
bottomMargin: units.gridUnit

View file

@ -278,8 +278,6 @@ PlasmaCore.ColorScope {
focus: passwordFlickable.contentY === passwordFlickable.columnHeight
swipeProgress: passwordFlickable.contentY / passwordFlickable.columnHeight
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";
}
}
}
}
}
}