on ee7f9fe help sign in
unity8/qml/Components/PinLockscreen.qml
262 lines 9.4 kB history raw
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import Ubuntu.Components.ListItems 1.3
20import "../Components"
22FocusScope {
23 id: root
24 focus: true
26 property string infoText
27 property string retryText
28 property string errorText
29 property int minPinLength: -1
30 property int maxPinLength: -1
31 property bool showCancelButton: true
32 property color foregroundColor: "#000000"
34 readonly property string passphrase: pinentryField.text
36 signal entered(string passphrase)
37 signal cancel()
39 property bool entryEnabled: true
41 function clear(showAnimation) {
42 pinentryField.text = "";
43 if (showAnimation) {
44 pinentryField.incorrectOverride = true;
45 wrongPasswordAnimation.start();
46 }
47 }
49 function showText(text) {
50 pinentryField.text = text;
51 }
53 Keys.onPressed: {
54 if (pinentryField.text.length == root.maxPinLength)
55 return;
57 if (event.key === Qt.Key_Backspace) {
58 pinentryField.backspace();
59 } else if (event.key === Qt.Key_Delete || event.key === Qt.Key_Escape) {
60 closeButton.clicked()
61 } else if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
62 confirmButton.clicked()
63 } else {
64 var digit = parseInt(event.text);
65 if (!isNaN(digit) && typeof digit == "number") {
66 pinentryField.appendNumber(digit);
67 }
68 }
69 }
71 Column {
72 anchors {
73 left: parent.left;
74 right: parent.right;
75 verticalCenter: parent.verticalCenter;
76 verticalCenterOffset: Math.max(-units.gu(10), -(root.height - height) / 2) + units.gu(4)
77 }
78 spacing: units.gu(4)
80 Column {
81 id: shakeContainer
82 anchors.horizontalCenter: parent.horizontalCenter
83 width: parent.width
84 spacing: units.gu(1)
86 Label {
87 id: infoField
88 objectName: "infoTextLabel"
89 fontSize: "large"
90 color: root.foregroundColor
91 anchors.horizontalCenter: parent.horizontalCenter
92 text: root.infoText
93 }
95 Item {
96 id: pinContainer
97 anchors { left: parent.left; right: parent.right; margins: units.gu(2) }
98 height: units.gu(4)
100 Row {
101 id: pinentryField
102 objectName: "pinentryField"
103 anchors.horizontalCenter: parent.horizontalCenter
104 anchors.verticalCenter: parent.verticalCenter
105 spacing: Math.max(0, Math.min(units.gu(3), (parent.width / root.maxPinLength) - units.gu(3)))
107 property string text
108 property bool incorrectOverride: false
110 Repeater {
111 model: pinentryField.text.length
112 delegate: Rectangle {
113 color: root.foregroundColor
114 width: Math.min(units.gu(2), (pinContainer.width - pinContainer.height*2 ) / (root.maxPinLength >= 0 ? root.maxPinLength : 16))
115 height: width
116 radius: width / 2
117 }
118 }
120 function appendNumber(number) {
121 if (incorrectOverride) {
122 incorrectOverride = false;
123 }
125 pinentryField.text = pinentryField.text + number
127 if (root.minPinLength > 0 && root.maxPinLength > 0
128 && root.minPinLength == root.maxPinLength && pinentryField.text.length == root.minPinLength) {
129 root.entered(pinentryField.text)
130 }
131 }
133 function backspace() {
134 pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1)
135 }
136 }
137 Label {
138 id: wrongNoticeLabel
139 objectName: "wrongNoticeLabel"
140 fontSize: "x-large"
141 color: root.foregroundColor
142 anchors.horizontalCenter: parent.horizontalCenter
143 horizontalAlignment: Text.AlignHCenter
144 text: root.errorText
145 visible: pinentryField.incorrectOverride
146 scale: Math.min(1, parent.width / width)
147 }
149 AbstractButton {
150 objectName: "backspaceIcon"
151 anchors { right: parent.right; top: parent.top; bottom: parent.bottom; margins: -units.gu(1) }
152 width: height
153 enabled: root.entryEnabled
155 Icon {
156 anchors.fill: parent
157 anchors.margins: units.gu(1)
158 name: "erase"
159 color: root.foregroundColor
160 }
162 opacity: (pinentryField.text.length > 0 && !pinentryField.incorrectOverride) ? 1 : 0
164 Behavior on opacity {
165 UbuntuNumberAnimation {}
166 }
168 onClicked: pinentryField.backspace()
169 }
170 }
172 Label {
173 objectName: "retryLabel"
174 fontSize: "x-small"
175 color: root.foregroundColor
176 anchors.horizontalCenter: parent.horizontalCenter
177 text: root.retryText || " "
178 }
179 }
181 Grid {
182 id: numbersGrid
183 objectName: "numbersGrid"
184 anchors { horizontalCenter: parent.horizontalCenter }
185 columns: 3
187 property int maxWidth: Math.min(units.gu(50), root.width - units.gu(8))
188 property int buttonWidth: maxWidth / 3
189 property int buttonHeight: buttonWidth * 2 / 3
191 Repeater {
192 model: 9
194 PinPadButton {
195 objectName: "pinPadButton" + text
196 text: index + 1
197 height: numbersGrid.buttonHeight
198 width: numbersGrid.buttonWidth
199 foregroundColor: root.foregroundColor
200 enabled: root.entryEnabled && (root.maxPinLength == -1 ||
201 pinentryField.text.length < root.maxPinLength ||
202 pinentryField.incorrectOverride)
204 onClicked: {
205 pinentryField.appendNumber(index + 1)
206 }
207 }
208 }
209 Item {
210 height: numbersGrid.buttonHeight
211 width: numbersGrid.buttonWidth
212 }
213 PinPadButton {
214 text: "0"
215 height: numbersGrid.buttonHeight
216 width: numbersGrid.buttonWidth
217 foregroundColor: root.foregroundColor
218 enabled: root.entryEnabled && (root.maxPinLength == -1 ||
219 pinentryField.text.length < root.maxPinLength ||
220 pinentryField.incorrectOverride)
222 onClicked: {
223 pinentryField.appendNumber(0)
224 }
225 }
226 Item {
227 height: numbersGrid.buttonHeight
228 width: numbersGrid.buttonWidth
229 }
230 PinPadButton {
231 id: closeButton
232 iconName: "close"
233 height: units.gu(5) // visual spec has this row a little closer in
234 width: numbersGrid.buttonWidth
235 foregroundColor: root.foregroundColor
236 onClicked: root.cancel()
237 visible: root.showCancelButton
238 }
239 Item {
240 height: units.gu(5)
241 width: numbersGrid.buttonWidth
242 }
243 PinPadButton {
244 id: confirmButton
245 iconName: "tick"
246 objectName: "confirmButton"
247 height: units.gu(5)
248 width: numbersGrid.buttonWidth
249 foregroundColor: root.foregroundColor
250 enabled: root.enabled && pinentryField.text.length >= root.minPinLength
251 visible: root.minPinLength == -1 || root.minPinLength !== root.maxPinLength
253 onClicked: root.entered(pinentryField.text)
254 }
255 }
256 WrongPasswordAnimation {
257 id: wrongPasswordAnimation
258 objectName: "wrongPasswordAnimation"
259 target: shakeContainer
260 }
261 }