comparison main.qml @ 0:57ffb39f29d4

First commit of new carousel page to allow battery charging current to be adjusted.
author Daniel O'Connor <darius@dons.net.au>
date Mon, 13 Dec 2021 23:05:38 +1030
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:57ffb39f29d4
1 import QtQuick 1.1
2
3 import Qt.labs.components.native 1.0
4 import com.victron.velib 1.0
5 import "utils.js" as Utils
6
7 PageStackWindow {
8 id: rootWindow
9
10 gpsConnected: gpsFix.value === 1
11 onCompletedChanged: checkAlarm()
12 initialPage: PageMain {}
13
14 property VeQuickItem gpsService: VeQuickItem { uid: "dbus/com.victronenergy.system/GpsService" }
15 property VeQuickItem gpsFix: VeQuickItem { uid: Utils.path("dbus/", gpsService.value, "/Fix") }
16 property bool completed: false
17 property bool showAlert: NotificationCenter.alert
18 property bool alarm: NotificationCenter.alarm
19 property bool overviewsLoaded: defaultOverview.valid && generatorOverview.valid && mobileOverview.valid && tanksOverview.valid && startWithMenu.valid
20 property string bindPrefix: "com.victronenergy.settings"
21
22 property bool isNotificationPage: pageStack.currentPage && pageStack.currentPage.title === qsTr("Notifications")
23 property bool isOverviewPage: pageStack.currentPage && pageStack.currentPage.model === overviewModel;
24 property bool isOfflineFwUpdatePage: pageStack.currentPage && pageStack.currentPage.objectName === "offlineFwUpdatePage";
25
26
27 property string hubOverviewType: theSystem.systemType.valid ?
28 withoutGridMeter.value === 1 ? "Hub" : theSystem.systemType.value : ""
29
30 // Keep track of the current view (menu/overview) to show as default next time the
31 // CCGX is restarted
32 onIsOverviewPageChanged: startWithMenu.setValue(isOverviewPage ? 0 : 1)
33
34 // Add the correct OverviewHub page
35 onHubOverviewTypeChanged: {
36 switch(hubOverviewType){
37 case "Hub":
38 case "Hub-1":
39 case "Hub-2":
40 case "Hub-3":
41 replaceOverview("OverviewGridParallel.qml", "OverviewHub.qml");
42 break;
43 case "Hub-4":
44 case "ESS":
45 replaceOverview("OverviewHub.qml", "OverviewGridParallel.qml");
46 break;
47 default:
48 break;
49 }
50 // Workaround the QTBUG-17012 (only the first sentence in each case of Switch Statement can be executed)
51 // by adding a return statement
52 return
53 }
54
55 VBusItem {
56 id: generatorOverview
57 bind: "com.victronenergy.settings/Settings/Relay/Function"
58 onValueChanged: extraOverview("OverviewGeneratorRelay.qml", value === 1)
59 }
60
61 VBusItem {
62 id: fischerPandaGenOverview
63 bind: "com.victronenergy.settings/Settings/Services/FischerPandaAutoStartStop"
64 onValueChanged: extraOverview("OverviewGeneratorFp.qml", value === 1)
65 }
66
67 VBusItem {
68 id: mobileOverview
69 bind: "com.victronenergy.settings/Settings/Gui/MobileOverview"
70 onValueChanged:{
71 extraOverview("OverviewMobile.qml", value === 1)
72 }
73 }
74 VBusItem {
75 id: tanksOverview
76 bind: "com.victronenergy.settings/Settings/Gui/TanksOverview"
77 onValueChanged:{
78 extraOverview("OverviewTanks.qml", value === 1)
79 }
80 }
81
82 VBusItem {
83 id: startWithMenu
84 bind: "com.victronenergy.settings/Settings/Gui/StartWithMenuView"
85 }
86
87 VBusItem {
88 id: withoutGridMeter
89 bind: "com.victronenergy.settings/Settings/CGwacs/RunWithoutGridMeter"
90 }
91
92
93 VBusItem {
94 id: defaultOverview
95 bind: "com.victronenergy.settings/Settings/Gui/DefaultOverview"
96 }
97
98 // Note: finding a firmware image on the storage device is error 4 for vrm storage
99 // since it should not be used for logging. That fact is used here to determine if
100 // there is a firmware image.
101 Connections {
102 target: storageEvents
103 onVrmStorageError: {
104 if (error === 4) {
105 setTopPage(offlineFwUpdates)
106 }
107 }
108 }
109
110 onAlarmChanged: {
111 if (completed)
112 checkAlarm()
113 }
114
115 // always keep track of system information
116 HubData {
117 id: theSystem
118 }
119
120 // note: used for leaving the overviews as well
121 function backToMainMenu()
122 {
123 pageStack.pop(initialPage);
124 }
125
126 Toast {
127 id: toast
128 transform: Scale {
129 xScale: screen.scaleX
130 yScale: screen.scaleY
131 origin.x: toast.width / 2
132 origin.y: toast.height / 2
133 }
134 }
135
136 SignalToaster {}
137
138 ToolbarHandlerPages {
139 id: mainToolbarHandler
140 isDefault: true
141 }
142
143 ToolBarLayout {
144 id: mbTools
145 height: parent.height
146
147 Item {
148 anchors.verticalCenter: parent.verticalCenter
149 anchors.left: mbTools.left
150 height: mbTools.height
151 width: 200
152
153 MouseArea {
154 anchors.fill: parent
155 onClicked: {
156 if (pageStack.currentPage)
157 pageStack.currentPage.toolbarHandler.leftAction(true)
158 }
159 }
160
161 Row {
162 anchors.centerIn: parent
163
164 MbIcon {
165 anchors.verticalCenter: parent.verticalCenter
166 iconId: pageStack.currentPage ? pageStack.currentPage.leftIcon : ""
167 }
168
169 Text {
170 anchors.verticalCenter: parent.verticalCenter
171 text: pageStack.currentPage ? pageStack.currentPage.leftText : ""
172 color: "white"
173 font.bold: true
174 font.pixelSize: 16
175 }
176 }
177 }
178
179 MbIcon {
180 id: centerScrollIndicator
181
182 anchors {
183 horizontalCenter: parent.horizontalCenter
184 verticalCenter: mbTools.verticalCenter
185 }
186 iconId: pageStack.currentPage ? pageStack.currentPage.scrollIndicator : ""
187 }
188
189 Item {
190 anchors.verticalCenter: parent.verticalCenter
191 height: mbTools.height
192 anchors.right: mbTools.right
193 width: 200
194
195 MouseArea {
196 anchors.fill: parent
197 onClicked: {
198 if (pageStack.currentPage)
199 pageStack.currentPage.toolbarHandler.rightAction(true)
200 }
201 }
202
203 Row {
204 anchors.centerIn: parent
205
206 MbIcon {
207 iconId: pageStack.currentPage ? pageStack.currentPage.rightIcon : ""
208 anchors.verticalCenter: parent.verticalCenter
209 }
210
211 Text {
212 text: pageStack.currentPage ? pageStack.currentPage.rightText : ""
213 anchors.verticalCenter: parent.verticalCenter
214 color: "white"
215 font.bold: true
216 font.pixelSize: 16
217 }
218 }
219 }
220 }
221
222 Component.onCompleted: {
223 completed = true
224 }
225
226 ListModel {
227 id: overviewModel
228 ListElement {
229 pageSource: "OverviewHub.qml"
230 }
231 ListElement {
232 pageSource: "OverviewTiles.qml"
233 }
234 // ---> OverviewJD sentinel
235 ListElement {
236 pageSource: "OverviewJD.qml"
237 }
238 // <--- OverviewJD trailer
239 }
240
241 Component {
242 id: overviewComponent
243 PageFlow {
244 // Display default overview when loaded
245 defaultIndex: getDefaultOverviewIndex()
246 // Store the current overview page as default
247 onCurrentIndexChanged: if (active) defaultOverview.setValue(overviewModel.get(currentIndex).pageSource.replace(".qml", ""))
248 model: overviewModel
249 }
250 }
251
252 // When all the related settings items are valid, show the overview page if was the last oppened page
253 // before restarting
254 Timer {
255 interval: 2000
256 running: completed && overviewsLoaded && startWithMenu.valid
257 onTriggered: if (startWithMenu.value === 0) showOverview()
258 }
259
260 function getDefaultOverviewIndex()
261 {
262 if(!defaultOverview.valid)
263 return 0
264 for (var i = 0; i < overviewModel.count; i++){
265 if (overviewModel.get(i).pageSource.replace(".qml", "") === defaultOverview.value) {
266 return i
267 }
268 }
269 return 0
270 }
271
272 Component {
273 id: noticationsComponent
274 PageNotifications {}
275 }
276
277 Component {
278 id: offlineFwUpdates
279 PageSettingsFirmwareOffline { checkOnCompleted: true}
280
281 }
282
283 // Add or remove extra overviews. for example, generator overview
284 // shouldn't be shown if the start/stop functionality is not enabled.
285 // Index parameter is optional, usefull to keep an order.
286 function extraOverview(name, show, index)
287 {
288 var i = 0
289 if (show) {
290 if (index !== undefined) {
291 if (overviewModel.get(index).pageSource === name)
292 return
293 // First append the page
294 overviewModel.append({"pageSource": name})
295 // Then move all the pages behind index
296 overviewModel.move(index, overviewModel.count - 2, overviewModel.count - 2)
297 } else {
298 for (i = 0; i < overviewModel.count; i++)
299 if (overviewModel.get(i).pageSource === name)
300 // Don't append if already exists
301 return
302 overviewModel.append({"pageSource": name})
303 }
304 } else {
305 for (i = 0; i < overviewModel.count; i++)
306 if (overviewModel.get(i).pageSource === name)
307 overviewModel.remove(i)
308 }
309 }
310
311 function replaceOverview(oldPage, newPage)
312 {
313 for (var i = 0; i < overviewModel.count; i++)
314 if (overviewModel.get(i).pageSource === oldPage)
315 overviewModel.get(i).pageSource = newPage
316 }
317
318 // Central mover for the ball animation on the overviews
319 // Instead of using a timer per line, using a central one
320 // reduces the CPU usage a little bit and makes the animations
321 // smoother.
322 Timer {
323 id: mover
324 property double pos: _counter / _loops
325 property int _counter
326 property int _loops: 13
327
328 interval: 100
329 running: true
330 repeat: true
331 onTriggered: if (_counter >= (_loops - 1)) _counter = 0; else _counter++
332 }
333
334 // If an overview or notifications is active, the new page will replace it
335 // instead to be pushed. This way we prevent an unwanted stackpage depth
336 // increment everytime another page wants to be on top.
337 function setTopPage(page)
338 {
339 if (isNotificationPage || isOverviewPage || isOfflineFwUpdatePage)
340 rootWindow.pageStack.replace(page);
341 else
342 rootWindow.pageStack.push(page);
343 }
344
345 function spuriousKeyPress()
346 {
347 return !pageStack.currentPage || !pageStack.currentPage.active
348 }
349
350 function showOverview()
351 {
352 if (spuriousKeyPress() || isOverviewPage)
353 return
354 setTopPage(overviewComponent)
355 }
356
357 function showPageNotifications()
358 {
359 if (spuriousKeyPress() || isNotificationPage)
360 return
361 setTopPage(noticationsComponent)
362 }
363
364 function checkAlarm()
365 {
366 if (alarm)
367 showPageNotifications()
368 }
369 }