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 204 205 206 207 208 209 210 211 212 213 214 215 216 217
|
/*
* 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 Lomiri.Components 1.3
import "../Components"
FocusScope {
id: root
objectName: "promptPassword"
property string text
property bool isSecret
property bool interactive: true
property bool loginError: false
property bool hasKeyboard: false
property alias enteredText: passwordInput.text
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
}
Rectangle {
anchors.fill: parent
radius: units.gu(0.5)
color: "#7A111111"
Behavior on border.color {
ColorAnimation{}
}
border {
color: root.loginError ? d.errorColor : d.drawColor
width: root.loginError ? units.dp(2): units.dp(1)
}
}
TextField {
id: passwordInput
objectName: "promptField"
anchors.fill: parent
focus: root.focus
opacity: fakeLabel.visible ? 0 : 1
activeFocusOnTab: true
onSelectedTextChanged: passwordInput.deselect()
validator: RegExpValidator {
regExp: /^.*$/
}
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText |
Qt.ImhMultiLine // so OSK doesn't close on Enter
echoMode: root.isSecret ? TextInput.Password : TextInput.Normal
hasClearButton: false
passwordCharacter: "●"
color: d.drawColor
readonly property real frameSpacing: units.gu(1)
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: styledItem.frameSpacing
// Properties needed by FocusShape
readonly property bool enabled: styledItem.enabled
readonly property bool keyNavigationFocus: styledItem.keyNavigationFocus
property bool activeFocusOnTab
}
secondaryItem: [
Row {
id: extraIcons
spacing: passwordInput.frameSpacing
anchors.verticalCenter: parent.verticalCenter
Icon {
name: "keyboard-caps-enabled"
height: units.gu(3)
width: units.gu(3)
color: d.drawColor
visible: root.isSecret && false // TODO: detect when caps lock is on
anchors.verticalCenter: parent.verticalCenter
}
Icon {
objectName: "greeterPromptKeyboardButton"
name: "input-keyboard-symbolic"
height: units.gu(3)
width: units.gu(3)
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: units.gu(3)
color: d.drawColor
visible: root.loginError
anchors.verticalCenter: parent.verticalCenter
}
Icon {
name: "toolkit_chevron-ltr_2gu"
height: units.gu(2.5)
width: units.gu(2.5)
color: d.drawColor
visible: !root.loginError
anchors.verticalCenter: parent.verticalCenter
MouseArea {
anchors.fill: parent
onClicked: root.accepted(passwordInput.text)
}
}
}
]
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;
}
onAccepted: respond()
function respond() {
if (root.interactive) {
root.accepted(passwordInput.text);
}
}
Keys.onEscapePressed: {
lomiriSettings.alwaysShowOsk = false
root.canceled();
event.accepted = true;
}
}
// We use our own custom placeholder label instead of the standard
// TextField one because the standard one hardcodes baseText as the
// palette color, whereas we want raisedSecondaryText.
Label {
id: passwordHint
objectName: "promptHint"
anchors {
left: passwordInput ? passwordInput.left : undefined
right: passwordInput ? passwordInput.right : undefined
verticalCenter: passwordInput ? passwordInput.verticalCenter : undefined
leftMargin: units.gu(2)
rightMargin: anchors.leftMargin + extraIcons.width
}
text: root.text
visible: passwordInput.text == "" && !passwordInput.inputMethodComposing
enabled: visible
color: d.drawColor
elide: Text.ElideRight
}
// 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.
FadingLabel {
id: fakeLabel
anchors.verticalCenter: parent ? parent.verticalCenter : undefined
anchors.left: parent ? parent.left : undefined
anchors.right: parent ? parent.right : undefined
anchors.leftMargin: passwordInput.frameSpacing * 2
anchors.rightMargin: passwordInput.frameSpacing * 2 + extraIcons.width
color: d.drawColor
text: passwordInput.displayText
visible: !root.interactive
enabled: visible
}
}
|