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