From 4d6082e806aeff6a95a64f994f9ff81b727c4171 Mon Sep 17 00:00:00 2001 From: Alex Jbanca Date: Tue, 5 Mar 2024 00:07:09 +0200 Subject: [PATCH] feat(ProfileShowcase): Updates based on comments --- .../ProfileShowcaseAccountsPanelPage.qml | 35 +-- .../pages/ProfileShowcaseAssetsPanelPage.qml | 14 +- .../ProfileShowcaseCollectiblesPanelPage.qml | 56 +++-- .../ProfileShowcaseCommunitiesPanelPage.qml | 38 +-- .../pages/ProfileShowcaseDirtyStatePage.qml | 53 +++-- storybook/pages/ProfileShowcaseModelsPage.qml | 216 ++++++++++++------ storybook/pages/ProfileShowcasePanelPage.qml | 43 ++-- storybook/src/Storybook/GenericListView.qml | 41 ++-- ui/StatusQ/src/movablemodel.cpp | 148 ++++++------ ui/StatusQ/tests/tst_MovableModel.cpp | 74 +++++- ui/app/AppLayouts/Profile/ProfileLayout.qml | 1 + .../controls/ProfileShowcasePanelDelegate.qml | 4 +- .../Profile/controls/ShowcaseDelegate.qml | 10 +- .../helpers/ProfileShowcaseDirtyState.qml | 33 ++- .../helpers/ProfileShowcaseModelAdapter.qml | 95 ++++---- .../Profile/helpers/ProfileShowcaseModels.qml | 18 +- .../VisibilityAndPositionDirtyStateModel.qml | 26 +-- .../panels/ProfileShowcaseAccountsPanel.qml | 4 +- .../panels/ProfileShowcaseAssetsPanel.qml | 2 +- .../ProfileShowcaseCollectiblesPanel.qml | 15 +- .../Profile/panels/ProfileShowcasePanel.qml | 32 +-- .../Profile/views/MyProfileView.qml | 34 ++- ui/imports/shared/views/ProfileDialogView.qml | 4 + 23 files changed, 588 insertions(+), 408 deletions(-) diff --git a/storybook/pages/ProfileShowcaseAccountsPanelPage.qml b/storybook/pages/ProfileShowcaseAccountsPanelPage.qml index 6b62c3340e..2f5c785e31 100644 --- a/storybook/pages/ProfileShowcaseAccountsPanelPage.qml +++ b/storybook/pages/ProfileShowcaseAccountsPanelPage.qml @@ -26,27 +26,30 @@ SplitView { id: hiddenModelItem ListElement { name: "My Status Account" - key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420" + address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420" + showcaseKey: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420" colorId: "primary" emoji: "πŸ‡¨πŸ‡Ώ" walletType: "" - visibility: 0 + showcaseVisibility: Constants.ShowcaseVisibility.NoOne } ListElement { name: "testing (no emoji, colored, seed)" - key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000" + address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000" + showcaseKey: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000" colorId: "" emoji: "" walletType: "seed" - visibility: 0 + showcaseVisibility: Constants.ShowcaseVisibility.NoOne } ListElement { name: "My Bro's Account" - key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421" + address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421" + showcaseKey: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421" colorId: "orange" emoji: "πŸ‡ΈπŸ‡°" walletType: "watch" - visibility: 0 + showcaseVisibility: Constants.ShowcaseVisibility.NoOne } } @@ -55,27 +58,33 @@ SplitView { ListElement { name: "My Status Account" - key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420" + address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420" + showcaseKey: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420" colorId: "primary" emoji: "πŸ‡¨πŸ‡Ώ" walletType: "" - visibility: 1 + showcaseVisibility: Constants.ShowcaseVisibility.Everyone + showcasePosition: 0 } ListElement { name: "testing (no emoji, colored, seed)" - key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000" + address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000" + showcaseKey: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000" colorId: "" emoji: "" walletType: "seed" - visibility: 1 + showcaseVisibility: Constants.ShowcaseVisibility.Everyone + showcasePosition: 1 } ListElement { name: "My Bro's Account" - key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421" + address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421" + showcaseKey: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421" colorId: "orange" emoji: "πŸ‡ΈπŸ‡°" walletType: "watch" - visibility: 1 + showcaseVisibility: Constants.ShowcaseVisibility.Everyone + showcasePosition: 2 } } @@ -102,7 +111,7 @@ SplitView { ColumnLayout { Label { - text: "β“˜ Shwcase interaction implemented in ProfileShowcasePanelPage" + text: "β“˜ Showcase interaction implemented in ProfileShowcasePanelPage" } CheckBox { diff --git a/storybook/pages/ProfileShowcaseAssetsPanelPage.qml b/storybook/pages/ProfileShowcaseAssetsPanelPage.qml index ff20b68907..dcbef58c6e 100644 --- a/storybook/pages/ProfileShowcaseAssetsPanelPage.qml +++ b/storybook/pages/ProfileShowcaseAssetsPanelPage.qml @@ -35,11 +35,11 @@ SplitView { sourceModel: !emptyModelChecker.checked ? walletAssetStore.groupedAccountAssetsModel : null proxyRoles: [ FastExpressionRole { - name: "key" + name: "showcaseKey" expression: "Asset 1" + index }, FastExpressionRole { - name: "visibility" + name: "showcaseVisibility" expression: 1 } ] @@ -50,11 +50,11 @@ SplitView { sourceModel: !emptyModelChecker.checked ? walletAssetStore.groupedAccountAssetsModel : null proxyRoles: [ FastExpressionRole { - name: "key" + name: "showcaseKey" expression: "Asset 2" + index }, FastExpressionRole { - name: "visibility" + name: "showcaseVisibility" expression: 0 } ] @@ -89,12 +89,6 @@ SplitView { logsView.logText: logs.logText ColumnLayout { - Button { - text: "Reset (clear settings)" - - onClicked: showcasePanel.settings.reset() - } - CheckBox { id: hasAllAccountsChecker diff --git a/storybook/pages/ProfileShowcaseCollectiblesPanelPage.qml b/storybook/pages/ProfileShowcaseCollectiblesPanelPage.qml index a9d92c2269..7c7540c320 100644 --- a/storybook/pages/ProfileShowcaseCollectiblesPanelPage.qml +++ b/storybook/pages/ProfileShowcaseCollectiblesPanelPage.qml @@ -27,62 +27,62 @@ SplitView { id: hiddenModelItem readonly property var data: [ { - key: "1234", + showcaseKey: "1234", name: "SNTT", collectionName: "Super Nitro Toluen (with pink bg)", backgroundColor: "pink", imageUrl: ModelsData.collectibles.custom, isLoading: false, communityId: "ddls", - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne }, { - key: "3454565676", + showcaseKey: "3454565676", name: "Kitty 3", collectionName: "Kitties", backgroundColor: "", imageUrl: ModelsData.collectibles.kitty1Big, isLoading: false, - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne }, { - key: "12345", + showcaseKey: "12345", name: "Kitty 4", collectionName: "", backgroundColor: "", imageUrl: ModelsData.collectibles.kitty2Big, isLoading: false, communityId: "sox", - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne }, { - key: "123456454595374", + showcaseKey: "123456454595374", name: "", collectionName: "Super Kitties", backgroundColor: "oink", imageUrl: ModelsData.collectibles.kitty3Big, isLoading: false, communityId: "ast", - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne }, { - key: "6912", + showcaseKey: "6912", name: "KILLABEAR", collectionName: "KILLABEARS", backgroundColor: "#807c56", imageUrl: "https://assets.killabears.com/content/killabears/img/691-e81f892696a8ae700e0dbc62eb072060679a2046d1ef5eb2671bdb1fad1f68e3.png", isLoading: true, - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne }, { - key: "8876", + showcaseKey: "8876", name: "AIORBIT", description: "", collectionName: "AIORBIT (Animated SVG)", backgroundColor: "", imageUrl: "https://dl.openseauserdata.com/cache/originImage/files/8b14ef530b28853445c27d6693c4e805.svg", isLoading: false, - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne } ] Component.onCompleted: append(data) @@ -93,62 +93,68 @@ SplitView { readonly property var data: [ { - key: "123", + uid: "123", + showcaseKey: "1234", name: "SNT", collectionName: "Super Nitro Toluen (with pink bg)", backgroundColor: "pink", imageUrl: ModelsData.collectibles.custom, isLoading: false, communityId: "ddls", - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone }, { - key: "34545656768", + uid: "34545656768", + showcaseKey: "3454565676", name: "Kitty 1", collectionName: "Kitties", backgroundColor: "", imageUrl: ModelsData.collectibles.kitty1Big, isLoading: false, - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone }, { - key: "123456", + uid: "123456", + showcaseKey: "12345", name: "Kitty 2", collectionName: "", backgroundColor: "", imageUrl: ModelsData.collectibles.kitty2Big, isLoading: false, communityId: "sox", - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone }, { - key: "12345645459537432", + uid: "12345645459537432", + showcaseKey: "123456454595374", name: "", collectionName: "Super Kitties", backgroundColor: "oink", imageUrl: ModelsData.collectibles.kitty3Big, isLoading: false, communityId: "ast", - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone }, { - key: "691", + uid: "691", + showcaseKey: "6912", name: "KILLABEAR", collectionName: "KILLABEARS", backgroundColor: "#807c56", imageUrl: "https://assets.killabears.com/content/killabears/img/691-e81f892696a8ae700e0dbc62eb072060679a2046d1ef5eb2671bdb1fad1f68e3.png", isLoading: true, - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone }, { - key: "8876", + uid: "8876", + showcaseKey: "8876", name: "AIORBIT", description: "", collectionName: "AIORBIT (Animated SVG)", backgroundColor: "", imageUrl: "https://dl.openseauserdata.com/cache/originImage/files/8b14ef530b28853445c27d6693c4e805.svg", isLoading: false, - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone } ] Component.onCompleted: append(data) @@ -221,7 +227,7 @@ SplitView { ColumnLayout { Label { - text: "β“˜ Shwcase interaction implemented in ProfileShowcasePanelPage" + text: "β“˜ Showcase interaction implemented in ProfileShowcasePanelPage" } CheckBox { diff --git a/storybook/pages/ProfileShowcaseCommunitiesPanelPage.qml b/storybook/pages/ProfileShowcaseCommunitiesPanelPage.qml index a16e06bd01..c34da7fa6c 100644 --- a/storybook/pages/ProfileShowcaseCommunitiesPanelPage.qml +++ b/storybook/pages/ProfileShowcaseCommunitiesPanelPage.qml @@ -25,44 +25,44 @@ SplitView { id: hiddenModelItem Component.onCompleted: append([{ - key: "0x0006", + showcaseKey: "0x0006", name: "Test community 6", joined: true, memberRole: Constants.memberRole.owner, isControlNode: true, image: ModelsData.icons.dribble, color: "yellow", - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne }, { - key: "0x0007", + showcaseKey: "0x0007", name: "Test community 7", joined: true, memberRole: Constants.memberRole.none, isControlNode: false, image: ModelsData.collectibles.custom, color: "peach", - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne }, { - key: "0x0008", + showcaseKey: "0x0008", name: "Test community 8", joined: true, memberRole: Constants.memberRole.none, isControlNode: false, image: "", color: "whitesmoke", - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne }, { - key: "0x0009", + showcaseKey: "0x0009", name: "Test community 9", joined: true, memberRole: Constants.memberRole.admin, isControlNode: false, image: ModelsData.icons.spotify, color: "green", - visibility: Constants.ShowcaseVisibility.NoOne + showcaseVisibility: Constants.ShowcaseVisibility.NoOne }, ]) } @@ -72,44 +72,48 @@ SplitView { Component.onCompleted: append([{ - key: "0x0001", + id: "0x0001", + showcaseKey: "0x0001", name: "Test community", joined: true, memberRole: Constants.memberRole.owner, isControlNode: true, image: ModelsData.icons.dribble, color: "yellow", - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone }, { - key: "0x0002", + id: "0x0002", + showcaseKey: "0x0002", name: "Test community 2", joined: true, memberRole: Constants.memberRole.none, isControlNode: false, image: ModelsData.collectibles.custom, color: "peach", - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone }, { - key: "0x0004", + id: "0x0004", + showcaseKey: "0x0004", name: "Test community 3", joined: true, memberRole: Constants.memberRole.none, isControlNode: false, image: "", color: "whitesmoke", - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone }, { - key: "0x0005", + id: "0x0005", + showcaseKey: "0x0005", name: "Test community 4", joined: true, memberRole: Constants.memberRole.admin, isControlNode: false, image: ModelsData.icons.spotify, color: "green", - visibility: Constants.ShowcaseVisibility.Everyone + showcaseVisibility: Constants.ShowcaseVisibility.Everyone }, ]) } @@ -137,7 +141,7 @@ SplitView { ColumnLayout { Label { - text: "β“˜ Shwcase interaction implemented in ProfileShowcasePanelPage" + text: "β“˜ Showcase interaction implemented in ProfileShowcasePanelPage" } CheckBox { diff --git a/storybook/pages/ProfileShowcaseDirtyStatePage.qml b/storybook/pages/ProfileShowcaseDirtyStatePage.qml index a62fd3c918..c8cb77522c 100644 --- a/storybook/pages/ProfileShowcaseDirtyStatePage.qml +++ b/storybook/pages/ProfileShowcaseDirtyStatePage.qml @@ -17,24 +17,24 @@ Item { ListModel { id: communitiesModel - ListElement { key: "1"; name: "Crypto Kitties" } - ListElement { key: "2"; name: "Status" } - ListElement { key: "3"; name: "Fun Stuff" } - ListElement { key: "4"; name: "Other Stuff" } + ListElement { showcaseKey: "1"; name: "Crypto Kitties" } + ListElement { showcaseKey: "2"; name: "Status" } + ListElement { showcaseKey: "3"; name: "Fun Stuff" } + ListElement { showcaseKey: "4"; name: "Other Stuff" } } ListModel { id: communitiesShowcaseModel ListElement { - key: "1" - visibility: Constants.ShowcaseVisibility.IdVerifiedContacts - position: 0 + showcaseKey: "1" + showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts + showcasePosition: 0 } ListElement { - key: "3" - visibility: Constants.ShowcaseVisibility.Contacts - position: 9 + showcaseKey: "3" + showcaseVisibility: Constants.ShowcaseVisibility.Contacts + showcasePosition: 9 } } @@ -72,6 +72,7 @@ Item { anchors.fill: parent Grid { + id: grid Layout.fillWidth: true Layout.fillHeight: true Layout.margins: 10 @@ -90,7 +91,7 @@ Item { } GenericListView { - width: 200 + width: grid.width / 3 - grid.spacing height: 300 model: communitiesModel @@ -98,12 +99,12 @@ Item { } GenericListView { - width: 200 + width: grid.width / 3 - grid.spacing height: 300 model: communitiesShowcaseModel label: "SHOWCASE MODEL" - roles: ["key", "visibility", "position"] + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] } Label { @@ -113,7 +114,7 @@ Item { } GenericListView { - width: 350 + width: grid.width / 3 - grid.spacing height: 300 model: dirtyState.joined_ @@ -121,12 +122,12 @@ Item { } GenericListView { - width: 350 + width: grid.width / 3 - grid.spacing height: 300 model: dirtyState.writable_ label: "WRITABLE MODEL" - roles: ["key", "visibility", "position", "name"] + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition", "name"] } @@ -137,19 +138,17 @@ Item { } GenericListView { - width: 450 + width: grid.width / 3 - grid.spacing height: 300 model: movableModel label: "IN SHOWCASE" movable: true - roles: ["key", "visibility", "position"] + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] onMoveRequested: { movableModel.move(from, to) - - const key = ModelUtils.get(movableModel, to, "key") - dirtyState.changePosition(key, to); + dirtyState.changePosition(from, to); } insetComponent: RowLayout { @@ -158,7 +157,7 @@ Item { RoundButton { text: "❌" onClicked: dirtyState.setVisibility( - model.key, + model.showcaseKey, Constants.ShowcaseVisibility.NoOne) } @@ -169,13 +168,13 @@ Item { if (!completed || topModel.index < 0) return - dirtyState.setVisibility(topModel.key, currentValue) + dirtyState.setVisibility(topModel.showcaseKey, currentValue) } property bool completed: false Component.onCompleted: { - currentIndex = indexOfValue(topModel.visibility) + currentIndex = indexOfValue(topModel.showcaseVisibility) completed = true } @@ -186,19 +185,19 @@ Item { } GenericListView { - width: 450 + width: grid.width / 3 - grid.spacing height: 300 model: dirtyState.hiddenModel label: "HIDDEN" - roles: ["key", "visibility", "position"] + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] insetComponent: Button { text: "unhide" onClicked: dirtyState.setVisibility( - model.key, + model.showcaseKey, Constants.ShowcaseVisibility.IdVerifiedContacts) } } diff --git a/storybook/pages/ProfileShowcaseModelsPage.qml b/storybook/pages/ProfileShowcaseModelsPage.qml index d2d76f9eb5..ef3f7ff977 100644 --- a/storybook/pages/ProfileShowcaseModelsPage.qml +++ b/storybook/pages/ProfileShowcaseModelsPage.qml @@ -8,6 +8,8 @@ import StatusQ.Core.Utils 0.1 import Storybook 1.0 +import SortFilterProxyModel 0.2 + import utils 1.0 import AppLayouts.Profile.helpers 1.0 @@ -16,53 +18,150 @@ ColumnLayout { ListModel { id: accountsModel - ListElement { key: "1"; name: "Crypto Kitties" } - ListElement { key: "2"; name: "Status" } - ListElement { key: "3"; name: "Fun Stuff" } - ListElement { key: "4"; name: "Other Stuff" } + ListElement { address: "1"; name: "Crypto Kitties" } + ListElement { address: "2"; name: "Status" } + ListElement { address: "3"; name: "Fun Stuff" } + ListElement { address: "4"; name: "Other Stuff" } } ListModel { id: accountsShowcaseModel - ListElement { - key: "1" - visibility: Constants.ShowcaseVisibility.IdVerifiedContacts - position: 0 + address: "1" + showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts + order: 0 + name: "name" + colorId: "colorId" + emoji: "emoji" } ListElement { - key: "3" - visibility: Constants.ShowcaseVisibility.Contacts - position: 9 + address: "2" + showcaseVisibility: Constants.ShowcaseVisibility.Contacts + order: 1 + name: "name" + colorId: "colorId" + emoji: "emoji" + } + ListElement { + address: "3" + showcaseVisibility: Constants.ShowcaseVisibility.Contacts + order: 2 + name: "name" + colorId: "colorId" + emoji: "emoji" } } ListModel { - id: collectiblesModel + id: accounts13 + ListElement { accountAddress: "1" } + ListElement { accountAddress: "3" } + } - ListElement { key: "1"; name: "Collectible 1"; accounts: "1:3" } - ListElement { key: "2"; name: "Collectible 2"; accounts: "3" } - ListElement { key: "3"; name: "Collectible 3"; accounts: "1:2:3" } - ListElement { key: "4"; name: "Collectible 4"; accounts: "1:4" } + ListModel { + id: accounts3 + ListElement { accountAddress: "3" } + } + + ListModel { + id: accounts123 + ListElement { accountAddress: "1" } + ListElement { accountAddress: "2" } + ListElement { accountAddress: "3" } + } + + ListModel { + id: accounts14 + ListElement { accountAddress: "1" } + ListElement { accountAddress: "4" } + } + + ListModel { + id: collectiblesListModel + + ListElement { item: 1 } + ListElement { item: 2 } + ListElement { item: 3 } + ListElement { item: 4 } + } + + SortFilterProxyModel { + id: collectiblesModel + sourceModel: collectiblesListModel + proxyRoles: [ + FastExpressionRole { + name: "ownership" + expression: { + if (index == 0) { + return accounts13 + } else if (index == 1) { + return accounts3 + } else if (index == 2) { + return accounts123 + } else if (index == 3) { + return accounts14 + } + return undefined + } + }, + FastExpressionRole { + name: "uid" + expression: { + return index + 1 + } + }, + FastExpressionRole { + name: "name" + expression: { + return "Collectible " + (index + 1) + } + } + ] } ListModel { id: collectiblesShowcaseModel - ListElement { - key: "1" - visibility: Constants.ShowcaseVisibility.IdVerifiedContacts - position: 0 + uid: "1" + showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts + order: 0 + name: "name" + backgroundColor: "backgroundColor" + chainId: "chainId" + communityId: "communityId" + collectionName: "collectionName" + imageUrl: "imageUrl" + isLoading: "isLoading" + contractAddress: "contractAddress" + tokenId: "tokenId" } ListElement { - key: "2" - visibility: Constants.ShowcaseVisibility.Contacts - position: 2 + uid: "2" + showcaseVisibility: Constants.ShowcaseVisibility.Contacts + order: 2 + name: "name" + backgroundColor: "backgroundColor" + chainId: "chainId" + communityId: "communityId" + collectionName: "collectionName" + imageUrl: "imageUrl" + isLoading: "isLoading" + contractAddress: "contractAddress" + tokenId: "tokenId" } ListElement { - key: "3" - visibility: Constants.ShowcaseVisibility.Contacts - position: 1 + uid: "3" + showcaseVisibility: Constants.ShowcaseVisibility.Contacts + order: 1 + name: "name" + backgroundColor: "backgroundColor" + chainId: "chainId" + communityId: "communityId" + collectionName: "collectionName" + imageUrl: "imageUrl" + isLoading: "isLoading" + contractAddress: "contractAddress" + tokenId: "tokenId" } } @@ -76,18 +175,6 @@ ColumnLayout { collectiblesShowcaseModel: collectiblesShowcaseModel } - MovableModel { - id: accountsMovableModel - - sourceModel: showcaseModels.accountsVisibleModel - } - - MovableModel { - id: collectiblesMovableModel - - sourceModel: showcaseModels.collectiblesVisibleModel - } - ListModel { id: comboBoxModel @@ -139,7 +226,7 @@ ColumnLayout { } GenericListView { - width: 200 + width: 300 height: 300 model: accountsModel @@ -147,12 +234,12 @@ ColumnLayout { } GenericListView { - width: 200 + width: 300 height: 300 model: accountsShowcaseModel label: "SHOWCASE MODEL" - roles: ["key", "visibility", "position"] + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] } Label { @@ -165,16 +252,13 @@ ColumnLayout { width: 420 height: 300 - model: accountsMovableModel + model: showcaseModels.accountsVisibleModel label: "IN SHOWCASE" movable: true - roles: ["key", "visibility", "position"] + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] onMoveRequested: { - accountsMovableModel.move(from, to) - - const key = ModelUtils.get(accountsMovableModel, to, "key") - showcaseModels.changeAccountPosition(key, to); + showcaseModels.changeAccountPosition(from, to); } insetComponent: RowLayout { @@ -183,7 +267,7 @@ ColumnLayout { RoundButton { text: "❌" onClicked: showcaseModels.setAccountVisibility( - model.key, + model.showcaseKey, Constants.ShowcaseVisibility.NoOne) } @@ -195,11 +279,11 @@ ColumnLayout { return showcaseModels.setAccountVisibility( - topModel.key, currentValue) + topModel.showcaseKey, currentValue) } Component.onCompleted: { - currentIndex = indexOfValue(topModel.visibility) + currentIndex = indexOfValue(topModel.showcaseVisibility) completed = true } } @@ -214,14 +298,14 @@ ColumnLayout { label: "HIDDEN" - roles: ["key", "visibility", "position"] + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] insetComponent: Button { text: "unhide" onClicked: showcaseModels.setAccountVisibility( - model.key, + model.showcaseKey, Constants.ShowcaseVisibility.IdVerifiedContacts) } } @@ -238,8 +322,6 @@ ColumnLayout { model: collectiblesModel label: "COLLECTIBLES MODEL" - - roles: ["key", "name", "accounts"] } GenericListView { @@ -248,7 +330,7 @@ ColumnLayout { model: collectiblesShowcaseModel label: "SHOWCASE MODEL" - roles: ["key", "visibility", "position"] + roles: ["uid", "showcaseVisibility", "order"] } Label { @@ -261,16 +343,13 @@ ColumnLayout { width: 610 height: 300 - model: collectiblesMovableModel + model: showcaseModels.collectiblesVisibleModel label: "IN SHOWCASE" movable: true - roles: ["key", "visibility", "position", "accounts", "maxVisibility"] + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] onMoveRequested: { - collectiblesMovableModel.move(from, to) - - const key = ModelUtils.get(collectiblesMovableModel, to, "key") - showcaseModels.changeCollectiblePosition(key, to); + showcaseModels.changeCollectiblePosition(from, to); } insetComponent: RowLayout { @@ -279,7 +358,7 @@ ColumnLayout { RoundButton { text: "❌" onClicked: showcaseModels.setCollectibleVisibility( - model.key, + model.showcaseKey, Constants.ShowcaseVisibility.NoOne) } @@ -291,11 +370,11 @@ ColumnLayout { return showcaseModels.setCollectibleVisibility( - topModel.key, currentValue) + topModel.showcaseKey, currentValue) } Component.onCompleted: { - currentIndex = indexOfValue(topModel.visibility) + currentIndex = indexOfValue(topModel.showcaseVisibility) completed = true } } @@ -310,7 +389,7 @@ ColumnLayout { label: "HIDDEN" - roles: ["key", "visibility", "position", + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition", "accounts", "maxVisibility"] insetComponent: Button { @@ -318,7 +397,7 @@ ColumnLayout { onClicked: showcaseModels.setCollectibleVisibility( - model.key, + model.showcaseKey, Constants.ShowcaseVisibility.IdVerifiedContacts) } } @@ -340,14 +419,13 @@ ColumnLayout { Button { text: "SAVE" + //TODO: enable when showcaseModels backend APIs is integrated + enabled: false onClicked: { const accountsToBeSaved = showcaseModels.accountsCurrentState() const collectiblesToBeSaved = showcaseModels.collectiblesCurrentState() - accountsMovableModel.syncOrder() - collectiblesMovableModel.syncOrder() - accountsShowcaseModel.clear() accountsShowcaseModel.append(accountsToBeSaved) diff --git a/storybook/pages/ProfileShowcasePanelPage.qml b/storybook/pages/ProfileShowcasePanelPage.qml index e70326ca3e..15efe8db18 100644 --- a/storybook/pages/ProfileShowcasePanelPage.qml +++ b/storybook/pages/ProfileShowcasePanelPage.qml @@ -4,6 +4,7 @@ import QtQuick.Layouts 1.15 import AppLayouts.Profile.panels 1.0 import AppLayouts.Profile.controls 1.0 +import AppLayouts.Wallet.controls 1.0 import StatusQ.Components 0.1 import utils 1.0 @@ -11,7 +12,7 @@ import utils 1.0 import Storybook 1.0 SplitView { - //id: root + id: root property int inShowcaseModelCount: inShowcaseCounter.value property int hiddenModelCount: hiddenCounter.value @@ -23,13 +24,13 @@ SplitView { ListModel { id: inShowcaseModelItem ListElement { - key: 1 + showcaseKey: 1 title: "Item 1" secondaryTitle: "Description 1" hasImage: true image: "https://picsum.photos/200/300?random=1" iconName: "https://picsum.photos/40/40?random=1" - visibility: 1 + showcaseVisibility: 1 name: "Test community" joined: true isControlNode: true @@ -44,13 +45,13 @@ SplitView { ListModel { id: hiddenModelItem ListElement { - key: 2 + showcaseKey: 2 title: "Item 1" secondaryTitle: "Description 1" hasImage: true image: "https://picsum.photos/200/300?random=1" iconName: "https://picsum.photos/40/40?random=1" - visibility: 0 + showcaseVisibility: 0 name: "Test community" joined: true isControlNode: true @@ -63,7 +64,6 @@ SplitView { } ProfileShowcasePanel { - id: root inShowcaseModel: inShowcaseModelItem hiddenModel: hiddenModelItem SplitView.fillWidth: true @@ -75,8 +75,8 @@ SplitView { } onSetVisibilityRequested: function (key, toVisibility) { for (var i = 0; i < inShowcaseModelItem.count; i++) { - if (inShowcaseModelItem.get(i).key === key) { - inShowcaseModelItem.setProperty(i, "visibility", toVisibility) + if (inShowcaseModelItem.get(i).showcaseKey === key) { + inShowcaseModelItem.setProperty(i, "showcaseVisibility", toVisibility) if(toVisibility === 0) { let item = inShowcaseModelItem.get(i) hiddenModelItem.append(item) @@ -87,8 +87,8 @@ SplitView { } for (var i = 0; i < hiddenModelItem.count; i++) { - if (hiddenModelItem.get(i).key === key) { - hiddenModelItem.setProperty(i, "visibility", toVisibility) + if (hiddenModelItem.get(i).showcaseKey === key) { + hiddenModelItem.setProperty(i, "showcaseVisibility", toVisibility) if(toVisibility !== 0) { let item = hiddenModelItem.get(i) inShowcaseModelItem.append(item) @@ -107,10 +107,17 @@ SplitView { icon.source: model ? model.image : "" icon.color: model ? model.color : "" - tag.visible: model ? model.hasTag : false - tag.text: model ? model.tagText : "" - tag.asset.name: model ? model.tagAsset : "" - tag.loading: model ? model.tagLoading : false + actionComponent: model && model.hasTag ? manageTokensCommunityTag : null + + Component { + id: manageTokensCommunityTag + ManageTokensCommunityTag { + Layout.maximumWidth: delegate.width *.4 + text: model ? model.tagText : "" + asset.name: model ? model.tagAsset : "" + loading: model ? model.tagLoading : false + } + } } } @@ -153,13 +160,13 @@ SplitView { let count = inShowcaseModelCount - inShowcaseModelItem.count; let operation = count > 0 ? (i) =>{ inShowcaseModelItem.append({ - key: Math.random() * Math.random() * Math.random() * 1000, + showcaseKey: Math.random() * Math.random() * Math.random() * 1000, title: "Item " + i, secondaryTitle: "Description " + i, hasImage: true, image: "https://picsum.photos/200/300?random=" + i, iconName: "https://picsum.photos/40/40?random=" + i, - visibility: Math.ceil(Math.random() * 3), + showcaseVisibility: Math.ceil(Math.random() * 3), name: "Test community", joined: true, isControlNode: true, @@ -181,13 +188,13 @@ SplitView { let count = hiddenModelCount - hiddenModelItem.count; let operation = count > 0 ? (i) =>{ hiddenModelItem.append({ - key: Math.random() * Math.random() * Math.random() * 1000, + showcaseKey: Math.random() * Math.random() * Math.random() * 1000, title: "Item " + i, secondaryTitle: "Description " + i, hasImage: true, image: "https://picsum.photos/200/300?random=" + i, iconName: "https://picsum.photos/40/40?random=" + i, - visibility: 0, + showcaseVisibility: 0, name: "Test community", joined: true, memberRole: Constants.memberRole.owner, diff --git a/storybook/src/Storybook/GenericListView.qml b/storybook/src/Storybook/GenericListView.qml index c8e326f35e..8782ef5d51 100644 --- a/storybook/src/Storybook/GenericListView.qml +++ b/storybook/src/Storybook/GenericListView.qml @@ -84,6 +84,8 @@ ListView { Drag.hotSpot.x: width / 2 Drag.hotSpot.y: height / 2 + anchors.fill: delegateRoot + states: State { when: dragArea.pressed @@ -117,29 +119,32 @@ ListView { drag.axis: Drag.YAxis } } - - Repeater { - model: rowModel - - Label { - readonly property var value: - delegateRoot.topModel[roleName] - - readonly property var valueSanitized: - value === undefined ? "-" : value - - readonly property bool last: index === rowModel.count - 1 - readonly property string separator: last ? "" : "," - - text: `${roleName}: ${valueSanitized}${separator}` - } - } - Loader { readonly property var model: delegateRoot.topModel sourceComponent: insetComponent } + Flow { + Layout.fillWidth: true + Layout.fillHeight: true + Repeater { + model: rowModel + + Label { + readonly property var value: + delegateRoot.topModel[roleName] + + readonly property var valueSanitized: + value === undefined ? "-" : value + + readonly property bool last: index === rowModel.count - 1 + readonly property string separator: last ? "" : "," + + text: `${roleName}: ${valueSanitized}${separator}` + } + } + } + Item { Layout.fillWidth: true } diff --git a/ui/StatusQ/src/movablemodel.cpp b/ui/StatusQ/src/movablemodel.cpp index e3e3aa981b..62983f75c2 100644 --- a/ui/StatusQ/src/movablemodel.cpp +++ b/ui/StatusQ/src/movablemodel.cpp @@ -20,8 +20,7 @@ void MovableModel::setSourceModel(QAbstractItemModel* sourceModel) disconnect(m_sourceModel, nullptr, this, nullptr); m_sourceModel = sourceModel; - connectSignalsForSyncedState(); - + syncOrder(); emit sourceModelChanged(); endResetModel(); @@ -67,68 +66,89 @@ QHash MovableModel::roleNames() const void MovableModel::desyncOrder() { - if (!m_synced || m_sourceModel == nullptr) - return; + if (m_synced) + { + m_indexes.clear(); + m_synced = false; + emit syncedChanged(); + } - disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, - &MovableModel::beginInsertRows); + if (m_sourceModel != nullptr) + { + disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, + &MovableModel::beginInsertRows); - disconnect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, - &MovableModel::endInsertRows); + disconnect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, + &MovableModel::endInsertRows); - disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, - &MovableModel::beginRemoveRows); + disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, + &MovableModel::beginRemoveRows); - disconnect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, - &MovableModel::endRemoveRows); + disconnect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, + &MovableModel::endRemoveRows); - disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, - &MovableModel::beginMoveRows); + disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, + &MovableModel::beginMoveRows); - disconnect(m_sourceModel, &QAbstractItemModel::rowsMoved, this, - &MovableModel::endMoveRows); + disconnect(m_sourceModel, &QAbstractItemModel::rowsMoved, this, + &MovableModel::endMoveRows); - disconnect(m_sourceModel, &QAbstractItemModel::dataChanged, this, - &MovableModel::syncedSourceDataChanged); + disconnect(m_sourceModel, &QAbstractItemModel::dataChanged, this, + &MovableModel::syncedSourceDataChanged); - disconnect(m_sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, - &MovableModel::sourceLayoutAboutToBeChanged); + disconnect(m_sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, + &MovableModel::sourceLayoutAboutToBeChanged); - disconnect(m_sourceModel, &QAbstractItemModel::layoutChanged, this, - &MovableModel::sourceLayoutChanged); + disconnect(m_sourceModel, &QAbstractItemModel::layoutChanged, this, + &MovableModel::sourceLayoutChanged); - connect(m_sourceModel, &QAbstractItemModel::dataChanged, this, - &MovableModel::desyncedSourceDataChanged, Qt::UniqueConnection); + connect(m_sourceModel, &QAbstractItemModel::dataChanged, this, + &MovableModel::desyncedSourceDataChanged); - connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, - &MovableModel::sourceRowsInserted, Qt::UniqueConnection); + connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, + &MovableModel::sourceRowsInserted); - connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, - &MovableModel::sourceRowsAboutToBeRemoved, Qt::UniqueConnection); + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, + &MovableModel::sourceRowsAboutToBeRemoved); - auto count = m_sourceModel->rowCount(); + auto count = m_sourceModel->rowCount(); + m_indexes.reserve(count); - m_indexes.clear(); - m_indexes.reserve(count); - - for (auto i = 0; i < count; i++) - m_indexes.emplace_back(m_sourceModel->index(i, 0)); - - m_synced = false; - emit syncedChanged(); + for (auto i = 0; i < count; i++) + m_indexes.emplace_back(m_sourceModel->index(i, 0)); + } } void MovableModel::syncOrder() { - if (m_synced || m_sourceModel == nullptr) - return; + if (m_sourceModel) + { + emit layoutAboutToBeChanged(); - emit layoutAboutToBeChanged(); + auto sourceModel = m_sourceModel; - auto sourceModel = m_sourceModel; + disconnect(m_sourceModel, nullptr, this, nullptr); + connectSignalsForSyncedState(); - resetInternalData(); - emit layoutChanged(); + for (int i = 0; i < m_indexes.size(); ++i) { + const QModelIndex idx = m_indexes[i]; + + if (i == idx.row()) + continue; + + changePersistentIndex(index(i, 0), index(idx.row(), 0)); + } + + emit layoutChanged(); + } + + + m_indexes.clear(); + if (!m_synced) + { + m_synced = true; + emit syncedChanged(); + } } void MovableModel::move(int from, int to, int count) @@ -187,26 +207,10 @@ bool MovableModel::synced() const void MovableModel::resetInternalData() { - disconnect(m_sourceModel, nullptr, this, nullptr); - connectSignalsForSyncedState(); - - for (int i = 0; i < m_indexes.size(); ++i) { - const QModelIndex idx = m_indexes[i]; - - if (i == idx.row()) - continue; - - changePersistentIndex(index(i, 0), index(idx.row(), 0)); - } - QAbstractListModel::resetInternalData(); - m_indexes.clear(); - - if (!m_synced) { - m_synced = true; - emit syncedChanged(); - } + if (!m_synced) + syncOrder(); } void MovableModel::syncedSourceDataChanged(const QModelIndex& topLeft, @@ -342,37 +346,37 @@ void MovableModel::connectSignalsForSyncedState() return; connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, - &MovableModel::beginInsertRows, Qt::UniqueConnection); + &MovableModel::beginInsertRows); connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, - &MovableModel::endInsertRows, Qt::UniqueConnection); + &MovableModel::endInsertRows); connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, - &MovableModel::beginRemoveRows, Qt::UniqueConnection); + &MovableModel::beginRemoveRows); connect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, - &MovableModel::endRemoveRows, Qt::UniqueConnection); + &MovableModel::endRemoveRows); connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, - &MovableModel::beginMoveRows, Qt::UniqueConnection); + &MovableModel::beginMoveRows); connect(m_sourceModel, &QAbstractItemModel::rowsMoved, this, - &MovableModel::endMoveRows, Qt::UniqueConnection); + &MovableModel::endMoveRows); connect(m_sourceModel, &QAbstractItemModel::dataChanged, this, - &MovableModel::syncedSourceDataChanged, Qt::UniqueConnection); + &MovableModel::syncedSourceDataChanged); connect(m_sourceModel, &QAbstractItemModel::layoutAboutToBeChanged, this, - &MovableModel::sourceLayoutAboutToBeChanged, Qt::UniqueConnection); + &MovableModel::sourceLayoutAboutToBeChanged); connect(m_sourceModel, &QAbstractItemModel::layoutChanged, this, - &MovableModel::sourceLayoutChanged, Qt::UniqueConnection); + &MovableModel::sourceLayoutChanged); connect(m_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, - &MovableModel::beginResetModel, Qt::UniqueConnection); + &MovableModel::beginResetModel); connect(m_sourceModel, &QAbstractItemModel::modelReset, this, - &MovableModel::endResetModel, Qt::UniqueConnection); + &MovableModel::endResetModel); disconnect(m_sourceModel, &QAbstractItemModel::dataChanged, this, &MovableModel::desyncedSourceDataChanged); diff --git a/ui/StatusQ/tests/tst_MovableModel.cpp b/ui/StatusQ/tests/tst_MovableModel.cpp index 1a25d2f7c7..89cfc10aeb 100644 --- a/ui/StatusQ/tests/tst_MovableModel.cpp +++ b/ui/StatusQ/tests/tst_MovableModel.cpp @@ -647,9 +647,12 @@ private slots: model.setSourceModel(sourceModel2); - QCOMPARE(signalsSpy.count(), 2); + QCOMPARE(signalsSpy.count(), 4); QCOMPARE(signalsSpy.modelAboutToBeResetSpy.count(), 1); QCOMPARE(signalsSpy.modelResetSpy.count(), 1); + QCOMPARE(signalsSpy.layoutAboutToBeChangedSpy.count(), 1); + QCOMPARE(signalsSpy.layoutChangedSpy.count(), 1); + QCOMPARE(syncedChangedSpy.count(), 1); QCOMPARE(model.synced(), true); @@ -685,7 +688,9 @@ private slots: { ModelSignalsSpy signalsSpy(&model); model.syncOrder(); - QCOMPARE(signalsSpy.count(), 0); + QCOMPARE(signalsSpy.count(), 2); + QCOMPARE(signalsSpy.layoutAboutToBeChangedSpy.count(), 1); + QCOMPARE(signalsSpy.layoutChangedSpy.count(), 1); } PersistentIndexesTester indexesTester(&model); @@ -725,7 +730,6 @@ private slots: ])"; ListModelWrapper sourceModel(engine, source); - ListModelWrapper sourceModelCopy(engine, source); QSortFilterProxyModel sfpm; sfpm.setSourceModel(sourceModel); @@ -754,6 +758,70 @@ private slots: QCOMPARE(signalsSpy.count(), signalsSpySfpm.count()); QVERIFY(indexesTester.compare()); } + + void sourceModelReset() + { + QQmlEngine engine; + + auto source = R"([ + { "name": "A", "subname": "a1" }, + { "name": "A", "subname": "a2" }, + { "name": "B", "subname": "b1" }, + { "name": "C", "subname": "c1" }, + { "name": "C", "subname": "c2" }, + { "name": "C", "subname": "c3" } + ])"; + + ListModelWrapper sourceModel(engine, source); + + QSortFilterProxyModel sfpm; + sfpm.setSourceModel(sourceModel); + + MovableModel model; + model.setSourceModel(&sfpm); + + ModelSignalsSpy signalsSpy(&model); + ModelSignalsSpy signalsSpySfpm(&sfpm); + + PersistentIndexesTester indexesTester(&model); + + sfpm.setSortRole(1); + sfpm.sort(0, Qt::DescendingOrder); + + model.move(0, 1); + + ListModelWrapper expectedSorted(engine, R"([ + { "name": "C", "subname": "c3" }, + { "name": "C", "subname": "c2" }, + { "name": "C", "subname": "c1" }, + { "name": "B", "subname": "b1" }, + { "name": "A", "subname": "a2" }, + { "name": "A", "subname": "a1" } + ])"); + + + auto source2 = R"([ + { "name": "E", "subname": "a1" }, + { "name": "F", "subname": "a2" }, + { "name": "F", "subname": "b1" }, + { "name": "G", "subname": "c1" }, + { "name": "H", "subname": "c2" }, + { "name": "H", "subname": "c3" } + ])"; + + ListModelWrapper sourceModel2(engine, source2); + sfpm.setSourceModel(sourceModel2); + sfpm.setFilterRole(0); + sfpm.setFilterFixedString("H"); + + QCOMPARE(model.rowCount(), 2); + QCOMPARE(signalsSpy.modelResetSpy.count(), 1); + QCOMPARE(signalsSpy.rowsAboutToBeRemovedSpy.count(), 1); + QCOMPARE(signalsSpy.rowsAboutToBeRemovedSpy.at(0).at(0), QModelIndex{}); + QCOMPARE(signalsSpy.rowsAboutToBeRemovedSpy.at(0).at(1), 2); + QCOMPARE(signalsSpy.rowsAboutToBeRemovedSpy.at(0).at(2), 5); + QCOMPARE(signalsSpy.rowsRemovedSpy.count(), 1); + } }; QTEST_MAIN(TestMovableModel) diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml index 9fa5555439..ad35421bee 100644 --- a/ui/app/AppLayouts/Profile/ProfileLayout.qml +++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml @@ -134,6 +134,7 @@ StatusSectionLayout { implicitHeight: parent.height leftParentLayoutMargin: d.leftMargin + walletAssetsStore: root.walletAssetsStore currencyStore: root.currencyStore walletStore: root.store.walletStore profileStore: root.store.profileStore diff --git a/ui/app/AppLayouts/Profile/controls/ProfileShowcasePanelDelegate.qml b/ui/app/AppLayouts/Profile/controls/ProfileShowcasePanelDelegate.qml index fcfd9692a1..84dbbd3609 100644 --- a/ui/app/AppLayouts/Profile/controls/ProfileShowcasePanelDelegate.qml +++ b/ui/app/AppLayouts/Profile/controls/ProfileShowcasePanelDelegate.qml @@ -18,13 +18,13 @@ ShowcaseDelegate { // required property visualIndexData readonly property var model: modelData - readonly property var key: model ? model.key : null + readonly property var key: model ? model.showcaseKey : null Drag.keys: dragKeysData dragParent: dragParentData visualIndex: visualIndexData dragAxis: Drag.YAxis - showcaseVisibility: model ? model.visibility ?? Constants.ShowcaseVisibility.NoOne : + showcaseVisibility: model ? model.showcaseVisibility ?? Constants.ShowcaseVisibility.NoOne : Constants.ShowcaseVisibility.NoOne } diff --git a/ui/app/AppLayouts/Profile/controls/ShowcaseDelegate.qml b/ui/app/AppLayouts/Profile/controls/ShowcaseDelegate.qml index 553c0ca0bc..83b2c567ed 100644 --- a/ui/app/AppLayouts/Profile/controls/ShowcaseDelegate.qml +++ b/ui/app/AppLayouts/Profile/controls/ShowcaseDelegate.qml @@ -17,7 +17,7 @@ import utils 1.0 StatusDraggableListItem { id: root - property alias tag: tagItem + property alias actionComponent: additionalActionsLoader.sourceComponent property int showcaseVisibility: Constants.ShowcaseVisibility.NoOne property bool blurState: false @@ -45,11 +45,11 @@ StatusDraggableListItem { dragAxis: Drag.XAndYAxis actions: [ - ManageTokensCommunityTag { - id: tagItem + Loader { Layout.maximumWidth: root.width *.4 - visible: false - }, + id: additionalActionsLoader + } + , StatusRoundButton { icon.name: ProfileUtils.visibilityIcon(root.showcaseVisibility) Layout.preferredWidth: 58 diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml index 7b1536e93e..349206ef2d 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml @@ -34,13 +34,28 @@ QObject { /** * Returns dirty state of the showcase model. */ - readonly property bool dirty: writable.dirty || !visibleModel.synced || !hiddenModel.synced + readonly property bool dirty: writable.dirty || !visibleModel.synced function revert() { + visible.syncOrder() writable.revert() } function currentState() { + if (visibleModel.synced) { + return writable.currentState() + } + const newOrder = visible.order() + let writableIndexes = [] + + for (var i = 0; i < newOrder.length; i++) { + writableIndexes.push(visibleSFPM.mapFromSource(newOrder[i])) + } + + for (var i = 0; i < newOrder.length; i++) { + writable.set(writableIndexes[i], { "showcasePosition": i}) + } + return writable.currentState() } @@ -58,11 +73,11 @@ QObject { component HiddenFilter: AnyOf { UndefinedFilter { - roleName: "visibility" + roleName: "showcaseVisibility" } ValueFilter { - roleName: "visibility" + roleName: "showcaseVisibility" value: Constants.ShowcaseVisibility.NoOne } } @@ -70,7 +85,7 @@ QObject { LeftJoinModel { id: joined - joinRole: "key" + joinRole: "showcaseKey" } VisibilityAndPositionDirtyStateModel { @@ -87,7 +102,7 @@ QObject { delayed: true filters: HiddenFilter { inverted: true } - sorters: RoleSorter { roleName: "position" } + sorters: RoleSorter { roleName: "showcasePosition" } } MovableModel { @@ -97,17 +112,11 @@ QObject { } SortFilterProxyModel { - id: hiddenSFPM + id: hidden sourceModel: writable delayed: true filters: HiddenFilter {} } - - MovableModel { - id: hidden - - sourceModel: hiddenSFPM - } } diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml index d13603679a..eef90b8701 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml @@ -8,55 +8,52 @@ import SortFilterProxyModel 0.2 QObject { id: root - // input models - property alias communitiesSourceModel: communityRenamingSource.sourceModel - property alias communitiesShowcaseModel: communityRenamingShowcase.sourceModel + // Communities input models + property alias communitiesSourceModel: communitySFPM.sourceModel + property alias communitiesShowcaseModel: communityShowcaseRenaming.sourceModel // adapted models - readonly property alias adaptedCommunitiesSourceModel: communityRenamingSource - readonly property alias adaptedCommunitiesShowcaseModel: communityRenamingShowcase + readonly property alias adaptedCommunitiesSourceModel: communitySFPM + readonly property alias adaptedCommunitiesShowcaseModel: communityShowcaseRenaming - // input models - property alias accountsSourceModel: accountsRenamingSource.sourceModel + // Accounts input models + property alias accountsSourceModel: accountsSFPM.sourceModel property alias accountsShowcaseModel: accountsRenamingShowcase.sourceModel // adapted models - readonly property alias adaptedAccountsSourceModel: accountsRenamingSource + readonly property alias adaptedAccountsSourceModel: accountsSFPM readonly property alias adaptedAccountsShowcaseModel: accountsRenamingShowcase - // input models - property alias collectiblesSourceModel: collectiblesRenamingSource.sourceModel + // Collectibles input models + property alias collectiblesSourceModel: collectiblesSFPM.sourceModel property alias collectiblesShowcaseModel: collectiblesRenamingShowcase.sourceModel // adapted models - readonly property alias adaptedCollectiblesSourceModel: collectiblesRenamingSource + readonly property alias adaptedCollectiblesSourceModel: collectiblesSFPM readonly property alias adaptedCollectiblesShowcaseModel: collectiblesRenamingShowcase - RolesRenamingModel { - id: communityRenamingSource - mapping: [ - RoleRename { - from: "id" - to: "key" + SortFilterProxyModel { + id: communitySFPM + proxyRoles: [ + FastExpressionRole { + name: "showcaseKey" + expression: model.id + expectedRoles: ["id"] } ] } RolesRenamingModel { - id: communityRenamingShowcase + id: communityShowcaseRenaming mapping: [ RoleRename { from: "id" - to: "key" + to: "showcaseKey" }, RoleRename { from: "order" - to: "position" - }, - RoleRename { - from: "showcaseVisibility" - to: "visibility" + to: "showcasePosition" }, // Removing model duplicates // TODO: remove this when the lightweigth model is used @@ -92,35 +89,27 @@ QObject { ] } - RolesRenamingModel { - id: accountsRenamingSource - mapping: [ - RoleRename { - from: "address" - to: "key" - }, - RoleRename { - from: "position" - to: "positions" + SortFilterProxyModel { + id: accountsSFPM + proxyRoles: [ + FastExpressionRole { + name: "showcaseKey" + expression: model.address + expectedRoles: ["address"] } ] } - RolesRenamingModel { id: accountsRenamingShowcase mapping: [ RoleRename { from: "address" - to: "key" + to: "showcaseKey" }, RoleRename { from: "order" - to: "position" - }, - RoleRename { - from: "showcaseVisibility" - to: "visibility" + to: "showcasePosition" }, // Removing model duplicates // TODO: remove this when the lightweigth model is used @@ -140,33 +129,27 @@ QObject { ] } - RolesRenamingModel { - id: collectiblesRenamingSource - sourceModel: root.collectiblesSourceModel - mapping: [ - RoleRename { - from: "uid" - to: "key" + SortFilterProxyModel { + id: collectiblesSFPM + proxyRoles: [ + FastExpressionRole { + name: "showcaseKey" + expression: model.uid + expectedRoles: ["uid"] } ] } RolesRenamingModel { id: collectiblesRenamingShowcase - sourceModel: root.collectiblesShowcaseModel - mapping: [ RoleRename { from: "uid" - to: "key" + to: "showcaseKey" }, RoleRename { from: "order" - to: "position" - }, - RoleRename { - from: "showcaseVisibility" - to: "visibility" + to: "showcasePosition" }, // Removing model duplicates // TODO: remove this when the lightweigth model is used diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml index 723480e68a..4d687c88fd 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml @@ -131,16 +131,20 @@ QObject { // singletons cannot be used in expressions readonly property int hidden: Constants.ShowcaseVisibility.NoOne - expression: { + function getMaxVisibility(ownershipModel) { const visibilityMap = root.accountsVisibilityMap - const accounts = model.accounts.split(":") - const visibilities = accounts.map(a => visibilityMap[a]).filter( + const accounts = ModelUtils.modelToFlatArray(ownershipModel, "accountAddress") + const visibilities = accounts.map(a => visibilityMap[a.toLowerCase()]).filter( v => v !== undefined) return visibilities.length ? Math.min(...visibilities) : hidden } - expectedRoles: ["accounts"] + expression: { + return getMaxVisibility(model.ownership) + } + + expectedRoles: ["ownership"] } filters: ValueFilter { @@ -160,13 +164,13 @@ QObject { function updateAccountsList() { const keysAndVisibility = ModelUtils.modelToArray( - accounts.visibleModel, ["key", "visibility"]) + accounts.visibleModel, ["showcaseKey", "showcaseVisibility"]) - visibleAccountsList = keysAndVisibility.map(e => e.key) + visibleAccountsList = keysAndVisibility.map(e => e.showcaseKey) accountsVisibilityMap = keysAndVisibility.reduce( (acc, val) => Object.assign( - acc, {[val.key]: val.visibility}), {}) + acc, {[val.showcaseKey]: val.showcaseVisibility}), {}) } function onDataChanged() { diff --git a/ui/app/AppLayouts/Profile/helpers/VisibilityAndPositionDirtyStateModel.qml b/ui/app/AppLayouts/Profile/helpers/VisibilityAndPositionDirtyStateModel.qml index 086174e00d..385417648e 100644 --- a/ui/app/AppLayouts/Profile/helpers/VisibilityAndPositionDirtyStateModel.qml +++ b/ui/app/AppLayouts/Profile/helpers/VisibilityAndPositionDirtyStateModel.qml @@ -23,9 +23,9 @@ WritableProxyModel { /* Provides the list of objects representing the current state in the * in the following format: * [ { - * key: - * position: - * visibility: + * showcaseKey: + * showcasePosition: + * showcaseVisibility: * } * ] * @@ -33,9 +33,9 @@ WritableProxyModel { */ function currentState() { const visible = d.getVisibleEntries() - const minPos = Math.min(...visible.map(e => e.position)) + const minPos = Math.min(...visible.map(e => e.showcasePosition)) - return visible.map(e => { e.position -= minPos; return e }) + return visible.map(e => { e.showcasePosition -= minPos; return e }) } /* Sets the visibility of the given item. If the element was hidden, it is @@ -51,33 +51,33 @@ WritableProxyModel { // hiding, changing visibility level if (visibility === visibilityHidden || oldVisibility !== visibilityHidden) { - set(sourceIdx, { visibility: visibility }) + set(sourceIdx, { showcaseVisibility: visibility }) return } // unhiding - const positions = d.getVisibleEntries().map(e => e.position) + const positions = d.getVisibleEntries().map(e => e.showcasePosition) const position = Math.max(-1, ...positions) + 1 - set(sourceIdx, { visibility, position }) + set(sourceIdx, { showcaseVisibility: visibility, showcasePosition: position }) } readonly property QtObject d_: QtObject { id: d function indexByKey(key) { - return ModelUtils.indexOf(root, "key", key) + return ModelUtils.indexOf(root, "showcaseKey", key) } function getVisibleEntries() { - const roles = ["key", "position", "visibility"] + const roles = ["showcaseKey", "showcasePosition", "showcaseVisibility"] const keysAndPos = ModelUtils.modelToArray(root, roles) - return keysAndPos.filter(p => p.visibility - && p.visibility !== root.visibilityHidden) + return keysAndPos.filter(p => p.showcaseVisibility + && p.showcaseVisibility !== root.visibilityHidden) } function getVisibility(idx) { - return ModelUtils.get(root, idx, "visibility") + return ModelUtils.get(root, idx, "showcaseVisibility") || root.visibilityHidden } } diff --git a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAccountsPanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAccountsPanel.qml index d545c5cfae..d33c15111c 100644 --- a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAccountsPanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAccountsPanel.qml @@ -17,11 +17,11 @@ ProfileShowcasePanel { delegate: ProfileShowcasePanelDelegate { title: model ? model.name : "" - secondaryTitle: WalletUtils.addressToDisplay(model ? model.key : "", "", true, containsMouse) + secondaryTitle: WalletUtils.addressToDisplay(model ? model.address ?? "" : "", "", true, containsMouse) hasEmoji: model && !!model.emoji hasIcon: !hasEmoji icon.name: hasEmoji ? model.emoji : "filled-account" icon.color: model && model.colorId ? Utils.getColorForId(model.colorId) : Theme.palette.primaryColor3 - highlighted: model ? model.key === root.currentWallet : false + highlighted: model ? model.address === root.currentWallet : false } } diff --git a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAssetsPanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAssetsPanel.qml index 02e9902962..167c8ab64c 100644 --- a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAssetsPanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAssetsPanel.qml @@ -24,7 +24,7 @@ ProfileShowcasePanel { delegate: ProfileShowcasePanelDelegate { - property double totalValue: !!model && !!model.decimals ? balancesAggregator.value/(10 ** model.decimals): 0 + readonly property double totalValue: !!model && !!model.decimals ? balancesAggregator.value/(10 ** model.decimals): 0 title: !!model && !!model.name ? model.name : "" secondaryTitle: !!model && !!model.enabledNetworkBalance ? diff --git a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseCollectiblesPanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseCollectiblesPanel.qml index 7e75e4ccdf..b229300f59 100644 --- a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseCollectiblesPanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseCollectiblesPanel.qml @@ -8,6 +8,7 @@ import utils 1.0 import shared.panels 1.0 import AppLayouts.Profile.controls 1.0 +import AppLayouts.Wallet.controls 1.0 ProfileShowcasePanel { id: root @@ -30,10 +31,16 @@ ProfileShowcasePanel { bgRadius: Style.current.radius assetBgColor: !!model && !!model.backgroundColor ? model.backgroundColor : "transparent" - tag.visible: model && !!model.communityId - tag.text: model && !!model.communityName ? model.communityName : "" - tag.asset.name: model && !!model.communityImage ? model.communityImage : "" - tag.loading: model && !!model.communityImageLoading ? model.communityImageLoading : false + actionComponent: model && !!model.communityId ? communityTokenTagComponent : null + + Component { + id: communityTokenTagComponent + ManageTokensCommunityTag { + text: model && !!model.communityName ? model.communityName : "" + asset.name: model && !!model.communityImage ? model.communityImage : "" + loading: model && !!model.communityImageLoading ? model.communityImageLoading : false + } + } } Component { diff --git a/ui/app/AppLayouts/Profile/panels/ProfileShowcasePanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileShowcasePanel.qml index 323e0ef41c..882c6c069c 100644 --- a/ui/app/AppLayouts/Profile/panels/ProfileShowcasePanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ProfileShowcasePanel.qml @@ -131,8 +131,6 @@ DoubleFlickableWithFolding { rightInset: 1 text: qsTr("Hide") dropAreaKeys: d.dragShowcaseItemKey - - onDropped: root.setVisibilityRequested(drop.source.key, visibility) } onToggleFolding: root.flip2Folding() @@ -158,8 +156,6 @@ DoubleFlickableWithFolding { height: ProfileUtils.defaultDelegateHeight - Style.current.padding text: qsTr("Hide") dropAreaKeys: d.dragShowcaseItemKey - - onDropped: root.setVisibilityRequested(drop.source.key, visibility) } } } @@ -172,8 +168,6 @@ DoubleFlickableWithFolding { property int showcaseVisibility: Constants.ShowcaseVisibility.NoOne property var dropAreaKeys - signal dropped(var drop, int visibility) - padding: Style.current.halfPadding spacing: padding/2 @@ -194,7 +188,7 @@ DoubleFlickableWithFolding { } onDropped: function(drop) { - visibilityDropAreaButton.dropped(drop, visibilityDropAreaButton.showcaseVisibility) + root.setVisibilityRequested(drop.source.key, visibilityDropAreaButton.showcaseVisibility) } } } @@ -232,10 +226,6 @@ DoubleFlickableWithFolding { readonly property bool verifiedContainsDrag: dropAreaVerified.containsDrag property int margins: Style.current.halfPadding - function dropped(drop, visibility) { - root.setVisibilityRequested(drop.source.key, visibility) - } - RowLayout { anchors.fill: parent anchors.margins: visibilityDropAreaRow.margins @@ -248,8 +238,6 @@ DoubleFlickableWithFolding { showcaseVisibility: Constants.ShowcaseVisibility.Everyone text: qsTr("Everyone") dropAreaKeys: d.dragHiddenItemKey - - onDropped: visibilityDropAreaRow.dropped(drop, visibility) } VisibilityDropAreaButton { @@ -259,8 +247,6 @@ DoubleFlickableWithFolding { showcaseVisibility: Constants.ShowcaseVisibility.Contacts text: qsTr("Contacts") dropAreaKeys: d.dragHiddenItemKey - - onDropped: visibilityDropAreaRow.dropped(drop, visibility) } VisibilityDropAreaButton { @@ -270,8 +256,6 @@ DoubleFlickableWithFolding { showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts text: qsTr("Verified") dropAreaKeys: d.dragHiddenItemKey - - onDropped: visibilityDropAreaRow.dropped(drop, visibility) } } } @@ -292,7 +276,7 @@ DoubleFlickableWithFolding { required property var model required property int index readonly property int visualIndex: index - readonly property bool isHiddenShowcaseItem: !model.visibility || model.visibility === Constants.ShowcaseVisibility.NoOne + readonly property bool isHiddenShowcaseItem: !model.showcaseVisibility || model.showcaseVisibility === Constants.ShowcaseVisibility.NoOne function handleEntered(drag) { if (!showcaseDelegateRoot.isHiddenShowcaseItem) { @@ -337,7 +321,7 @@ DoubleFlickableWithFolding { sourceComponent: root.delegate onItemChanged: { if (item) { - item.showcaseVisibilityRequested.connect((toVisibility) => root.setVisibilityRequested(showcaseDelegateRoot.model.key, toVisibility)) + item.showcaseVisibilityRequested.connect((toVisibility) => root.setVisibilityRequested(showcaseDelegateRoot.model.showcaseKey, toVisibility)) } } } @@ -364,16 +348,6 @@ DoubleFlickableWithFolding { visible: showcaseDraggableDelegateLoader.item && showcaseDraggableDelegateLoader.item.dragActive } - - // Delegate shadow background when dragging: - Rectangle { - width: parent.width - height: d.defaultDelegateHeight - anchors.centerIn: parent - color: Theme.palette.baseColor5 - radius: Style.current.radius - visible: showcaseShadow.visible - } } } } diff --git a/ui/app/AppLayouts/Profile/views/MyProfileView.qml b/ui/app/AppLayouts/Profile/views/MyProfileView.qml index 067f6ba26a..4a4bd66c89 100644 --- a/ui/app/AppLayouts/Profile/views/MyProfileView.qml +++ b/ui/app/AppLayouts/Profile/views/MyProfileView.qml @@ -32,6 +32,7 @@ SettingsContentBase { property PrivacyStore privacyStore property ContactsStore contactsStore property NetworkConnectionStore networkConnectionStore + required property WalletAssetsStore walletAssetsStore required property CurrenciesStore currencyStore property var communitiesModel @@ -49,6 +50,7 @@ SettingsContentBase { Communities = 1, Accounts = 2, Collectibles = 3, + //Assets = 4, Web = 4 } @@ -102,6 +104,13 @@ SettingsContentBase { text: qsTr("Collectibles") } + // TODO: Uncomment when assets tab is implemented + // StatusTabButton { + // objectName: "assetsTabButton" + // width: implicitWidth + // text: qsTr("Assets") + // } + StatusTabButton { objectName: "webTabButton" width: implicitWidth @@ -231,13 +240,12 @@ SettingsContentBase { // collectibles ProfileShowcaseCollectiblesPanel { id: profileShowcaseCollectiblesPanel - - addAccountsButtonVisible: priv.showcaseModels.accountsHiddenModel > 0 - onNavigateToAccountsTab: profileTabBar.currentIndex = MyProfileView.TabIndex.Accounts - inShowcaseModel: priv.showcaseModels.collectiblesVisibleModel hiddenModel: priv.showcaseModels.collectiblesHiddenModel - + addAccountsButtonVisible: priv.showcaseModels.accountsHiddenModel.count > 0 + + onNavigateToAccountsTab: profileTabBar.currentIndex = MyProfileView.TabIndex.Accounts + onChangePositionRequested: function (from, to) { priv.showcaseModels.changeCollectiblePosition(from, to) } @@ -247,6 +255,22 @@ SettingsContentBase { } } + // assets + // TODO: Integrate the assets tab with the new backend + // ProfileShowcaseAssetsPanel { + // id: profileShowcaseAssetsPanel + + // baseModel: root.walletAssetsStore.groupedAccountAssetsModel // TODO: instantiate an assets model in profile module + // showcaseModel: root.profileStore.profileShowcaseAssetsModel + // addAccountsButtonVisible: root.profileStore.profileShowcaseAccountsModel.hiddenCount > 0 + // formatCurrencyAmount: function(amount, symbol) { + // return root.currencyStore.formatCurrencyAmount(amount, symbol) + // } + + // onShowcaseEntryChanged: priv.hasAnyProfileShowcaseChanges = true + // onNavigateToAccountsTab: profileTabBar.currentIndex = MyProfileView.TabIndex.Accounts + // } + // web ProfileSocialLinksPanel { profileStore: root.profileStore diff --git a/ui/imports/shared/views/ProfileDialogView.qml b/ui/imports/shared/views/ProfileDialogView.qml index fdc0dc9a1c..b294ce5bad 100644 --- a/ui/imports/shared/views/ProfileDialogView.qml +++ b/ui/imports/shared/views/ProfileDialogView.qml @@ -598,6 +598,10 @@ Pane { width: implicitWidth text: qsTr("Collectibles") } + // StatusTabButton { + // width: implicitWidth + // text: qsTr("Assets") + // } } // Profile Showcase