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 assetsWithFilteredBalances: groupedAccountsAssetsModel
} }
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml ManageAssetsPanel {
id: showcasePanel
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.fillHeight: true SplitView.fillHeight: true
Component.onCompleted: forceActiveFocus()
ManageAssetsPanel { getCurrencyAmount: function (balance, symbol) {
id: showcasePanel return ({
width: 500 amount: balance,
getCurrencyAmount: function (balance, symbol) { symbol: symbol,
return ({ displayDecimals: 2,
amount: balance, stripTrailingZeroes: false
symbol: symbol, })
displayDecimals: 2, }
stripTrailingZeroes: false getCurrentCurrencyAmount: function (balance) {
}) return ({
} amount: balance,
getCurrentCurrencyAmount: function (balance) { symbol: "USD",
return ({ displayDecimals: 2,
amount: balance, stripTrailingZeroes: false
symbol: "USD", })
displayDecimals: 2, }
stripTrailingZeroes: false
}) controller: ManageTokensController {
} sourceModel: ctrlEmptyModel.checked ? null : walletAssetStore.groupedAccountAssetsModel
controller: ManageTokensController { settingsKey: "WalletAssets"
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.fillWidth: true
SplitView.fillHeight: true SplitView.fillHeight: true
Component.onCompleted: forceActiveFocus()
ManageCollectiblesPanel { controller: ManageTokensController {
id: showcasePanel sourceModel: renamedModel
width: 500 settingsKey: "WalletCollectibles"
controller: ManageTokensController {
sourceModel: renamedModel
settingsKey: "WalletCollectibles"
}
} }
} }
@ -94,7 +92,4 @@ SplitView {
} }
// category: Panels // 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/eM26pyHZUeAwMLviaS1KJn/%E2%9A%99%EF%B8%8F-Wallet-Settings%3A-Manage-Tokens
// 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

View File

@ -52,33 +52,30 @@ SplitView {
settingsKey: "WalletCollectibles" settingsKey: "WalletCollectibles"
} }
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml ManageHiddenPanel {
id: showcasePanel
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.fillHeight: true SplitView.fillHeight: true
Component.onCompleted: forceActiveFocus()
ManageHiddenPanel { assetsController: assetsController
id: showcasePanel collectiblesController: collectiblesController
width: 500
assetsController: assetsController
collectiblesController: collectiblesController
getCurrencyAmount: function (balance, symbol) { getCurrencyAmount: function (balance, symbol) {
return ({ return ({
amount: balance, amount: balance,
symbol: symbol, symbol: symbol,
displayDecimals: 2, displayDecimals: 2,
stripTrailingZeroes: false stripTrailingZeroes: false
}) })
} }
getCurrentCurrencyAmount: function (balance) { getCurrentCurrencyAmount: function (balance) {
return ({ return ({
amount: balance, amount: balance,
symbol: "USD", symbol: "USD",
displayDecimals: 2, displayDecimals: 2,
stripTrailingZeroes: false stripTrailingZeroes: false
}) })
}
} }
} }

View File

@ -12,7 +12,7 @@ import utils 1.0
Item { Item {
id: root id: root
width: 600 width: 600
height: 400 height: 2000
ManageCollectiblesModel { ManageCollectiblesModel {
id: collectiblesModel id: collectiblesModel
@ -33,6 +33,7 @@ Item {
id: componentUnderTest id: componentUnderTest
ManageCollectiblesPanel { ManageCollectiblesPanel {
width: 500 width: 500
height: contentItem.contentHeight
controller: ManageTokensController { controller: ManageTokensController {
sourceModel: renamedModel sourceModel: renamedModel
settingsKey: "WalletCollectibles" settingsKey: "WalletCollectibles"
@ -59,7 +60,7 @@ Item {
property ManageCollectiblesPanel controlUnderTest: null property ManageCollectiblesPanel controlUnderTest: null
function findDelegateIndexWithTitle(listview, title) { function findDelegateIndexWithTitle(listview, title) {
waitForItemPolished(listview) waitForRendering(listview)
const count = listview.count const count = listview.count
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const item = listview.itemAtIndex(i) const item = listview.itemAtIndex(i)
@ -74,9 +75,12 @@ Item {
verify(!!token) verify(!!token)
const delegateBtn = findChild(token, "btnManageTokenMenu-%1".arg(index)) const delegateBtn = findChild(token, "btnManageTokenMenu-%1".arg(index))
verify(!!delegateBtn) verify(!!delegateBtn)
waitForItemPolished(delegateBtn)
mouseClick(delegateBtn) mouseClick(delegateBtn)
const btnMenuLoader = findChild(delegateBtn, "manageTokensContextMenuLoader") const btnMenuLoader = findChild(delegateBtn, "manageTokensContextMenuLoader")
verify(!!btnMenuLoader) verify(!!btnMenuLoader)
tryCompare(btnMenuLoader, "active", true) tryCompare(btnMenuLoader, "active", true)
const btnMenu = btnMenuLoader.item const btnMenu = btnMenuLoader.item
verify(!!btnMenu) verify(!!btnMenu)
@ -92,105 +96,120 @@ Item {
function init() { function init() {
controlUnderTest = createTemporaryObject(componentUnderTest, root) controlUnderTest = createTemporaryObject(componentUnderTest, root)
controlUnderTest.clearSettings()
notificationSpy.clear() notificationSpy.clear()
} }
function cleanup() {
controlUnderTest.clearSettings()
}
function test_showHideSingleToken() { function test_showHideSingleToken() {
waitForItemPolished(controlUnderTest)
verify(!controlUnderTest.dirty) verify(!controlUnderTest.dirty)
const lvRegular = findChild(controlUnderTest, "lvRegularTokens") const lvOther = findChild(controlUnderTest, "otherTokensListView")
verify(!!lvRegular) verify(!!lvOther)
const lvRegularCount = lvRegular.count
verify(lvRegularCount === 7)
const delegate0 = findChild(lvRegular, "manageTokensDelegate-0") tryCompare(lvOther, "count", 7)
const delegate0 = findChild(lvOther, "manageTokensDelegate-0")
verify(!!delegate0) verify(!!delegate0)
const title = delegate0.title const title = delegate0.title
tryCompare(notificationSpy, "count", 0) tryCompare(notificationSpy, "count", 0)
triggerDelegateMenuAction(lvRegular, 0, "miHideCollectionToken") triggerDelegateMenuAction(lvOther, 0, "miHideCollectionToken")
// verify the signal to show the notification toast got fired // verify the signal to show the notification toast got fired
tryCompare(notificationSpy, "count", 1) tryCompare(notificationSpy, "count", 1)
// verify we now have -1 regular tokens after the "hide" operation // verify we now have -1 regular tokens after the "hide" operation
tryCompare(lvRegular, "count", lvRegularCount-1) tryCompare(lvOther, "count", 6)
} }
function test_showHideCommunityGroup() { function test_showHideCommunityGroup() {
verify(!controlUnderTest.dirty) verify(!controlUnderTest.dirty)
const loaderCommunityTokens = findChild(controlUnderTest, "loaderCommunityTokens") const communityHeader = findChild(controlUnderTest, "communityHeader")
verify(!!loaderCommunityTokens) verify(!!communityHeader)
tryCompare(loaderCommunityTokens, "active", true) const switchArrangeByCommunity = findChild(communityHeader, "switch")
const switchArrangeByCommunity = findChild(controlUnderTest, "switchArrangeByCommunity")
verify(!!switchArrangeByCommunity) verify(!!switchArrangeByCommunity)
switchArrangeByCommunity.toggle()
const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups") waitForRendering(switchArrangeByCommunity)
verify(!!lvCommunityTokenGroups) 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 // verify we have 2 community collectible groups
tryCompare(lvCommunityTokenGroups, "count", 3) tryCompare(lvCommunity, "count", 3)
tryCompare(notificationSpy, "count", 0) tryCompare(notificationSpy, "count", 0)
triggerDelegateMenuAction(lvCommunityTokenGroups, 0, "miHideTokenGroup", true) triggerDelegateMenuAction(lvCommunity, 0, "miHideTokenGroup", true)
// verify the signal to show the notification toast got fired // verify the signal to show the notification toast got fired
tryCompare(notificationSpy, "count", 1) tryCompare(notificationSpy, "count", 1)
// verify we have one less group // verify we have one less group
waitForItemPolished(lvCommunityTokenGroups) waitForItemPolished(lvCommunity)
tryCompare(lvCommunityTokenGroups, "count", 2) tryCompare(lvCommunity, "count", 2)
} }
function test_dnd() { function test_dnd() {
verify(!controlUnderTest.dirty) verify(!controlUnderTest.dirty)
const lvRegular = findChild(controlUnderTest, "lvRegularTokens") const lvOther = findChild(controlUnderTest, "otherTokensListView")
verify(!!lvRegular) verify(!!lvOther)
verify(lvRegular.count !== 0) verify(lvOther.count !== 0)
const delegate0 = findChild(lvRegular, "manageTokensDelegate-0") const delegate0 = findChild(lvOther, "manageTokensDelegate-0")
verify(!!delegate0) verify(!!delegate0)
const title0 = delegate0.title const title0 = delegate0.title
verify(!!title0) verify(!!title0)
const title1 = findChild(lvRegular, "manageTokensDelegate-1").title const delegate1 = findChild(lvOther, "manageTokensDelegate-1")
const title1 = delegate1.title
verify(!!title1) verify(!!title1)
// DND one item down (~80px in height) waitForRendering(delegate1)
mouseDrag(delegate0, delegate0.width/2, delegate0.height/2, 0, 80)
// DND one item up
mouseDrag(delegate1, delegate1.width/2, delegate1.height/2, 0, -delegate1.height)
// cross compare the titles // cross compare the titles
tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", title1) tryCompare(findChild(lvOther, "manageTokensDelegate-0"), "title", title1)
tryCompare(findChild(lvRegular, "manageTokensDelegate-1"), "title", title0) tryCompare(findChild(lvOther, "manageTokensDelegate-1"), "title", title0)
verify(controlUnderTest.dirty) verify(controlUnderTest.dirty)
} }
function test_group_dnd() { function test_group_dnd() {
verify(!controlUnderTest.dirty) verify(!controlUnderTest.dirty)
const switchArrangeByCommunity = findChild(controlUnderTest, "switchArrangeByCommunity") const communityHeader = findChild(controlUnderTest, "communityHeader")
verify(!!communityHeader)
const switchArrangeByCommunity = findChild(communityHeader, "switch")
verify(!!switchArrangeByCommunity) verify(!!switchArrangeByCommunity)
waitForItemPolished(switchArrangeByCommunity)
mouseClick(switchArrangeByCommunity) mouseClick(switchArrangeByCommunity)
const loaderCommunityTokens = findChild(controlUnderTest, "loaderCommunityTokens") const lvCommunity = findChild(controlUnderTest, "communityTokensListView")
verify(!!loaderCommunityTokens) verify(!!lvCommunity)
tryCompare(loaderCommunityTokens, "active", true) waitForItemPolished(lvCommunity)
const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups") tryCompare(lvCommunity, "count", 3)
verify(!!lvCommunityTokenGroups)
waitForItemPolished(lvCommunityTokenGroups)
tryCompare(lvCommunityTokenGroups, "count", 3)
const group0 = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0") const group0 = findChild(lvCommunity, "manageTokensGroupDelegate-0")
const title0 = group0.title const title0 = group0.title
verify(!!title0) verify(!!title0)
const title1 = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1").title const group1 = findChild(lvCommunity, "manageTokensGroupDelegate-1")
const title1 = group1.title
verify(!!title1) verify(!!title1)
verify(title0 !== title1) verify(title0 !== title1)
// DND one group down (~80px in height) waitForRendering(group1)
mouseDrag(group0, group0.width/2, group0.height/2, 0, 80)
mouseDrag(group1, group1.width/2, group1.height/2, 0, -group1.height)
// cross compare the titles // cross compare the titles
tryCompare(findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0"), "title", title1) tryCompare(findChild(lvCommunity, "manageTokensGroupDelegate-0"), "title", title1)
tryCompare(findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1"), "title", title0) tryCompare(findChild(lvCommunity, "manageTokensGroupDelegate-1"), "title", title0)
verify(controlUnderTest.dirty) verify(controlUnderTest.dirty)
} }
@ -199,101 +218,101 @@ Item {
verify(!controlUnderTest.dirty) verify(!controlUnderTest.dirty)
const titleToTest = "Bearz" const titleToTest = "Bearz"
const switchArrangeByCommunity = findChild(controlUnderTest, "switchArrangeByCommunity") const communityHeader = findChild(controlUnderTest, "communityHeader")
verify(!!communityHeader)
const switchArrangeByCommunity = findChild(communityHeader, "switch")
verify(!!switchArrangeByCommunity) verify(!!switchArrangeByCommunity)
waitForRendering(switchArrangeByCommunity)
mouseClick(switchArrangeByCommunity) mouseClick(switchArrangeByCommunity)
const loaderCommunityTokens = findChild(controlUnderTest, "loaderCommunityTokens") const lvCommunity = findChild(controlUnderTest, "communityTokensListView")
verify(!!loaderCommunityTokens) verify(!!lvCommunity)
tryCompare(loaderCommunityTokens, "active", true) waitForItemPolished(lvCommunity)
const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups") tryCompare(lvCommunity, "count", 3)
verify(!!lvCommunityTokenGroups)
waitForItemPolished(lvCommunityTokenGroups)
tryCompare(lvCommunityTokenGroups, "count", 3)
// get the "Bearz" group at index 1 // get the "Bearz" group at index 1
var bearzGroupTokenDelegate = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1") var bearzGroupTokenDelegate = findChild(lvCommunity, "manageTokensGroupDelegate-1")
const bearzTitle = bearzGroupTokenDelegate.title const bearzTitle = bearzGroupTokenDelegate.title
compare(bearzTitle, titleToTest) compare(bearzTitle, titleToTest)
verify(!!bearzGroupTokenDelegate) verify(!!bearzGroupTokenDelegate)
waitForItemPolished(bearzGroupTokenDelegate) waitForItemPolished(bearzGroupTokenDelegate)
// now move the Bearz group up so that it's first (ends up at index 0) // now move the Bearz group up so that it's first (ends up at index 0)
waitForItemPolished(lvCommunityTokenGroups) waitForItemPolished(lvCommunity)
triggerDelegateMenuAction(lvCommunityTokenGroups, 1, "miMoveUp", true) triggerDelegateMenuAction(lvCommunity, 1, "miMoveUp", true)
verify(controlUnderTest.dirty) verify(controlUnderTest.dirty)
bearzGroupTokenDelegate = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0") bearzGroupTokenDelegate = findChild(lvCommunity, "manageTokensGroupDelegate-0")
verify(!!bearzGroupTokenDelegate) verify(!!bearzGroupTokenDelegate)
// finally verify that the Bearz group is still at top // finally verify that the Bearz group is still at top
waitForItemPolished(lvCommunityTokenGroups) waitForItemPolished(lvCommunity)
tryCompare(findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0"), "title", titleToTest) tryCompare(findChild(lvCommunity, "manageTokensGroupDelegate-0"), "title", titleToTest)
} }
function test_moveOperations() { function test_moveOperations() {
verify(!controlUnderTest.dirty) verify(!controlUnderTest.dirty)
const lvRegular = findChild(controlUnderTest, "lvRegularTokens") const lvOther = findChild(controlUnderTest, "otherTokensListView")
verify(!!lvRegular) verify(!!lvOther)
verify(lvRegular.count !== 0) verify(lvOther.count !== 0)
var delegate0 = findChild(lvRegular, "manageTokensDelegate-0") var delegate0 = findChild(lvOther, "manageTokensDelegate-0")
verify(!!delegate0) verify(!!delegate0)
const title = delegate0.title const title = delegate0.title
// verify moveUp and moveToTop is not available for the first item // 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) tryCompare(moveUpAction, "enabled", false)
const moveTopAction = findDelegateMenuAction(lvRegular, 0, "miMoveToTop") const moveTopAction = findDelegateMenuAction(lvOther, 0, "miMoveToTop")
tryCompare(moveTopAction, "enabled", false) tryCompare(moveTopAction, "enabled", false)
// trigger move to bottom // trigger move to bottom
triggerDelegateMenuAction(lvRegular, 0, "miMoveToBottom") waitForItemPolished(lvOther)
waitForItemPolished(lvRegular) triggerDelegateMenuAction(lvOther, 0, "miMoveToBottom")
verify(controlUnderTest.dirty) verify(controlUnderTest.dirty)
// verify the previous first and current last are actually the same item // 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) verify(!!delegateN)
const titleN = delegateN.title const titleN = delegateN.title
compare(title, titleN) compare(title, titleN)
// verify move down and to bottom is not available for the last item // 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) tryCompare(moveDownAction, "enabled", false)
const moveBottomAction = findDelegateMenuAction(lvRegular, lvRegular.count-1, "miMoveToBottom") const moveBottomAction = findDelegateMenuAction(lvOther, lvOther.count-1, "miMoveToBottom")
tryCompare(moveBottomAction, "enabled", false) tryCompare(moveBottomAction, "enabled", false)
// trigger move to top and verify we got the same title (item) again // trigger move to top and verify we got the same title (item) again
triggerDelegateMenuAction(lvRegular, lvRegular.count-1, "miMoveToTop") triggerDelegateMenuAction(lvOther, lvOther.count-1, "miMoveToTop")
waitForItemPolished(lvRegular) waitForItemPolished(lvOther)
tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", title) tryCompare(findChild(lvOther, "manageTokensDelegate-0"), "title", title)
// trigger move down and verify we got the same title (item) again // trigger move down and verify we got the same title (item) again
triggerDelegateMenuAction(lvRegular, 0, "miMoveDown") triggerDelegateMenuAction(lvOther, 0, "miMoveDown")
tryCompare(findChild(lvRegular, "manageTokensDelegate-1"), "title", title) tryCompare(findChild(lvOther, "manageTokensDelegate-1"), "title", title)
// trigger move up and verify we got the same title (item) again // trigger move up and verify we got the same title (item) again
triggerDelegateMenuAction(lvRegular, 1, "miMoveUp") triggerDelegateMenuAction(lvOther, 1, "miMoveUp")
tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", title) tryCompare(findChild(lvOther, "manageTokensDelegate-0"), "title", title)
} }
function test_saveLoad() { function test_saveLoad() {
verify(!controlUnderTest.dirty) verify(!controlUnderTest.dirty)
const titleToTest = "Big Kitty" const titleToTest = "Big Kitty"
let lvRegular = findChild(controlUnderTest, "lvRegularTokens") let lvOther = findChild(controlUnderTest, "otherTokensListView")
verify(!!lvRegular) verify(!!lvOther)
const bigKittyIndex = findDelegateIndexWithTitle(lvRegular, titleToTest) const bigKittyIndex = findDelegateIndexWithTitle(lvOther, titleToTest)
verify(bigKittyIndex !== -1) verify(bigKittyIndex !== -1)
const title0 = findChild(lvRegular, "manageTokensDelegate-0").title const title0 = findChild(lvOther, "manageTokensDelegate-0").title
verify(!!title0) verify(!!title0)
verify(title0 !== titleToTest) verify(title0 !== titleToTest)
// trigger move to top and verify we got the correct title // trigger move to top and verify we got the correct title
triggerDelegateMenuAction(lvRegular, bigKittyIndex, "miMoveToTop") triggerDelegateMenuAction(lvOther, bigKittyIndex, "miMoveToTop")
waitForItemPolished(lvRegular) waitForItemPolished(lvOther)
tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", titleToTest) tryCompare(findChild(lvOther, "manageTokensDelegate-0"), "title", titleToTest)
// save // save
verify(controlUnderTest.dirty) verify(controlUnderTest.dirty)
@ -303,11 +322,11 @@ Item {
// load the settings and check BigKitty is still on top // load the settings and check BigKitty is still on top
controlUnderTest.revert() controlUnderTest.revert()
verify(!controlUnderTest.dirty) verify(!controlUnderTest.dirty)
lvRegular = findChild(controlUnderTest, "lvRegularTokens") lvOther = findChild(controlUnderTest, "otherTokensListView")
verify(!!lvRegular) verify(!!lvOther)
waitForItemPolished(lvRegular) waitForItemPolished(lvOther)
tryVerify(() => lvRegular.count > 0) tryVerify(() => lvOther.count > 0)
const topItem = findChild(lvRegular, "manageTokensDelegate-0") const topItem = findChild(lvOther, "manageTokensDelegate-0")
verify(!!topItem) verify(!!topItem)
tryCompare(topItem, "title", titleToTest) tryCompare(topItem, "title", titleToTest)
} }

View File

@ -23,9 +23,9 @@ Switch {
implicitWidth: 52 implicitWidth: 52
implicitHeight: 28 implicitHeight: 28
anchors.left: parent.left anchors.left: root.left
anchors.leftMargin: root.leftPadding anchors.leftMargin: root.leftPadding
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: root.verticalCenter
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
@ -45,8 +45,8 @@ Switch {
color: Theme.palette.white color: Theme.palette.white
layer.enabled: true layer.enabled: true
layer.effect: DropShadow { layer.effect: DropShadow {
width: parent.width width: circle.width
height: parent.height height: circle.height
visible: true visible: true
verticalOffset: 1 verticalOffset: 1
fast: true fast: true

View File

@ -28,6 +28,10 @@ FocusScope {
property bool saveChangesButtonEnabled: false property bool saveChangesButtonEnabled: false
readonly property alias toast: settingsDirtyToastMessage readonly property alias toast: settingsDirtyToastMessage
readonly property real availableHeight:
scrollView.availableHeight - settingsDirtyToastMessagePlaceholder.height
- Style.current.bigPadding
signal baseAreaClicked() signal baseAreaClicked()
signal saveChangesClicked() signal saveChangesClicked()
signal saveForLaterClicked() signal saveForLaterClicked()
@ -118,7 +122,8 @@ FocusScope {
} }
Item { Item {
// This is a settingsDirtyToastMessage placeholder id: settingsDirtyToastMessagePlaceholder
width: settingsDirtyToastMessage.implicitWidth width: settingsDirtyToastMessage.implicitWidth
height: settingsDirtyToastMessage.active && !root.ignoreDirty ? settingsDirtyToastMessage.implicitHeight : 0 height: settingsDirtyToastMessage.active && !root.ignoreDirty ? settingsDirtyToastMessage.implicitHeight : 0

View File

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

View File

@ -17,7 +17,7 @@ import utils 1.0
import AppLayouts.Profile.panels 1.0 import AppLayouts.Profile.panels 1.0
import AppLayouts.Wallet.panels 1.0 import AppLayouts.Wallet.panels 1.0
ColumnLayout { Item {
id: root id: root
required property var sourcesOfTokensModel // Expected roles: key, name, updatedAt, source, version, tokensCount, image required property var sourcesOfTokensModel // Expected roles: key, name, updatedAt, source, version, tokensCount, image
@ -121,157 +121,162 @@ ColumnLayout {
} }
} }
StatusTabBar { ColumnLayout {
id: tabBar anchors.fill: parent
Layout.fillWidth: true StatusTabBar {
Layout.topMargin: 5 id: tabBar
StatusTabButton { Layout.fillWidth: true
leftPadding: 0 Layout.topMargin: 5
width: implicitWidth
text: qsTr("Assets")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Collectibles")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Hidden")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Advanced")
}
}
// NB: we want to discard any pending unsaved changes when switching tabs or navigating away StatusTabButton {
Loader { leftPadding: 0
id: loader width: implicitWidth
Layout.fillWidth: true text: qsTr("Assets")
Layout.fillHeight: true }
active: visible StatusTabButton {
width: implicitWidth
sourceComponent: { text: qsTr("Collectibles")
switch (tabBar.currentIndex) { }
case d.assetsTabIndex: StatusTabButton {
return tokensPanel width: implicitWidth
case d.collectiblesTabIndex: text: qsTr("Hidden")
return collectiblesPanel }
case d.hiddenTabIndex: StatusTabButton {
return hiddenPanel width: implicitWidth
case d.advancedTabIndex: text: qsTr("Advanced")
return advancedTab
} }
} }
}
Component { // NB: we want to discard any pending unsaved changes when switching tabs or navigating away
id: tokensPanel Loader {
ManageAssetsPanel { id: loader
getCurrencyAmount: function (balance, symbol) { Layout.fillWidth: true
return root.getCurrencyAmount(balance, symbol) Layout.fillHeight: true
} active: visible
getCurrentCurrencyAmount: function (balance) {
return root.getCurrentCurrencyAmount(balance)
}
controller: d.assetsController
}
}
Component { sourceComponent: {
id: collectiblesPanel switch (tabBar.currentIndex) {
ManageCollectiblesPanel { case d.assetsTabIndex:
controller: d.collectiblesController return tokensPanel
Component.onCompleted: d.checkLoadMoreCollectibles() case d.collectiblesTabIndex:
} return collectiblesPanel
} case d.hiddenTabIndex:
return hiddenPanel
Component { case d.advancedTabIndex:
id: hiddenPanel return advancedTab
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
} }
} }
StatusDialogDivider { }
Layout.fillWidth: true
}
StatusListItem {
Layout.fillWidth: true
title: qsTr("Dont display assets with balance lower than")
components: [ Component {
CurrencyAmountInput { id: tokensPanel
enabled: displayThresholdSwitch.checked ManageAssetsPanel {
currencySymbol: SharedStores.RootStore.currencyStore.currentCurrency getCurrencyAmount: function (balance, symbol) {
value: 0.10 // FIXME integrate with backend (#13178) return root.getCurrencyAmount(balance, symbol)
},
StatusSwitch {
id: displayThresholdSwitch
checked: false // FIXME integrate with backend (#13178)
onCheckedChanged: {
// FIXME integrate with backend (#13178)
}
}
]
onClicked: {
displayThresholdSwitch.checked = !displayThresholdSwitch.checked
} }
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 Component {
Layout.topMargin: 18 id: hiddenPanel
Layout.bottomMargin: 18 ManageHiddenPanel {
StatusBaseText { 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 Layout.fillWidth: true
text: qsTr("Token lists") title: qsTr("Show community assets when sending tokens")
color: Style.current.textColor
components: [
StatusSwitch {
id: showCommunityAssetsSwitch
checked: true // FIXME integrate with backend (#13178)
onCheckedChanged: {
// FIXME integrate with backend (#13178)
}
}
]
onClicked: {
showCommunityAssetsSwitch.checked = !showCommunityAssetsSwitch.checked
}
} }
StatusBaseText { StatusDialogDivider {
Layout.alignment: Qt.AlignRight Layout.fillWidth: true
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 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"] keys: isCommunityToken ? ["x-status-draggable-community-token-item"] : ["x-status-draggable-regular-token-item"]
width: ListView.view ? ListView.view.width : 0 width: ListView.view ? ListView.view.width : 0
height: visible ? delegate.height : 0 height: delegate.height
onEntered: function(drag) { onEntered: function(drag) {
const from = drag.source.visualIndex const from = drag.source.visualIndex
const to = delegate.visualIndex const to = delegate.visualIndex
if (to === from) if (to === from)
return return
ListView.view.model.moveItem(from, to) ListView.view.model.moveItem(from, to)
drag.accept() drag.accept()
} }

View File

@ -35,7 +35,7 @@ DropArea {
keys: isCollection ? ["x-status-draggable-collection-group-item"] : ["x-status-draggable-community-group-item"] keys: isCollection ? ["x-status-draggable-collection-group-item"] : ["x-status-draggable-community-group-item"]
width: ListView.view ? ListView.view.width : 0 width: ListView.view ? ListView.view.width : 0
height: visible ? groupedCommunityTokenDelegate.implicitHeight : 0 height: groupedCommunityTokenDelegate.implicitHeight
onEntered: function(drag) { onEntered: function(drag) {
const from = drag.source.visualIndex const from = drag.source.visualIndex

View File

@ -1,17 +1,22 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.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.Components 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Models 0.1 import StatusQ.Models 0.1
import utils 1.0 import shared.controls 1.0
import AppLayouts.Wallet.controls 1.0 import AppLayouts.Wallet.controls 1.0
import "internals"
Control { Control {
id: root id: root
@ -37,18 +42,35 @@ Control {
root.controller.clearSettings(); root.controller.clearSettings();
} }
QtObject {
id: d
contentItem: ColumnLayout { readonly property int sectionHeight: 64
spacing: Style.current.padding }
StatusListView { contentItem: DoubleFlickableWithFolding {
Layout.fillWidth: true id: doubleFlickable
clip: true
ScrollBar.vertical: StatusScrollBar {
policy: ScrollBar.AsNeeded
visible: resolveVisibility(policy, doubleFlickable.height,
doubleFlickable.contentHeight)
}
flickable1: ManageTokensListViewBase {
model: root.controller.regularTokensModel model: root.controller.regularTokensModel
implicitHeight: contentHeight width: doubleFlickable.width
interactive: false
displaced: Transition { ScrollBar.vertical: null
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
header: FoldableHeader {
width: ListView.view.width
title: qsTr("Assets")
folded: doubleFlickable.flickable1Folded
onToggleFolding: doubleFlickable.flip1Folding()
} }
delegate: ManageTokensDelegate { delegate: ManageTokensDelegate {
@ -63,78 +85,69 @@ Control {
return root.getCurrentCurrencyAmount(balance) return root.getCurrentCurrencyAmount(balance)
} }
} }
placeholderText: qsTr("Your assets will appear here")
} }
RowLayout { flickable2: ManageTokensListViewBase {
Layout.fillWidth: true width: doubleFlickable.width
Layout.topMargin: Style.current.padding
visible: root.controller.communityTokensModel.count model: root.controller.arrangeByCommunity ? communityGroupedModel
StatusBaseText { : communityNonGroupedModel
Layout.fillWidth: true
text: qsTr("Community") header: FoldableHeader {
} width: ListView.view.width
StatusSwitch { title: qsTr("Community minted")
LayoutMirroring.enabled: true switchText: qsTr("Arrange by community")
LayoutMirroring.childrenInherit: true folded: doubleFlickable.flickable2Folded
id: switchArrangeByCommunity
textColor: Theme.palette.baseColor1
font.pixelSize: 13
text: qsTr("Arrange by community")
checked: root.controller.arrangeByCommunity checked: root.controller.arrangeByCommunity
onToggled: root.controller.arrangeByCommunity = checked
}
}
Loader { onToggleFolding: doubleFlickable.flip2Folding()
Layout.fillWidth: true onToggleSwitch: root.controller.arrangeByCommunity = checked
active: root.controller.communityTokensModel.count }
visible: active
sourceComponent: switchArrangeByCommunity.checked ? cmpCommunityTokenGroups : cmpCommunityTokens placeholderText: qsTr("Your community minted assets will appear here")
} }
} }
Component { DelegateModel {
id: cmpCommunityTokens id: communityNonGroupedModel
StatusListView {
model: root.controller.communityTokensModel
implicitHeight: contentHeight
interactive: false
displaced: Transition { model: root.controller.communityTokensModel
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
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)
} }
getCurrentCurrencyAmount: function (balance) {
delegate: ManageTokensDelegate { return root.getCurrentCurrencyAmount(balance)
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)
}
} }
} }
} }
Component { DelegateModel {
id: cmpCommunityTokenGroups id: communityGroupedModel
StatusListView {
model: root.controller.communityTokenGroupsModel
implicitHeight: contentHeight
interactive: false
displaced: Transition { model: root.controller.communityTokenGroupsModel
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
delegate: ManageTokensGroupDelegate { function moveItem(from, to) {
controller: root.controller model.moveItem(from, to)
dragParent: root }
dragEnabled: root.controller.communityTokenGroupsModel.count > 1
} 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 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.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.Controls 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Models 0.1 import StatusQ.Core.Utils 0.1
import utils 1.0
import shared.controls 1.0
import AppLayouts.Wallet.controls 1.0 import AppLayouts.Wallet.controls 1.0
import "internals"
Control { Control {
id: root id: root
@ -36,157 +33,133 @@ Control {
root.controller.clearSettings(); root.controller.clearSettings();
} }
contentItem: ColumnLayout { contentItem: DoubleFlickableWithFolding {
spacing: Style.current.padding id: doubleFlickable
ShapeRectangle { clip: true
Layout.fillWidth: true
Layout.margins: 2 ScrollBar.vertical: StatusScrollBar {
visible: !root.controller.regularTokensModel.count && !root.controller.communityTokensModel.count policy: ScrollBar.AsNeeded
text: qsTr("Youll be able to manage the display of your collectibles here") visible: resolveVisibility(policy, doubleFlickable.height,
doubleFlickable.contentHeight)
} }
RowLayout { flickable1: ManageTokensListViewBase {
Layout.fillWidth: true objectName: "communityTokensListView"
Layout.topMargin: Style.current.padding
visible: root.controller.communityTokensModel.count width: doubleFlickable.width
StatusBaseText {
Layout.fillWidth: true model: root.controller.arrangeByCommunity
text: qsTr("Community minted") ? communityGroupedModel : communityNonGroupedModel
}
StatusSwitch { header: FoldableHeader {
objectName: "switchArrangeByCommunity" objectName: "communityHeader"
LayoutMirroring.enabled: true
LayoutMirroring.childrenInherit: true width: ListView.view.width
id: switchArrangeByCommunity title: qsTr("Community minted")
textColor: Theme.palette.baseColor1 switchText: qsTr("Arrange by community")
font.pixelSize: 13 folded: doubleFlickable.flickable1Folded
text: qsTr("Arrange by community")
checked: root.controller.arrangeByCommunity 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 { flickable2: ManageTokensListViewBase {
objectName: "loaderCommunityTokens" objectName: "otherTokensListView"
Layout.fillWidth: true
active: root.controller.communityTokensModel.count
visible: active
sourceComponent: switchArrangeByCommunity.checked ? cmpCommunityTokenGroups : cmpCommunityTokens
}
RowLayout { width: doubleFlickable.width
Layout.fillWidth: true
Layout.topMargin: Style.current.padding model: root.controller.arrangeByCollection
visible: root.controller.regularTokensModel.count ? otherGroupedModel : otherNonGroupedModel
StatusBaseText {
Layout.fillWidth: true header: FoldableHeader {
text: qsTr("Other") objectName: "nonCommunityHeader"
}
StatusSwitch { width: ListView.view.width
LayoutMirroring.enabled: true title: qsTr("Other")
LayoutMirroring.childrenInherit: true switchText: qsTr("Arrange by collection")
id: switchArrangeByCollection folded: doubleFlickable.flickable2Folded
textColor: Theme.palette.baseColor1
font.pixelSize: 13
text: qsTr("Arrange by collection")
checked: root.controller.arrangeByCollection checked: root.controller.arrangeByCollection
onToggled: root.controller.arrangeByCollection = checked
}
}
Loader { onToggleFolding: doubleFlickable.flip2Folding()
objectName: "loaderRegularTokens" onToggleSwitch: root.controller.arrangeByCollection = checked
Layout.fillWidth: true }
active: root.controller.regularTokensModel.count
visible: active placeholderText: qsTr("Your other collectibles will appear here")
sourceComponent: switchArrangeByCollection.checked ? cmpCollectionTokenGroups : cmpRegularTokens
} }
} }
Component { DelegateModel {
id: cmpCommunityTokens id: communityNonGroupedModel
StatusListView {
objectName: "lvCommunityTokens"
model: root.controller.communityTokensModel
implicitHeight: contentHeight
interactive: false
displaced: Transition { model: root.controller.communityTokensModel
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
delegate: ManageTokensDelegate { function moveItem(from, to) {
isCollectible: true model.moveItem(from, to)
controller: root.controller }
dragParent: root
count: root.controller.communityTokensModel.count delegate: ManageTokensDelegate {
dragEnabled: count > 1 isCollectible: true
} controller: root.controller
dragParent: root
count: root.controller.communityTokensModel.count
dragEnabled: count > 1
} }
} }
Component { DelegateModel {
id: cmpCommunityTokenGroups id: communityGroupedModel
StatusListView {
objectName: "lvCommunityTokenGroups"
model: root.controller.communityTokenGroupsModel
implicitHeight: contentHeight
interactive: false
displaced: Transition { model: root.controller.communityTokenGroupsModel
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
delegate: ManageTokensGroupDelegate { function moveItem(from, to) {
isCollectible: true model.moveItem(from, to)
controller: root.controller }
dragParent: root
dragEnabled: root.controller.communityTokenGroupsModel.count > 1 delegate: ManageTokensGroupDelegate {
} isCollectible: true
controller: root.controller
dragParent: root
dragEnabled: root.controller.communityTokenGroupsModel.count > 1
} }
} }
Component { DelegateModel {
id: cmpRegularTokens id: otherNonGroupedModel
StatusListView {
objectName: "lvRegularTokens"
model: root.controller.regularTokensModel
implicitHeight: contentHeight
interactive: false
displaced: Transition { model: root.controller.regularTokensModel
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
delegate: ManageTokensDelegate { function moveItem(from, to) {
isCollectible: true model.moveItem(from, to)
controller: root.controller }
dragParent: root
count: root.controller.regularTokensModel.count delegate: ManageTokensDelegate {
dragEnabled: count > 1 isCollectible: true
} controller: root.controller
dragParent: root
count: root.controller.regularTokensModel.count
dragEnabled: count > 1
} }
} }
Component { DelegateModel {
id: cmpCollectionTokenGroups id: otherGroupedModel
StatusListView {
objectName: "lvCollectionTokenGroups"
model: root.controller.collectionGroupsModel
implicitHeight: contentHeight
interactive: false
displaced: Transition { model: root.controller.collectionGroupsModel
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
delegate: ManageTokensGroupDelegate { function moveItem(from, to) {
isCollection: true model.moveItem(from, to)
controller: root.controller }
dragParent: root
dragEnabled: root.controller.collectionGroupsModel.count > 1 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 ColumnLayout { // no assets placeholder
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: false
spacing: 0 spacing: 0
visible: !d.assetsCount visible: !d.assetsCount
SectionDelegate { SectionDelegate {
@ -196,9 +198,11 @@ Control {
} }
StatusListView { StatusListView {
id: listView
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: contentHeight
Layout.fillHeight: true Layout.fillHeight: true
model: d.sfpm model: d.sfpm
displaced: Transition { displaced: Transition {
@ -221,21 +225,29 @@ Control {
isCollectible: section == "true" isCollectible: section == "true"
} }
section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart 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 Item {
Layout.fillWidth: true Layout.fillHeight: true
spacing: 0 visible: listView.count === 0
visible: !d.collectiblesCount
SectionDelegate {
Layout.fillWidth: true
isCollectible: true
}
Placeholder {
Layout.fillWidth: true
isCollectible: true
visible: d.collectiblesExpanded
}
} }
} }
} }

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