Lomiri
Loading...
Searching...
No Matches
TextPrompt.qml
1/*
2 * Copyright (C) 2021 Capsia
3 * Copyright (C) 2016 Canonical, Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18import QtQuick 2.12
19import Lomiri.Components 1.3
20import "../Components"
21
22FocusScope {
23 id: root
24 objectName: "promptPassword"
25
26 property string text
27 property bool isSecret
28 property bool interactive: true
29 property bool loginError: false
30 property bool hasKeyboard: false
31 property alias enteredText: passwordInput.text
32
33 signal clicked()
34 signal canceled()
35 signal accepted(string response)
36
37 StyledItem {
38 id: d
39
40 readonly property color textColor: passwordInput.enabled ? theme.palette.normal.raisedText
41 : theme.palette.disabled.raisedText
42 readonly property color selectedColor: passwordInput.enabled ? theme.palette.normal.raised
43 : theme.palette.disabled.raised
44 readonly property color drawColor: passwordInput.enabled ? theme.palette.normal.raisedSecondaryText
45 : theme.palette.disabled.raisedSecondaryText
46 readonly property color errorColor: passwordInput.enabled ? theme.palette.normal.negative
47 : theme.palette.disabled.negative
48 }
49
50 Rectangle {
51 anchors.fill: parent
52 radius: units.gu(0.5)
53 color: "#7A111111"
54 Behavior on border.color {
55 ColorAnimation{}
56 }
57 border {
58 color: root.loginError ? d.errorColor : d.drawColor
59 width: root.loginError ? units.dp(2): units.dp(1)
60 }
61 }
62
63 TextField {
64 id: passwordInput
65 objectName: "promptField"
66 anchors.fill: parent
67 focus: root.focus
68
69 opacity: fakeLabel.visible ? 0 : 1
70 activeFocusOnTab: true
71
72 onSelectedTextChanged: passwordInput.deselect()
73
74 validator: RegExpValidator {
75 regExp: /^.*$/
76 }
77
78 inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText |
79 Qt.ImhMultiLine // so OSK doesn't close on Enter
80 echoMode: root.isSecret ? TextInput.Password : TextInput.Normal
81 hasClearButton: false
82
83 passwordCharacter: "●"
84 color: d.drawColor
85
86 readonly property real frameSpacing: units.gu(1)
87
88 style: StyledItem {
89 anchors.fill: parent
90 styleName: "FocusShape"
91
92 // Properties needed by TextField
93 readonly property color color: d.textColor
94 readonly property color selectedTextColor: d.selectedColor
95 readonly property color selectionColor: d.textColor
96 readonly property color borderColor: "transparent"
97 readonly property color backgroundColor: "transparent"
98 readonly property color errorColor: d.errorColor
99 readonly property real frameSpacing: styledItem.frameSpacing
100
101 // Properties needed by FocusShape
102 readonly property bool enabled: styledItem.enabled
103 readonly property bool keyNavigationFocus: styledItem.keyNavigationFocus
104 property bool activeFocusOnTab
105 }
106
107 secondaryItem: [
108 Row {
109 id: extraIcons
110 spacing: passwordInput.frameSpacing
111 anchors.verticalCenter: parent.verticalCenter
112 Icon {
113 name: "keyboard-caps-enabled"
114 height: units.gu(3)
115 width: units.gu(3)
116 color: d.drawColor
117 visible: root.isSecret && false // TODO: detect when caps lock is on
118 anchors.verticalCenter: parent.verticalCenter
119 }
120 Icon {
121 objectName: "greeterPromptKeyboardButton"
122 name: "input-keyboard-symbolic"
123 height: units.gu(3)
124 width: units.gu(3)
125 color: d.drawColor
126 visible: !lomiriSettings.alwaysShowOsk && root.hasKeyboard
127 anchors.verticalCenter: parent.verticalCenter
128 MouseArea {
129 anchors.fill: parent
130 onClicked: lomiriSettings.alwaysShowOsk = true
131 }
132 }
133 Icon {
134 name: "dialog-warning-symbolic"
135 height: units.gu(3)
136 width: units.gu(3)
137 color: d.drawColor
138 visible: root.loginError
139 anchors.verticalCenter: parent.verticalCenter
140 }
141 Icon {
142 name: "toolkit_chevron-ltr_2gu"
143 height: units.gu(2.5)
144 width: units.gu(2.5)
145 color: d.drawColor
146 visible: !root.loginError
147 anchors.verticalCenter: parent.verticalCenter
148 MouseArea {
149 anchors.fill: parent
150 onClicked: root.accepted(passwordInput.text)
151 }
152 }
153 }
154 ]
155
156 onDisplayTextChanged: {
157 // We use onDisplayTextChanged instead of onTextChanged because
158 // displayText changes after text and if we did this before it
159 // updated, we would use the wrong displayText for fakeLabel.
160 root.loginError = false;
161 }
162
163 onAccepted: respond()
164
165 function respond() {
166 if (root.interactive) {
167 root.accepted(passwordInput.text);
168 }
169 }
170
171 Keys.onEscapePressed: {
172 root.canceled();
173 event.accepted = true;
174 }
175 }
176
177 // We use our own custom placeholder label instead of the standard
178 // TextField one because the standard one hardcodes baseText as the
179 // palette color, whereas we want raisedSecondaryText.
180 Label {
181 id: passwordHint
182 objectName: "promptHint"
183 anchors {
184 left: passwordInput ? passwordInput.left : undefined
185 right: passwordInput ? passwordInput.right : undefined
186 verticalCenter: passwordInput ? passwordInput.verticalCenter : undefined
187 leftMargin: units.gu(2)
188 rightMargin: anchors.leftMargin + extraIcons.width
189 }
190 text: root.text
191 visible: passwordInput.text == "" && !passwordInput.inputMethodComposing
192 enabled: visible
193 color: d.drawColor
194 elide: Text.ElideRight
195 }
196
197 // Have a fake label that covers the text field after the user presses
198 // enter. What we *really* want is a disabled mode that doesn't lose OSK
199 // focus. Because our goal here is simply to keep the OSK up while
200 // we wait for PAM to get back to us, and while waiting, we don't want
201 // the user to be able to edit the field (simply because it would look
202 // weird if we allowed that). But until we have such a disabled mode,
203 // we'll fake it by covering the real text field with a label.
204 FadingLabel {
205 id: fakeLabel
206 anchors.verticalCenter: parent ? parent.verticalCenter : undefined
207 anchors.left: parent ? parent.left : undefined
208 anchors.right: parent ? parent.right : undefined
209 anchors.leftMargin: passwordInput.frameSpacing * 2
210 anchors.rightMargin: passwordInput.frameSpacing * 2 + extraIcons.width
211 color: d.drawColor
212 text: passwordInput.displayText
213 visible: !root.interactive
214 enabled: visible
215 }
216}