From fbc3b36ae4d6dcd96d7dbab9948f067d86019bec Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 7 Jan 2025 17:19:26 +1000 Subject: [PATCH 1/4] ListNavigation: fix reference to press area --- components/listitems/core/ListNavigation.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/listitems/core/ListNavigation.qml b/components/listitems/core/ListNavigation.qml index 344feaf28..e5496bd01 100644 --- a/components/listitems/core/ListNavigation.qml +++ b/components/listitems/core/ListNavigation.qml @@ -37,7 +37,7 @@ ListItem { anchors.verticalCenter: parent.verticalCenter source: "qrc:/images/icon_arrow_32.svg" rotation: 180 - color: root.containsPress ? Theme.color_listItem_down_forwardIcon : Theme.color_listItem_forwardIcon + color: pressArea.containsPress ? Theme.color_listItem_down_forwardIcon : Theme.color_listItem_forwardIcon visible: root.enabled } ] From a4c7892a205b523aea289dc9c9894c919a87199c Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 7 Jan 2025 17:36:41 +1000 Subject: [PATCH 2/4] ListItem: rework layout and add bottomContentSizeMode Allow the bottom content horizontal sizing to be customized: - 'stretch' size mode: bottom content spans the full width of the list item (as per existing behavior). - 'compact' size mode: the bottom content spans from the list item's left side, to the edge of the item's right-hand content. The 'compact' size is useful if the right-hand content is taller than the primaryLabel text; in this case, the caption text should wrap at the edge of the right-hand content, instead of dropping below it. Use a GridLayout with row and column spans to make this layout more easily configurable. Part of #1811 --- components/listitems/core/ListItem.qml | 81 ++++++++++++----------- pages/settings/PageSettingsWifi.qml | 6 +- pages/settings/debug/PageSettingsDemo.qml | 41 ++++++++++-- src/enums.h | 6 ++ themes/geometry/FiveInch.json | 1 - themes/geometry/SevenInch.json | 2 - 6 files changed, 86 insertions(+), 51 deletions(-) diff --git a/components/listitems/core/ListItem.qml b/components/listitems/core/ListItem.qml index a926e8d8a..cd1966898 100644 --- a/components/listitems/core/ListItem.qml +++ b/components/listitems/core/ListItem.qml @@ -4,6 +4,7 @@ */ import QtQuick +import QtQuick.Layouts import Victron.VenusOS Item { @@ -28,17 +29,16 @@ Item { readonly property bool defaultAllowed: userHasReadAccess readonly property alias primaryLabel: primaryLabel - readonly property int defaultImplicitHeight: { - const bottomHeight = bottomContent.height > 0 ? bottomContent.height + bottomContentMargin : 0 - const labelHeight = primaryLabel.implicitHeight + Theme.geometry_listItem_content_verticalMargin*2 - return Math.max(flat ? Theme.geometry_listItem_flat_height : Theme.geometry_listItem_height, - Math.max(content.height, labelHeight) + bottomHeight) - } + readonly property int defaultImplicitHeight: contentLayout.height + Theme.geometry_gradientList_spacing readonly property int availableWidth: width - leftPadding - rightPadding - content.spacing property int maximumContentWidth: availableWidth * 0.7 property bool allowed: defaultAllowed + property int bottomContentSizeMode: content.height > primaryLabel.height + ? VenusOS.ListItem_BottomContentSizeMode_Compact + : VenusOS.ListItem_BottomContentSizeMode_Stretch + visible: allowed implicitHeight: allowed ? defaultImplicitHeight : 0 implicitWidth: parent ? parent.width : 0 @@ -47,7 +47,7 @@ Item { id: backgroundRect z: -2 - height: root.height - root.spacing + height: root.height - Theme.geometry_gradientList_spacing color: Theme.color_listItem_background visible: !root.flat // TODO how to indicate read-only setting? @@ -69,39 +69,46 @@ Item { } } - Label { - id: primaryLabel - - anchors { - left: parent.left - leftMargin: root.leftPadding - verticalCenter: parent.verticalCenter - verticalCenterOffset: -root.spacing/2 - - (bottomContent.height > 0 - ? bottomContent.height/2 + bottomContentMargin/2 - : 0) - } - font.pixelSize: flat ? Theme.font_size_body1 : Theme.font_size_body2 - wrapMode: Text.Wrap - width: root.availableWidth - content.width - Theme.geometry_listItem_content_spacing - } + GridLayout { + id: contentLayout - Row { - id: content + width: parent.width + columns: 2 + columnSpacing: Theme.geometry_listItem_content_spacing + rowSpacing: 0 + + Label { + id: primaryLabel + + Layout.topMargin: Theme.geometry_listItem_content_verticalMargin + Layout.leftMargin: root.leftPadding + Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + font.pixelSize: flat ? Theme.font_size_body1 : Theme.font_size_body2 + wrapMode: Text.Wrap + width: root.availableWidth - content.width - Theme.geometry_listItem_content_spacing + } - anchors { - right: parent.right - rightMargin: root.rightPadding - verticalCenter: primaryLabel.verticalCenter + Row { + id: content + + // The topMargin ensures the content is vertically aligned with primaryLabel when the + // content height is small and there is no bottom content. + Layout.topMargin: height <= primaryLabel.height ? Theme.geometry_listItem_content_verticalMargin : 0 + Layout.rightMargin: root.rightPadding + Layout.maximumWidth: root.maximumContentWidth + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.rowSpan: root.bottomContentSizeMode === VenusOS.ListItem_BottomContentSizeMode_Stretch ? 1 : 2 + spacing: Theme.geometry_listItem_content_spacing } - spacing: Theme.geometry_listItem_content_spacing - width: Math.min(implicitWidth, root.maximumContentWidth) - } - Column { - id: bottomContent - y: Math.max(primaryLabel.y + primaryLabel.height + bottomContentMargin, - content.y + content.height + bottomContentMargin) - width: parent.width + Column { + id: bottomContent + + Layout.fillWidth: true + Layout.columnSpan: root.bottomContentSizeMode === VenusOS.ListItem_BottomContentSizeMode_Stretch ? 2 : 1 + Layout.topMargin: height > 0 ? Theme.geometry_listItem_content_verticalMargin / 2 : 0 + Layout.bottomMargin: Theme.geometry_listItem_content_verticalMargin + } } } diff --git a/pages/settings/PageSettingsWifi.qml b/pages/settings/PageSettingsWifi.qml index fa9b9dfe1..8610547d6 100644 --- a/pages/settings/PageSettingsWifi.qml +++ b/pages/settings/PageSettingsWifi.qml @@ -84,10 +84,8 @@ Page { primaryLabel.leftPadding: Theme.geometry_icon_size_medium + Theme.geometry_listItem_content_spacing CP.ColorImage { - anchors { - left: delagate.primaryLabel.left - verticalCenter: delagate.primaryLabel.verticalCenter - } + parent: delagate.primaryLabel + anchors.verticalCenter: parent.verticalCenter source: "qrc:/images/icon_checkmark_32.svg" color: Theme.color_green visible: model.favorite diff --git a/pages/settings/debug/PageSettingsDemo.qml b/pages/settings/debug/PageSettingsDemo.qml index ca87d5cc0..7bcb98edc 100644 --- a/pages/settings/debug/PageSettingsDemo.qml +++ b/pages/settings/debug/PageSettingsDemo.qml @@ -272,20 +272,47 @@ Page { id: customListItem text: "Custom bottom content item" + content.children: [ + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: 100 + height: 100 + radius: width / 2 + color: "orange" + + MouseArea { + anchors.fill: parent + onClicked: { + customListItem.bottomContentSizeMode = customListItem.bottomContentSizeMode === VenusOS.ListItem_BottomContentSizeMode_Compact + ? VenusOS.ListItem_BottomContentSizeMode_Stretch + : VenusOS.ListItem_BottomContentSizeMode_Compact + } + } + } + ] + bottomContentChildren: [ PrimaryListLabel { - width: Math.min(implicitWidth, customListItem.maximumContentWidth) - topPadding: 0 - bottomPadding: 0 - color: Theme.color_font_secondary - text: "Custom text label" + color: Theme.color_listItem_secondaryText + font.pixelSize: Theme.font_size_body1 + text: "This can wrap next to the content item, or be placed below the content item and stretch to the full item size. Click the orange button to toggle this size mode." } ] } ListText { - text: "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum occaecat cupidatat" - secondaryText: "Occaecat cupidatat" + text: "Primary text is long, maybe long enough to span multiple lines" + secondaryText: "Short secondary text" + } + + ListText { + text: "Short primary text" + secondaryText: "Secondary text is long, maybe long enough to span multiple lines" + } + + ListText { + text: "Both primary and secondary text are quite long" + secondaryText: "Both primary and secondary text are quite long" } ListItem { diff --git a/src/enums.h b/src/enums.h index 0b60788a0..084ceac6e 100644 --- a/src/enums.h +++ b/src/enums.h @@ -731,6 +731,12 @@ class Enums : public QObject }; Q_ENUM(StartPage_Type) + enum ListItem_BottomContentSizeMode { + ListItem_BottomContentSizeMode_Stretch, + ListItem_BottomContentSizeMode_Compact + }; + Q_ENUM(ListItem_BottomContentSizeMode) + Q_INVOKABLE QString battery_modeToText(Battery_Mode mode) const; Q_INVOKABLE Battery_Mode battery_modeFromPower(qreal power) const; diff --git a/themes/geometry/FiveInch.json b/themes/geometry/FiveInch.json index e0cbb103d..80e88a4bd 100644 --- a/themes/geometry/FiveInch.json +++ b/themes/geometry/FiveInch.json @@ -36,7 +36,6 @@ "geometry_radioButton_indicator_width": 24, "geometry_radioButton_indicator_dot_width": 16, "geometry_radioButton_border_width": 2, - "geometry_radioButton_bottomContentMargin": 6, "geometry_scrollBar_bar_width": 8, "geometry_scrollBar_bar_radius": 8, diff --git a/themes/geometry/SevenInch.json b/themes/geometry/SevenInch.json index 74191bb3e..a73496cab 100644 --- a/themes/geometry/SevenInch.json +++ b/themes/geometry/SevenInch.json @@ -36,8 +36,6 @@ "geometry_radioButton_indicator_width": 24, "geometry_radioButton_indicator_dot_width": 16, "geometry_radioButton_border_width": 2, - "geometry_radioButton_bottomContentMargin": 6, - "geometry_scrollBar_bar_width": 8, "geometry_scrollBar_bar_radius": 8, From 806f440b773c97e5a5e182cf3896d0e121acd3dc Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 7 Jan 2025 17:38:31 +1000 Subject: [PATCH 3/4] ListItem: remove spacing and bottomContentMargin properties These are no longer needed. The 'spacing' was confusing in any case because there are multiple types of spacing within ListItem. --- components/listitems/core/ListItem.qml | 2 -- components/listitems/core/ListNavigation.qml | 7 ++----- components/listitems/core/ListQuantityGroupNavigation.qml | 2 +- components/listitems/core/ListRadioButton.qml | 6 +----- components/listitems/core/ListRadioButtonGroup.qml | 1 - components/listitems/core/ListSwitch.qml | 8 ++------ components/widgets/DcLoadsWidget.qml | 5 +---- pages/settings/debug/PageDebug.qml | 5 +---- 8 files changed, 8 insertions(+), 28 deletions(-) diff --git a/components/listitems/core/ListItem.qml b/components/listitems/core/ListItem.qml index cd1966898..92f961abd 100644 --- a/components/listitems/core/ListItem.qml +++ b/components/listitems/core/ListItem.qml @@ -17,8 +17,6 @@ Item { property bool down property bool flat property alias backgroundRect: backgroundRect - property int spacing: Theme.geometry_gradientList_spacing - property int bottomContentMargin: Theme.geometry_listItem_content_spacing property int leftPadding: flat ? Theme.geometry_listItem_flat_content_horizontalMargin : Theme.geometry_listItem_content_horizontalMargin property int rightPadding: flat ? Theme.geometry_listItem_flat_content_horizontalMargin : Theme.geometry_listItem_content_horizontalMargin diff --git a/components/listitems/core/ListNavigation.qml b/components/listitems/core/ListNavigation.qml index e5496bd01..dfd4f419d 100644 --- a/components/listitems/core/ListNavigation.qml +++ b/components/listitems/core/ListNavigation.qml @@ -27,7 +27,7 @@ ListItem { font.pixelSize: Theme.font_size_body2 color: Theme.color_listItem_secondaryText wrapMode: Text.Wrap - width: Math.min(implicitWidth, root.maximumContentWidth - icon.width - parent.spacing) + width: Math.min(implicitWidth, root.maximumContentWidth - icon.width - root.content.spacing) horizontalAlignment: Text.AlignRight }, @@ -45,11 +45,8 @@ ListItem { ListPressArea { id: pressArea + anchors.fill: parent.backgroundRect radius: backgroundRect.radius - anchors { - fill: parent - bottomMargin: root.spacing - } onClicked: root.clicked() } } diff --git a/components/listitems/core/ListQuantityGroupNavigation.qml b/components/listitems/core/ListQuantityGroupNavigation.qml index f7186bf4b..09466d924 100644 --- a/components/listitems/core/ListQuantityGroupNavigation.qml +++ b/components/listitems/core/ListQuantityGroupNavigation.qml @@ -21,6 +21,6 @@ ListNavigation { right: parent.right rightMargin: Theme.geometry_listItem_content_horizontalMargin + Theme.geometry_icon_size_medium } - height: parent.height - parent.spacing + height: parent.height - Theme.geometry_gradientList_spacing } } diff --git a/components/listitems/core/ListRadioButton.qml b/components/listitems/core/ListRadioButton.qml index 95391126f..f342860b2 100644 --- a/components/listitems/core/ListRadioButton.qml +++ b/components/listitems/core/ListRadioButton.qml @@ -30,12 +30,8 @@ ListItem { ListPressArea { id: pressArea + anchors.fill: parent.backgroundRect radius: backgroundRect.radius - anchors { - fill: parent - bottomMargin: root.spacing - } - onClicked: root.clicked() } } diff --git a/components/listitems/core/ListRadioButtonGroup.qml b/components/listitems/core/ListRadioButtonGroup.qml index b7aaf6b1f..81b9d66d4 100644 --- a/components/listitems/core/ListRadioButtonGroup.qml +++ b/components/listitems/core/ListRadioButtonGroup.qml @@ -116,7 +116,6 @@ ListNavigation { C.ButtonGroup.group: radioButtonGroup bottomContent.z: model.index === optionsListView.currentIndex ? 1 : -1 - bottomContentMargin: Theme.geometry_radioButton_bottomContentMargin bottomContentChildren: Loader { id: bottomContentLoader diff --git a/components/listitems/core/ListSwitch.qml b/components/listitems/core/ListSwitch.qml index a646e6dbf..873c61b74 100644 --- a/components/listitems/core/ListSwitch.qml +++ b/components/listitems/core/ListSwitch.qml @@ -43,7 +43,7 @@ ListItem { anchors.verticalCenter: switchItem.verticalCenter color: Theme.color_font_secondary font.pixelSize: Theme.font_size_body2 - width: Math.min(implicitWidth, root.maximumContentWidth - switchItem.width - parent.spacing) + width: Math.min(implicitWidth, root.maximumContentWidth - switchItem.width - root.content.spacing) wrapMode: Text.Wrap }, Switch { @@ -58,12 +58,8 @@ ListItem { ListPressArea { id: pressArea + anchors.fill: parent.backgroundRect radius: backgroundRect.radius - anchors { - fill: parent - bottomMargin: root.spacing - } - onClicked: root._setChecked(!switchItem.checked) } diff --git a/components/widgets/DcLoadsWidget.qml b/components/widgets/DcLoadsWidget.qml index 805d7413f..c2627a0dc 100644 --- a/components/widgets/DcLoadsWidget.qml +++ b/components/widgets/DcLoadsWidget.qml @@ -63,11 +63,8 @@ OverviewWidget { ListPressArea { id: delegatePressArea + anchors.fill: parent.backgroundRect radius: backgroundRect.radius - anchors { - fill: parent - bottomMargin: deviceDelegate.spacing - } onClicked: root._showSettingsPage(device) } diff --git a/pages/settings/debug/PageDebug.qml b/pages/settings/debug/PageDebug.qml index 437344fbc..1df3d0a96 100644 --- a/pages/settings/debug/PageDebug.qml +++ b/pages/settings/debug/PageDebug.qml @@ -24,11 +24,8 @@ Page { } ListPressArea { + anchors.fill: switchItem.backgroundRect radius: switchItem.backgroundRect.radius - anchors { - fill: parent - bottomMargin: switchItem.spacing - } onClicked: switchItem.clicked() } } From 8edf37c90ae2048387663168352969964495da02 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 7 Jan 2025 17:43:55 +1000 Subject: [PATCH 4/4] Add ListLink component to show either QR code or link button Part of #1811 --- CMakeLists.txt | 2 + components/listitems/ListLink.qml | 79 +++++++++++++++++++++++ images/icon_open_link_32.svg | 4 ++ pages/settings/debug/PageSettingsDemo.qml | 5 ++ src/enums.h | 6 ++ themes/geometry/FiveInch.json | 2 + themes/geometry/SevenInch.json | 2 + 7 files changed, 100 insertions(+) create mode 100644 components/listitems/ListLink.qml create mode 100644 images/icon_open_link_32.svg diff --git a/CMakeLists.txt b/CMakeLists.txt index 508395a07..ea028136e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -322,6 +322,7 @@ set (VENUS_QML_MODULE_SOURCES components/listitems/ListFirmwareCheckButton.qml components/listitems/ListFirmwareVersion.qml components/listitems/ListGeneratorError.qml + components/listitems/ListLink.qml components/listitems/ListMqttAccessSwitch.qml components/listitems/ListMountStateButton.qml components/listitems/ListPvInverterPositionRadioButtonGroup.qml @@ -1049,6 +1050,7 @@ qt_add_resources(${PROJECT_NAME} "${PROJECT_NAME}_large_resources" images/icon_hydraulic_oil_24.svg images/icon_lng_24.svg images/icon_lpg_24.svg + images/icon_open_link_32.svg images/icon_to_grid.svg images/fueltank.svg images/gauge_intro_5_matte_black.gif diff --git a/components/listitems/ListLink.qml b/components/listitems/ListLink.qml new file mode 100644 index 000000000..9a0bf4618 --- /dev/null +++ b/components/listitems/ListLink.qml @@ -0,0 +1,79 @@ +/* +** Copyright (C) 2024 Victron Energy B.V. +** See LICENSE.txt for license information. +*/ + +import QtQuick +import QtQuick.Controls.impl as CP +import Victron.VenusOS + +ListItem { + id: root + + property string url + property string caption: root.mode === VenusOS.ListLink_Mode_LinkButton ? "" + //: %1 = url text + //% "Scan the QR code with your portable device.
Or insert the link: %1" + : qsTrId("listlink_scan_qr_code").arg(formattedUrl) + readonly property string formattedUrl: "%2".arg(Theme.color_font_primary).arg(url) + + readonly property int mode: Qt.platform.os == "wasm" ? VenusOS.ListLink_Mode_LinkButton : VenusOS.ListLink_Mode_QRCode + + down: pressArea.containsPress + + content.children: [ + SecondaryListLabel { + visible: root.mode === VenusOS.ListLink_Mode_LinkButton + anchors.verticalCenter: parent.verticalCenter + width: Math.min(implicitWidth, root.maximumContentWidth - icon.width - root.content.spacing) + //% "Open link" + text: qsTrId("listlink_open_link") + }, + + CP.ColorImage { + id: icon + + visible: root.mode === VenusOS.ListLink_Mode_LinkButton + anchors.verticalCenter: parent.verticalCenter + source: "qrc:/images/icon_open_link_32.svg" + rotation: 180 + color: pressArea.containsPress ? Theme.color_listItem_down_forwardIcon : Theme.color_listItem_forwardIcon + }, + + Item { + visible: root.mode === VenusOS.ListLink_Mode_QRCode + width: Theme.geometry_listLink_qrCodeSize + height: Theme.geometry_listLink_qrCodeSize + (2 * Theme.geometry_listItem_content_verticalMargin) + + Image { + anchors.centerIn: parent + source: root.mode === VenusOS.ListLink_Mode_QRCode + ? `image://QZXing/encode/${root.url}?correctionLevel=M&format=qrcode` + : "" + sourceSize.width: Theme.geometry_listLink_qrCodeSize + sourceSize.height: Theme.geometry_listLink_qrCodeSize + } + } + ] + + bottomContentChildren: [ + PrimaryListLabel { + font.pixelSize: Theme.font_size_body1 + horizontalAlignment: Text.AlignLeft + color: Theme.color_listItem_secondaryText + text: root.caption + visible: root.mode === VenusOS.ListLink_Mode_QRCode + } + ] + + ListPressArea { + id: pressArea + + enabled: root.mode === VenusOS.ListLink_Mode_LinkButton + radius: backgroundRect.radius + anchors.fill: root.backgroundRect + onClicked: { + BackendConnection.openUrl(root.url) + } + } +} diff --git a/images/icon_open_link_32.svg b/images/icon_open_link_32.svg new file mode 100644 index 000000000..f79d3df48 --- /dev/null +++ b/images/icon_open_link_32.svg @@ -0,0 +1,4 @@ + + + + diff --git a/pages/settings/debug/PageSettingsDemo.qml b/pages/settings/debug/PageSettingsDemo.qml index 7bcb98edc..1f6446800 100644 --- a/pages/settings/debug/PageSettingsDemo.qml +++ b/pages/settings/debug/PageSettingsDemo.qml @@ -327,6 +327,11 @@ Page { } ] } + + ListLink { + text: "Victron Energy" + url: "https://www.victronenergy.com" + } } } diff --git a/src/enums.h b/src/enums.h index 084ceac6e..b4a8d4a68 100644 --- a/src/enums.h +++ b/src/enums.h @@ -737,6 +737,12 @@ class Enums : public QObject }; Q_ENUM(ListItem_BottomContentSizeMode) + enum ListLink_Mode { + ListLink_Mode_LinkButton, + ListLink_Mode_QRCode + }; + Q_ENUM(ListLink_Mode) + Q_INVOKABLE QString battery_modeToText(Battery_Mode mode) const; Q_INVOKABLE Battery_Mode battery_modeFromPower(qreal power) const; diff --git a/themes/geometry/FiveInch.json b/themes/geometry/FiveInch.json index 80e88a4bd..91e2b088f 100644 --- a/themes/geometry/FiveInch.json +++ b/themes/geometry/FiveInch.json @@ -58,6 +58,8 @@ "geometry_listItem_textField_minimumWidth": 200, "geometry_listItem_textField_maximumWidth": 376, + "geometry_listLink_qrCodeSize": 96, + "geometry_slider_groove_height": 8, "geometry_slider_groove_radius": 8, diff --git a/themes/geometry/SevenInch.json b/themes/geometry/SevenInch.json index a73496cab..9632d829b 100644 --- a/themes/geometry/SevenInch.json +++ b/themes/geometry/SevenInch.json @@ -58,6 +58,8 @@ "geometry_listItem_textField_minimumWidth": 236, "geometry_listItem_textField_maximumWidth": 472, + "geometry_listLink_qrCodeSize": 96, + "geometry_slider_groove_height": 8, "geometry_slider_groove_radius": 8,