875 lines
34 KiB
QML
875 lines
34 KiB
QML
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
* Copyright (C) 2013 - 2024, nymea GmbH
|
|
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
|
*
|
|
* This file is part of nymea-app-energy-overlay.
|
|
*
|
|
* nymea-app-energy-overlay is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* nymea-app-energy-overlay is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with nymea-app-energy-overlay. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Controls.Material
|
|
|
|
|
|
import QtQuick.Layouts
|
|
import QtQuick.Window
|
|
|
|
import Qt5Compat.GraphicalEffects
|
|
|
|
|
|
import Nymea
|
|
|
|
import "qrc:/ui/components/"
|
|
import "qrc:/styles/light"
|
|
import "../components"
|
|
|
|
ColumnLayout {
|
|
id: root
|
|
|
|
property Thing evCharger
|
|
property NymeaEnergy nymeaEnergy
|
|
property ChargingConfiguration chargingConfiguration
|
|
|
|
// Objects
|
|
readonly property Thing car: engine.thingManager.things.getThing(chargingConfiguration.assignedCarId)
|
|
readonly property ChargingState chargingState: nymeaEnergy.chargingStates.count > 0 && evCharger ?
|
|
nymeaEnergy.chargingStates.getChargingState(evCharger.id) : null
|
|
|
|
// States
|
|
readonly property State wallBoxPowerState: evCharger ? evCharger.stateByName("power") : null
|
|
readonly property State wallBoxChargingState: evCharger ? evCharger.stateByName("charging") : null
|
|
readonly property State wallBoxPluggedInState: evCharger ? evCharger.stateByName("pluggedIn") : null
|
|
readonly property State wallBoxDesiredPhaseCountState: evCharger ? evCharger.stateByName("desiredPhaseCount") : null
|
|
readonly property State wallBoxConnectedState: evCharger ? evCharger.stateByName("connected") : null
|
|
readonly property State wallBoxCurrentPowerState: evCharger ? evCharger.stateByName("currentPower") : null
|
|
readonly property State wallBoxSessionEnergyState: evCharger ? evCharger.stateByName("sessionEnergy") : null
|
|
readonly property State wallBoxMaxAmpereState: evCharger ? evCharger.stateByName("maxChargingCurrent") : null
|
|
|
|
readonly property bool hasEnergyMetering: wallBoxCurrentPowerState != null
|
|
readonly property bool hasSessionEnergy: wallBoxSessionEnergyState != null
|
|
|
|
readonly property bool wallBoxConnected: wallBoxConnectedState ? wallBoxConnectedState.value : false
|
|
readonly property bool wallBoxCharging: wallBoxConnectedState ? wallBoxChargingState.value : false
|
|
|
|
readonly property bool carConnected: wallBoxPluggedInState ? wallBoxPluggedInState.value : false
|
|
|
|
readonly property bool phaseSwitchingAvailable: wallBoxDesiredPhaseCountState != null &&
|
|
wallBoxDesiredPhaseCountState.possibleValues.length > 1
|
|
|
|
readonly property bool surplusChargingAvailable: car !== null &&
|
|
chargingConfiguration.chargingMode !== NymeaEnergyUtils.ChargingModeNormal &&
|
|
rootMeter !== null
|
|
|
|
readonly property bool spotmarketChargingAvailable: car !== null &&
|
|
chargingConfiguration.chargingMode !== NymeaEnergyUtils.ChargingModeNormal &&
|
|
nymeaEnergy.spotMarketEnabled &&
|
|
engine.jsonRpcClient.experiences["NymeaEnergy"] >= 0.6
|
|
|
|
property color chargerStateColor: {
|
|
// Plugged in but not charging, or preparing for charging
|
|
if (!wallBoxChargingState.value && wallBoxPluggedInState.value)
|
|
return Style.yellow
|
|
|
|
if (wallBoxChargingState.value) {
|
|
return Style.green
|
|
} else {
|
|
return Style.gray
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
id: chargingConfigurationConnections
|
|
|
|
target: root.chargingConfiguration
|
|
|
|
onChargingModeChanged: {
|
|
// Handle mode tabs
|
|
switch (chargingConfiguration.chargingMode) {
|
|
case NymeaEnergyUtils.ChargingModeEco:
|
|
modeTabBar.currentIndex = 0
|
|
useTargetTimeSwitch.checked = false
|
|
break;
|
|
case NymeaEnergyUtils.ChargingModeEcoWithTargetTime:
|
|
modeTabBar.currentIndex = 0
|
|
useTargetTimeSwitch.checked = true
|
|
break;
|
|
case NymeaEnergyUtils.ChargingModeNormal:
|
|
modeTabBar.currentIndex = 1
|
|
break;
|
|
}
|
|
}
|
|
|
|
onAssignedCarIdChanged: {
|
|
if (chargingConfiguration.assignedCarId === "{00000000-0000-0000-0000-000000000000}") {
|
|
carComboBox.currentIndex = -1
|
|
} else {
|
|
for (var i = 0; i < carsProxy.count; i++) {
|
|
if (carsProxy.get(i).id === chargingConfiguration.assignedCarId) {
|
|
carComboBox.currentIndex = i
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
QtObject {
|
|
id: internal
|
|
property int pendingCommand: -1
|
|
}
|
|
|
|
Connections {
|
|
id: nymeaEnergyConnections
|
|
target: nymeaEnergy
|
|
onSetChargingModeReply: (commandId) => {
|
|
if (commandId === internal.pendingCommand) {
|
|
internal.pendingCommand = -1
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: engine.thingManager
|
|
onExecuteActionReply: (commandId) => {
|
|
if (commandId === internal.pendingCommand) {
|
|
internal.pendingCommand = -1
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: wallBoxDesiredPhaseCountState
|
|
onValueChanged: {
|
|
phaseCountSwitch.checked = root.wallBoxDesiredPhaseCountState.value > 1
|
|
}
|
|
}
|
|
|
|
// Car selection
|
|
RowLayout {
|
|
spacing: Style.margins
|
|
Layout.fillWidth: true
|
|
|
|
Rectangle {
|
|
Layout.preferredWidth: Style.largeIconSize
|
|
Layout.preferredHeight: Style.largeIconSize
|
|
Layout.alignment: Qt.AlignVCenter
|
|
|
|
radius: Style.smallCornerRadius
|
|
color: "transparent"
|
|
border.width: 1
|
|
border.color: Style.foregroundColor
|
|
|
|
ColorIcon {
|
|
anchors.centerIn: parent
|
|
width: Style.iconSize
|
|
height: width
|
|
source: carConnected ? "/images/car-plugged-in.svg" : "/images/car-plugged-out.svg"
|
|
}
|
|
}
|
|
|
|
OverlayComboBoxCar {
|
|
id: carComboBox
|
|
|
|
Layout.fillWidth: true
|
|
model: carsProxy
|
|
textRole: "name"
|
|
iconSource: "/images/car.svg"
|
|
iconSourceActive: "/images/car-filled.svg"
|
|
displayText: currentIndex < 0 ? qsTr("Select a car") : currentText
|
|
currentIndex: carsProxy.indexOf(carsProxy.getThing(chargingConfiguration.assignedCarId))
|
|
actionRequired: currentIndex < 0
|
|
onCurrentIndexChanged: {
|
|
if (currentIndex < 0)
|
|
return
|
|
|
|
console.log("Car selection current index changed:", currentIndex)
|
|
nymeaEnergy.assignCar(evCharger.id, carsProxy.get(currentIndex).id)
|
|
}
|
|
}
|
|
}
|
|
|
|
TabBar {
|
|
id: modeTabBar
|
|
|
|
Layout.fillWidth: true
|
|
|
|
currentIndex: root.chargingConfiguration.chargingMode == NymeaEnergyUtils.ChargingModeNormal ? 1 : 0
|
|
|
|
background: Rectangle {
|
|
implicitHeight: 40
|
|
color: "transparent"
|
|
}
|
|
|
|
OverlayTabButton {
|
|
text: qsTr("Eco")
|
|
activeTab: modeTabBar.currentIndex == TabBar.index
|
|
iconSource: activeTab ? "/images/eco-charging-filled.svg" : "/images/eco-charging.svg"
|
|
onActiveTabChanged: {
|
|
if (activeTab && evCharger && root.chargingConfiguration && internal.pendingCommand < 0) {
|
|
internal.pendingCommand = nymeaEnergy.setChargingModeEco(evCharger.id)
|
|
}
|
|
}
|
|
}
|
|
|
|
OverlayTabButton {
|
|
text: qsTr("Quick")
|
|
activeTab: modeTabBar.currentIndex == TabBar.index
|
|
iconSource: activeTab ? "/images/quick-charging-filled.svg" : "/images/quick-charging.svg"
|
|
onActiveTabChanged: {
|
|
if (activeTab && evCharger && root.chargingConfiguration && internal.pendingCommand < 0) {
|
|
internal.pendingCommand = nymeaEnergy.setChargingModeManual(evCharger.id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
StackLayout {
|
|
id: modeStackLayout
|
|
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
Layout.minimumWidth: 250
|
|
Layout.minimumHeight: Layout.minimumWidth
|
|
|
|
currentIndex: modeTabBar.currentIndex
|
|
|
|
ColumnLayout {
|
|
id: ecoTab
|
|
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
RowLayout {
|
|
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Style.delegateHeight
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: qsTr("Use target time")
|
|
}
|
|
|
|
OverlaySwitch {
|
|
id: useTargetTimeSwitch
|
|
Layout.alignment: Qt.AlignVCenter
|
|
checked: root.chargingConfiguration.chargingMode === NymeaEnergyUtils.ChargingModeEcoWithTargetTime
|
|
onCheckedChanged: {
|
|
if (!root.chargingConfiguration)
|
|
return
|
|
|
|
if (internal.pendingCommand < 0) {
|
|
if (checked) {
|
|
var endDateTime = new Date()
|
|
endDateTime.setDate(endDateTime.getDate() + 1)
|
|
endDateTime.setHours(7, 0, 0, 0)
|
|
internal.pendingCommand = root.nymeaEnergy.setChargingModeEcoWithTargetDateTime(root.evCharger.id, endDateTime,
|
|
root.chargingConfiguration.targetPercentage);
|
|
} else {
|
|
internal.pendingCommand = root.nymeaEnergy.setChargingModeEco(root.evCharger.id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
//Rectangle { anchors.fill: parent; color: "green"; opacity: 0.2 }
|
|
|
|
readonly property real itemSize: Math.min(width, height)
|
|
|
|
EcoModeControl {
|
|
id: ecoModeControl
|
|
anchors.centerIn: parent
|
|
width: parent.itemSize
|
|
height: width
|
|
enabled: wallBoxConnected
|
|
}
|
|
|
|
Binding {
|
|
target: ecoModeControl
|
|
property: "nymeaEnergy"
|
|
value: root.nymeaEnergy
|
|
}
|
|
|
|
Binding {
|
|
target: ecoModeControl
|
|
property: "evCharger"
|
|
value: root.evCharger
|
|
}
|
|
|
|
Binding {
|
|
target: ecoModeControl
|
|
property: "car"
|
|
value: root.car
|
|
}
|
|
|
|
Binding {
|
|
target: ecoModeControl
|
|
property: "chargingConfiguration"
|
|
value: root.chargingConfiguration
|
|
}
|
|
|
|
Binding {
|
|
target: ecoModeControl
|
|
property: "chargingState"
|
|
value: root.chargingState
|
|
}
|
|
|
|
Binding {
|
|
target: ecoModeControl
|
|
property: "chargerStateColor"
|
|
value: root.chargerStateColor
|
|
}
|
|
|
|
Binding {
|
|
target: ecoModeControl
|
|
property: "busy"
|
|
value: root.wallBoxCharging
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
id: quickTab
|
|
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
RowLayout {
|
|
id: phaseSwitchingLayout
|
|
Layout.preferredHeight: Style.delegateHeight
|
|
Layout.fillWidth: true
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: qsTr("Charging phases")
|
|
opacity: phaseSwitchingAvailable ? 1 : 0
|
|
}
|
|
|
|
PhaseCountSwitch {
|
|
id: phaseCountSwitch
|
|
Layout.alignment: Qt.AlignVCenter
|
|
visible: phaseSwitchingAvailable
|
|
enabled: root.wallBoxConnected
|
|
checked: root.wallBoxDesiredPhaseCountState.value > 1
|
|
onCheckedChanged: {
|
|
if (internal.pendingCommand < 0) {
|
|
var desiredPhaseCount = root.wallBoxDesiredPhaseCountState && checked ? 3 : 1
|
|
console.log("Setting desired phase count to " + desiredPhaseCount)
|
|
internal.pendingCommand = root.evCharger.executeAction("desiredPhaseCount", [
|
|
{ paramName: "desiredPhaseCount", value: desiredPhaseCount }
|
|
])
|
|
}
|
|
}
|
|
|
|
//Component.onCompleted: checked = (root.wallBoxDesiredPhaseCountState && root.wallBoxDesiredPhaseCountState.value === 3)
|
|
}
|
|
}
|
|
|
|
Item {
|
|
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
readonly property real itemSize: Math.min(width, height)
|
|
|
|
QuickModeControl {
|
|
id: quickModeControl
|
|
anchors.centerIn: parent
|
|
width: parent.itemSize
|
|
height: width
|
|
enabled: wallBoxConnected
|
|
}
|
|
|
|
Binding {
|
|
target: quickModeControl
|
|
property: "nymeaEnergy"
|
|
value: root.nymeaEnergy
|
|
}
|
|
|
|
Binding {
|
|
target: quickModeControl
|
|
property: "evCharger"
|
|
value: root.evCharger
|
|
}
|
|
|
|
Binding {
|
|
target: quickModeControl
|
|
property: "car"
|
|
value: root.car
|
|
}
|
|
|
|
Binding {
|
|
target: quickModeControl
|
|
property: "chargingConfiguration"
|
|
value: root.chargingConfiguration
|
|
}
|
|
|
|
Binding {
|
|
target: ecoModeControl
|
|
property: "chargingState"
|
|
value: root.chargingState
|
|
}
|
|
|
|
Binding {
|
|
target: quickModeControl
|
|
property: "chargerStateColor"
|
|
value: root.chargerStateColor
|
|
}
|
|
|
|
Binding {
|
|
target: quickModeControl
|
|
property: "busy"
|
|
value: root.wallBoxCharging
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Style.smallDelegateHeight
|
|
|
|
RowLayout {
|
|
id: sessionInfoRow
|
|
|
|
anchors.fill: parent
|
|
visible: root.wallBoxConnected
|
|
|
|
SessionInfoItem {
|
|
Layout.fillWidth: true
|
|
//available: wallBoxPluggedInState && wallBoxPluggedInState.value && hasEnergyMetering
|
|
title: qsTr("Power")
|
|
value: {
|
|
if (hasEnergyMetering) {
|
|
if (Math.abs(wallBoxCurrentPowerState.value) < 1000) {
|
|
return Math.abs(Math.round(wallBoxCurrentPowerState.value * 100)) / 100
|
|
} else {
|
|
return Math.round(Math.abs(wallBoxCurrentPowerState.value / 10)) / 100
|
|
}
|
|
}
|
|
|
|
if (wallBoxMaxAmpereState) {
|
|
return wallBoxMaxAmpereState.value
|
|
}
|
|
|
|
return 0
|
|
}
|
|
unit: {
|
|
if (hasEnergyMetering) {
|
|
if (wallBoxCurrentPowerState && Math.abs(wallBoxCurrentPowerState.value) < 1000) {
|
|
return "W"
|
|
} else {
|
|
return "kW"
|
|
}
|
|
}
|
|
|
|
return "A"
|
|
}
|
|
}
|
|
|
|
SessionInfoItem {
|
|
Layout.fillWidth: true
|
|
visible: hasSessionEnergy
|
|
title: qsTr("Energy")
|
|
value: wallBoxSessionEnergyState ? Math.abs(Math.round(wallBoxSessionEnergyState.value * 100)) / 100 : "--"
|
|
unit: "kWh"
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ChargerPanelInfosProxy {
|
|
id: panelInfosProxy
|
|
|
|
chargerConnected: root.wallBoxConnected
|
|
carConnected: root.carConnected
|
|
chargingState: root.chargingState
|
|
chargingConfiguration: root.chargingConfiguration
|
|
|
|
Component.onCompleted: {
|
|
|
|
// We add the different message types here since they are easier to translate in QML. The entire
|
|
// logic which message will be shown where is in the proxy filter implementation
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeChargerNotConnectedWarning,
|
|
ChargerPanelInfo.IconTypeError,
|
|
qsTr("The charger is not available"),
|
|
qsTr("Please make sure the charger is connected and reachable."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeNoCarSelected,
|
|
ChargerPanelInfo.IconTypeError,
|
|
qsTr("No car assigned"),
|
|
qsTr("The eco mode is only available if there is a car assigned to the charger. Assign an existing car to the charger or add a new one."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeOverloadProtectionActive,
|
|
ChargerPanelInfo.IconTypeWarning,
|
|
qsTr("Overload protection is active"),
|
|
qsTr("One or more phases have reached the limit and charging has been throttled."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeIdleRecommended,
|
|
ChargerPanelInfo.IconTypeInfo,
|
|
qsTr("Car not plugged in"),
|
|
qsTr("The car is currently not plugged into the charger."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeTargetPercentageReached,
|
|
ChargerPanelInfo.IconTypeLock,
|
|
// Max length
|
|
qsTr("Charging target reached"),
|
|
qsTr("Continue charging has been disabled in the charger settings."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypePowerLockActive,
|
|
ChargerPanelInfo.IconTypeLock,
|
|
qsTr("Charging mode locked for %1"),
|
|
qsTr("To avoid frequent charging interruptions, the current charging mode is fixed.\n\nBackground: Some vehicles classify the energy source as unreliable in the event of frequent interruptions and block the charging process."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeTargetTimeOvershot,
|
|
ChargerPanelInfo.IconTypeWarning,
|
|
qsTr("Unreachable charging target"),
|
|
qsTr("It is not possible to reach the desired target in time. It would take additional %1 to reach the desired target."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeBatteryLevelConsiderationActive,
|
|
ChargerPanelInfo.IconTypeInfo,
|
|
qsTr("Prefer the storage up to %1%"),
|
|
qsTr("The home storage system will be charged up to %1%. As soon as this charge level has been reached, excess energy will be used to charge the vehicle."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeSurplusCharging,
|
|
ChargerPanelInfo.IconTypeSurplus,
|
|
qsTr("Charging from surplus"),
|
|
qsTr("The car is currently charging using surplus energy."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeSpotMarketCharging,
|
|
ChargerPanelInfo.IconTypeSpotMarket,
|
|
qsTr("Charging from spot market"),
|
|
qsTr("The car is currently charging from cheap spot market energy."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeTimeRequirementCharging,
|
|
ChargerPanelInfo.IconTypeTimeRequirement,
|
|
qsTr("Forced charging"),
|
|
qsTr("Charging as fast as possible in order to meet the charging target in time."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeSurplusRecommended,
|
|
ChargerPanelInfo.IconTypeSurplus,
|
|
qsTr("Surplus available"),
|
|
qsTr("Charging is recommended."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeSpotMarketRecommended,
|
|
ChargerPanelInfo.IconTypeSpotMarket,
|
|
qsTr("Cheap energy price"),
|
|
qsTr("Charging is recommended."));
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// < 1.0
|
|
ChargerPanelInfosProxy {
|
|
id: panelInfosProxyOld
|
|
|
|
chargerConnected: root.wallBoxConnected
|
|
carConnected: root.carConnected
|
|
chargingState: root.chargingState
|
|
chargingConfiguration: root.chargingConfiguration
|
|
|
|
Component.onCompleted: {
|
|
|
|
// We add the different message types here since they are easier to translate in QML. The entire
|
|
// logic which message will be shown where is in the proxy filter implementation
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeChargerNotConnectedWarning,
|
|
ChargerPanelInfo.IconTypeError,
|
|
qsTr("The charger is not available"),
|
|
qsTr("Please make sure the charger is connected and reachable."));
|
|
|
|
chargerPanelInfos.addPanelInfo(ChargerPanelInfo.TypeNoCarSelected,
|
|
ChargerPanelInfo.IconTypeError,
|
|
qsTr("No car assigned"),
|
|
qsTr("The eco mode is only available if there is a car assigned to the charger. Assign an existing car to the charger or add a new one."));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Item {
|
|
id: infoPanel
|
|
|
|
property ChargerPanelInfosProxy infoProxy: engine.jsonRpcClient.experiences["NymeaEnergy"] >= 1.0 ? panelInfosProxy : panelInfosProxyOld
|
|
|
|
property int indicatorHeight: 16
|
|
property int indicatorSize: 4
|
|
|
|
property bool panelVisible: infoProxy.count > 0
|
|
|
|
Layout.fillWidth: true
|
|
Layout.minimumHeight: Style.delegateHeight + indicatorHeight
|
|
|
|
Rectangle {
|
|
id: infoPanelBackground
|
|
|
|
visible: infoPanel.panelVisible
|
|
|
|
anchors.fill: parent
|
|
radius: Style.smallCornerRadius
|
|
color: Style.tooltipBackgroundColor
|
|
}
|
|
|
|
Column {
|
|
anchors.fill: parent
|
|
anchors.leftMargin: Style.margins
|
|
anchors.rightMargin: Style.margins
|
|
|
|
visible: infoPanel.panelVisible
|
|
|
|
Item {
|
|
width: parent.width
|
|
height: infoPanel.indicatorHeight
|
|
|
|
Row {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
spacing: infoPanel.indicatorSize
|
|
|
|
visible: infoPanel.infoProxy.count > 1
|
|
|
|
Repeater {
|
|
model: infoPanel.infoProxy
|
|
delegate: Rectangle {
|
|
height: infoPanel.indicatorSize
|
|
width: infoPanel.indicatorSize
|
|
radius: infoPanel.indicatorSize / 2
|
|
color: {
|
|
switch (model.iconType) {
|
|
case ChargerPanelInfo.IconTypeWarning:
|
|
return Style.orange
|
|
case ChargerPanelInfo.IconTypeError:
|
|
return Style.red
|
|
default:
|
|
return Style.iconColor
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ListView {
|
|
id: infoPanelListView
|
|
|
|
width: parent.width
|
|
height: Style.smallDelegateHeight
|
|
|
|
clip: true
|
|
interactive: false
|
|
|
|
model: infoPanel.infoProxy
|
|
|
|
delegate: RowLayout {
|
|
width: infoPanel.width
|
|
height: Style.smallDelegateHeight
|
|
|
|
ColorIcon {
|
|
id: infoPanelIcon
|
|
source: {
|
|
switch (model.iconType) {
|
|
case ChargerPanelInfo.IconTypeInfo:
|
|
return "qrc:/icons/info.svg"
|
|
case ChargerPanelInfo.IconTypeWarning:
|
|
return "qrc:/icons/dialog-warning-symbolic.svg"
|
|
case ChargerPanelInfo.IconTypeLock:
|
|
return "qrc:/icons/lock-closed.svg"
|
|
case ChargerPanelInfo.IconTypeError:
|
|
return "qrc:/icons/dialog-error-symbolic.svg"
|
|
case ChargerPanelInfo.IconTypeSurplus:
|
|
return "qrc:/images/pv-available.svg"
|
|
default:
|
|
return "qrc:/icons/info.svg"
|
|
}
|
|
}
|
|
|
|
color: {
|
|
switch (model.iconType) {
|
|
case ChargerPanelInfo.IconTypeWarning:
|
|
return Style.orange
|
|
case ChargerPanelInfo.IconTypeError:
|
|
return Style.red
|
|
default:
|
|
return Style.iconColor
|
|
}
|
|
}
|
|
|
|
Layout.alignment: Qt.AlignVCenter
|
|
Layout.preferredWidth: Style.iconSize
|
|
Layout.preferredHeight: Style.iconSize
|
|
}
|
|
|
|
Label {
|
|
id: infoLabel
|
|
text: model.text
|
|
wrapMode: Text.WordWrap
|
|
Layout.maximumWidth: infoPanelListView.width - infoPanelIcon.width - Style.margins
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
enabled: infoPanel.panelVisible
|
|
onClicked: {
|
|
var popup = infoPanelDialogComponent.createObject(
|
|
root,
|
|
{
|
|
panelY: infoPanel.y + infoPanel.height,
|
|
infoProxy: infoPanel.infoProxy,
|
|
x: infoPanel.x,
|
|
width: infoPanel.width,
|
|
})
|
|
popup.open()
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: infoPanelDialogComponent
|
|
|
|
Dialog {
|
|
id: infoPanelDialog
|
|
|
|
property ChargerPanelInfosProxy infoProxy: null
|
|
property real panelY: 0
|
|
|
|
height: Math.min(dialogListView.contentHeight + Style.smallDelegateHeight, panelY)
|
|
y: panelY - height
|
|
|
|
background: Rectangle {
|
|
id: infoPanelBackground
|
|
|
|
anchors.fill: parent
|
|
radius: Style.smallCornerRadius
|
|
color: Style.tooltipBackgroundColor
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
anchors.topMargin: -Style.margins
|
|
anchors.bottomMargin: -Style.margins
|
|
spacing: 0
|
|
|
|
ListView {
|
|
id: dialogListView
|
|
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
|
|
clip: true
|
|
interactive: true
|
|
spacing: 0
|
|
model: infoProxy
|
|
|
|
delegate: Item {
|
|
|
|
implicitWidth: itemColumn.width
|
|
implicitHeight: itemColumn.implicitHeight
|
|
|
|
ColumnLayout {
|
|
id: itemColumn
|
|
|
|
width: parent.width
|
|
spacing: 0
|
|
|
|
RowLayout {
|
|
id: textRowLayout
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: Style.delegateHeight
|
|
|
|
ColorIcon {
|
|
id: infoIcon
|
|
|
|
Layout.alignment: Qt.AlignVCenter
|
|
Layout.preferredWidth: Style.iconSize
|
|
Layout.preferredHeight: Style.iconSize
|
|
|
|
source: {
|
|
switch (model.iconType) {
|
|
case ChargerPanelInfo.IconTypeInfo:
|
|
return "qrc:/icons/info.svg"
|
|
case ChargerPanelInfo.IconTypeWarning:
|
|
return "qrc:/icons/dialog-warning-symbolic.svg"
|
|
case ChargerPanelInfo.IconTypeLock:
|
|
return "qrc:/icons/lock-closed.svg"
|
|
case ChargerPanelInfo.IconTypeError:
|
|
return "qrc:/icons/dialog-error-symbolic.svg"
|
|
case ChargerPanelInfo.IconTypeSurplus:
|
|
return "qrc:/images/pv-available.svg"
|
|
default:
|
|
return "qrc:/icons/info.svg"
|
|
}
|
|
}
|
|
|
|
color: {
|
|
switch (model.iconType) {
|
|
case ChargerPanelInfo.IconTypeWarning:
|
|
return Style.orange
|
|
case ChargerPanelInfo.IconTypeError:
|
|
return Style.red
|
|
default:
|
|
return Style.iconColor
|
|
}
|
|
}
|
|
}
|
|
|
|
Label {
|
|
id: infoLabel
|
|
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignVCenter
|
|
text: model.text
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
}
|
|
|
|
Label {
|
|
id: descriptionLabel
|
|
|
|
visible: model.description.length > 0
|
|
|
|
Layout.preferredWidth: dialogListView.width - Style.iconSize - textRowLayout.spacing - Style.margins
|
|
Layout.leftMargin: Style.iconSize + textRowLayout.spacing
|
|
Layout.rightMargin: Style.margins
|
|
|
|
text: model.description
|
|
verticalAlignment: Text.AlignVCenter
|
|
horizontalAlignment: Text.AlignLeft
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|