diff --git a/AddDeviceScreen.qml b/AddDeviceScreen.qml index f93eadf..9c5a96a 100644 --- a/AddDeviceScreen.qml +++ b/AddDeviceScreen.qml @@ -4,6 +4,10 @@ import QtQuick.Layouts import EVChargerApp NavigationPage { + function backPressed() { + return false + } + title: qsTr("Setup or add device") WhiteBox { diff --git a/AppInstance.qml b/AppInstance.qml index 1ca2db2..809fe38 100644 --- a/AppInstance.qml +++ b/AppInstance.qml @@ -3,41 +3,28 @@ import QtQuick.Controls.Material import QtQuick.Layouts import EVChargerApp -Loader { - id: loader - - sourceComponent: deviceList +AnimatedStackView { + id: stackView function backPressed() { - return loader.item.backPressed() - } - - DevicesModel { - id: devicesModel - - settings: theSettings - - Component.onCompleted: start() - } - - Component { - id: deviceList - - DeviceListScreen { - //onDeviceSelected: (url, password) => loader.setSource("DeviceScreen.qml", { url, password }) - onDeviceSelected: function(url, password) { - loader.sourceComponent = deviceScreen - loader.item.url = url; - loader.item.password = password; - } + if (stackView.currentItem.backPressed()) + return true + if (depth > 1) { + pop() + return true } + return false + } + + initialItem: DeviceListScreen { + onDeviceSelected: (url, password) => stackView.push(deviceScreenComponent, { url, password }) } Component { - id: deviceScreen + id: deviceScreenComponent DeviceScreen { - onClose: loader.sourceComponent = deviceList + onCloseRequested: stackView.pop() } } } diff --git a/AppSettingsPage.qml b/AppSettingsPage.qml index ad88001..69b97b6 100644 --- a/AppSettingsPage.qml +++ b/AppSettingsPage.qml @@ -7,6 +7,10 @@ import EVChargerApp NavigationPage { title: qsTr("App Settings") + function backPressed() { + return false + } + WhiteBox { Layout.fillWidth: true diff --git a/ChargerTabPage.qml b/ChargerTabPage.qml index bc18087..f841c0c 100644 --- a/ChargerTabPage.qml +++ b/ChargerTabPage.qml @@ -6,6 +6,8 @@ import EVChargerApp AnimatedStackView { id: stackView + signal closeRequested() + function backPressed() { if (depth > 1) { pop() @@ -46,7 +48,7 @@ AnimatedStackView { Layout.fillHeight: true text: qsTr("Devices") - onClicked: loader.close() + onClicked: closeRequested() } } } diff --git a/ConnectingScreen.qml b/ConnectingScreen.qml index 917cc89..47cb464 100644 --- a/ConnectingScreen.qml +++ b/ConnectingScreen.qml @@ -9,8 +9,7 @@ ColumnLayout { required property DeviceConnection deviceConnection function backPressed() { - close() - return true + return false } Connections { @@ -47,6 +46,6 @@ ColumnLayout { Button { text: qsTr("Cancel") - onClicked: close() + onClicked: stackView.pop() } } diff --git a/DeviceListScreen.qml b/DeviceListScreen.qml index 7ba25fa..01244b3 100644 --- a/DeviceListScreen.qml +++ b/DeviceListScreen.qml @@ -3,307 +3,299 @@ import QtQuick.Controls import QtQuick.Layouts import EVChargerApp -AnimatedStackView { - id: stackView +BaseNavigationPage { + id: page + title: qsTr("Device list") signal deviceSelected(url: string, password: string) function backPressed() { - if (depth > 1) { - pop() - return true - } return false } - initialItem: BaseNavigationPage { - id: page - title: qsTr("Device list") - - CloudUrlsModel { - id: cloudUrlsModel - } - - headerItems: [ - Button { - text: qsTr("App Settings") - icon.source: "material-icons/settings.svg" - display: AbstractButton.IconOnly - - onClicked: stackView.push(appSettingsPage) - - Component { - id: appSettingsPage - - AppSettingsPage { - } - } - } - ] - - ListView { - id: listView - model: devicesModel - - Layout.fillWidth: true - Layout.fillHeight: true - clip: true - spacing: 10 - contentX: -15 - - ScrollBar.vertical: ScrollBar { - interactive: false - } - - footer: Item { - height: 75 - } - - section.property: "saved" - section.criteria: ViewSection.FullString - section.delegate: Component { - id: sectionHeading - Text { - width: ListView.view.width - 30 - height: implicitHeight + 50 - bottomPadding: 10 - - verticalAlignment: Text.AlignBottom - wrapMode: Text.Wrap - - required property bool section - - text: section ? qsTr("My devices") : qsTr("Found devices") - font.bold: true - font.pixelSize: 20 - } - } - - delegate: SwipeDelegate { - id: delegate - checkable: true - width: ListView.view.width - 30 - - required property int index - - required property string name - required property string serial - required property string manufacturer - required property string deviceType - required property string friendlyName - required property string password - required property bool saved - required property string hostName - required property string ip - - Component.onCompleted: { - background.color = "white" - background.radius = 5 - } - - swipe.enabled: saved - - swipe.right: Label { - id: deleteLabel - text: qsTr("Delete") - color: "white" - verticalAlignment: Label.AlignVCenter - padding: 12 - height: parent.height - anchors.right: parent.right - - SwipeDelegate.onClicked: { - listView.model.removeRow(delegate.index) - swipe.close() - delegate.checked = false; - } - - background: Rectangle { - color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato" - } - } - - contentItem: ColumnLayout { - RowLayout { - Image { - height: parent.height - //Layout.fillHeight: true - source: { - if (delegate.deviceType == "go-eCharger_V5" || - delegate.deviceType == "go-eCharger_V4" || - delegate.deviceType == "wattpilot_V2") - { - return "icons/ChargerV4.svg" - } else if (delegate.deviceType == "go-eCharger" || - delegate.deviceType == "wattpilot") { - return "icons/ChargerV3.svg" - } else if (delegate.deviceType == "go-eCharger_Phoenix") { - return "icons/Charger.svg" - } else if (delegate.deviceType.includes("controller")) { - return "icons/Controller.svg" - } - } - } - - ColumnLayout { - Layout.fillWidth: true - Layout.fillHeight: true - - Text { - Layout.fillWidth: true - text: delegate.friendlyName - font.bold: true - elide: Text.ElideRight - } - - Text { - Layout.fillWidth: true - text: qsTr("Serial Number %0").arg(delegate.serial); - } - } - } - - GridLayout { - id: grid - visible: false - - columns: 2 - rowSpacing: 10 - columnSpacing: 10 - - Text { - text: qsTr("Manufacturer:") - Layout.leftMargin: 60 - } - - Text { - text: delegate.manufacturer - font.bold: true - elide: Text.ElideRight - Layout.fillWidth: true - } - - Text { - text: qsTr("Device Type:") - Layout.leftMargin: 60 - } - - Text { - text: delegate.deviceType - font.bold: true - elide: Text.ElideRight - Layout.fillWidth: true - } - - Text { - text: qsTr("Host Name:") - Layout.leftMargin: 60 - } - - Text { - text: delegate.hostName - font.bold: true - elide: Text.ElideRight - Layout.fillWidth: true - } - - Text { - text: qsTr("Ip:") - Layout.leftMargin: 60 - } - - Text { - text: delegate.ip - font.bold: true - elide: Text.ElideRight - Layout.fillWidth: true - } - - RowLayout { - Layout.columnSpan: 2 - - Button { - Layout.fillWidth: true - enabled: delegate.ip != "" - - text: qsTr("Local") - onClicked: deviceSelected("ws://" + delegate.ip + "/ws", delegate.password) - } - - Button { - Layout.fillWidth: true - property var cloudUrl: { - for (let i = 0; i < cloudUrlsModel.count; ++i) { - const entry = cloudUrlsModel.get(i); - if (delegate.manufacturer === entry.manufacturer && - delegate.deviceType.includes(entry.deviceType)) { - return entry.url; - } - } - return null; - } - - enabled: cloudUrl !== null - - text: qsTr("Cloud") - onClicked: deviceSelected(cloudUrl + delegate.serial, delegate.password) - } - - Button { - Layout.fillWidth: true - text: qsTr("Solala") - onClicked: deviceSelected("wss://solalaweb.com/" + delegate.serial, delegate.password) - visible: theSettings.showSolalaweb - } - } - } - } - - states: [ - State { - name: "expanded" - when: delegate.checked - - PropertyChanges { - // TODO: When Qt Design Studio supports generalized grouped properties, change to: - // grid.visible: true - // qmllint disable Quick.property-changes-parsed - target: grid - visible: true - } - } - ] - } - } + CloudUrlsModel { + id: cloudUrlsModel + } + headerItems: [ Button { - parent: page - anchors { - right: parent.right - rightMargin: 10 - bottom: parent.bottom - bottomMargin: 25 - } + text: qsTr("App Settings") + icon.source: "material-icons/settings.svg" + display: AbstractButton.IconOnly - text: qsTr("Add or setup device") - icon.source: "material-icons/add.svg" - - font.pointSize: 12 - font.bold: true - - highlighted: true - Material.accent: Material.Blue - - display: listView.contentY < 20 ? AbstractButton.TextBesideIcon : AbstractButton.IconOnly - - onClicked: stackView.push(addDeviceScreen) + onClicked: stackView.push(appSettingsPage) Component { - id: addDeviceScreen + id: appSettingsPage - AddDeviceScreen { + AppSettingsPage { } } } + ] + + ListView { + id: listView + model: devicesModel + + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + spacing: 10 + contentX: -15 + + ScrollBar.vertical: ScrollBar { + interactive: false + } + + footer: Item { + height: 75 + } + + section.property: "saved" + section.criteria: ViewSection.FullString + section.delegate: Component { + id: sectionHeading + Text { + width: ListView.view.width - 30 + height: implicitHeight + 50 + bottomPadding: 10 + + verticalAlignment: Text.AlignBottom + wrapMode: Text.Wrap + + required property bool section + + text: section ? qsTr("My devices") : qsTr("Found devices") + font.bold: true + font.pixelSize: 20 + } + } + + delegate: SwipeDelegate { + id: delegate + checkable: true + width: ListView.view.width - 30 + + required property int index + + required property string name + required property string serial + required property string manufacturer + required property string deviceType + required property string friendlyName + required property string password + required property bool saved + required property string hostName + required property string ip + + Component.onCompleted: { + background.color = "white" + background.radius = 5 + } + + swipe.enabled: saved + + swipe.right: Label { + id: deleteLabel + text: qsTr("Delete") + color: "white" + verticalAlignment: Label.AlignVCenter + padding: 12 + height: parent.height + anchors.right: parent.right + + SwipeDelegate.onClicked: { + listView.model.removeRow(delegate.index) + swipe.close() + delegate.checked = false; + } + + background: Rectangle { + color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato" + } + } + + contentItem: ColumnLayout { + RowLayout { + Image { + height: parent.height + //Layout.fillHeight: true + source: { + if (delegate.deviceType == "go-eCharger_V5" || + delegate.deviceType == "go-eCharger_V4" || + delegate.deviceType == "wattpilot_V2") + { + return "icons/ChargerV4.svg" + } else if (delegate.deviceType == "go-eCharger" || + delegate.deviceType == "wattpilot") { + return "icons/ChargerV3.svg" + } else if (delegate.deviceType == "go-eCharger_Phoenix") { + return "icons/Charger.svg" + } else if (delegate.deviceType.includes("controller")) { + return "icons/Controller.svg" + } + } + } + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + + Text { + Layout.fillWidth: true + text: delegate.friendlyName + font.bold: true + elide: Text.ElideRight + } + + Text { + Layout.fillWidth: true + text: qsTr("Serial Number %0").arg(delegate.serial); + } + } + } + + GridLayout { + id: grid + visible: false + + columns: 2 + rowSpacing: 10 + columnSpacing: 10 + + Text { + text: qsTr("Manufacturer:") + Layout.leftMargin: 60 + } + + Text { + text: delegate.manufacturer + font.bold: true + elide: Text.ElideRight + Layout.fillWidth: true + } + + Text { + text: qsTr("Device Type:") + Layout.leftMargin: 60 + } + + Text { + text: delegate.deviceType + font.bold: true + elide: Text.ElideRight + Layout.fillWidth: true + } + + Text { + text: qsTr("Host Name:") + Layout.leftMargin: 60 + } + + Text { + text: delegate.hostName + font.bold: true + elide: Text.ElideRight + Layout.fillWidth: true + } + + Text { + text: qsTr("Ip:") + Layout.leftMargin: 60 + } + + Text { + text: delegate.ip + font.bold: true + elide: Text.ElideRight + Layout.fillWidth: true + } + + RowLayout { + Layout.columnSpan: 2 + + Button { + Layout.fillWidth: true + enabled: delegate.ip != "" + + text: qsTr("Local") + onClicked: deviceSelected("ws://" + delegate.ip + "/ws", delegate.password) + } + + Button { + Layout.fillWidth: true + property var cloudUrl: { + for (let i = 0; i < cloudUrlsModel.count; ++i) { + const entry = cloudUrlsModel.get(i); + if (delegate.manufacturer === entry.manufacturer && + delegate.deviceType.includes(entry.deviceType)) { + return entry.url; + } + } + return null; + } + + enabled: cloudUrl !== null + + text: qsTr("Cloud") + onClicked: deviceSelected(cloudUrl + delegate.serial, delegate.password) + } + + Button { + Layout.fillWidth: true + text: qsTr("Solala") + onClicked: deviceSelected("wss://solalaweb.com/" + delegate.serial, delegate.password) + visible: theSettings.showSolalaweb + } + } + } + } + + states: [ + State { + name: "expanded" + when: delegate.checked + + PropertyChanges { + // TODO: When Qt Design Studio supports generalized grouped properties, change to: + // grid.visible: true + // qmllint disable Quick.property-changes-parsed + target: grid + visible: true + } + } + ] + } + } + + Button { + parent: page + anchors { + right: parent.right + rightMargin: 10 + bottom: parent.bottom + bottomMargin: 25 + } + + text: qsTr("Add or setup device") + icon.source: "material-icons/add.svg" + + font.pointSize: 12 + font.bold: true + + highlighted: true + Material.accent: Material.Blue + + display: listView.contentY < 20 ? AbstractButton.TextBesideIcon : AbstractButton.IconOnly + + onClicked: stackView.push(addDeviceScreen) + + Component { + id: addDeviceScreen + + AddDeviceScreen { + } + } } } diff --git a/DeviceScreen.qml b/DeviceScreen.qml index 8ed7d38..ccfa2ae 100644 --- a/DeviceScreen.qml +++ b/DeviceScreen.qml @@ -6,7 +6,7 @@ import EVChargerApp Loader { id: loader - signal close + signal closeRequested() property alias url: theDeviceConnection.url property alias password: theDeviceConnection.password @@ -61,6 +61,7 @@ Loader { MainScreen { deviceConnection: theDeviceConnection + onCloseRequested: loader.closeRequested() } } diff --git a/EVChargerApp.qml b/EVChargerApp.qml index e2a659d..18d342d 100644 --- a/EVChargerApp.qml +++ b/EVChargerApp.qml @@ -16,6 +16,14 @@ ApplicationWindow { id: theSettings } + DevicesModel { + id: devicesModel + + settings: theSettings + + Component.onCompleted: start() + } + FontLoader { id: materialIcons source: "ui-icons/MaterialIcons-Regular.ttf" @@ -33,6 +41,7 @@ ApplicationWindow { AppInstance { width: view.width + height: view.height } } } diff --git a/MainScreen.qml b/MainScreen.qml index 4f008cb..96e9f0a 100644 --- a/MainScreen.qml +++ b/MainScreen.qml @@ -6,6 +6,8 @@ import EVChargerApp ColumnLayout { id: mainScreen + signal closeRequested + required property DeviceConnection deviceConnection function backPressed() { @@ -16,8 +18,7 @@ ColumnLayout { stackLayout.currentIndex = Qt.binding(() => tabBar.currentIndex) return true } - loader.close() - return true + return false } ApiKeyValueHelper { @@ -187,6 +188,10 @@ ColumnLayout { delegate: Loader { source: model.source + onLoaded: { + if (item.closeRequested) + item.closeRequested.connect(closeRequested) + } } } } diff --git a/SelectLogicModeItem.qml b/SelectLogicModeItem.qml index 9be90d3..00deac5 100644 --- a/SelectLogicModeItem.qml +++ b/SelectLogicModeItem.qml @@ -60,10 +60,17 @@ WhiteBox { description: qsTr("Specific energy and time") onClicked: { if (selectedMode) - stackView.push("DailyTripPage.qml") + stackView.push(dailyTripPageComponent) else valueChanger.sendMessage({type: "setValue", key: "lmo", value: 5}) } + + Component { + id: dailyTripPageComponent + + DailyTripPage { + } + } } BusyIndicator { diff --git a/WiFiPage.qml b/WiFiPage.qml index bb39e84..ebe8fa6 100644 --- a/WiFiPage.qml +++ b/WiFiPage.qml @@ -54,8 +54,15 @@ NavigationPage { } text: qsTr("(%0) Wi-Fi Scan").arg(wifiScanResult.value == null ? 0 : wifiScanResult.value.length) - onClicked: stackView.push("WiFiScanPage.qml", {wifiScanResult} ) + onClicked: stackView.push(wiFiScanPageComponent, {wifiScanResult} ) enabled: wifiScanResult.value != null + + Component { + id: wiFiScanPageComponent + + WiFiScanPage { + } + } } Button { @@ -66,8 +73,15 @@ NavigationPage { } text: qsTr("(%0) Wi-Fi Errors").arg(wifiErrorLog.value == null ? 0 : wifiErrorLog.value.length) - onClicked: stackView.push("WiFiErrorsPage.qml", {wifiErrorLog} ) + onClicked: stackView.push(wiFiErrorsPageComponent, {wifiErrorLog} ) enabled: wifiErrorLog.value != null + + Component { + id: wiFiErrorsPageComponent + + WiFiErrorsPage { + } + } } Item {