Lomiri
PassphraseLockscreen.qml
1 /*
2  * Copyright (C) 2013, 2014, 2015 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.12
18 import Lomiri.Components 1.3
19 import "../Components"
20 
21 FocusScope {
22  id: root
23  y: units.gu(4)
24  height: shakeContainer.height
25  focus: true
26 
27  property string infoText
28  property string errorText
29  property bool entryEnabled: true
30  property color foregroundColor: "#000000"
31 
32  readonly property string passphrase: pinentryField.text
33 
34  signal entered(string passphrase)
35  signal cancel()
36 
37  function clear(playAnimation) {
38  pinentryField.text = "";
39  pinentryField.incorrectOverride = false;
40  pinentryField.forceActiveFocus();
41  if (playAnimation) {
42  wrongPasswordAnimation.start();
43  }
44  }
45 
46  Column {
47  id: shakeContainer
48  anchors.horizontalCenter: parent.horizontalCenter
49  width: parent.width
50  spacing: units.gu(2)
51 
52  Label {
53  id: infoField
54  objectName: "infoTextLabel"
55  fontSize: "x-large"
56  color: root.foregroundColor
57  anchors.horizontalCenter: parent.horizontalCenter
58  text: root.infoText
59  }
60 
61  FocusScope {
62  id: entryContainer
63  anchors { left: parent.left; right: parent.right; margins: units.gu(2) }
64  height: units.gu(4)
65  focus: true
66 
67  TextInput {
68  id: pinentryField
69  objectName: "pinentryField"
70  focus: true
71 
72  property bool incorrectOverride: false
73 
74  anchors {
75  top: parent.top
76  left: parent.left
77  right: parent.right
78  }
79  horizontalAlignment: Text.AlignHCenter
80  font.pixelSize: FontUtils.sizeToPixels("large")
81  echoMode: TextInput.Password
82  inputMethodHints: Qt.ImhHiddenText | Qt.ImhSensitiveData |
83  Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
84  color: root.foregroundColor
85  cursorDelegate: Item {} // disable cursor
86  onCursorPositionChanged: {
87  // And because we don't show the cursor, always position the
88  // cursor at the end of the string (so backspace works like
89  // the user expects, even if they've clicked on us and
90  // thus accidentally moved the cursor)
91  if (cursorPosition !== length) {
92  cursorPosition = length
93  }
94  }
95  clip: true
96 
97  // This is so that we can draw our own dots, for we want
98  // complete control over the pixel sizes. (The lomiri font
99  // has oddly sized password characters that don't scale right)
100  opacity: 0
101 
102  // simulate being disabled, but without removing OSK focus
103  maximumLength: root.entryEnabled ? 32767 : length
104 
105  onTextChanged: incorrectOverride = true
106 
107  onAccepted: {
108  if (pinentryField.text) {
109  root.entered(pinentryField.text);
110  }
111  }
112  }
113 
114  Row {
115  id: dotRow
116  anchors.centerIn: entryContainer
117 
118  property real dotSize: Math.min(units.gu(2), entryContainer.width / pinentryField.length)
119  spacing: Math.min(units.gu(2), Math.max(0, (entryContainer.width / pinentryField.length) - dotSize))
120 
121  Repeater {
122  model: pinentryField.length
123  delegate: Rectangle {
124  color: root.foregroundColor
125  width: dotRow.dotSize
126  height: width
127  radius: width / 2
128  }
129  }
130  }
131 
132  Label {
133  id: wrongNoticeLabel
134  objectName: "wrongNoticeLabel"
135  fontSize: "large"
136  color: root.foregroundColor
137  anchors.horizontalCenter: parent.horizontalCenter
138  horizontalAlignment: Text.AlignHCenter
139  text: root.errorText
140  visible: pinentryField.text.length == 0 && !pinentryField.incorrectOverride
141  }
142  }
143  }
144 
145  WrongPasswordAnimation {
146  id: wrongPasswordAnimation
147  objectName: "wrongPasswordAnimation"
148  target: shakeContainer
149  }
150 }