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