1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
/*
* Copyright (C) 2021 Capsia
* Copyright (C) 2016 Canonical, Ltd.
*
* 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; version 3.
*
* 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.15
import AccountsService 0.1
import Lomiri.Components 1.3
import "../Components"
FocusScope {
id: root
property string text
property bool isSecret
property bool interactive: true
property bool loginError: false
property bool hasKeyboard: false
property alias enteredText: passwordInput.text
property int pincodeLength: AccountsService.pincodeLength
signal clicked()
signal canceled()
signal accepted(string response)
StyledItem {
id: d
readonly property color textColor: passwordInput.enabled ? theme.palette.normal.raisedText
: theme.palette.disabled.raisedText
readonly property color selectedColor: passwordInput.enabled ? theme.palette.normal.raised
: theme.palette.disabled.raised
readonly property color drawColor: passwordInput.enabled ? theme.palette.normal.raisedSecondaryText
: theme.palette.disabled.raisedSecondaryText
readonly property color errorColor: passwordInput.enabled ? theme.palette.normal.negative
: theme.palette.disabled.negative
}
TextField {
id: passwordInput
objectName: "promptField"
anchors.left: extraIcons.left
anchors.right: extraIcons.right
focus: root.focus
opacity: fakeLabel.visible ? 0 : 1
activeFocusOnTab: true
onSelectedTextChanged: passwordInput.deselect()
onCursorPositionChanged: cursorPosition = length
validator: RegExpValidator {
regExp: /^\d{4,}$/
}
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText |
Qt.ImhMultiLine | // so OSK doesn't close on Enter
Qt.ImhDigitsOnly
echoMode: TextInput.Password
hasClearButton: false
cursorDelegate: Item {}
passwordCharacter: "●"
color: d.drawColor
readonly property real letterSpacing: units.gu(1.75)
readonly property real frameSpacing: letterSpacing
font.pixelSize: units.gu(3)
font.letterSpacing: letterSpacing
style: StyledItem {
anchors.fill: parent
styleName: "FocusShape"
// Properties needed by TextField
readonly property color color: d.textColor
readonly property color selectedTextColor: d.selectedColor
readonly property color selectionColor: d.textColor
readonly property color borderColor: "transparent"
readonly property color backgroundColor: "transparent"
readonly property color errorColor: d.errorColor
readonly property real frameSpacing: 0
// Properties needed by FocusShape
readonly property bool enabled: styledItem.enabled
readonly property bool keyNavigationFocus: styledItem.keyNavigationFocus
property bool activeFocusOnTab
}
onDisplayTextChanged: {
// We use onDisplayTextChanged instead of onTextChanged because
// displayText changes after text and if we did this before it
// updated, we would use the wrong displayText for fakeLabel.
root.loginError = false;
if (text.length === root.pincodeLength) {
respond();
}
}
onAccepted: respond()
function respond() {
if (root.interactive) {
root.accepted(passwordInput.text);
}
}
Keys.onEscapePressed: {
root.canceled();
event.accepted = true;
}
}
Row {
id: extraIcons
spacing: passwordInput.frameSpacing
anchors {
horizontalCenter: parent ? parent.horizontalCenter : undefined
horizontalCenterOffset: passwordInput.letterSpacing / 2
verticalCenter: passwordInput ? passwordInput.verticalCenter : undefined
}
Label {
id: pinHint
objectName: "promptPinHint"
text: Array(root.pincodeLength).fill('○').join("")
enabled: visible
color: d.drawColor
font {
pixelSize: units.gu(3)
letterSpacing: units.gu(1.75)
}
elide: Text.ElideRight
}
Icon {
name: "keyboard-caps-enabled"
height: units.gu(3)
width: height
color: d.drawColor
visible: false // TODO: detect when caps lock is on
anchors.verticalCenter: parent.verticalCenter
}
Icon {
objectName: "greeterPromptKeyboardButton"
name: "input-keyboard-symbolic"
height: units.gu(3)
width: height
color: d.drawColor
visible: !lomiriSettings.alwaysShowOsk && root.hasKeyboard
anchors.verticalCenter: parent.verticalCenter
MouseArea {
anchors.fill: parent
onClicked: lomiriSettings.alwaysShowOsk = true
}
}
Icon {
name: "dialog-warning-symbolic"
height: units.gu(3)
width: height
color: d.drawColor
visible: root.loginError
anchors.verticalCenter: parent.verticalCenter
}
}
// Have a fake label that covers the text field after the user presses
// enter. What we *really* want is a disabled mode that doesn't lose OSK
// focus. Because our goal here is simply to keep the OSK up while
// we wait for PAM to get back to us, and while waiting, we don't want
// the user to be able to edit the field (simply because it would look
// weird if we allowed that). But until we have such a disabled mode,
// we'll fake it by covering the real text field with a label.
Label {
id: fakeLabel
anchors.verticalCenter: extraIcons ? extraIcons.verticalCenter : undefined
anchors.left: extraIcons ? extraIcons.left : undefined
anchors.right: parent ? parent.right : undefined
anchors.rightMargin: passwordInput.frameSpacing * 2 + extraIcons.width
color: d.drawColor
font {
pixelSize: pinHint.font.pixelSize
letterSpacing: pinHint.font.letterSpacing
}
text: passwordInput.displayText
visible: !root.interactive
enabled: visible
}
}
|