Lomiri
CoverPage.qml
1/*
2 * Copyright (C) 2013-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 QtGraphicalEffects 1.12
20import Lomiri.Components 1.3
21import Lomiri.Gestures 0.1
22import "../Components"
23
24Showable {
25 id: root
26
27 property real dragHandleLeftMargin
28 property real launcherOffset
29 property alias background: greeterBackground.source
30 property alias backgroundSourceSize: greeterBackground.sourceSize
31 property alias hasCustomBackground: backgroundShade.visible
32 property real panelHeight
33 property var infographicModel
34 property bool draggable: true
35
36 property alias infographics: infographics
37
38 property alias blurAreaHeight: loginBoxEffects.height
39 property alias blurAreaWidth: loginBoxEffects.width
40 property alias blurAreaX: loginBoxEffects.x
41 property alias blurAreaY: loginBoxEffects.y
42
43 readonly property real showProgress: MathUtils.clamp((width - Math.abs(x + launcherOffset)) / width, 0, 1)
44
45 signal tease()
46 signal clicked()
47
48 function hideRight() {
49 d.forceRightOnNextHideAnimation = true;
50 hide();
51 }
52
53 function showErrorMessage(msg) {
54 d.errorMessage = msg;
55 showLabelAnimation.start();
56 errorMessageAnimation.start();
57 }
58
59 QtObject {
60 id: d
61 property bool forceRightOnNextHideAnimation: false
62 property string errorMessage
63 }
64
65 prepareToHide: function () {
66 hideTranslation.from = root.x + translation.x
67 hideTranslation.to = root.x > 0 || d.forceRightOnNextHideAnimation ? root.width : -root.width;
68 d.forceRightOnNextHideAnimation = false;
69 }
70
71 // We don't directly bind "x" because that's owned by the DragHandle. So
72 // instead, we can get a little extra horizontal push by using transforms.
73 transform: Translate { id: translation; x: root.draggable ? launcherOffset : 0 }
74
75 // Eat events elsewhere on the coverpage, except mouse clicks which we pass
76 // up (they are used in the NarrowView to hide the cover page)
77 MouseArea {
78 anchors.fill: parent
79 onClicked: root.clicked()
80
81 MultiPointTouchArea {
82 anchors.fill: parent
83 mouseEnabled: false
84 }
85 }
86
87 Rectangle {
88 // In case background fails to load
89 id: backgroundBackup
90 anchors.fill: parent
91 color: "black"
92 }
93
94 Wallpaper {
95 id: greeterBackground
96 objectName: "greeterBackground"
97 anchors {
98 fill: parent
99 }
100 }
101
102 Rectangle {
103 id: loginBoxEffects
104 color: "transparent"
105 }
106
107 ShaderEffectSource {
108 id: effectSource
109
110 sourceItem: greeterBackground
111 anchors.centerIn: loginBoxEffects
112 width: loginBoxEffects.width
113 height: loginBoxEffects.height
114 sourceRect: Qt.rect(x,y, width, height)
115 }
116
117 FastBlur {
118 visible: !draggable
119 anchors.fill: effectSource
120 source: effectSource
121 radius: 64
122 transparentBorder: true
123 }
124
125 // Darkens wallpaper so that we can read text on it and see infographic
126 Rectangle {
127 id: backgroundShade
128 objectName: "backgroundShade"
129 anchors.fill: parent
130 color: "black"
131 opacity: 0.4
132 visible: false
133 }
134
135 Infographics {
136 id: infographics
137 objectName: "infographics"
138 model: root.infographicModel
139 clip: true // clip large data bubbles
140
141 anchors {
142 topMargin: root.panelHeight
143 top: parent.top
144 bottom: parent.bottom
145 left: parent.left
146 right: parent.right
147 }
148 }
149
150 Label {
151 id: swipeHint
152 objectName: "swipeHint"
153 property real baseOpacity: 0.5
154 opacity: 0.0
155 anchors.horizontalCenter: parent.horizontalCenter
156 anchors.bottom: parent.bottom
157 anchors.bottomMargin: units.gu(5)
158 text: "《 " + (d.errorMessage ? d.errorMessage : i18n.tr("Unlock")) + " 》"
159 color: "white"
160 font.weight: Font.Light
161
162 readonly property var opacityAnimation: showLabelAnimation // for testing
163
164 SequentialAnimation on opacity {
165 id: showLabelAnimation
166 running: false
167 loops: 2
168
169 StandardAnimation {
170 from: 0.0
171 to: swipeHint.baseOpacity
172 duration: LomiriAnimation.SleepyDuration
173 }
174 PauseAnimation { duration: LomiriAnimation.BriskDuration }
175 StandardAnimation {
176 from: swipeHint.baseOpacity
177 to: 0.0
178 duration: LomiriAnimation.SleepyDuration
179 }
180
181 onRunningChanged: {
182 if (!running)
183 d.errorMessage = "";
184 }
185 }
186 }
187
188 WrongPasswordAnimation {
189 id: errorMessageAnimation
190 objectName: "errorMessageAnimation"
191 target: swipeHint
192 }
193
194 DragHandle {
195 id: dragHandle
196 objectName: "coverPageDragHandle"
197 anchors.fill: parent
198 anchors.leftMargin: root.dragHandleLeftMargin
199 enabled: root.draggable
200 direction: Direction.Horizontal
201
202 onPressedChanged: {
203 if (pressed) {
204 root.tease();
205 showLabelAnimation.start();
206 }
207 }
208 }
209
210 // right side shadow
211 Image {
212 anchors.left: parent.right
213 anchors.top: parent.top
214 anchors.bottom: parent.bottom
215 fillMode: Image.Tile
216 source: "../graphics/dropshadow_right.png"
217 }
218
219 // left side shadow
220 Image {
221 anchors.right: parent.left
222 anchors.top: parent.top
223 anchors.bottom: parent.bottom
224 fillMode: Image.Tile
225 source: "../graphics/dropshadow_left.png"
226 }
227
228 Binding {
229 id: positionLock
230
231 property bool enabled: false
232 onEnabledChanged: {
233 if (enabled === __enabled) {
234 return;
235 }
236
237 if (enabled) {
238 if (root.x > 0) {
239 value = Qt.binding(function() { return root.width; })
240 } else {
241 value = Qt.binding(function() { return -root.width; })
242 }
243 }
244
245 __enabled = enabled;
246 }
247
248 property bool __enabled: false
249
250 target: root
251 when: __enabled
252 property: "x"
253 }
254
255 hideAnimation: SequentialAnimation {
256 id: hideAnimation
257 objectName: "hideAnimation"
258 property var target // unused, here to silence Showable warning
259 StandardAnimation {
260 id: hideTranslation
261 property: "x"
262 target: root
263 }
264 PropertyAction { target: root; property: "visible"; value: false }
265 PropertyAction { target: positionLock; property: "enabled"; value: true }
266 }
267
268 showAnimation: SequentialAnimation {
269 id: showAnimation
270 objectName: "showAnimation"
271 property var target // unused, here to silence Showable warning
272 PropertyAction { target: root; property: "visible"; value: true }
273 PropertyAction { target: positionLock; property: "enabled"; value: false }
274 StandardAnimation {
275 property: "x"
276 target: root
277 to: 0
278 duration: LomiriAnimation.FastDuration
279 }
280 }
281}