Unity 8
NotificationMenuItemFactory.qml
1 /*
2  * Copyright 2013-2016 Canonical Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 import QtQuick 2.4
18 import Ubuntu.Components 1.3
19 import QMenuModel 0.1
20 import "../Components"
21 
22 Loader {
23  id: menuFactory
24 
25  property QtObject menuModel: null
26  property QtObject menuData: null
27  property int menuIndex : -1
28  property int maxHeight
29  readonly property bool fullscreen: menuData.type === "com.canonical.snapdecision.pinlock"
30  property url background: ""
31 
32  signal accepted()
33 
34  property var _map: {
35  "com.canonical.snapdecision.textfield": textfield,
36  "com.canonical.snapdecision.pinlock" : pinLock,
37  }
38 
39  sourceComponent: {
40  if (menuData.type !== undefined) {
41  var component = _map[menuData.type];
42  if (component !== undefined) {
43  if (component === pinLock && shell.hasLockedApp) {
44  // In case we are in emergency mode, just skip this unlock.
45  // Happens with two locked SIMs but the user clicks
46  // Emergency Call on the first unlock dialog.
47  // TODO: if we ever allow showing the indicators in
48  // emergency mode, we'll need to differentiate between
49  // user-initiated ones which we *do* want to show and the
50  // dialogs that appear on boot, which we don't. But for
51  // now we can get away with skipping all such dialogs.
52  menuModel.activate(menuIndex, false);
53  return null;
54  }
55  return component;
56  }
57  }
58  }
59 
60  function getExtendedProperty(object, propertyName, defaultValue) {
61  if (object && object.hasOwnProperty(propertyName)) {
62  return object[propertyName];
63  }
64  return defaultValue;
65  }
66 
67  Component {
68  id: textfield
69 
70  Column {
71  spacing: notification.margins
72 
73  anchors {
74  left: parent.left
75  right: parent.right
76  margins: spacing
77  }
78 
79  Component.onCompleted: {
80  menuModel.loadExtendedAttributes(menuIndex, {"x-echo-mode-password": "bool"});
81  checkBox.checked = menuData.ext.xEchoModePassword ? false : true
82  checkBoxRow.visible = menuData.ext.xEchoModePassword
83  }
84 
85  Label {
86  text: menuData.label
87  color: theme.palette.normal.backgroundSecondaryText
88  }
89 
90  TextField {
91  // TODO using Qt.ImhNoPredictiveText here until lp #1291575 is fixed for ubuntu-ui-toolkit
92  inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
93  anchors {
94  left: parent.left
95  right: parent.right
96  }
97  echoMode: checkBox.checked ? TextInput.Normal : TextInput.Password
98  height: units.gu(5)
99  Component.onCompleted: {
100  forceActiveFocus();
101  }
102  onTextChanged: {
103  menuModel.changeState(menuIndex, text);
104  }
105  onAccepted: {
106  menuFactory.accepted()
107  }
108  }
109 
110  Row {
111  id: checkBoxRow
112 
113  spacing: notification.margins
114 
115  CheckBox {
116  id: checkBox
117 
118  checked: false
119  activeFocusOnPress: false
120  }
121 
122  Label {
123  anchors.verticalCenter: checkBox.verticalCenter
124  text: i18n.tr("Show password")
125  color: theme.palette.normal.backgroundSecondaryText
126 
127  MouseArea {
128  anchors.fill: parent
129  onClicked: { checkBox.checked = !checkBox.checked }
130  }
131  }
132  }
133  }
134  }
135 
136  Component {
137  id: pinLock
138 
139  Lockscreen {
140  anchors {
141  left: parent.left
142  right: parent.right
143  }
144  height: menuFactory.maxHeight
145  infoText: notification.summary
146  errorText: errorAction.valid ? errorAction.state : ""
147  retryText: notification.body
148  background: menuFactory.background
149  darkenBackground: 0.4
150 
151  onEntered: {
152  menuModel.changeState(menuIndex, passphrase);
153  clear(false);
154  }
155 
156  onCancel: {
157  menuModel.activate(menuIndex, false);
158  }
159 
160  onEmergencyCall: {
161  shell.startLockedApp("dialer-app");
162  menuModel.activate(menuIndex, false);
163  }
164 
165  property var extendedData: menuData && menuData.ext || undefined
166 
167  property var pinMinMaxAction : UnityMenuAction {
168  model: menuModel
169  index: menuIndex
170  name: getExtendedProperty(extendedData, "xCanonicalPinMinMax", "")
171 
172  onStateChanged: {
173  var min = pinMinMaxAction.state[0];
174  var max = pinMinMaxAction.state[1];
175 
176  if (min === 0) min = -1;
177  if (max === 0) max = -1;
178 
179  minPinLength = min
180  maxPinLength = max
181  }
182  }
183 
184  property var popupAction: UnityMenuAction {
185  model: menuModel
186  index: menuIndex
187  name: getExtendedProperty(extendedData, "xCanonicalPinPopup", "")
188  onStateChanged: {
189  if (state !== "")
190  showInfoPopup("", state);
191  }
192  }
193  onInfoPopupConfirmed: {
194  popupAction.activate();
195  }
196 
197  Timer {
198  id: errorTimer
199  interval: 4000;
200  running: false;
201  repeat: false
202  onTriggered: {
203  errorAction.activate();
204  }
205  }
206  property var errorAction: UnityMenuAction {
207  model: menuModel
208  index: menuIndex
209  name: getExtendedProperty(extendedData, "xCanonicalPinError", "")
210  onStateChanged: {
211  errorText = state;
212  if (state !== "") {
213  clear(true);
214  errorTimer.running = true;
215  }
216  }
217  }
218 
219  function loadAttributes() {
220  if (!menuModel || menuIndex == -1) return;
221  menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-pin-min-max': 'string',
222  'x-canonical-pin-popup': 'string',
223  'x-canonical-pin-error': 'string'});
224  }
225  Component.onCompleted: {
226  loadAttributes();
227  }
228  }
229  }
230 }