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