Lomiri
NarrowView.qml
1/*
2 * Copyright (C) 2015-2016 Canonical Ltd.
3 * Copyright (C) 2021 UBports Foundation
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18import QtQuick 2.4
19import QtQuick.Window 2.2
20import QtGraphicalEffects 1.12
21import Lomiri.Components 1.3
22import Lomiri.Telephony 0.1 as Telephony
23import "../Components"
24
25FocusScope {
26 id: root
27
28 property alias dragHandleLeftMargin: coverPage.dragHandleLeftMargin
29 property alias launcherOffset: coverPage.launcherOffset
30 property alias currentIndex: loginList.currentIndex
31 property alias delayMinutes: delayedLockscreen.delayMinutes
32 property real panelHeight
33 property url background
34 property real backgroundSourceSize
35 property bool hasCustomBackground
36 property bool locked
37 property alias alphanumeric: loginList.alphanumeric
38 property alias hasKeyboard: loginList.hasKeyboard
39 property alias userModel: loginList.model
40 property alias infographicModel: coverPage.infographicModel
41 property string sessionToStart
42 property bool waiting
43 readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
44 readonly property bool required: coverPage.required || lockscreen.required
45 readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
46
47 property rect inputMethodRect
48
49 signal selected(int index)
50 signal responded(string response)
51 signal tease()
52 signal emergencyCall()
53
54 function hide() {
55 lockscreen.hide();
56 coverPage.hide();
57 }
58
59 function showFakePassword() {
60 loginList.showFakePassword();
61 }
62
63 function notifyAuthenticationFailed() {
64 loginList.showError();
65 }
66
67 function showErrorMessage(msg) {
68 coverPage.showErrorMessage(msg);
69 }
70
71 function forceShow() {
72 coverPage.show();
73 }
74
75 function tryToUnlock(toTheRight) {
76 var coverChanged = coverPage.shown;
77 lockscreen.maybeShow();
78 if (toTheRight) {
79 coverPage.hideRight();
80 } else {
81 coverPage.hide();
82 }
83 return coverChanged;
84 }
85
86 onLockedChanged: {
87 if (locked) {
88 lockscreen.maybeShow();
89 } else {
90 lockscreen.hide();
91 }
92 }
93
94 Keys.onSpacePressed: coverPage.hide();
95 Keys.onReturnPressed: coverPage.hide();
96 Keys.onEnterPressed: coverPage.hide();
97
98 Showable {
99 id: lockscreen
100 objectName: "lockscreen"
101 anchors.fill: parent
102 shown: false
103 opacity: 0
104
105 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
106 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
107
108 Rectangle {
109 // In case background fails to load or doesn't cover the whole screen
110 id: backgroundBackup
111 anchors.fill: parent
112 color: "black"
113 }
114
115 Wallpaper {
116 id: lockscreenBackground
117 objectName: "lockscreenBackground"
118 anchors {
119 fill: parent
120 }
121 source: root.background
122 sourceSize: root.backgroundSourceSize
123 }
124
125 // Darken background to match CoverPage
126 Rectangle {
127 objectName: "lockscreenShade"
128 anchors.fill: parent
129 color: "black"
130 opacity: root.hasCustomBackground ? 0.4 : 0
131 }
132
133 LoginList {
134 id: loginList
135 objectName: "loginList"
136
137 anchors {
138 horizontalCenter: parent.horizontalCenter
139 top: parent.top
140 bottom: parent.bottom
141 }
142 width: units.gu(40)
143 boxVerticalOffset: units.gu(14)
144 enabled: !coverPage.shown && visible
145 visible: !delayedLockscreen.visible
146
147 locked: root.locked
148
149 onSelected: if (enabled) root.selected(index)
150 onResponded: root.responded(response)
151 }
152
153 DelayedLockscreen {
154 id: delayedLockscreen
155 objectName: "delayedLockscreen"
156 anchors.fill: parent
157 visible: delayMinutes > 0
158 alphaNumeric: loginList.alphanumeric
159 }
160
161 function maybeShow() {
162 if (root.locked && !shown) {
163 showNow();
164 }
165 }
166 }
167
168 Rectangle {
169 anchors.fill: parent
170 color: "black"
171 opacity: coverPage.showProgress * 0.8
172 }
173
174 CoverPage {
175 id: coverPage
176 objectName: "coverPage"
177 height: parent.height
178 width: parent.width
179 background: root.background
180 hasCustomBackground: root.hasCustomBackground
181 panelHeight: root.panelHeight
182 draggable: !root.waiting
183 onTease: root.tease()
184 onClicked: hide()
185 backgroundSourceSize: root.backgroundSourceSize
186
187 onShowProgressChanged: {
188 if (showProgress === 0) {
189 if (lockscreen.shown) {
190 loginList.tryToUnlock();
191 } else {
192 root.responded("");
193 }
194 }
195 }
196
197 Clock {
198 anchors {
199 top: parent.top
200 topMargin: units.gu(2) + panelHeight
201 horizontalCenter: parent.horizontalCenter
202 }
203 }
204 }
205
206 StyledItem {
207 id: bottomBar
208 visible: lockscreen.shown
209 height: units.gu(4)
210
211 anchors.left: parent.left
212 anchors.right: parent.right
213 anchors.top: parent.bottom
214 anchors.topMargin: - height * (1 - coverPage.showProgress)
215 - ( inputMethodRect.height )
216
217 Label {
218 text: i18n.tr("Cancel")
219 anchors.left: parent.left
220 anchors.leftMargin: units.gu(2)
221 anchors.top: parent.top
222 anchors.bottom: parent.bottom
223 verticalAlignment: Text.AlignVCenter
224 font.weight: Font.Light
225 fontSize: "small"
226 color: theme.palette.normal.raisedSecondaryText
227
228 AbstractButton {
229 anchors.fill: parent
230 anchors.leftMargin: -units.gu(2)
231 anchors.rightMargin: -units.gu(2)
232 onClicked: coverPage.show()
233 }
234 }
235
236 Label {
237 objectName: "emergencyCallLabel"
238 text: callManager.hasCalls ? i18n.tr("Return to Call") : i18n.tr("Emergency")
239 anchors.right: parent.right
240 anchors.rightMargin: units.gu(2)
241 anchors.top: parent.top
242 anchors.bottom: parent.bottom
243 verticalAlignment: Text.AlignVCenter
244 font.weight: Font.Light
245 fontSize: "small"
246 color: theme.palette.normal.raisedSecondaryText
247 // TODO: uncomment once bug 1616538 is fixed
248 // visible: telepathyHelper.ready && telepathyHelper.emergencyCallsAvailable
249 enabled: visible
250
251 AbstractButton {
252 anchors.fill: parent
253 anchors.leftMargin: -units.gu(2)
254 anchors.rightMargin: -units.gu(2)
255 onClicked: root.emergencyCall()
256 }
257 }
258 }
259
260 // FIXME: It's difficult to keep something tied closely to the OSK (bug
261 // 1616163). But as a hack to avoid the background peeking out,
262 // we add an extra Rectangle that just serves to hide the background
263 // during OSK animations.
264 Rectangle {
265 visible: bottomBar.visible
266 height: inputMethodRect.height
267 anchors.bottom: parent.bottom
268 anchors.left: parent.left
269 anchors.right: parent.right
270 color: LomiriColors.porcelain
271 }
272}