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
This commit is contained in:
Michał Cieślak 2024-01-26 15:39:42 +00:00 committed by Michał
parent 8509dd9c67
commit 2e29e847ac
15 changed files with 639 additions and 501 deletions

View File

@ -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"
}
}

View File

@ -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

View File

@ -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
})
}
}

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -305,6 +305,10 @@ SettingsContentBase {
ManageTokensView {
id: manageTokensView
implicitHeight: root.availableHeight
Layout.fillWidth: true
sourcesOfTokensModel: tokensStore.sourcesOfTokensModel
tokensListModel: tokensStore.extendedFlatTokensModel
baseWalletAssetsModel: RootStore.walletAssetsStore.groupedAccountAssetsModel

View File

@ -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("Dont 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("Dont 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
}
}
}

View File

@ -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()
}

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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("Youll 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
}
}
}

View File

@ -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
}
}
}

View File

@ -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()
}
}
}

View File

@ -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 }
}
}