diff --git a/look-and-feel/contents/lockscreen/Keypad.qml b/look-and-feel/contents/lockscreen/Keypad.qml index 67787ba8..983da932 100644 --- a/look-and-feel/contents/lockscreen/Keypad.qml +++ b/look-and-feel/contents/lockscreen/Keypad.qml @@ -23,12 +23,6 @@ Rectangle { color: Kirigami.ColorUtils.adjustColor(PlasmaCore.Theme.backgroundColor, {"alpha": 0.9*255}) property string pinLabel: qsTr("Enter PIN") - // for displaying temporary number in pin dot display - property int previewCharIndex: -2 - - // if waiting for result of auth - property bool waitingForAuth: false - // colour calculations property color buttonColor: Qt.lighter(PlasmaCore.Theme.backgroundColor, 1.3) property color buttonPressedColor: Qt.darker(PlasmaCore.Theme.backgroundColor, 1.08) @@ -48,70 +42,24 @@ Rectangle { signal passwordChanged() - // keypad functions function reset() { - waitingForAuth = false; - root.password = ""; - passwordChanged(); - keypadRoot.pinLabel = qsTr("Enter PIN"); - } - - function backspace() { - if (!keypadRoot.waitingForAuth) { - keypadRoot.previewCharIndex = -2; - root.password = root.password.substr(0, root.password.length - 1); - passwordChanged(); - } - } - - function clear() { - if (!keypadRoot.waitingForAuth) { - keypadRoot.previewCharIndex = -2; - root.password = ""; - passwordChanged(); - } - } - - function enter() { - 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); - } - } - - function keyPress(data) { - if (!keypadRoot.waitingForAuth) { - if (keypadRoot.pinLabel !== qsTr("Enter PIN")) { - keypadRoot.pinLabel = qsTr("Enter PIN"); - } - keypadRoot.previewCharIndex = root.password.length; - root.password += data - passwordChanged(); - - // trigger turning letter into dot later - letterTimer.restart(); - } + passwordBar.reset(); } Connections { target: authenticator function onSucceeded() { - pinLabel = qsTr("Logging in..."); - keypadRoot.waitingForAuth = false; + passwordBar.pinLabel = qsTr("Logging in..."); + passwordBar.waitingForAuth = false; } function onFailed() { root.password = ""; - passwordChanged(); - pinLabel = qsTr("Wrong PIN"); - keypadRoot.waitingForAuth = false; + passwordBar.pinLabel = qsTr("Wrong PIN"); + passwordBar.waitingForAuth = false; } function onGraceLockedChanged() { // try authenticating if it was waiting for grace lock to stop and it has stopped - if (!authenticator.graceLocked && keypadRoot.waitingForAuth) { + if (!authenticator.graceLocked && passwordBar.waitingForAuth) { authenticator.tryUnlock(root.password); } } @@ -121,26 +69,15 @@ Rectangle { Keys.onPressed: { if (event.modifiers === Qt.NoModifier) { if (event.key === Qt.Key_Backspace) { - keypadRoot.backspace(); + passwordBar.backspace(); } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - keypadRoot.enter(); + passwordBar.enter(); } else if (event.text != "") { - keypadRoot.keyPress(event.text); + passwordBar.keyPress(event.text); } } } - // trigger turning letter into dot after 500 milliseconds - Timer { - id: letterTimer - interval: 500 - running: false - repeat: false - onTriggered: { - keypadRoot.previewCharIndex = -2; - } - } - RectangularGlow { anchors.topMargin: 1 anchors.fill: passwordBar @@ -162,8 +99,15 @@ Rectangle { keypadOpen: swipeProgress === 1 password: root.password - previewCharIndex: keypadRoot.previewCharIndex - pinLabel: keypadRoot.pinLabel + previewCharIndex: -2 + pinLabel: qsTr("Enter PIN") + + onChangePassword: root.password = password + Binding { + target: passwordBar + property: "password" + value: root.password + } } // actual number keys @@ -238,16 +182,16 @@ Rectangle { onClicked: { if (modelData === "R") { - keypadRoot.backspace(); + passwordBar.backspace(); } else if (modelData === "E") { - keypadRoot.enter(); + passwordBar.enter(); } else { - keypadRoot.keyPress(modelData); + passwordBar.keyPress(modelData); } } onPressAndHold: { if (modelData === "R") { - clear(); + passwordBar.clear(); } } } diff --git a/look-and-feel/contents/lockscreen/LockScreen.qml b/look-and-feel/contents/lockscreen/LockScreen.qml index 6f865c4b..106f5b9c 100644 --- a/look-and-feel/contents/lockscreen/LockScreen.qml +++ b/look-and-feel/contents/lockscreen/LockScreen.qml @@ -235,6 +235,7 @@ PlasmaCore.ColorScope { anchors.fill: parent property int columnHeight: units.gridUnit * 20 + property int oldContentY: contentY height: columnHeight + root.height contentHeight: columnHeight + root.height @@ -253,9 +254,10 @@ PlasmaCore.ColorScope { // wipe password if it is more than half way down the screen onContentYChanged: { - if (contentY < columnHeight / 2) { + if (contentY < columnHeight / 2 && oldContentY >= columnHeight / 2) { keypad.reset(); } + oldContentY = contentY; } ColumnLayout { diff --git a/look-and-feel/contents/lockscreen/NotificationsList.qml b/look-and-feel/contents/lockscreen/NotificationsList.qml index cbc852d6..a7c81a7a 100644 --- a/look-and-feel/contents/lockscreen/NotificationsList.qml +++ b/look-and-feel/contents/lockscreen/NotificationsList.qml @@ -48,6 +48,7 @@ Item { } height: 1 color: Qt.rgba(1, 1, 1, 0.5) + opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight) } } Rectangle { @@ -77,6 +78,7 @@ Item { } height: 1 color: Qt.rgba(1, 1, 1, 0.5) + opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight) } } diff --git a/look-and-feel/contents/lockscreen/PasswordBar.qml b/look-and-feel/contents/lockscreen/PasswordBar.qml index 18abe93e..31535476 100644 --- a/look-and-feel/contents/lockscreen/PasswordBar.qml +++ b/look-and-feel/contents/lockscreen/PasswordBar.qml @@ -21,13 +21,81 @@ Rectangle { property bool isPinMode: true property string password + + // for displaying temporary number in pin dot display property int previewCharIndex + property string pinLabel property bool keypadOpen + // if waiting for result of auth + property bool waitingForAuth: false + 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}) + signal changePassword(); + + // keypad functions + function reset() { + waitingForAuth = false; + root.password = ""; + changePassword(); + root.pinLabel = qsTr("Enter PIN"); + } + + function backspace() { + if (!root.waitingForAuth) { + root.previewCharIndex = -2; + root.password = root.password.substr(0, root.password.length - 1); + changePassword(); + } + } + + function clear() { + if (!root.waitingForAuth) { + root.previewCharIndex = -2; + root.password = ""; + changePassword(); + } + } + + function enter() { + if (root.password !== "") { // prevent typing lock when password is empty + root.waitingForAuth = true; + } + + // don't try to unlock if there is a timeout (unlock once unlocked) + if (!authenticator.graceLocked) { + authenticator.tryUnlock(root.password); + } + } + + function keyPress(data) { + if (!root.waitingForAuth) { + if (root.pinLabel !== qsTr("Enter PIN")) { + root.pinLabel = qsTr("Enter PIN"); + } + root.previewCharIndex = root.password.length; + root.password += data + changePassword(); + + // trigger turning letter into dot later + letterTimer.restart(); + } + } + + // trigger turning letter into dot after 500 milliseconds + Timer { + id: letterTimer + interval: 500 + running: false + repeat: false + onTriggered: { + root.previewCharIndex = -2; + } + } + // we need to use a listmodel to avoid all delegates from reloading ListModel { id: dotDisplayModel @@ -43,10 +111,41 @@ Rectangle { // hidden textfield so that the virtual keyboard shows up TextField { - visible: false id: textField + visible: false focus: keypadOpen && !isPinMode z: 1 + + property bool externalEdit: false + property string prevText: "" + + Connections { + target: root + function onChangePassword() { + if (textField.text != root.password) { + textField.externalEdit = true; + textField.text = root.password; + } + } + } + onEditingFinished: { + if (textField.focus) { + root.enter(); + } + } + onTextChanged: { + if (!externalEdit) { + if (prevText.length > text.length) { // backspace + for (let i = 0; i < (prevText.length - text.length); i++) { + root.backspace(); + } + } else if (text.length > 0) { // key enter + root.keyPress(text.charAt(text.length - 1)); + } + prevText = text; + } + externalEdit = false; + } } // toggle between showing keypad and not @@ -123,7 +222,7 @@ Rectangle { scale: 0 anchors.fill: parent radius: width - color: keypadRoot.waitingForAuth ? root.headerTextInactiveColor : root.headerTextColor // dim when waiting for auth + color: root.waitingForAuth ? root.headerTextInactiveColor : root.headerTextColor // dim when waiting for auth PropertyAnimation { id: dotAnimation @@ -137,7 +236,7 @@ Rectangle { id: charLabel scale: 0 anchors.centerIn: parent - color: keypadRoot.waitingForAuth ? root.headerTextInactiveColor : root.headerTextColor // dim when waiting for auth + color: root.waitingForAuth ? root.headerTextInactiveColor : root.headerTextColor // dim when waiting for auth text: model.char font.pointSize: 12