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/>.
19import QtQuick.Window 2.2
20import QtGraphicalEffects 1.12
21import Lomiri.Components 1.3
22import Lomiri.Telephony 0.1 as Telephony
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();
94 if (coverPage.visible) {
102 function showFakePassword() {
103 loginList.showFakePassword();
106 function showErrorMessage(msg) {
107 coverPage.showErrorMessage(msg);
110 onLockedChanged: changeLockscreenState()
111 onMultiUserChanged: changeLockscreenState()
113 function changeLockscreenState() {
114 if (locked || multiUser) {
115 lockscreen.maybeShow();
121 Keys.onSpacePressed: coverPage.hide();
122 Keys.onReturnPressed: coverPage.hide();
123 Keys.onEnterPressed: coverPage.hide();
127 objectName: "lockscreen"
128 height: parent.height
133 background: root.background
134 backgroundSourceSize: root.backgroundSourceSize
135 panelHeight: root.panelHeight
136 hasCustomBackground: root.hasCustomBackground
137 backgroundShadeOpacity: 0.6
139 showInfographic: isLandscape && root.usageMode != "phone" && (root.usageMode != "tablet" || root.multiUser) && !delayedLockscreen.visible
140 infographicModel: root.infographicModel
145 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
146 hideAnimation: SequentialAnimation {
147 StandardAnimation { target: loginList; property: "opacity"; to: 0 }
148 StandardAnimation { property: "opacity"; to: 0.5 }
151 infographicsTopMargin: parent.height * 0.125
152 infographicsBottomMargin: parent.height * 0.125
153 infographicsLeftMargin: loginList.x + loginList.width
155 onTease: root.tease()
157 onShowProgressChanged: {
158 if (showProgress === 0 && !root.locked) {
165 objectName: "loginList"
170 bottom: parent.bottom
173 boxVerticalOffset: (height - highlightedHeight -
174 inputMethodRect.height) / 2
175 Behavior on boxVerticalOffset { LomiriNumberAnimation {} }
177 enabled: !coverPage.shown && visible
178 visible: !delayedLockscreen.visible
180 model: root.userModel
181 onResponded: root.responded(response)
182 onSelected: root.selected(index)
183 onSessionChooserButtonClicked: parent.state = "SessionsList"
184 onCurrentIndexChanged: setCurrentSession()
187 waiting: root.waiting
189 Keys.forwardTo: [sessionChooserLoader.item]
191 Component.onCompleted: setCurrentSession()
193 function setCurrentSession() {
194 currentSession = LightDMService.users.data(currentIndex, LightDMService.userRoles.SessionRole);
199 id: delayedLockscreen
200 objectName: "delayedLockscreen"
202 visible: delayMinutes > 0
203 alphaNumeric: loginList.alphanumeric
206 function maybeShow() {
207 if ((root.locked || root.multiUser) && !shown) {
213 id: sessionChooserLoader
215 height: loginList.height
216 width: loginList.width
220 leftMargin: Math.min(parent.width * 0.16, units.gu(20))
226 onLoaded: sessionChooserLoader.item.forceActiveFocus();
229 item.updateHighlight(loginList.currentSession);
233 target: sessionChooserLoader.item
234 onSessionSelected: loginList.currentSession = sessionKey
236 lockscreen.state = "LoginList"
237 loginList.tryToUnlock();
239 ignoreUnknownSignals: true
243 // Use an AbstractButton due to icon limitations with Button
246 objectName: "sessionChooserButton"
248 readonly property url icon: LightDMService.sessions.iconUrl(loginList.currentSession)
250 visible: LightDMService.sessions.count > 1 &&
251 !LightDMService.users.data(loginList.currentUserIndex, LightDMService.userRoles.LoggedInRole)
253 height: units.gu(3.5)
256 activeFocusOnTab: true
259 rightMargin: units.gu(2)
261 bottom: parent.bottom
262 bottomMargin: units.gu(1.5)
269 visible: parent.activeFocus
271 border.color: theme.palette.normal.focus
272 border.width: units.dp(1)
279 anchors.margins: units.dp(3)
280 keyColor: "#ffffff" // icon providers give us white icons
281 color: theme.palette.normal.raisedSecondaryText
282 source: sessionChooser.icon
285 Keys.onReturnPressed: {
286 parent.state = "SessionsList";
290 parent.state = "SessionsList";
293 // Refresh the icon path if looking at different places at runtime
294 // this is mainly for testing
296 target: LightDMService.sessions
297 onIconSearchDirectoriesChanged: {
298 badge.source = LightDMService.sessions.iconUrl(root.currentSession)
306 PropertyChanges { target: loginList; opacity: 0 }
307 PropertyChanges { target: sessionChooserLoader;
310 source: "SessionsList.qml"
316 PropertyChanges { target: loginList; opacity: 1 }
317 PropertyChanges { target: sessionChooserLoader;
329 LomiriNumberAnimation {
335 Component.onCompleted: if (root.multiUser) showNow()
341 opacity: coverPage.showProgress * 0.8
346 objectName: "coverPage"
347 height: parent.height
349 background: root.background
350 hasCustomBackground: root.hasCustomBackground
351 backgroundShadeOpacity: 0.4
352 panelHeight: root.panelHeight
353 draggable: !root.waiting
354 onTease: root.tease()
356 backgroundSourceSize: root.backgroundSourceSize
357 infographicModel: root.infographicModel
359 showInfographic: !root.multiUser && root.usageMode != "desktop"
361 onShowProgressChanged: {
362 if (showProgress === 0) {
363 if (lockscreen.shown) {
364 loginList.tryToUnlock();
373 anchors.centerIn: parent
378 name: "landscape-with-infographics"
379 when: isLandscape && coverPage.showInfographic
382 anchors.top: undefined
383 anchors.horizontalCenter: undefined
384 anchors.verticalCenter: undefined
388 anchors.topMargin: undefined
389 anchors.centerIn: coverPage
390 anchors.horizontalCenterOffset: - coverPage.width / 2 + clock.width / 2 + units.gu(8)
394 infographicsLeftMargin: clock.width + units.gu(8)
399 when: isPortrait && coverPage.showInfographic
402 anchors.top: coverPage.top
403 anchors.horizontalCenter: coverPage.horizontalCenter
404 anchors.verticalCenter: undefined
408 anchors.topMargin: units.gu(2) + panelHeight
409 anchors.centerIn: undefined
410 anchors.horizontalCenterOffset: 0
414 infographicsLeftMargin: 0
418 name: "without-infographics"
419 when: !coverPage.showInfographic
422 anchors.top: undefined
423 anchors.horizontalCenter: coverPage.horizontalCenter
424 anchors.verticalCenter: coverPage.verticalCenter
429 anchors.centerIn: undefined
430 anchors.horizontalCenterOffset: 0
434 infographicsLeftMargin: 0
442 visible: usageMode == "phone" && lockscreen.shown
445 anchors.left: parent.left
446 anchors.right: parent.right
447 anchors.top: parent.bottom
448 anchors.topMargin: - height * (1 - coverPage.showProgress)
449 - ( inputMethodRect.height )
452 text: i18n.tr("Cancel")
453 anchors.left: parent.left
454 anchors.leftMargin: units.gu(2)
455 anchors.top: parent.top
456 anchors.bottom: parent.bottom
457 verticalAlignment: Text.AlignVCenter
458 font.weight: Font.Light
460 color: theme.palette.normal.raisedSecondaryText
464 anchors.leftMargin: -units.gu(2)
465 anchors.rightMargin: -units.gu(2)
466 onClicked: coverPage.show()
471 objectName: "emergencyCallLabel"
472 text: callManager.hasCalls ? i18n.tr("Return to Call") : i18n.tr("Emergency")
473 anchors.right: parent.right
474 anchors.rightMargin: units.gu(2)
475 anchors.top: parent.top
476 anchors.bottom: parent.bottom
477 verticalAlignment: Text.AlignVCenter
478 font.weight: Font.Light
480 color: theme.palette.normal.raisedSecondaryText
481 // TODO: uncomment once bug 1616538 is fixed
482 // visible: telepathyHelper.ready && telepathyHelper.emergencyCallsAvailable
487 anchors.leftMargin: -units.gu(2)
488 anchors.rightMargin: -units.gu(2)
489 onClicked: root.emergencyCall()
497 when: root.usageMode == "phone" || (root.usageMode == "tablet" && isPortrait)
500 anchors.horizontalCenter: lockscreen.horizontalCenter;
501 anchors.left: undefined;
505 anchors.leftMargin: 0;
510 when: root.usageMode == "tablet" && isLandscape
513 anchors.horizontalCenter: undefined;
514 anchors.left: lockscreen.left;
518 anchors.leftMargin: Math.min(lockscreen.width * 0.16, units.gu(8));
523 when: root.usageMode == "desktop"
526 anchors.horizontalCenter: undefined;
527 anchors.left: lockscreen.left;
531 anchors.leftMargin: Math.min(lockscreen.width * 0.16, units.gu(20));