Unity 8
PinLockscreen.qml
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  */
16 
17 import QtQuick 2.0
18 import Ubuntu.Components 0.1
19 import Ubuntu.Components.ListItems 0.1
20 import "../Components"
21 
22 Item {
23  id: root
24 
25  property string infoText
26  property string retryText
27  property string errorText
28  property int minPinLength: -1
29  property int maxPinLength: -1
30  property bool showCancelButton: true
31  property color foregroundColor: "#000000"
32 
33  readonly property string passphrase: pinentryField.text
34 
35  signal entered(string passphrase)
36  signal cancel()
37 
38  property bool entryEnabled: true
39 
40  function clear(showAnimation) {
41  pinentryField.text = "";
42  if (showAnimation) {
43  pinentryField.incorrectOverride = true;
44  wrongPasswordAnimation.start();
45  }
46  }
47 
48  Column {
49  anchors {
50  left: parent.left;
51  right: parent.right;
52  verticalCenter: parent.verticalCenter;
53  verticalCenterOffset: Math.max(-units.gu(10), -(root.height - height) / 2) + units.gu(4)
54  }
55  spacing: units.gu(2)
56 
57  Column {
58  id: shakeContainer
59  anchors.horizontalCenter: parent.horizontalCenter
60  width: parent.width
61  spacing: units.gu(1)
62 
63  Label {
64  id: infoField
65  objectName: "infoTextLabel"
66  fontSize: "large"
67  color: root.foregroundColor
68  anchors.horizontalCenter: parent.horizontalCenter
69  text: root.infoText
70  }
71 
72  Item {
73  id: pinContainer
74  anchors { left: parent.left; right: parent.right; margins: units.gu(2) }
75  height: units.gu(4)
76 
77  Row {
78  id: pinentryField
79  objectName: "pinentryField"
80  anchors.horizontalCenter: parent.horizontalCenter
81  anchors.verticalCenter: parent.verticalCenter
82  spacing: Math.max(0, Math.min(units.gu(3), (parent.width / root.maxPinLength) - units.gu(3)))
83 
84  property string text
85  property bool incorrectOverride: false
86 
87  Repeater {
88  model: pinentryField.text.length
89  delegate: Rectangle {
90  color: root.foregroundColor
91  width: Math.min(units.gu(2), (pinContainer.width - pinContainer.height*2 ) / (root.maxPinLength >= 0 ? root.maxPinLength : 16))
92  height: width
93  radius: width / 2
94  }
95  }
96 
97  function appendNumber(number) {
98  if (incorrectOverride) {
99  incorrectOverride = false;
100  }
101 
102  pinentryField.text = pinentryField.text + number
103 
104  if (root.minPinLength > 0 && root.maxPinLength > 0
105  && root.minPinLength == root.maxPinLength && pinentryField.text.length == root.minPinLength) {
106  root.entered(pinentryField.text)
107  }
108  }
109 
110  function backspace() {
111  pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1)
112  }
113  }
114  Label {
115  id: wrongNoticeLabel
116  objectName: "wrongNoticeLabel"
117  fontSize: "x-large"
118  color: root.foregroundColor
119  anchors.horizontalCenter: parent.horizontalCenter
120  horizontalAlignment: Text.AlignHCenter
121  text: root.errorText
122  visible: pinentryField.incorrectOverride
123  scale: Math.min(1, parent.width / width)
124  }
125 
126  AbstractButton {
127  objectName: "backspaceIcon"
128  anchors { right: parent.right; top: parent.top; bottom: parent.bottom }
129  width: height
130  enabled: root.entryEnabled
131 
132  Icon {
133  anchors.fill: parent
134  name: "erase"
135  color: root.foregroundColor
136  }
137 
138  opacity: (pinentryField.text.length > 0 && !pinentryField.incorrectOverride) ? 1 : 0
139 
140  Behavior on opacity {
141  UbuntuNumberAnimation {}
142  }
143 
144  onClicked: pinentryField.backspace()
145  }
146  }
147 
148  Label {
149  objectName: "retryLabel"
150  fontSize: "x-small"
151  color: root.foregroundColor
152  anchors.horizontalCenter: parent.horizontalCenter
153  text: root.retryText || " "
154  }
155  }
156 
157  ThinDivider {
158  anchors { left: parent.left; right: parent.right; margins: units.gu(2) }
159  }
160 
161  Grid {
162  id: numbersGrid
163  objectName: "numbersGrid"
164  anchors { horizontalCenter: parent.horizontalCenter }
165  columns: 3
166 
167  property int maxWidth: Math.min(units.gu(50), root.width - units.gu(8))
168  property int buttonWidth: maxWidth / 3
169  property int buttonHeight: buttonWidth * 2 / 3
170 
171  Repeater {
172  model: 9
173 
174  PinPadButton {
175  objectName: "pinPadButton" + text
176  text: index + 1
177  height: numbersGrid.buttonHeight
178  width: numbersGrid.buttonWidth
179  foregroundColor: root.foregroundColor
180  enabled: root.entryEnabled && (root.maxPinLength == -1 ||
181  pinentryField.text.length < root.maxPinLength ||
182  pinentryField.incorrectOverride)
183 
184  onClicked: {
185  pinentryField.appendNumber(index + 1)
186  }
187  }
188  }
189  Item {
190  height: numbersGrid.buttonHeight
191  width: numbersGrid.buttonWidth
192  }
193  PinPadButton {
194  text: "0"
195  height: numbersGrid.buttonHeight
196  width: numbersGrid.buttonWidth
197  foregroundColor: root.foregroundColor
198  enabled: root.entryEnabled && (root.maxPinLength == -1 ||
199  pinentryField.text.length < root.maxPinLength ||
200  pinentryField.incorrectOverride)
201 
202  onClicked: {
203  pinentryField.appendNumber(0)
204  }
205  }
206  Item {
207  height: numbersGrid.buttonHeight
208  width: numbersGrid.buttonWidth
209  }
210  PinPadButton {
211  iconName: "close"
212  height: units.gu(5) // visual spec has this row a little closer in
213  width: numbersGrid.buttonWidth
214  foregroundColor: root.foregroundColor
215  onClicked: root.cancel()
216  visible: root.showCancelButton
217  }
218  Item {
219  height: units.gu(5)
220  width: numbersGrid.buttonWidth
221  }
222  PinPadButton {
223  iconName: "tick"
224  objectName: "confirmButton"
225  height: units.gu(5)
226  width: numbersGrid.buttonWidth
227  foregroundColor: root.foregroundColor
228  enabled: root.enabled && pinentryField.text.length >= root.minPinLength
229  visible: root.minPinLength == -1 || root.minPinLength !== root.maxPinLength
230 
231  onClicked: root.entered(pinentryField.text)
232  }
233  }
234  WrongPasswordAnimation {
235  id: wrongPasswordAnimation
236  objectName: "wrongPasswordAnimation"
237  target: shakeContainer
238  }
239  }
240 }