2 * Copyright (C) 2015-2016 Canonical, Ltd.
3 * Copyright (C) 2021 UBports Foundation
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.
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.
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/>.
19 import QtQuick.Window 2.2
20 import QtGraphicalEffects 1.12
21 import Ubuntu.Components 1.3
22 import Ubuntu.Telephony 0.1 as Telephony
23 import "../Components"
27 objectName: "GreeterView"
31 property url background
32 property real backgroundSourceSize
33 property real panelHeight
34 property bool hasCustomBackground
35 property alias dragHandleLeftMargin: coverPage.dragHandleLeftMargin
36 property var infographicModel
37 property alias launcherOffset: coverPage.launcherOffset
38 property alias currentIndex: loginList.currentIndex
39 property alias delayMinutes: delayedLockscreen.delayMinutes // TODO
40 property alias alphanumeric: loginList.alphanumeric
41 property alias hasKeyboard: loginList.hasKeyboard
44 property var userModel // Set from outside
45 property bool multiUser: false
46 property int orientation
47 property bool isLandscape: root.orientation == Qt.LandscapeOrientation ||
48 root.orientation == Qt.InvertedLandscapeOrientation ||
49 usageMode == "desktop"
50 property bool isPortrait: (root.orientation == Qt.PortraitOrientation ||
51 root.orientation == Qt.InvertedPortraitOrientation) &&
52 usageMode != "desktop"
54 property string usageMode
56 readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running
57 readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
58 readonly property bool required: coverPage.required || lockscreen.required
59 readonly property alias sessionToStart: loginList.currentSession
61 property rect inputMethodRect
63 signal selected(int index)
64 signal responded(string response)
66 signal emergencyCall() // unused
68 function notifyAuthenticationFailed() {
69 loginList.showError();
72 function forceShow() {
76 function tryToUnlock(toTheRight) {
77 var coverChanged = coverPage.shown;
79 coverPage.hideRight();
85 loginList.tryToUnlock();
98 function showFakePassword() {
99 loginList.showFakePassword();
102 function showErrorMessage(msg) {
103 coverPage.showErrorMessage(msg);
106 onLockedChanged: changeLockscreenState()
107 onMultiUserChanged: changeLockscreenState()
109 function changeLockscreenState() {
110 if (locked || multiUser) {
111 lockscreen.maybeShow();
117 Keys.onSpacePressed: coverPage.hide();
118 Keys.onReturnPressed: coverPage.hide();
119 Keys.onEnterPressed: coverPage.hide();
124 opacity: lockscreen.showProgress * 0.8
129 objectName: "lockscreen"
130 height: parent.height
135 background: root.background
136 backgroundSourceSize: root.backgroundSourceSize
137 panelHeight: root.panelHeight
138 hasCustomBackground: root.hasCustomBackground
139 backgroundShadeOpacity: 0.6
141 showInfographic: isLandscape && root.usageMode != "phone" && (root.usageMode != "tablet" || root.multiUser) && !delayedLockscreen.visible
142 infographicModel: root.infographicModel
147 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
148 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
150 infographicsTopMargin: parent.height * 0.125
151 infographicsBottomMargin: parent.height * 0.125
152 infographicsLeftMargin: loginList.x + loginList.width
154 onTease: root.tease()
156 onShowProgressChanged: {
157 if (showProgress === 0 && !root.locked) {
164 objectName: "loginList"
169 bottom: parent.bottom
172 boxVerticalOffset: (height - highlightedHeight -
173 inputMethodRect.height) / 2
174 Behavior on boxVerticalOffset { UbuntuNumberAnimation {} }
176 enabled: !coverPage.shown && visible
177 visible: !delayedLockscreen.visible
179 model: root.userModel
180 onResponded: root.responded(response)
181 onSelected: root.selected(index)
182 onSessionChooserButtonClicked: parent.state = "SessionsList"
183 onCurrentIndexChanged: setCurrentSession()
186 waiting: root.waiting
188 Keys.forwardTo: [sessionChooserLoader.item]
190 Component.onCompleted: setCurrentSession()
192 function setCurrentSession() {
193 currentSession = LightDMService.users.data(currentIndex, LightDMService.userRoles.SessionRole);
198 id: delayedLockscreen
199 objectName: "delayedLockscreen"
201 visible: delayMinutes > 0
202 alphaNumeric: loginList.alphanumeric
205 function maybeShow() {
206 if ((root.locked || root.multiUser) && !shown) {
212 id: sessionChooserLoader
214 height: loginList.height
215 width: loginList.width
219 leftMargin: Math.min(parent.width * 0.16, units.gu(20))
225 onLoaded: sessionChooserLoader.item.forceActiveFocus();
228 item.updateHighlight(loginList.currentSession);
232 target: sessionChooserLoader.item
233 onSessionSelected: loginList.currentSession = sessionKey
235 lockscreen.state = "LoginList"
236 loginList.tryToUnlock();
238 ignoreUnknownSignals: true
242 // Use an AbstractButton due to icon limitations with Button
245 objectName: "sessionChooserButton"
247 readonly property url icon: LightDMService.sessions.iconUrl(loginList.currentSession)
249 visible: LightDMService.sessions.count > 1 &&
250 !LightDMService.users.data(loginList.currentUserIndex, LightDMService.userRoles.LoggedInRole)
252 height: units.gu(3.5)
255 activeFocusOnTab: true
258 rightMargin: units.gu(2)
260 bottom: parent.bottom
261 bottomMargin: units.gu(1.5)
268 visible: parent.activeFocus
270 border.color: theme.palette.normal.focus
271 border.width: units.dp(1)
278 anchors.margins: units.dp(3)
279 keyColor: "#ffffff" // icon providers give us white icons
280 color: theme.palette.normal.raisedSecondaryText
281 source: sessionChooser.icon
284 Keys.onReturnPressed: {
285 parent.state = "SessionsList";
289 parent.state = "SessionsList";
292 // Refresh the icon path if looking at different places at runtime
293 // this is mainly for testing
295 target: LightDMService.sessions
296 onIconSearchDirectoriesChanged: {
297 badge.source = LightDMService.sessions.iconUrl(root.currentSession)
305 PropertyChanges { target: loginList; opacity: 0 }
306 PropertyChanges { target: sessionChooserLoader;
309 source: "SessionsList.qml"
315 PropertyChanges { target: loginList; opacity: 1 }
316 PropertyChanges { target: sessionChooserLoader;
328 UbuntuNumberAnimation {
334 Component.onCompleted: if (root.multiUser) showNow()
340 opacity: coverPage.showProgress * 0.8
345 objectName: "coverPage"
346 height: parent.height
348 background: root.background
349 hasCustomBackground: root.hasCustomBackground
350 backgroundShadeOpacity: 0.4
351 panelHeight: root.panelHeight
352 draggable: !root.waiting
353 onTease: root.tease()
355 backgroundSourceSize: root.backgroundSourceSize
356 infographicModel: root.infographicModel
358 showInfographic: !root.multiUser && root.usageMode != "desktop"
360 onShowProgressChanged: {
361 if (showProgress === 0) {
362 if (lockscreen.shown) {
363 loginList.tryToUnlock();
372 anchors.centerIn: parent
377 name: "landscape-with-infographics"
378 when: isLandscape && coverPage.showInfographic
381 anchors.top: undefined
382 anchors.horizontalCenter: undefined
383 anchors.verticalCenter: undefined
387 anchors.topMargin: undefined
388 anchors.centerIn: coverPage
389 anchors.horizontalCenterOffset: - coverPage.width / 2 + clock.width / 2 + units.gu(8)
393 infographicsLeftMargin: clock.width + units.gu(8)
398 when: isPortrait && coverPage.showInfographic
401 anchors.top: coverPage.top
402 anchors.horizontalCenter: coverPage.horizontalCenter
403 anchors.verticalCenter: undefined
407 anchors.topMargin: units.gu(2) + panelHeight
408 anchors.centerIn: undefined
409 anchors.horizontalCenterOffset: 0
413 infographicsLeftMargin: 0
417 name: "without-infographics"
418 when: !coverPage.showInfographic
421 anchors.top: undefined
422 anchors.horizontalCenter: coverPage.horizontalCenter
423 anchors.verticalCenter: coverPage.verticalCenter
428 anchors.centerIn: undefined
429 anchors.horizontalCenterOffset: 0
433 infographicsLeftMargin: 0
441 visible: usageMode == "phone" && lockscreen.shown
444 anchors.left: parent.left
445 anchors.right: parent.right
446 anchors.top: parent.bottom
447 anchors.topMargin: - height * (1 - coverPage.showProgress)
448 - ( inputMethodRect.height )
451 text: i18n.tr("Cancel")
452 anchors.left: parent.left
453 anchors.leftMargin: units.gu(2)
454 anchors.top: parent.top
455 anchors.bottom: parent.bottom
456 verticalAlignment: Text.AlignVCenter
457 font.weight: Font.Light
459 color: theme.palette.normal.raisedSecondaryText
463 anchors.leftMargin: -units.gu(2)
464 anchors.rightMargin: -units.gu(2)
465 onClicked: coverPage.show()
470 objectName: "emergencyCallLabel"
471 text: callManager.hasCalls ? i18n.tr("Return to Call") : i18n.tr("Emergency")
472 anchors.right: parent.right
473 anchors.rightMargin: units.gu(2)
474 anchors.top: parent.top
475 anchors.bottom: parent.bottom
476 verticalAlignment: Text.AlignVCenter
477 font.weight: Font.Light
479 color: theme.palette.normal.raisedSecondaryText
480 // TODO: uncomment once bug 1616538 is fixed
481 // visible: telepathyHelper.ready && telepathyHelper.emergencyCallsAvailable
486 anchors.leftMargin: -units.gu(2)
487 anchors.rightMargin: -units.gu(2)
488 onClicked: root.emergencyCall()
496 when: root.usageMode == "phone" || (root.usageMode == "tablet" && isPortrait)
499 anchors.horizontalCenter: lockscreen.horizontalCenter;
500 anchors.left: undefined;
504 anchors.leftMargin: 0;
509 when: root.usageMode == "tablet" && isLandscape
512 anchors.horizontalCenter: undefined;
513 anchors.left: lockscreen.left;
517 anchors.leftMargin: Math.min(lockscreen.width * 0.16, units.gu(8));
522 when: root.usageMode == "desktop"
525 anchors.horizontalCenter: undefined;
526 anchors.left: lockscreen.left;
530 anchors.leftMargin: Math.min(lockscreen.width * 0.16, units.gu(20));