From 2e29e847acf14ac8d44b9d724f44e935f1d3853e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cie=C5=9Blak?= Date: Fri, 26 Jan 2024 15:39:42 +0000 Subject: [PATCH] chore(WalletSettings): Use DoubleFlickable for assets/collectibles tabs in manage tokens It provides visual alignments to the current design and also significantly improves performance because ListView components are not "unrolled" causing instantiation of too many delegates. Closes: #12703 Closes: #13043 --- storybook/pages/ManageAssetsPanelPage.qml | 49 ++-- .../pages/ManageCollectiblesPanelPage.qml | 21 +- storybook/pages/ManageHiddenPanelPage.qml | 43 ++- .../tests/tst_ManageCollectiblesPanel.qml | 195 ++++++------ .../src/StatusQ/Controls/StatusSwitch.qml | 8 +- .../Profile/views/SettingsContentBase.qml | 7 +- .../AppLayouts/Profile/views/WalletView.qml | 4 + .../Profile/views/wallet/ManageTokensView.qml | 277 +++++++++--------- .../Wallet/controls/ManageTokensDelegate.qml | 3 +- .../controls/ManageTokensGroupDelegate.qml | 2 +- .../Wallet/panels/ManageAssetsPanel.qml | 147 +++++----- .../Wallet/panels/ManageCollectiblesPanel.qml | 229 +++++++-------- .../Wallet/panels/ManageHiddenPanel.qml | 40 ++- .../panels/internals/FoldableHeader.qml | 64 ++++ .../internals/ManageTokensListViewBase.qml | 51 ++++ 15 files changed, 639 insertions(+), 501 deletions(-) create mode 100644 ui/app/AppLayouts/Wallet/panels/internals/FoldableHeader.qml create mode 100644 ui/app/AppLayouts/Wallet/panels/internals/ManageTokensListViewBase.qml diff --git a/storybook/pages/ManageAssetsPanelPage.qml b/storybook/pages/ManageAssetsPanelPage.qml index c3c73b1e04..f3bd389b8d 100644 --- a/storybook/pages/ManageAssetsPanelPage.qml +++ b/storybook/pages/ManageAssetsPanelPage.qml @@ -24,33 +24,32 @@ SplitView { assetsWithFilteredBalances: groupedAccountsAssetsModel } - StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml + ManageAssetsPanel { + id: showcasePanel + SplitView.fillWidth: true SplitView.fillHeight: true - Component.onCompleted: forceActiveFocus() - ManageAssetsPanel { - id: showcasePanel - width: 500 - getCurrencyAmount: function (balance, symbol) { - return ({ - amount: balance, - symbol: symbol, - displayDecimals: 2, - stripTrailingZeroes: false - }) - } - getCurrentCurrencyAmount: function (balance) { - return ({ - amount: balance, - symbol: "USD", - displayDecimals: 2, - stripTrailingZeroes: false - }) - } - controller: ManageTokensController { - sourceModel: ctrlEmptyModel.checked ? null : walletAssetStore.groupedAccountAssetsModel - settingsKey: "WalletAssets" - } + + getCurrencyAmount: function (balance, symbol) { + return ({ + amount: balance, + symbol: symbol, + displayDecimals: 2, + stripTrailingZeroes: false + }) + } + getCurrentCurrencyAmount: function (balance) { + return ({ + amount: balance, + symbol: "USD", + displayDecimals: 2, + stripTrailingZeroes: false + }) + } + + controller: ManageTokensController { + sourceModel: ctrlEmptyModel.checked ? null : walletAssetStore.groupedAccountAssetsModel + settingsKey: "WalletAssets" } } diff --git a/storybook/pages/ManageCollectiblesPanelPage.qml b/storybook/pages/ManageCollectiblesPanelPage.qml index c67c7260fd..f078dfbae0 100644 --- a/storybook/pages/ManageCollectiblesPanelPage.qml +++ b/storybook/pages/ManageCollectiblesPanelPage.qml @@ -35,17 +35,15 @@ SplitView { ] } - StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml + ManageCollectiblesPanel { + id: showcasePanel + SplitView.fillWidth: true SplitView.fillHeight: true - Component.onCompleted: forceActiveFocus() - ManageCollectiblesPanel { - id: showcasePanel - width: 500 - controller: ManageTokensController { - sourceModel: renamedModel - settingsKey: "WalletCollectibles" - } + + controller: ManageTokensController { + sourceModel: renamedModel + settingsKey: "WalletCollectibles" } } @@ -94,7 +92,4 @@ SplitView { } // category: Panels -// https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?type=design&node-id=19341-250476&mode=design&t=jR53lJ7aDzVHE4hZ-0 -// https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?type=design&node-id=19655-204534&mode=design&t=jR53lJ7aDzVHE4hZ-0 -// https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?type=design&node-id=19622-173583&mode=design&t=jR53lJ7aDzVHE4hZ-0 -// https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?type=design&node-id=19622-179146&mode=design&t=jR53lJ7aDzVHE4hZ-0 +// https://www.figma.com/file/eM26pyHZUeAwMLviaS1KJn/%E2%9A%99%EF%B8%8F-Wallet-Settings%3A-Manage-Tokens diff --git a/storybook/pages/ManageHiddenPanelPage.qml b/storybook/pages/ManageHiddenPanelPage.qml index 9fa00de559..cbd8fe1d31 100644 --- a/storybook/pages/ManageHiddenPanelPage.qml +++ b/storybook/pages/ManageHiddenPanelPage.qml @@ -52,33 +52,30 @@ SplitView { settingsKey: "WalletCollectibles" } - StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml + ManageHiddenPanel { + id: showcasePanel + SplitView.fillWidth: true SplitView.fillHeight: true - Component.onCompleted: forceActiveFocus() - ManageHiddenPanel { - id: showcasePanel - width: 500 - assetsController: assetsController - collectiblesController: collectiblesController + assetsController: assetsController + collectiblesController: collectiblesController - getCurrencyAmount: function (balance, symbol) { - return ({ - amount: balance, - symbol: symbol, - displayDecimals: 2, - stripTrailingZeroes: false - }) - } - getCurrentCurrencyAmount: function (balance) { - return ({ - amount: balance, - symbol: "USD", - displayDecimals: 2, - stripTrailingZeroes: false - }) - } + getCurrencyAmount: function (balance, symbol) { + return ({ + amount: balance, + symbol: symbol, + displayDecimals: 2, + stripTrailingZeroes: false + }) + } + getCurrentCurrencyAmount: function (balance) { + return ({ + amount: balance, + symbol: "USD", + displayDecimals: 2, + stripTrailingZeroes: false + }) } } diff --git a/storybook/qmlTests/tests/tst_ManageCollectiblesPanel.qml b/storybook/qmlTests/tests/tst_ManageCollectiblesPanel.qml index 92a3539135..f6a31cdef6 100644 --- a/storybook/qmlTests/tests/tst_ManageCollectiblesPanel.qml +++ b/storybook/qmlTests/tests/tst_ManageCollectiblesPanel.qml @@ -12,7 +12,7 @@ import utils 1.0 Item { id: root width: 600 - height: 400 + height: 2000 ManageCollectiblesModel { id: collectiblesModel @@ -33,6 +33,7 @@ Item { id: componentUnderTest ManageCollectiblesPanel { width: 500 + height: contentItem.contentHeight controller: ManageTokensController { sourceModel: renamedModel settingsKey: "WalletCollectibles" @@ -59,7 +60,7 @@ Item { property ManageCollectiblesPanel controlUnderTest: null function findDelegateIndexWithTitle(listview, title) { - waitForItemPolished(listview) + waitForRendering(listview) const count = listview.count for (let i = 0; i < count; i++) { const item = listview.itemAtIndex(i) @@ -74,9 +75,12 @@ Item { verify(!!token) const delegateBtn = findChild(token, "btnManageTokenMenu-%1".arg(index)) verify(!!delegateBtn) + + waitForItemPolished(delegateBtn) mouseClick(delegateBtn) const btnMenuLoader = findChild(delegateBtn, "manageTokensContextMenuLoader") verify(!!btnMenuLoader) + tryCompare(btnMenuLoader, "active", true) const btnMenu = btnMenuLoader.item verify(!!btnMenu) @@ -92,105 +96,120 @@ Item { function init() { controlUnderTest = createTemporaryObject(componentUnderTest, root) - controlUnderTest.clearSettings() notificationSpy.clear() } + function cleanup() { + controlUnderTest.clearSettings() + } + function test_showHideSingleToken() { + waitForItemPolished(controlUnderTest) verify(!controlUnderTest.dirty) - const lvRegular = findChild(controlUnderTest, "lvRegularTokens") - verify(!!lvRegular) - const lvRegularCount = lvRegular.count - verify(lvRegularCount === 7) + const lvOther = findChild(controlUnderTest, "otherTokensListView") + verify(!!lvOther) - const delegate0 = findChild(lvRegular, "manageTokensDelegate-0") + tryCompare(lvOther, "count", 7) + const delegate0 = findChild(lvOther, "manageTokensDelegate-0") verify(!!delegate0) const title = delegate0.title tryCompare(notificationSpy, "count", 0) - triggerDelegateMenuAction(lvRegular, 0, "miHideCollectionToken") + triggerDelegateMenuAction(lvOther, 0, "miHideCollectionToken") // verify the signal to show the notification toast got fired tryCompare(notificationSpy, "count", 1) // verify we now have -1 regular tokens after the "hide" operation - tryCompare(lvRegular, "count", lvRegularCount-1) + tryCompare(lvOther, "count", 6) } function test_showHideCommunityGroup() { verify(!controlUnderTest.dirty) - const loaderCommunityTokens = findChild(controlUnderTest, "loaderCommunityTokens") - verify(!!loaderCommunityTokens) - tryCompare(loaderCommunityTokens, "active", true) - const switchArrangeByCommunity = findChild(controlUnderTest, "switchArrangeByCommunity") + const communityHeader = findChild(controlUnderTest, "communityHeader") + verify(!!communityHeader) + const switchArrangeByCommunity = findChild(communityHeader, "switch") verify(!!switchArrangeByCommunity) - switchArrangeByCommunity.toggle() - const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups") - verify(!!lvCommunityTokenGroups) + + waitForRendering(switchArrangeByCommunity) + mouseClick(switchArrangeByCommunity) + tryCompare(switchArrangeByCommunity, "checked", true) + + tryCompare(controlUnderTest.controller, "arrangeByCommunity", true) + + waitForRendering(controlUnderTest) + const lvCommunity = findChild(controlUnderTest, "communityTokensListView") + verify(!!lvCommunity) // verify we have 2 community collectible groups - tryCompare(lvCommunityTokenGroups, "count", 3) + tryCompare(lvCommunity, "count", 3) tryCompare(notificationSpy, "count", 0) - triggerDelegateMenuAction(lvCommunityTokenGroups, 0, "miHideTokenGroup", true) + triggerDelegateMenuAction(lvCommunity, 0, "miHideTokenGroup", true) // verify the signal to show the notification toast got fired tryCompare(notificationSpy, "count", 1) // verify we have one less group - waitForItemPolished(lvCommunityTokenGroups) - tryCompare(lvCommunityTokenGroups, "count", 2) + waitForItemPolished(lvCommunity) + tryCompare(lvCommunity, "count", 2) } function test_dnd() { verify(!controlUnderTest.dirty) - const lvRegular = findChild(controlUnderTest, "lvRegularTokens") - verify(!!lvRegular) - verify(lvRegular.count !== 0) + const lvOther = findChild(controlUnderTest, "otherTokensListView") + verify(!!lvOther) + verify(lvOther.count !== 0) - const delegate0 = findChild(lvRegular, "manageTokensDelegate-0") + const delegate0 = findChild(lvOther, "manageTokensDelegate-0") verify(!!delegate0) const title0 = delegate0.title verify(!!title0) - const title1 = findChild(lvRegular, "manageTokensDelegate-1").title + const delegate1 = findChild(lvOther, "manageTokensDelegate-1") + const title1 = delegate1.title verify(!!title1) - // DND one item down (~80px in height) - mouseDrag(delegate0, delegate0.width/2, delegate0.height/2, 0, 80) + waitForRendering(delegate1) + + // DND one item up + mouseDrag(delegate1, delegate1.width/2, delegate1.height/2, 0, -delegate1.height) // cross compare the titles - tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", title1) - tryCompare(findChild(lvRegular, "manageTokensDelegate-1"), "title", title0) + tryCompare(findChild(lvOther, "manageTokensDelegate-0"), "title", title1) + tryCompare(findChild(lvOther, "manageTokensDelegate-1"), "title", title0) verify(controlUnderTest.dirty) } function test_group_dnd() { verify(!controlUnderTest.dirty) - const switchArrangeByCommunity = findChild(controlUnderTest, "switchArrangeByCommunity") + const communityHeader = findChild(controlUnderTest, "communityHeader") + verify(!!communityHeader) + const switchArrangeByCommunity = findChild(communityHeader, "switch") verify(!!switchArrangeByCommunity) + + waitForItemPolished(switchArrangeByCommunity) mouseClick(switchArrangeByCommunity) - const loaderCommunityTokens = findChild(controlUnderTest, "loaderCommunityTokens") - verify(!!loaderCommunityTokens) - tryCompare(loaderCommunityTokens, "active", true) - const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups") - verify(!!lvCommunityTokenGroups) - waitForItemPolished(lvCommunityTokenGroups) - tryCompare(lvCommunityTokenGroups, "count", 3) + const lvCommunity = findChild(controlUnderTest, "communityTokensListView") + verify(!!lvCommunity) + waitForItemPolished(lvCommunity) + tryCompare(lvCommunity, "count", 3) - const group0 = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0") + const group0 = findChild(lvCommunity, "manageTokensGroupDelegate-0") const title0 = group0.title verify(!!title0) - const title1 = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1").title + const group1 = findChild(lvCommunity, "manageTokensGroupDelegate-1") + const title1 = group1.title verify(!!title1) verify(title0 !== title1) - // DND one group down (~80px in height) - mouseDrag(group0, group0.width/2, group0.height/2, 0, 80) + waitForRendering(group1) + + mouseDrag(group1, group1.width/2, group1.height/2, 0, -group1.height) // cross compare the titles - tryCompare(findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0"), "title", title1) - tryCompare(findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1"), "title", title0) + tryCompare(findChild(lvCommunity, "manageTokensGroupDelegate-0"), "title", title1) + tryCompare(findChild(lvCommunity, "manageTokensGroupDelegate-1"), "title", title0) verify(controlUnderTest.dirty) } @@ -199,101 +218,101 @@ Item { verify(!controlUnderTest.dirty) const titleToTest = "Bearz" - const switchArrangeByCommunity = findChild(controlUnderTest, "switchArrangeByCommunity") + const communityHeader = findChild(controlUnderTest, "communityHeader") + verify(!!communityHeader) + const switchArrangeByCommunity = findChild(communityHeader, "switch") verify(!!switchArrangeByCommunity) + waitForRendering(switchArrangeByCommunity) mouseClick(switchArrangeByCommunity) - const loaderCommunityTokens = findChild(controlUnderTest, "loaderCommunityTokens") - verify(!!loaderCommunityTokens) - tryCompare(loaderCommunityTokens, "active", true) - const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups") - verify(!!lvCommunityTokenGroups) - waitForItemPolished(lvCommunityTokenGroups) - tryCompare(lvCommunityTokenGroups, "count", 3) + const lvCommunity = findChild(controlUnderTest, "communityTokensListView") + verify(!!lvCommunity) + waitForItemPolished(lvCommunity) + tryCompare(lvCommunity, "count", 3) // get the "Bearz" group at index 1 - var bearzGroupTokenDelegate = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1") + var bearzGroupTokenDelegate = findChild(lvCommunity, "manageTokensGroupDelegate-1") const bearzTitle = bearzGroupTokenDelegate.title compare(bearzTitle, titleToTest) verify(!!bearzGroupTokenDelegate) waitForItemPolished(bearzGroupTokenDelegate) // now move the Bearz group up so that it's first (ends up at index 0) - waitForItemPolished(lvCommunityTokenGroups) - triggerDelegateMenuAction(lvCommunityTokenGroups, 1, "miMoveUp", true) + waitForItemPolished(lvCommunity) + triggerDelegateMenuAction(lvCommunity, 1, "miMoveUp", true) verify(controlUnderTest.dirty) - bearzGroupTokenDelegate = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0") + bearzGroupTokenDelegate = findChild(lvCommunity, "manageTokensGroupDelegate-0") verify(!!bearzGroupTokenDelegate) // finally verify that the Bearz group is still at top - waitForItemPolished(lvCommunityTokenGroups) - tryCompare(findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0"), "title", titleToTest) + waitForItemPolished(lvCommunity) + tryCompare(findChild(lvCommunity, "manageTokensGroupDelegate-0"), "title", titleToTest) } function test_moveOperations() { verify(!controlUnderTest.dirty) - const lvRegular = findChild(controlUnderTest, "lvRegularTokens") - verify(!!lvRegular) - verify(lvRegular.count !== 0) + const lvOther = findChild(controlUnderTest, "otherTokensListView") + verify(!!lvOther) + verify(lvOther.count !== 0) - var delegate0 = findChild(lvRegular, "manageTokensDelegate-0") + var delegate0 = findChild(lvOther, "manageTokensDelegate-0") verify(!!delegate0) const title = delegate0.title // verify moveUp and moveToTop is not available for the first item - const moveUpAction = findDelegateMenuAction(lvRegular, 0, "miMoveUp") + const moveUpAction = findDelegateMenuAction(lvOther, 0, "miMoveUp") tryCompare(moveUpAction, "enabled", false) - const moveTopAction = findDelegateMenuAction(lvRegular, 0, "miMoveToTop") + const moveTopAction = findDelegateMenuAction(lvOther, 0, "miMoveToTop") tryCompare(moveTopAction, "enabled", false) // trigger move to bottom - triggerDelegateMenuAction(lvRegular, 0, "miMoveToBottom") - waitForItemPolished(lvRegular) + waitForItemPolished(lvOther) + triggerDelegateMenuAction(lvOther, 0, "miMoveToBottom") verify(controlUnderTest.dirty) // verify the previous first and current last are actually the same item - const delegateN = findChild(lvRegular, "manageTokensDelegate-%1".arg(lvRegular.count-1)) + const delegateN = findChild(lvOther, "manageTokensDelegate-%1".arg(lvOther.count-1)) verify(!!delegateN) const titleN = delegateN.title compare(title, titleN) // verify move down and to bottom is not available for the last item - const moveDownAction = findDelegateMenuAction(lvRegular, lvRegular.count-1, "miMoveDown") + const moveDownAction = findDelegateMenuAction(lvOther, lvOther.count-1, "miMoveDown") tryCompare(moveDownAction, "enabled", false) - const moveBottomAction = findDelegateMenuAction(lvRegular, lvRegular.count-1, "miMoveToBottom") + const moveBottomAction = findDelegateMenuAction(lvOther, lvOther.count-1, "miMoveToBottom") tryCompare(moveBottomAction, "enabled", false) // trigger move to top and verify we got the same title (item) again - triggerDelegateMenuAction(lvRegular, lvRegular.count-1, "miMoveToTop") - waitForItemPolished(lvRegular) - tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", title) + triggerDelegateMenuAction(lvOther, lvOther.count-1, "miMoveToTop") + waitForItemPolished(lvOther) + tryCompare(findChild(lvOther, "manageTokensDelegate-0"), "title", title) // trigger move down and verify we got the same title (item) again - triggerDelegateMenuAction(lvRegular, 0, "miMoveDown") - tryCompare(findChild(lvRegular, "manageTokensDelegate-1"), "title", title) + triggerDelegateMenuAction(lvOther, 0, "miMoveDown") + tryCompare(findChild(lvOther, "manageTokensDelegate-1"), "title", title) // trigger move up and verify we got the same title (item) again - triggerDelegateMenuAction(lvRegular, 1, "miMoveUp") - tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", title) + triggerDelegateMenuAction(lvOther, 1, "miMoveUp") + tryCompare(findChild(lvOther, "manageTokensDelegate-0"), "title", title) } function test_saveLoad() { verify(!controlUnderTest.dirty) const titleToTest = "Big Kitty" - let lvRegular = findChild(controlUnderTest, "lvRegularTokens") - verify(!!lvRegular) - const bigKittyIndex = findDelegateIndexWithTitle(lvRegular, titleToTest) + let lvOther = findChild(controlUnderTest, "otherTokensListView") + verify(!!lvOther) + const bigKittyIndex = findDelegateIndexWithTitle(lvOther, titleToTest) verify(bigKittyIndex !== -1) - const title0 = findChild(lvRegular, "manageTokensDelegate-0").title + const title0 = findChild(lvOther, "manageTokensDelegate-0").title verify(!!title0) verify(title0 !== titleToTest) // trigger move to top and verify we got the correct title - triggerDelegateMenuAction(lvRegular, bigKittyIndex, "miMoveToTop") - waitForItemPolished(lvRegular) - tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", titleToTest) + triggerDelegateMenuAction(lvOther, bigKittyIndex, "miMoveToTop") + waitForItemPolished(lvOther) + tryCompare(findChild(lvOther, "manageTokensDelegate-0"), "title", titleToTest) // save verify(controlUnderTest.dirty) @@ -303,11 +322,11 @@ Item { // load the settings and check BigKitty is still on top controlUnderTest.revert() verify(!controlUnderTest.dirty) - lvRegular = findChild(controlUnderTest, "lvRegularTokens") - verify(!!lvRegular) - waitForItemPolished(lvRegular) - tryVerify(() => lvRegular.count > 0) - const topItem = findChild(lvRegular, "manageTokensDelegate-0") + lvOther = findChild(controlUnderTest, "otherTokensListView") + verify(!!lvOther) + waitForItemPolished(lvOther) + tryVerify(() => lvOther.count > 0) + const topItem = findChild(lvOther, "manageTokensDelegate-0") verify(!!topItem) tryCompare(topItem, "title", titleToTest) } diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusSwitch.qml b/ui/StatusQ/src/StatusQ/Controls/StatusSwitch.qml index 4a2cf76b09..baf5b7fc9a 100644 --- a/ui/StatusQ/src/StatusQ/Controls/StatusSwitch.qml +++ b/ui/StatusQ/src/StatusQ/Controls/StatusSwitch.qml @@ -23,9 +23,9 @@ Switch { implicitWidth: 52 implicitHeight: 28 - anchors.left: parent.left + anchors.left: root.left anchors.leftMargin: root.leftPadding - anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenter: root.verticalCenter Rectangle { anchors.fill: parent @@ -45,8 +45,8 @@ Switch { color: Theme.palette.white layer.enabled: true layer.effect: DropShadow { - width: parent.width - height: parent.height + width: circle.width + height: circle.height visible: true verticalOffset: 1 fast: true diff --git a/ui/app/AppLayouts/Profile/views/SettingsContentBase.qml b/ui/app/AppLayouts/Profile/views/SettingsContentBase.qml index ec2c1d10b0..0b138e41f8 100644 --- a/ui/app/AppLayouts/Profile/views/SettingsContentBase.qml +++ b/ui/app/AppLayouts/Profile/views/SettingsContentBase.qml @@ -28,6 +28,10 @@ FocusScope { property bool saveChangesButtonEnabled: false readonly property alias toast: settingsDirtyToastMessage + readonly property real availableHeight: + scrollView.availableHeight - settingsDirtyToastMessagePlaceholder.height + - Style.current.bigPadding + signal baseAreaClicked() signal saveChangesClicked() signal saveForLaterClicked() @@ -118,7 +122,8 @@ FocusScope { } Item { - // This is a settingsDirtyToastMessage placeholder + id: settingsDirtyToastMessagePlaceholder + width: settingsDirtyToastMessage.implicitWidth height: settingsDirtyToastMessage.active && !root.ignoreDirty ? settingsDirtyToastMessage.implicitHeight : 0 diff --git a/ui/app/AppLayouts/Profile/views/WalletView.qml b/ui/app/AppLayouts/Profile/views/WalletView.qml index 323b39d5a6..3d87c82b59 100644 --- a/ui/app/AppLayouts/Profile/views/WalletView.qml +++ b/ui/app/AppLayouts/Profile/views/WalletView.qml @@ -305,6 +305,10 @@ SettingsContentBase { ManageTokensView { id: manageTokensView + + implicitHeight: root.availableHeight + Layout.fillWidth: true + sourcesOfTokensModel: tokensStore.sourcesOfTokensModel tokensListModel: tokensStore.extendedFlatTokensModel baseWalletAssetsModel: RootStore.walletAssetsStore.groupedAccountAssetsModel diff --git a/ui/app/AppLayouts/Profile/views/wallet/ManageTokensView.qml b/ui/app/AppLayouts/Profile/views/wallet/ManageTokensView.qml index 0d33bc2524..f7433f7e5a 100644 --- a/ui/app/AppLayouts/Profile/views/wallet/ManageTokensView.qml +++ b/ui/app/AppLayouts/Profile/views/wallet/ManageTokensView.qml @@ -17,7 +17,7 @@ import utils 1.0 import AppLayouts.Profile.panels 1.0 import AppLayouts.Wallet.panels 1.0 -ColumnLayout { +Item { id: root required property var sourcesOfTokensModel // Expected roles: key, name, updatedAt, source, version, tokensCount, image @@ -121,157 +121,162 @@ ColumnLayout { } } - StatusTabBar { - id: tabBar + ColumnLayout { + anchors.fill: parent - Layout.fillWidth: true - Layout.topMargin: 5 + StatusTabBar { + id: tabBar - StatusTabButton { - leftPadding: 0 - width: implicitWidth - text: qsTr("Assets") - } - StatusTabButton { - width: implicitWidth - text: qsTr("Collectibles") - } - StatusTabButton { - width: implicitWidth - text: qsTr("Hidden") - } - StatusTabButton { - width: implicitWidth - text: qsTr("Advanced") - } - } + Layout.fillWidth: true + Layout.topMargin: 5 - // NB: we want to discard any pending unsaved changes when switching tabs or navigating away - Loader { - id: loader - Layout.fillWidth: true - Layout.fillHeight: true - active: visible - - sourceComponent: { - switch (tabBar.currentIndex) { - case d.assetsTabIndex: - return tokensPanel - case d.collectiblesTabIndex: - return collectiblesPanel - case d.hiddenTabIndex: - return hiddenPanel - case d.advancedTabIndex: - return advancedTab + StatusTabButton { + leftPadding: 0 + width: implicitWidth + text: qsTr("Assets") + } + StatusTabButton { + width: implicitWidth + text: qsTr("Collectibles") + } + StatusTabButton { + width: implicitWidth + text: qsTr("Hidden") + } + StatusTabButton { + width: implicitWidth + text: qsTr("Advanced") } } - } - Component { - id: tokensPanel - ManageAssetsPanel { - getCurrencyAmount: function (balance, symbol) { - return root.getCurrencyAmount(balance, symbol) - } - getCurrentCurrencyAmount: function (balance) { - return root.getCurrentCurrencyAmount(balance) - } - controller: d.assetsController - } - } + // NB: we want to discard any pending unsaved changes when switching tabs or navigating away + Loader { + id: loader + Layout.fillWidth: true + Layout.fillHeight: true + active: visible - Component { - id: collectiblesPanel - ManageCollectiblesPanel { - controller: d.collectiblesController - Component.onCompleted: d.checkLoadMoreCollectibles() - } - } - - Component { - id: hiddenPanel - ManageHiddenPanel { - getCurrencyAmount: function (balance, symbol) { - return root.getCurrencyAmount(balance, symbol) - } - getCurrentCurrencyAmount: function (balance) { - return root.getCurrentCurrencyAmount(balance) - } - assetsController: d.assetsController - collectiblesController: d.collectiblesController - } - } - - Component { - id: advancedTab - ColumnLayout { - spacing: 8 - StatusListItem { - Layout.fillWidth: true - title: qsTr("Show community assets when sending tokens") - - components: [ - StatusSwitch { - id: showCommunityAssetsSwitch - checked: true // FIXME integrate with backend (#13178) - onCheckedChanged: { - // FIXME integrate with backend (#13178) - } - } - ] - onClicked: { - showCommunityAssetsSwitch.checked = !showCommunityAssetsSwitch.checked + sourceComponent: { + switch (tabBar.currentIndex) { + case d.assetsTabIndex: + return tokensPanel + case d.collectiblesTabIndex: + return collectiblesPanel + case d.hiddenTabIndex: + return hiddenPanel + case d.advancedTabIndex: + return advancedTab } } - StatusDialogDivider { - Layout.fillWidth: true - } - StatusListItem { - Layout.fillWidth: true - title: qsTr("Don’t display assets with balance lower than") + } - components: [ - CurrencyAmountInput { - enabled: displayThresholdSwitch.checked - currencySymbol: SharedStores.RootStore.currencyStore.currentCurrency - value: 0.10 // FIXME integrate with backend (#13178) - }, - StatusSwitch { - id: displayThresholdSwitch - checked: false // FIXME integrate with backend (#13178) - onCheckedChanged: { - // FIXME integrate with backend (#13178) - } - } - ] - onClicked: { - displayThresholdSwitch.checked = !displayThresholdSwitch.checked + Component { + id: tokensPanel + ManageAssetsPanel { + getCurrencyAmount: function (balance, symbol) { + return root.getCurrencyAmount(balance, symbol) } + getCurrentCurrencyAmount: function (balance) { + return root.getCurrentCurrencyAmount(balance) + } + + controller: d.assetsController } - StatusDialogDivider { - Layout.fillWidth: true + } + + Component { + id: collectiblesPanel + ManageCollectiblesPanel { + controller: d.collectiblesController + Component.onCompleted: d.checkLoadMoreCollectibles() } - RowLayout { - Layout.fillWidth: true - Layout.preferredHeight: 64 - Layout.topMargin: 18 - Layout.bottomMargin: 18 - StatusBaseText { + } + + Component { + id: hiddenPanel + ManageHiddenPanel { + getCurrencyAmount: function (balance, symbol) { + return root.getCurrencyAmount(balance, symbol) + } + getCurrentCurrencyAmount: function (balance) { + return root.getCurrentCurrencyAmount(balance) + } + assetsController: d.assetsController + collectiblesController: d.collectiblesController + } + } + + Component { + id: advancedTab + ColumnLayout { + spacing: 8 + StatusListItem { Layout.fillWidth: true - text: qsTr("Token lists") - color: Style.current.textColor + title: qsTr("Show community assets when sending tokens") + + components: [ + StatusSwitch { + id: showCommunityAssetsSwitch + checked: true // FIXME integrate with backend (#13178) + onCheckedChanged: { + // FIXME integrate with backend (#13178) + } + } + ] + onClicked: { + showCommunityAssetsSwitch.checked = !showCommunityAssetsSwitch.checked + } } - StatusBaseText { - Layout.alignment: Qt.AlignRight - text: qsTr("Last updated %1 @%2").arg(LocaleUtils.formatDate(root.sourcesOfTokensModel.get(0).updatedAt * 1000)).arg(LocaleUtils.formatTime(root.sourcesOfTokensModel.get(0).updatedAt, Locale.ShortFormat)) - color: Style.current.darkGrey + StatusDialogDivider { + Layout.fillWidth: true + } + StatusListItem { + Layout.fillWidth: true + title: qsTr("Don’t display assets with balance lower than") + + components: [ + CurrencyAmountInput { + enabled: displayThresholdSwitch.checked + currencySymbol: SharedStores.RootStore.currencyStore.currentCurrency + value: 0.10 // FIXME integrate with backend (#13178) + }, + StatusSwitch { + id: displayThresholdSwitch + checked: false // FIXME integrate with backend (#13178) + onCheckedChanged: { + // FIXME integrate with backend (#13178) + } + } + ] + onClicked: { + displayThresholdSwitch.checked = !displayThresholdSwitch.checked + } + } + StatusDialogDivider { + Layout.fillWidth: true + } + RowLayout { + Layout.fillWidth: true + Layout.preferredHeight: 64 + Layout.topMargin: 18 + Layout.bottomMargin: 18 + StatusBaseText { + Layout.fillWidth: true + text: qsTr("Token lists") + color: Style.current.textColor + } + StatusBaseText { + Layout.alignment: Qt.AlignRight + text: qsTr("Last updated %1 @%2").arg(LocaleUtils.formatDate(root.sourcesOfTokensModel.get(0).updatedAt * 1000)).arg(LocaleUtils.formatTime(root.sourcesOfTokensModel.get(0).updatedAt, Locale.ShortFormat)) + color: Style.current.darkGrey + } + } + SupportedTokenListsPanel { + Layout.fillWidth: true + Layout.fillHeight: true + sourcesOfTokensModel: root.sourcesOfTokensModel + tokensListModel: root.tokensListModel } - } - SupportedTokenListsPanel { - Layout.fillWidth: true - Layout.fillHeight: true - sourcesOfTokensModel: root.sourcesOfTokensModel - tokensListModel: root.tokensListModel } } } diff --git a/ui/app/AppLayouts/Wallet/controls/ManageTokensDelegate.qml b/ui/app/AppLayouts/Wallet/controls/ManageTokensDelegate.qml index fb72d1f96a..208e37794b 100644 --- a/ui/app/AppLayouts/Wallet/controls/ManageTokensDelegate.qml +++ b/ui/app/AppLayouts/Wallet/controls/ManageTokensDelegate.qml @@ -47,13 +47,14 @@ DropArea { keys: isCommunityToken ? ["x-status-draggable-community-token-item"] : ["x-status-draggable-regular-token-item"] width: ListView.view ? ListView.view.width : 0 - height: visible ? delegate.height : 0 + height: delegate.height onEntered: function(drag) { const from = drag.source.visualIndex const to = delegate.visualIndex if (to === from) return + ListView.view.model.moveItem(from, to) drag.accept() } diff --git a/ui/app/AppLayouts/Wallet/controls/ManageTokensGroupDelegate.qml b/ui/app/AppLayouts/Wallet/controls/ManageTokensGroupDelegate.qml index 7e7a9e4795..dc64e529d5 100644 --- a/ui/app/AppLayouts/Wallet/controls/ManageTokensGroupDelegate.qml +++ b/ui/app/AppLayouts/Wallet/controls/ManageTokensGroupDelegate.qml @@ -35,7 +35,7 @@ DropArea { keys: isCollection ? ["x-status-draggable-collection-group-item"] : ["x-status-draggable-community-group-item"] width: ListView.view ? ListView.view.width : 0 - height: visible ? groupedCommunityTokenDelegate.implicitHeight : 0 + height: groupedCommunityTokenDelegate.implicitHeight onEntered: function(drag) { const from = drag.source.visualIndex diff --git a/ui/app/AppLayouts/Wallet/panels/ManageAssetsPanel.qml b/ui/app/AppLayouts/Wallet/panels/ManageAssetsPanel.qml index 79d455e177..7ff89237f5 100644 --- a/ui/app/AppLayouts/Wallet/panels/ManageAssetsPanel.qml +++ b/ui/app/AppLayouts/Wallet/panels/ManageAssetsPanel.qml @@ -1,17 +1,22 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 +import QtQml.Models 2.15 +import QtQml 2.15 -import StatusQ.Core 0.1 import StatusQ.Components 0.1 import StatusQ.Controls 0.1 +import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 +import StatusQ.Core.Utils 0.1 import StatusQ.Models 0.1 -import utils 1.0 +import shared.controls 1.0 import AppLayouts.Wallet.controls 1.0 +import "internals" + Control { id: root @@ -37,18 +42,35 @@ Control { root.controller.clearSettings(); } + QtObject { + id: d - contentItem: ColumnLayout { - spacing: Style.current.padding + readonly property int sectionHeight: 64 + } - StatusListView { - Layout.fillWidth: true + contentItem: DoubleFlickableWithFolding { + id: doubleFlickable + + clip: true + + ScrollBar.vertical: StatusScrollBar { + policy: ScrollBar.AsNeeded + visible: resolveVisibility(policy, doubleFlickable.height, + doubleFlickable.contentHeight) + } + + flickable1: ManageTokensListViewBase { model: root.controller.regularTokensModel - implicitHeight: contentHeight - interactive: false + width: doubleFlickable.width - displaced: Transition { - NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } + ScrollBar.vertical: null + + header: FoldableHeader { + width: ListView.view.width + title: qsTr("Assets") + folded: doubleFlickable.flickable1Folded + + onToggleFolding: doubleFlickable.flip1Folding() } delegate: ManageTokensDelegate { @@ -63,78 +85,69 @@ Control { return root.getCurrentCurrencyAmount(balance) } } + + placeholderText: qsTr("Your assets will appear here") } - RowLayout { - Layout.fillWidth: true - Layout.topMargin: Style.current.padding - visible: root.controller.communityTokensModel.count - StatusBaseText { - Layout.fillWidth: true - text: qsTr("Community") - } - StatusSwitch { - LayoutMirroring.enabled: true - LayoutMirroring.childrenInherit: true - id: switchArrangeByCommunity - textColor: Theme.palette.baseColor1 - font.pixelSize: 13 - text: qsTr("Arrange by community") + flickable2: ManageTokensListViewBase { + width: doubleFlickable.width + + model: root.controller.arrangeByCommunity ? communityGroupedModel + : communityNonGroupedModel + + header: FoldableHeader { + width: ListView.view.width + title: qsTr("Community minted") + switchText: qsTr("Arrange by community") + folded: doubleFlickable.flickable2Folded checked: root.controller.arrangeByCommunity - onToggled: root.controller.arrangeByCommunity = checked - } - } - Loader { - Layout.fillWidth: true - active: root.controller.communityTokensModel.count - visible: active - sourceComponent: switchArrangeByCommunity.checked ? cmpCommunityTokenGroups : cmpCommunityTokens + onToggleFolding: doubleFlickable.flip2Folding() + onToggleSwitch: root.controller.arrangeByCommunity = checked + } + + placeholderText: qsTr("Your community minted assets will appear here") } } - Component { - id: cmpCommunityTokens - StatusListView { - model: root.controller.communityTokensModel - implicitHeight: contentHeight - interactive: false + DelegateModel { + id: communityNonGroupedModel - displaced: Transition { - NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } + model: root.controller.communityTokensModel + + function moveItem(from, to) { + model.moveItem(from, to) + } + + delegate: ManageTokensDelegate { + controller: root.controller + dragParent: root + count: root.controller.communityTokensModel.count + dragEnabled: count > 1 + getCurrencyAmount: function (balance, symbol) { + return root.getCurrencyAmount(balance, symbol) } - - delegate: ManageTokensDelegate { - controller: root.controller - dragParent: root - count: root.controller.communityTokensModel.count - dragEnabled: count > 1 - getCurrencyAmount: function (balance, symbol) { - return root.getCurrencyAmount(balance, symbol) - } - getCurrentCurrencyAmount: function (balance) { - return root.getCurrentCurrencyAmount(balance) - } + getCurrentCurrencyAmount: function (balance) { + return root.getCurrentCurrencyAmount(balance) } } } - Component { - id: cmpCommunityTokenGroups - StatusListView { - model: root.controller.communityTokenGroupsModel - implicitHeight: contentHeight - interactive: false + DelegateModel { + id: communityGroupedModel - displaced: Transition { - NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } - } + model: root.controller.communityTokenGroupsModel - delegate: ManageTokensGroupDelegate { - controller: root.controller - dragParent: root - dragEnabled: root.controller.communityTokenGroupsModel.count > 1 - } + function moveItem(from, to) { + model.moveItem(from, to) + } + + delegate: ManageTokensGroupDelegate { + height: 76 + + controller: root.controller + dragParent: root + dragEnabled: root.controller.communityTokenGroupsModel.count > 1 } } } diff --git a/ui/app/AppLayouts/Wallet/panels/ManageCollectiblesPanel.qml b/ui/app/AppLayouts/Wallet/panels/ManageCollectiblesPanel.qml index 466f6b22fa..8b6c25804c 100644 --- a/ui/app/AppLayouts/Wallet/panels/ManageCollectiblesPanel.qml +++ b/ui/app/AppLayouts/Wallet/panels/ManageCollectiblesPanel.qml @@ -1,19 +1,16 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 +import QtQml.Models 2.15 -import StatusQ 0.1 -import StatusQ.Core 0.1 -import StatusQ.Components 0.1 import StatusQ.Controls 0.1 import StatusQ.Core.Theme 0.1 -import StatusQ.Models 0.1 - -import utils 1.0 -import shared.controls 1.0 +import StatusQ.Core.Utils 0.1 import AppLayouts.Wallet.controls 1.0 +import "internals" + Control { id: root @@ -36,157 +33,133 @@ Control { root.controller.clearSettings(); } - contentItem: ColumnLayout { - spacing: Style.current.padding + contentItem: DoubleFlickableWithFolding { + id: doubleFlickable - ShapeRectangle { - Layout.fillWidth: true - Layout.margins: 2 - visible: !root.controller.regularTokensModel.count && !root.controller.communityTokensModel.count - text: qsTr("You’ll be able to manage the display of your collectibles here") + clip: true + + ScrollBar.vertical: StatusScrollBar { + policy: ScrollBar.AsNeeded + visible: resolveVisibility(policy, doubleFlickable.height, + doubleFlickable.contentHeight) } - RowLayout { - Layout.fillWidth: true - Layout.topMargin: Style.current.padding - visible: root.controller.communityTokensModel.count - StatusBaseText { - Layout.fillWidth: true - text: qsTr("Community minted") - } - StatusSwitch { - objectName: "switchArrangeByCommunity" - LayoutMirroring.enabled: true - LayoutMirroring.childrenInherit: true - id: switchArrangeByCommunity - textColor: Theme.palette.baseColor1 - font.pixelSize: 13 - text: qsTr("Arrange by community") + flickable1: ManageTokensListViewBase { + objectName: "communityTokensListView" + + width: doubleFlickable.width + + model: root.controller.arrangeByCommunity + ? communityGroupedModel : communityNonGroupedModel + + header: FoldableHeader { + objectName: "communityHeader" + + width: ListView.view.width + title: qsTr("Community minted") + switchText: qsTr("Arrange by community") + folded: doubleFlickable.flickable1Folded checked: root.controller.arrangeByCommunity - onToggled: root.controller.arrangeByCommunity = checked + + onToggleFolding: doubleFlickable.flip1Folding() + onToggleSwitch: root.controller.arrangeByCommunity = checked } + + placeholderText: qsTr("Your community minted collectibles will appear here") } - Loader { - objectName: "loaderCommunityTokens" - Layout.fillWidth: true - active: root.controller.communityTokensModel.count - visible: active - sourceComponent: switchArrangeByCommunity.checked ? cmpCommunityTokenGroups : cmpCommunityTokens - } + flickable2: ManageTokensListViewBase { + objectName: "otherTokensListView" - RowLayout { - Layout.fillWidth: true - Layout.topMargin: Style.current.padding - visible: root.controller.regularTokensModel.count - StatusBaseText { - Layout.fillWidth: true - text: qsTr("Other") - } - StatusSwitch { - LayoutMirroring.enabled: true - LayoutMirroring.childrenInherit: true - id: switchArrangeByCollection - textColor: Theme.palette.baseColor1 - font.pixelSize: 13 - text: qsTr("Arrange by collection") + width: doubleFlickable.width + + model: root.controller.arrangeByCollection + ? otherGroupedModel : otherNonGroupedModel + + header: FoldableHeader { + objectName: "nonCommunityHeader" + + width: ListView.view.width + title: qsTr("Other") + switchText: qsTr("Arrange by collection") + folded: doubleFlickable.flickable2Folded checked: root.controller.arrangeByCollection - onToggled: root.controller.arrangeByCollection = checked - } - } - Loader { - objectName: "loaderRegularTokens" - Layout.fillWidth: true - active: root.controller.regularTokensModel.count - visible: active - sourceComponent: switchArrangeByCollection.checked ? cmpCollectionTokenGroups : cmpRegularTokens + onToggleFolding: doubleFlickable.flip2Folding() + onToggleSwitch: root.controller.arrangeByCollection = checked + } + + placeholderText: qsTr("Your other collectibles will appear here") } } - Component { - id: cmpCommunityTokens - StatusListView { - objectName: "lvCommunityTokens" - model: root.controller.communityTokensModel - implicitHeight: contentHeight - interactive: false + DelegateModel { + id: communityNonGroupedModel - displaced: Transition { - NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } - } + model: root.controller.communityTokensModel - delegate: ManageTokensDelegate { - isCollectible: true - controller: root.controller - dragParent: root - count: root.controller.communityTokensModel.count - dragEnabled: count > 1 - } + function moveItem(from, to) { + model.moveItem(from, to) + } + + delegate: ManageTokensDelegate { + isCollectible: true + controller: root.controller + dragParent: root + count: root.controller.communityTokensModel.count + dragEnabled: count > 1 } } - Component { - id: cmpCommunityTokenGroups - StatusListView { - objectName: "lvCommunityTokenGroups" - model: root.controller.communityTokenGroupsModel - implicitHeight: contentHeight - interactive: false + DelegateModel { + id: communityGroupedModel - displaced: Transition { - NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } - } + model: root.controller.communityTokenGroupsModel - delegate: ManageTokensGroupDelegate { - isCollectible: true - controller: root.controller - dragParent: root - dragEnabled: root.controller.communityTokenGroupsModel.count > 1 - } + function moveItem(from, to) { + model.moveItem(from, to) + } + + delegate: ManageTokensGroupDelegate { + isCollectible: true + controller: root.controller + dragParent: root + dragEnabled: root.controller.communityTokenGroupsModel.count > 1 } } - Component { - id: cmpRegularTokens - StatusListView { - objectName: "lvRegularTokens" - model: root.controller.regularTokensModel - implicitHeight: contentHeight - interactive: false + DelegateModel { + id: otherNonGroupedModel - displaced: Transition { - NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } - } + model: root.controller.regularTokensModel - delegate: ManageTokensDelegate { - isCollectible: true - controller: root.controller - dragParent: root - count: root.controller.regularTokensModel.count - dragEnabled: count > 1 - } + function moveItem(from, to) { + model.moveItem(from, to) + } + + delegate: ManageTokensDelegate { + isCollectible: true + controller: root.controller + dragParent: root + count: root.controller.regularTokensModel.count + dragEnabled: count > 1 } } - Component { - id: cmpCollectionTokenGroups - StatusListView { - objectName: "lvCollectionTokenGroups" - model: root.controller.collectionGroupsModel - implicitHeight: contentHeight - interactive: false + DelegateModel { + id: otherGroupedModel - displaced: Transition { - NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } - } + model: root.controller.collectionGroupsModel - delegate: ManageTokensGroupDelegate { - isCollection: true - controller: root.controller - dragParent: root - dragEnabled: root.controller.collectionGroupsModel.count > 1 - } + function moveItem(from, to) { + model.moveItem(from, to) + } + + delegate: ManageTokensGroupDelegate { + isCollection: true + controller: root.controller + dragParent: root + dragEnabled: root.controller.collectionGroupsModel.count > 1 } } } diff --git a/ui/app/AppLayouts/Wallet/panels/ManageHiddenPanel.qml b/ui/app/AppLayouts/Wallet/panels/ManageHiddenPanel.qml index 69822c82db..0e9bd7e570 100644 --- a/ui/app/AppLayouts/Wallet/panels/ManageHiddenPanel.qml +++ b/ui/app/AppLayouts/Wallet/panels/ManageHiddenPanel.qml @@ -184,6 +184,8 @@ Control { ColumnLayout { // no assets placeholder Layout.fillWidth: true + Layout.fillHeight: false + spacing: 0 visible: !d.assetsCount SectionDelegate { @@ -196,9 +198,11 @@ Control { } StatusListView { + id: listView + Layout.fillWidth: true - implicitHeight: contentHeight Layout.fillHeight: true + model: d.sfpm displaced: Transition { @@ -221,21 +225,29 @@ Control { isCollectible: section == "true" } section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart + + footer: ColumnLayout { // no collectibles placeholder + width: ListView.view.width + + spacing: 0 + visible: !d.collectiblesCount + height: visible ? implicitHeight : 0 + + SectionDelegate { + Layout.fillWidth: true + isCollectible: true + } + Placeholder { + Layout.fillWidth: true + isCollectible: true + visible: d.collectiblesExpanded + } + } } - ColumnLayout { // no collectibles placeholder - Layout.fillWidth: true - spacing: 0 - visible: !d.collectiblesCount - SectionDelegate { - Layout.fillWidth: true - isCollectible: true - } - Placeholder { - Layout.fillWidth: true - isCollectible: true - visible: d.collectiblesExpanded - } + Item { + Layout.fillHeight: true + visible: listView.count === 0 } } } diff --git a/ui/app/AppLayouts/Wallet/panels/internals/FoldableHeader.qml b/ui/app/AppLayouts/Wallet/panels/internals/FoldableHeader.qml new file mode 100644 index 0000000000..3848b45a50 --- /dev/null +++ b/ui/app/AppLayouts/Wallet/panels/internals/FoldableHeader.qml @@ -0,0 +1,64 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 + +import StatusQ.Controls 0.1 +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 + +Rectangle { + id: root + + property bool folded: false + property alias title: label.text + property alias switchText: modeSwitch.text + property alias checked: modeSwitch.checked + + signal toggleFolding + signal toggleSwitch + + height: headerContent.height + z: 1 + + color: Theme.palette.statusListItem.backgroundColor + + QtObject { + id: d + + readonly property int sectionHeight: 64 + } + + RowLayout { + id: headerContent + + width: parent.width + height: d.sectionHeight + + StatusFlatButton { + checkable: true + size: StatusBaseButton.Size.Small + icon.name: checked ? "chevron-down" : "next" + textColor: Theme.palette.baseColor1 + textHoverColor: Theme.palette.directColor1 + + checked: !root.folded + onToggled: root.toggleFolding() + } + + StatusBaseText { + id: label + + Layout.fillWidth: true + } + StatusSwitch { + id: modeSwitch + objectName: "switch" + + visible: !!text + LayoutMirroring.enabled: true + LayoutMirroring.childrenInherit: true + textColor: Theme.palette.baseColor1 + font.pixelSize: 13 + onToggled: root.toggleSwitch() + } + } +} diff --git a/ui/app/AppLayouts/Wallet/panels/internals/ManageTokensListViewBase.qml b/ui/app/AppLayouts/Wallet/panels/internals/ManageTokensListViewBase.qml new file mode 100644 index 0000000000..7aec75ffdc --- /dev/null +++ b/ui/app/AppLayouts/Wallet/panels/internals/ManageTokensListViewBase.qml @@ -0,0 +1,51 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import QtQml 2.15 + +import StatusQ.Controls 0.1 +import StatusQ.Core 0.1 +import QtQuick.Controls 2.15 +import StatusQ.Core.Theme 0.1 + +import shared.controls 1.0 + +StatusListView { + id: root + + property string placeholderText + + ScrollBar.vertical: null + + QtObject { + id: d + + readonly property int placeholderHeight: 44 + } + + Binding { + when: root.model && root.count === 0 + target: root + property: "footer" + restoreMode: Binding.RestoreBindingOrValue + + value: Component { + Item { + height: d.placeholderHeight + width: root.width + + ShapeRectangle { + id: shapeRectangle + + text: root.placeholderText + + anchors.fill: parent + anchors.margins: 1 + } + } + } + } + + displaced: Transition { + NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } + } +}