From 5d305a5221098757c2a7209c8435ba2e081ac92b Mon Sep 17 00:00:00 2001 From: Patryk Osmaczko Date: Mon, 28 Nov 2022 12:32:29 +0100 Subject: [PATCH] refactor(StatusAppNavBar): simplify navbar - removed imperative filtering - removed imperative size calculation - removed all ugly hacks fixes: #7167 fixes: #8463 --- .../global_shared/scripts/global_names.py | 5 +- ui/StatusQ/sandbox/DemoApp.qml | 118 ++++---- ui/StatusQ/sandbox/main.qml | 8 +- .../src/StatusQ/Layout/StatusAppNavBar.qml | 272 +++++++----------- ui/app/mainui/AppMain.qml | 123 ++++---- 5 files changed, 245 insertions(+), 281 deletions(-) diff --git a/test/ui-test/testSuites/global_shared/scripts/global_names.py b/test/ui-test/testSuites/global_shared/scripts/global_names.py index baa79ee22b..0cac515fdf 100644 --- a/test/ui-test/testSuites/global_shared/scripts/global_names.py +++ b/test/ui-test/testSuites/global_shared/scripts/global_names.py @@ -13,7 +13,6 @@ mainWindow_ScrollView_2 = {"container": statusDesktop_mainWindow, "occurrence": mainWindow_ProfileNavBarButton = {"container": statusDesktop_mainWindow, "objectName": "statusProfileNavBarTabButton", "type": "StatusNavBarTabButton", "visible": True} settings_navbar_settings_icon_StatusIcon = {"container": mainWindow_navBarListView_ListView, "objectName": "settings-icon", "type": "StatusIcon", "visible": True} splashScreen = {"container": statusDesktop_mainWindow, "objectName": "splashScreen", "type": "SplashScreen"} -navBarListView_Chat_navbar_StatusNavBarTabButton = {"checkable": True, "container": mainWindow_navBarListView_ListView, "objectName": "Chat-navbar", "type": "StatusNavBarTabButton", "visible": True} mainWindow_StatusToolBar = {"container": statusDesktop_mainWindow, "objectName": "statusToolBar", "type": "StatusToolBar", "visible": True} main_toolBar_back_button = {"container": mainWindow_StatusToolBar, "objectName": "toolBarBackButton", "type": "StatusFlatButton", "visible": True} mainWindow_emptyChatPanelImage = {"container": statusDesktop_mainWindow, "objectName": "emptyChatPanelImage", "type": "Image", "visible": True} @@ -33,7 +32,8 @@ modal_Close_Button = {"container": statusDesktop_mainWindow_overlay, "objectName delete_Channel_ConfirmationDialog_DeleteButton = {"container": statusDesktop_mainWindow_overlay, "objectName": "deleteChatConfirmationDialogDeleteButton", "type": "StatusButton"} # Main Window - chat related: -navBarListView_Chat_navbar_StatusNavBarTabButton = {"checkable": True, "container": mainWindow_navBarListView_ListView, "objectName": "Chat-navbar", "type": "StatusNavBarTabButton", "visible": True} +mainWindow_statusChatNavBarListView_ListView = {"container": statusDesktop_mainWindow, "objectName": "statusChatNavBarListView", "type": "ListView", "visible": True} +navBarListView_Chat_navbar_StatusNavBarTabButton = {"checkable": True, "container": mainWindow_statusChatNavBarListView_ListView, "objectName": "Chat-navbar", "type": "StatusNavBarTabButton", "visible": True} mainWindow_public_chat_icon_StatusIcon = {"container": statusDesktop_mainWindow, "objectName": "public-chat-icon", "source": "qrc:/StatusQ/src/assets/img/icons/public-chat.svg", "type": "StatusIcon", "visible": True} chatList_Repeater = {"container": statusDesktop_mainWindow, "objectName": "chatListItems", "type": "Repeater"} chatList = {"container": statusDesktop_mainWindow, "objectName": "ContactsColumnView_chatList", "type": "StatusChatList"} @@ -44,7 +44,6 @@ chatView_StatusChatInfoButton = {"container": statusDesktop_mainWindow, "objectN chatInfoButton_Pin_Text = {"container": chatView_StatusChatInfoButton, "objectName": "StatusChatInfo_pinText", "type": "StatusBaseText", "visible": True} joinPublicChat_input = {"container": statusDesktop_mainWindow_overlay, "objectName": "joinPublicChannelInput", "type": "TextEdit", "visible": True} startChat_Btn = {"container": statusDesktop_mainWindow_overlay, "objectName": "startChatButton", "type": "StatusButton"} -navBarListView_Chat_navbar_StatusNavBarTabButton = {"checkable": True, "container": mainWindow_navBarListView_ListView, "objectName": "Chat-navbar", "type": "StatusNavBarTabButton", "visible": True} # My Profile Popup ProfileHeader_userImage = {"container": statusDesktop_mainWindow_overlay, "objectName": "ProfileHeader_userImage", "type": "UserImage", "visible": True} diff --git a/ui/StatusQ/sandbox/DemoApp.qml b/ui/StatusQ/sandbox/DemoApp.qml index f593926b07..97722d5a82 100644 --- a/ui/StatusQ/sandbox/DemoApp.qml +++ b/ui/StatusQ/sandbox/DemoApp.qml @@ -12,6 +12,8 @@ import StatusQ.Platform 0.1 import "demoapp" import "demoapp/data" 1.0 +import SortFilterProxyModel 0.2 + Rectangle { id: demoApp height: 602 @@ -74,65 +76,27 @@ Rectangle { width: demoApp.width - demoApp.border.width * 2 leftPanel: StatusAppNavBar { - id: navBar - communityTypeRole: "sectionType" - communityTypeValue: appSectionType.community - sectionModel: Models.demoAppSectionsModel - - property bool communityAdded: false - - onAboutToUpdateFilteredRegularModel: { - communityAdded = false - } - - filterRegularItem: function(item) { - if(item.sectionType === appSectionType.community) - if(communityAdded) - return false - else - communityAdded = true - - return true - } - - filterCommunityItem: function(item) { - return item.sectionType === appSectionType.community - } - - regularNavBarButton: StatusNavBarTabButton { - anchors.horizontalCenter: parent.horizontalCenter - name: model.icon.length > 0? "" : model.name - icon.name: model.icon - icon.source: model.image - tooltip.text: model.name - autoExclusive: true - checked: model.active - badge.value: model.notificationsCount - badge.visible: model.hasNotification - badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor - badge.border.width: 2 - onClicked: { - if(model.sectionType === appSectionType.chat) - { - appView.sourceComponent = statusAppChatView - demoApp.setActiveItem(model.sectionId) - } - else if(model.sectionType === appSectionType.communitiesPortal) - { - appView.sourceComponent = statusCommunityPortalView - demoApp.setActiveItem(model.sectionId) - } - else if(model.sectionType === appSectionType.profileSettings) - { - appView.sourceComponent = statusAppProfileSettingsView - demoApp.setActiveItem(model.sectionId) - } + chatItemsModel: SortFilterProxyModel { + sourceModel: Models.demoAppSectionsModel + filters: ValueFilter { + roleName: "sectionType" + value: appSectionType.chat } } - communityNavBarButton: StatusNavBarTabButton { + chatItemDelegate: navButtonComponent + + communityItemsModel: SortFilterProxyModel { + sourceModel: Models.demoAppSectionsModel + filters: ValueFilter { + roleName: "sectionType" + value: appSectionType.community + } + } + + communityItemDelegate: StatusNavBarTabButton { anchors.horizontalCenter: parent.horizontalCenter name: model.icon.length > 0? "" : model.name icon.name: model.icon @@ -179,6 +143,52 @@ Rectangle { } } } + + regularItemsModel: SortFilterProxyModel { + sourceModel: Models.demoAppSectionsModel + filters: RangeFilter { + roleName: "sectionType" + minimumValue: appSectionType.communitiesPortal + maximumValue: appSectionType.demoApp + } + } + regularItemDelegate: navButtonComponent + + delegateHeight: 40 + + Component { + id: navButtonComponent + StatusNavBarTabButton { + anchors.horizontalCenter: parent.horizontalCenter + name: model.icon.length > 0? "" : model.name + icon.name: model.icon + icon.source: model.image + tooltip.text: model.name + autoExclusive: true + checked: model.active + badge.value: model.notificationsCount + badge.visible: model.hasNotification + badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor + badge.border.width: 2 + onClicked: { + if(model.sectionType === appSectionType.chat) + { + appView.sourceComponent = statusAppChatView + demoApp.setActiveItem(model.sectionId) + } + else if(model.sectionType === appSectionType.communitiesPortal) + { + appView.sourceComponent = statusCommunityPortalView + demoApp.setActiveItem(model.sectionId) + } + else if(model.sectionType === appSectionType.profileSettings) + { + appView.sourceComponent = statusAppProfileSettingsView + demoApp.setActiveItem(model.sectionId) + } + } + } + } } rightPanel: Loader { diff --git a/ui/StatusQ/sandbox/main.qml b/ui/StatusQ/sandbox/main.qml index 142f925d4f..de4a9a7356 100644 --- a/ui/StatusQ/sandbox/main.qml +++ b/ui/StatusQ/sandbox/main.qml @@ -70,11 +70,8 @@ StatusWindow { leftPanel: StatusAppNavBar { height: rootWindow.height - communityTypeRole: "sectionType" - communityTypeValue: appSectionType.community - sectionModel: Models.mainAppSectionsModel - - regularNavBarButton: StatusNavBarTabButton { + regularItemsModel: Models.mainAppSectionsModel + regularItemDelegate: StatusNavBarTabButton { anchors.horizontalCenter: parent.horizontalCenter name: model.icon.length > 0? "" : model.name icon.name: model.icon @@ -103,6 +100,7 @@ StatusWindow { rootWindow.setActiveItem(model.sectionId) } } + delegateHeight: 40 } rightPanel: Item { diff --git a/ui/StatusQ/src/StatusQ/Layout/StatusAppNavBar.qml b/ui/StatusQ/src/StatusQ/Layout/StatusAppNavBar.qml index caf86433c3..9dd4cc6284 100644 --- a/ui/StatusQ/src/StatusQ/Layout/StatusAppNavBar.qml +++ b/ui/StatusQ/src/StatusQ/Layout/StatusAppNavBar.qml @@ -1,8 +1,5 @@ import QtQuick 2.13 -import QtQuick.Layouts 1.13 -import QtQuick.Controls 2.13 -import QtQml.Models 2.13 -import Qt.labs.qmlmodels 1.0 +import QtQuick.Layouts 1.14 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 @@ -10,186 +7,129 @@ import StatusQ.Controls 0.1 import StatusQ.Popups 0.1 Rectangle { - id: statusAppNavBar + id: root + + property alias chatItemsModel: chatItemsListView.model + property alias chatItemDelegate: chatItemsListView.delegate + + property alias communityItemsModel: communityItemsListView.model + property alias communityItemDelegate: communityItemsListView.delegate + + property alias regularItemsModel: regularItemsListView.model + property alias regularItemDelegate: regularItemsListView.delegate + + property real delegateHeight + + property alias cameraComponent: cameraItemLoader.sourceComponent + property alias profileComponent: profileItemLoader.sourceComponent + + implicitWidth: 78 + implicitHeight: layout.implicitHeight - width: 78 - implicitHeight: 600 color: Theme.palette.statusAppNavBar.backgroundColor - property var sectionModel: [] - property string communityTypeRole: "" - property int communityTypeValue: -1 - property int navBarButtonSpacing: 12 + QtObject { + id: d - property StatusNavBarTabButton navBarCameraButton - property StatusNavBarTabButton navBarProfileButton - property Component regularNavBarButton - property Component communityNavBarButton + readonly property real spacing: 12 + readonly property real separatorWidth: 30 - property var filterRegularItem: function(item) { return true; } - property var filterCommunityItem: function(item) { return true; } - - signal aboutToUpdateFilteredRegularModel() - signal aboutToUpdateFilteredCommunityModel() - - onNavBarProfileButtonChanged: { - if (!!navBarProfileButton) { - navBarProfileButton.parent = navBarProfileButtonSlot + function implicitListViewHeight(listView) { + return listView.count ? listView.count * root.delegateHeight + (listView.count - 1) * listView.spacing : 0 } } - onNavBarCameraButtonChanged: { - if (!!navBarCameraButton) { - navBarCameraButton.parent = navBarCameraButtonSlot - } - } + ColumnLayout { + id: layout - function triggerUpdate(){ - navBarModel.update() - } - - StatusAppNavBarFilterModel { - id: navBarModel - - filterAcceptsItem: filterRegularItem - - model: statusAppNavBar.sectionModel - - onAboutToUpdateFilteredModel: { - statusAppNavBar.aboutToUpdateFilteredRegularModel() + anchors { + fill: parent + topMargin: 48 + bottomMargin: 24 } - DelegateChooser { - id: delegateChooser - role: communityTypeRole - DelegateChoice { roleValue: communityTypeValue; delegate: communityNavButton } - DelegateChoice { delegate: regularNavBarButton } + spacing: d.spacing + + ListView { + id: chatItemsListView + + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: root.delegateHeight + Layout.preferredHeight: d.implicitListViewHeight(this) + Layout.maximumHeight: Layout.preferredHeight + + objectName: "statusChatNavBarListView" + + visible: count + clip: true + spacing: d.spacing + boundsBehavior: contentHeight > height ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds } - delegate: delegateChooser - } + Rectangle { + id: firstSectionSeparator - Component { - id: communityNavButton + implicitHeight: 1 + Layout.preferredWidth: d.separatorWidth + Layout.alignment: Qt.AlignHCenter + color: Theme.palette.directColor7 + + visible: chatItemsListView.count && communityItemsListView.contentHeight > communityItemsListView.height + } + + ListView { + id: communityItemsListView + + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: root.delegateHeight + Layout.preferredHeight: d.implicitListViewHeight(this) + Layout.maximumHeight: Layout.preferredHeight + + visible: count + clip: true + spacing: d.spacing + boundsBehavior: contentHeight > height ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds + } + + Rectangle { + id: secondSectionSeparator + + implicitHeight: 1 + Layout.preferredWidth: d.separatorWidth + Layout.alignment: Qt.AlignHCenter + color: Theme.palette.directColor7 + visible: chatItemsListView.count || communityItemsListView.count + } + + ListView { + id: regularItemsListView + + Layout.fillWidth: true + Layout.preferredHeight: d.implicitListViewHeight(this) + + objectName: "statusMainNavBarListView" + + visible: count + clip: true + spacing: d.spacing + boundsBehavior: contentHeight > height ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds + } Item { - width: parent.width - height: (necessaryHightForCommunities > maxHightForCommunities)? - maxHightForCommunities : necessaryHightForCommunities + Layout.fillWidth: true + Layout.fillHeight: true + } - property int communityNavBarButtonHeight: 40 + Loader { + id: cameraItemLoader + Layout.alignment: Qt.AlignHCenter + } - property int maxHightForCommunities: { - let numOfOtherThanCommunityBtns = navBarListView.model.count - 1 - let numOfSpacingsForNavBar = navBarListView.model.count - 1 - - return navBarListView.height - - numOfOtherThanCommunityBtns * communityNavBarButtonHeight - - numOfSpacingsForNavBar * navBarButtonSpacing - } - - property int necessaryHightForCommunities: { - let numOfSpacingsForCommunities = communityListView.model.count - 1 - return communityListView.model.count * communityNavBarButtonHeight + - numOfSpacingsForCommunities * navBarButtonSpacing + - separatorBottom.height - } - - StatusAppNavBarFilterModel { - id: navBarCommunityModel - - filterAcceptsItem: filterCommunityItem - - model: statusAppNavBar.sectionModel - - delegate: communityNavBarButton - - onAboutToUpdateFilteredModel: { - statusAppNavBar.aboutToUpdateFilteredCommunityModel() - } - } - - Item { - id: separatorTop - width: parent.width - height: navBarButtonSpacing - anchors.top: parent.top - visible: parent.necessaryHightForCommunities > parent.maxHightForCommunities - - Rectangle { - height: 1 - width: 30 - color: Theme.palette.directColor7 - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter - } - } - - ListView { - id: communityListView - anchors.left: parent.left - anchors.right: parent.right - anchors.top: separatorTop.visible? separatorTop.bottom : parent.top - anchors.bottom: separatorBottom.top - clip: true - - boundsBehavior: contentHeight > height ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds - spacing: navBarButtonSpacing - - model: navBarCommunityModel - } - - Item { - id: separatorBottom - width: parent.width - height: navBarButtonSpacing - anchors.bottom: parent.bottom - - Rectangle { - height: 1 - width: 30 - color: Theme.palette.directColor7 - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - } - } + Loader { + id: profileItemLoader + Layout.alignment: Qt.AlignHCenter } } - - ListView { - id: navBarListView - objectName: "statusMainNavBarListView" - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: 48 - anchors.bottom: navBarProfileButtonSlot.top - anchors.bottomMargin: navBarButtonSpacing - - spacing: navBarButtonSpacing - - boundsBehavior: Flickable.StopAtBounds - model: navBarModel - } - - Item { - id: navBarCameraButtonSlot - anchors.horizontalCenter: parent.horizontalCenter - height: visible? statusAppNavBar.navBarProfileButton.height : 0 - width: visible? statusAppNavBar.navBarProfileButton.width : 0 - visible: !!statusAppNavBar.navBarCameraButton - anchors.bottom: navBarProfileButtonSlot.visible ? navBarProfileButtonSlot.top : parent.bottom - anchors.bottomMargin: visible ? 12 : 0 - } - - - Item { - id: navBarProfileButtonSlot - anchors.horizontalCenter: parent.horizontalCenter - height: visible? statusAppNavBar.navBarProfileButton.height : 0 - width: visible? statusAppNavBar.navBarProfileButton.width : 0 - visible: !!statusAppNavBar.navBarProfileButton - anchors.bottom: parent.bottom - anchors.bottomMargin: visible ? 24 : 0 - } } diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index d7012cf9cc..a6f91ecec7 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -34,9 +34,10 @@ import StatusQ.Popups.Dialog 0.1 import StatusQ.Core 0.1 import AppLayouts.Browser.stores 1.0 as BrowserStores - import AppLayouts.stores 1.0 +import SortFilterProxyModel 0.2 + import "popups" import "panels" import "activitycenter/popups" @@ -320,58 +321,35 @@ Item { anchors.fill: parent leftPanel: StatusAppNavBar { - communityTypeRole: "sectionType" - communityTypeValue: Constants.appSection.community - sectionModel: appMain.rootStore.mainModuleInst.sectionsModel - - Component.onCompleted: { - appMain.rootStore.mainModuleInst.sectionsModel.sectionVisibilityUpdated.connect(function(){ - triggerUpdate() - }) + chatItemsModel: SortFilterProxyModel { + sourceModel: appMain.rootStore.mainModuleInst.sectionsModel + filters: [ + ValueFilter { + roleName: "sectionType" + value: Constants.appSection.chat + }, + ValueFilter { + roleName: "enabled" + value: true + } + ] } + chatItemDelegate: navbarButton - property bool communityAdded: false - - onAboutToUpdateFilteredRegularModel: { - communityAdded = false + communityItemsModel: SortFilterProxyModel { + sourceModel: appMain.rootStore.mainModuleInst.sectionsModel + filters: [ + ValueFilter { + roleName: "sectionType" + value: Constants.appSection.community + }, + ValueFilter { + roleName: "enabled" + value: true + } + ] } - - filterRegularItem: function(item) { - if(!item.enabled) - return false - - if(item.sectionType === Constants.appSection.community) - if(communityAdded) - return false - else - communityAdded = true - - return true - } - - filterCommunityItem: function(item) { - return item.sectionType === Constants.appSection.community - } - - regularNavBarButton: StatusNavBarTabButton { - id: navbar - objectName: model.name + "-navbar" - anchors.horizontalCenter: parent.horizontalCenter - name: model.icon.length > 0? "" : model.name - icon.name: model.icon - icon.source: model.image - tooltip.text: model.name - checked: model.active - badge.value: model.notificationsCount - badge.visible: model.hasNotification - badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor - badge.border.width: 2 - onClicked: { - changeAppSectionBySectionId(model.id) - } - } - - communityNavBarButton: StatusNavBarTabButton { + communityItemDelegate: StatusNavBarTabButton { objectName: "CommunityNavBarButton" anchors.horizontalCenter: parent.horizontalCenter name: model.icon.length > 0? "" : model.name @@ -433,15 +411,33 @@ Item { } } - navBarProfileButton: StatusNavBarTabButton { + regularItemsModel: SortFilterProxyModel { + sourceModel: appMain.rootStore.mainModuleInst.sectionsModel + filters: [ + RangeFilter { + roleName: "sectionType" + minimumValue: Constants.appSection.wallet + maximumValue: Constants.appSection.communitiesPortal + }, + ValueFilter { + roleName: "enabled" + value: true + } + ] + } + regularItemDelegate: navbarButton + + delegateHeight: 40 + + profileComponent: StatusNavBarTabButton { id: profileButton objectName: "statusProfileNavBarTabButton" property bool opened: false name: appMain.rootStore.userProfileInst.name icon.source: appMain.rootStore.userProfileInst.icon - width: 32 - height: 32 + implicitWidth: 32 + implicitHeight: 32 identicon.asset.width: width identicon.asset.height: height identicon.asset.charactersLen: 2 @@ -481,6 +477,27 @@ Item { store: appMain.rootStore } } + + Component { + id: navbarButton + StatusNavBarTabButton { + id: navbar + objectName: model.name + "-navbar" + anchors.horizontalCenter: parent.horizontalCenter + name: model.icon.length > 0? "" : model.name + icon.name: model.icon + icon.source: model.image + tooltip.text: model.name + checked: model.active + badge.value: model.notificationsCount + badge.visible: model.hasNotification + badge.border.color: hovered ? Theme.palette.statusBadge.hoverBorderColor : Theme.palette.statusBadge.borderColor + badge.border.width: 2 + onClicked: { + changeAppSectionBySectionId(model.id) + } + } + } } rightPanel: ColumnLayout {