feat: Manage Collectibles panel UI component & model
- implements a QML panel to organize collectibles - factors out the delegates to separate files to be reusable with the Assets tab - adds QML tests to assess the UI functionality (move, show/hide, save/load) - does not cover the problematic "Arrange by collection" switch (TBD later) Fixes: https://github.com/status-im/status-desktop/issues/12379
This commit is contained in:
parent
48c9e372dc
commit
ba30afd202
|
@ -0,0 +1,87 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core 0.1
|
||||
|
||||
import AppLayouts.Wallet.panels 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import Storybook 1.0
|
||||
import Models 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
|
||||
Logs { id: logs }
|
||||
|
||||
orientation: Qt.Horizontal
|
||||
|
||||
ManageCollectiblesModel {
|
||||
id: collectiblesModel
|
||||
}
|
||||
|
||||
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
ManageCollectiblesPanel {
|
||||
id: showcasePanel
|
||||
width: 500
|
||||
baseModel: ctrlEmptyModel.checked ? null : collectiblesModel
|
||||
}
|
||||
}
|
||||
|
||||
LogsAndControlsPanel {
|
||||
id: logsAndControlsPanel
|
||||
|
||||
SplitView.minimumWidth: 150
|
||||
SplitView.preferredWidth: 250
|
||||
|
||||
logsView.logText: logs.logText
|
||||
|
||||
ColumnLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Dirty: %1".arg(showcasePanel.dirty ? "true" : "false")
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Save"
|
||||
onClicked: showcasePanel.saveSettings()
|
||||
}
|
||||
|
||||
Button {
|
||||
enabled: showcasePanel.dirty
|
||||
text: "Revert"
|
||||
onClicked: showcasePanel.revert()
|
||||
}
|
||||
|
||||
Button {
|
||||
enabled: false
|
||||
text: "Random data (TODO)"
|
||||
onClicked: {
|
||||
collectiblesModel.clear()
|
||||
collectiblesModel.randomizeData()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Clear settings"
|
||||
onClicked: showcasePanel.clearSettings()
|
||||
}
|
||||
|
||||
Switch {
|
||||
id: ctrlEmptyModel
|
||||
text: "Empty model"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
|
@ -1,5 +1,6 @@
|
|||
#include <QtQuickTest/quicktest.h>
|
||||
#include <QQmlEngine>
|
||||
#include <QtQuickTest>
|
||||
|
||||
#include "src/TextUtils.h"
|
||||
|
||||
class Setup : public QObject
|
||||
|
@ -21,6 +22,8 @@ public slots:
|
|||
engine->addImportPath(path);
|
||||
|
||||
qmlRegisterSingletonType<TextUtils>("TextUtils", 1, 0, "TextUtils", &TextUtils::qmlInstance);
|
||||
|
||||
QStandardPaths::setTestModeEnabled(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,374 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtTest 1.15
|
||||
|
||||
import AppLayouts.Wallet.panels 1.0
|
||||
|
||||
import Storybook 1.0
|
||||
import Models 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 600
|
||||
height: 400
|
||||
|
||||
ManageCollectiblesModel {
|
||||
id: collectiblesModel
|
||||
}
|
||||
|
||||
Component {
|
||||
id: componentUnderTest
|
||||
ManageCollectiblesPanel {
|
||||
id: showcasePanel
|
||||
width: 500
|
||||
baseModel: collectiblesModel
|
||||
}
|
||||
}
|
||||
|
||||
TestCase {
|
||||
name: "ManageCollectiblesPanel"
|
||||
when: windowShown
|
||||
|
||||
property ManageCollectiblesPanel controlUnderTest: null
|
||||
|
||||
function findDelegateIndexWithTitle(listview, title) {
|
||||
waitForItemPolished(listview)
|
||||
const count = listview.count
|
||||
for (let i = 0; i < count; i++) {
|
||||
const item = listview.itemAtIndex(i)
|
||||
if (!!item && item.visible && item.title === title)
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
function findDelegateMenuAction(listview, index, actionName, isGroup=false) {
|
||||
const token = findChild(listview, "manageTokens%2Delegate-%1".arg(index).arg(isGroup ? "Group" : ""))
|
||||
verify(!!token)
|
||||
const delegateBtn = findChild(token, "btnManageTokenMenu-%1".arg(index))
|
||||
verify(!!delegateBtn)
|
||||
mouseClick(delegateBtn)
|
||||
const btnMenuLoader = findChild(delegateBtn, "manageTokensContextMenuLoader")
|
||||
verify(!!btnMenuLoader)
|
||||
tryCompare(btnMenuLoader, "active", true)
|
||||
const btnMenu = btnMenuLoader.item
|
||||
verify(!!btnMenu)
|
||||
verify(btnMenu.open)
|
||||
return findChild(btnMenu, actionName)
|
||||
}
|
||||
|
||||
function triggerDelegateMenuAction(listview, index, actionName, isGroup=false) {
|
||||
const action = findDelegateMenuAction(listview, index, actionName, isGroup)
|
||||
verify(!!action)
|
||||
action.trigger()
|
||||
}
|
||||
|
||||
function init() {
|
||||
controlUnderTest = createTemporaryObject(componentUnderTest, root)
|
||||
}
|
||||
|
||||
function test_showHideToken() {
|
||||
verify(!controlUnderTest.dirty)
|
||||
|
||||
const lvHidden = findChild(controlUnderTest, "lvHiddenTokens")
|
||||
verify(!!lvHidden)
|
||||
verify(lvHidden.count === 0)
|
||||
|
||||
const lvRegular = findChild(controlUnderTest, "lvRegularTokens")
|
||||
verify(!!lvRegular)
|
||||
const lvRegularCount = lvRegular.count
|
||||
verify(lvRegularCount === 6)
|
||||
|
||||
const delegate0 = findChild(lvRegular, "manageTokensDelegate-0")
|
||||
verify(!!delegate0)
|
||||
const title = delegate0.title
|
||||
triggerDelegateMenuAction(lvRegular, 0, "miHideToken")
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
|
||||
// verify we now have +1 hidden and -1 regular tokens after the "hide" operation
|
||||
waitForItemPolished(lvHidden)
|
||||
tryCompare(lvHidden, "count", 1)
|
||||
tryCompare(lvRegular, "count", lvRegularCount-1)
|
||||
// verify it's the same item we've just hidden
|
||||
const hiddenToken = findChild(lvHidden, "manageTokensDelegate-0")
|
||||
compare(hiddenToken.title, title)
|
||||
|
||||
// trigger the "show" action
|
||||
triggerDelegateMenuAction(lvHidden, 0, "miShowToken")
|
||||
|
||||
// verify the counts are back to original
|
||||
waitForItemPolished(lvHidden)
|
||||
compare(lvHidden.count, 0)
|
||||
compare(lvRegular.count, lvRegularCount)
|
||||
|
||||
// verify we got appended to the regular list by checking we have the same title of the delegate
|
||||
const delegateN = findChild(lvRegular, "manageTokensDelegate-%1".arg(lvRegular.count-1))
|
||||
verify(!!delegateN)
|
||||
const titleN = delegateN.title
|
||||
compare(title, titleN)
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
}
|
||||
|
||||
function test_showHideCommunityGroup() {
|
||||
verify(!controlUnderTest.dirty)
|
||||
|
||||
const loaderCommunityTokens = findChild(controlUnderTest, "loaderCommunityTokens")
|
||||
verify(!!loaderCommunityTokens)
|
||||
tryCompare(loaderCommunityTokens, "active", true)
|
||||
const switchArrangeByCommunity = findChild(controlUnderTest, "switchArrangeByCommunity")
|
||||
verify(!!switchArrangeByCommunity)
|
||||
switchArrangeByCommunity.toggle()
|
||||
const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups")
|
||||
verify(!!lvCommunityTokenGroups)
|
||||
|
||||
// verify we have 2 community collectible groups
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
triggerDelegateMenuAction(lvCommunityTokenGroups, 0, "miHideTokenGroup", true)
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
|
||||
// verify we have one less group
|
||||
waitForItemPolished(lvCommunityTokenGroups)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 1)
|
||||
const lvHidden = findChild(controlUnderTest, "lvHiddenTokens")
|
||||
verify(!!lvHidden)
|
||||
tryCompare(lvHidden, "count", 4) // we've just hidden 4 collectibles coming from this group
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
|
||||
// verify hidden items are not draggable
|
||||
const hiddenToken = findChild(lvHidden, "manageTokensDelegate-0")
|
||||
verify(!!hiddenToken)
|
||||
compare(hiddenToken.dragEnabled, false)
|
||||
const hiddenDraggable = findChild(hiddenToken, "draggableDelegate")
|
||||
verify(!!hiddenDraggable)
|
||||
mousePress(hiddenToken)
|
||||
tryCompare(hiddenDraggable, "dragActive", false)
|
||||
mouseRelease(hiddenToken)
|
||||
|
||||
// now show one of the 4 hidden tokens
|
||||
waitForItemPolished(lvHidden)
|
||||
triggerDelegateMenuAction(lvHidden, 0, "miShowToken")
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
|
||||
// verify we again have 2 community groups, and one less hidden token
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
tryCompare(lvHidden, "count", 3)
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
|
||||
// now mass show tokens from this group, verify we have 0 hidden tokens and 2 visible groups
|
||||
triggerDelegateMenuAction(lvHidden, 0, "miShowTokenGroup")
|
||||
waitForItemPolished(lvHidden)
|
||||
tryCompare(lvHidden, "count", 0)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
}
|
||||
|
||||
function test_dnd() {
|
||||
verify(!controlUnderTest.dirty)
|
||||
|
||||
const lvRegular = findChild(controlUnderTest, "lvRegularTokens")
|
||||
verify(!!lvRegular)
|
||||
verify(lvRegular.count !== 0)
|
||||
|
||||
const delegate0 = findChild(lvRegular, "manageTokensDelegate-0")
|
||||
verify(!!delegate0)
|
||||
const title0 = delegate0.title
|
||||
verify(!!title0)
|
||||
const title1 = findChild(lvRegular, "manageTokensDelegate-1").title
|
||||
verify(!!title1)
|
||||
|
||||
// DND one item down (~80px in height)
|
||||
mouseDrag(delegate0, delegate0.width/2, delegate0.height/2, 0, 80)
|
||||
|
||||
// cross compare the titles
|
||||
tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", title1)
|
||||
tryCompare(findChild(lvRegular, "manageTokensDelegate-1"), "title", title0)
|
||||
verify(controlUnderTest.dirty)
|
||||
}
|
||||
|
||||
function test_group_dnd() {
|
||||
verify(!controlUnderTest.dirty)
|
||||
|
||||
const switchArrangeByCommunity = findChild(controlUnderTest, "switchArrangeByCommunity")
|
||||
verify(!!switchArrangeByCommunity)
|
||||
mouseClick(switchArrangeByCommunity)
|
||||
|
||||
const switchCollapseCommunityGroups = findChild(controlUnderTest, "switchCollapseCommunityGroups")
|
||||
verify(!!switchCollapseCommunityGroups)
|
||||
mouseClick(switchCollapseCommunityGroups)
|
||||
|
||||
const loaderCommunityTokens = findChild(controlUnderTest, "loaderCommunityTokens")
|
||||
verify(!!loaderCommunityTokens)
|
||||
tryCompare(loaderCommunityTokens, "active", true)
|
||||
const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups")
|
||||
verify(!!lvCommunityTokenGroups)
|
||||
waitForItemPolished(lvCommunityTokenGroups)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
|
||||
const group0 = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0")
|
||||
const title0 = group0.title
|
||||
verify(!!title0)
|
||||
const title1 = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1").title
|
||||
verify(!!title1)
|
||||
verify(title0 !== title1)
|
||||
|
||||
// DND one group down (~80px in height)
|
||||
mouseDrag(group0, group0.width/2, group0.height/2, 0, 80)
|
||||
|
||||
// cross compare the titles
|
||||
tryCompare(findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0"), "title", title1)
|
||||
tryCompare(findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1"), "title", title0)
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
}
|
||||
|
||||
function test_group_move_hide_show_community_token() {
|
||||
verify(!controlUnderTest.dirty)
|
||||
const titleToTest = "Bearz"
|
||||
|
||||
const switchArrangeByCommunity = findChild(controlUnderTest, "switchArrangeByCommunity")
|
||||
verify(!!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", 2)
|
||||
|
||||
// get the "Bearz" group at index 1
|
||||
var bearzGroupTokenDelegate = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1")
|
||||
const bearzTitle = bearzGroupTokenDelegate.title
|
||||
compare(bearzTitle, titleToTest)
|
||||
verify(!!bearzGroupTokenDelegate)
|
||||
waitForItemPolished(bearzGroupTokenDelegate)
|
||||
|
||||
// get the Bearz child listview
|
||||
const bearzChildLV = findChild(bearzGroupTokenDelegate, "manageTokensGroupListView")
|
||||
verify(!!bearzChildLV)
|
||||
|
||||
// find the 2385 delegate from the Bearz group and hide it
|
||||
const bear2385DelegateIdx = findDelegateIndexWithTitle(bearzChildLV, "KILLABEAR #2385")
|
||||
verify(bear2385DelegateIdx !== -1)
|
||||
triggerDelegateMenuAction(bearzChildLV, bear2385DelegateIdx, "miHideCommunityToken")
|
||||
verify(controlUnderTest.dirty)
|
||||
|
||||
// verify the hidden section now has 1 item and it's the one we just hid
|
||||
const lvHidden = findChild(controlUnderTest, "lvHiddenTokens")
|
||||
verify(!!lvHidden)
|
||||
waitForItemPolished(lvHidden)
|
||||
verify(lvHidden.count === 1)
|
||||
tryCompare(findChild(lvHidden, "manageTokensDelegate-0"), "title", "KILLABEAR #2385")
|
||||
|
||||
// now move the Bearz group up so that it's first (ends up at index 0)
|
||||
waitForItemPolished(controlUnderTest)
|
||||
triggerDelegateMenuAction(lvCommunityTokenGroups, 1, "miMoveUp", true)
|
||||
verify(controlUnderTest.dirty)
|
||||
bearzGroupTokenDelegate = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0")
|
||||
verify(!!bearzGroupTokenDelegate)
|
||||
|
||||
// get one of the other group's (Pandas) tokens and hide it
|
||||
const pandasGroupTokenDelegate = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1")
|
||||
verify(!!pandasGroupTokenDelegate)
|
||||
const pandasChildLV = findChild(pandasGroupTokenDelegate, "manageTokensGroupListView")
|
||||
verify(!!pandasChildLV)
|
||||
const panda909DelegateIdx = findDelegateIndexWithTitle(pandasChildLV, "Frenly Panda #909")
|
||||
triggerDelegateMenuAction(pandasChildLV, panda909DelegateIdx, "miHideCommunityToken")
|
||||
verify(controlUnderTest.dirty)
|
||||
|
||||
// finally verify that the Bearz group is still at top
|
||||
waitForItemPolished(lvCommunityTokenGroups)
|
||||
tryCompare(findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0"), "title", titleToTest)
|
||||
}
|
||||
|
||||
function test_moveOperations() {
|
||||
verify(!controlUnderTest.dirty)
|
||||
|
||||
const lvRegular = findChild(controlUnderTest, "lvRegularTokens")
|
||||
verify(!!lvRegular)
|
||||
verify(lvRegular.count !== 0)
|
||||
|
||||
var delegate0 = findChild(lvRegular, "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")
|
||||
tryCompare(moveUpAction, "enabled", false)
|
||||
const moveTopAction = findDelegateMenuAction(lvRegular, 0, "miMoveToTop")
|
||||
tryCompare(moveTopAction, "enabled", false)
|
||||
|
||||
// trigger move to bottom
|
||||
triggerDelegateMenuAction(lvRegular, 0, "miMoveToBottom")
|
||||
|
||||
waitForItemPolished(lvRegular)
|
||||
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))
|
||||
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")
|
||||
tryCompare(moveDownAction, "enabled", false)
|
||||
const moveBottomAction = findDelegateMenuAction(lvRegular, lvRegular.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)
|
||||
|
||||
// trigger move down and verify we got the same title (item) again
|
||||
triggerDelegateMenuAction(lvRegular, 0, "miMoveDown")
|
||||
tryCompare(findChild(lvRegular, "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)
|
||||
}
|
||||
|
||||
function test_saveLoad() {
|
||||
// start with clear settings
|
||||
controlUnderTest.clearSettings()
|
||||
controlUnderTest.revert()
|
||||
|
||||
verify(!controlUnderTest.dirty)
|
||||
const titleToTest = "Big Kitty"
|
||||
|
||||
const lvRegular = findChild(controlUnderTest, "lvRegularTokens")
|
||||
verify(!!lvRegular)
|
||||
const bigKittyIndex = findDelegateIndexWithTitle(lvRegular, titleToTest)
|
||||
verify(bigKittyIndex !== -1)
|
||||
const title0 = findChild(lvRegular, "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)
|
||||
|
||||
// save
|
||||
verify(controlUnderTest.dirty)
|
||||
controlUnderTest.saveSettings()
|
||||
verify(!controlUnderTest.dirty)
|
||||
|
||||
// load the settings and check BigKitty is still on top
|
||||
controlUnderTest.revert()
|
||||
verify(!controlUnderTest.dirty)
|
||||
waitForItemPolished(lvRegular)
|
||||
tryCompare(findChild(lvRegular, "manageTokensDelegate-0"), "title", titleToTest)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
import QtQuick 2.15
|
||||
import QtQml.Models 2.15
|
||||
|
||||
import Models 1.0
|
||||
|
||||
ListModel {
|
||||
function randomizeData() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
readonly property var data: [
|
||||
{
|
||||
uid: "fp#9140",
|
||||
name: "Frenly Panda #9140",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "fpan",
|
||||
communityName: "Frenly Pandas",
|
||||
communityImage: "https://pbs.twimg.com/profile_images/1599347398769143808/C6qG3RQv_400x400.jpg",
|
||||
imageUrl: "https://i.seadn.io/gae/qPfQjj4P1w0xVQXAmQJLmQ4ZtLFAJU6oiH69Lsny82LFbipLAgXhHKrcLBx2U09SmRnzeHY0ygz-3NIb-JegE_hWrZquFeL-qUPXPdw",
|
||||
isLoading: false,
|
||||
backgroundColor: "pink"
|
||||
},
|
||||
{
|
||||
uid: "123",
|
||||
name: "Punx not dead!",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
imageUrl: ModelsData.collectibles.cryptoPunks,
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "pp23",
|
||||
name: "pepepunk#23",
|
||||
collectionUid: "pepepunks",
|
||||
collectionName: "",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
imageUrl: "https://i.seadn.io/s/raw/files/ba2811bb5cd0bed67529d69fa92ef5aa.jpg?auto=format&dpr=1&w=1000",
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "34545656768",
|
||||
name: "Kitty 1",
|
||||
collectionUid: "KT",
|
||||
collectionName: "Kitties",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
imageUrl: ModelsData.collectibles.kitty1Big,
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "123456",
|
||||
name: "Kitty 2",
|
||||
collectionUid: "KT",
|
||||
collectionName: "Kitties",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
imageUrl: ModelsData.collectibles.kitty2Big,
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "12345645459537432",
|
||||
name: "Big Kitty",
|
||||
collectionUid: "KT",
|
||||
collectionName: "Kitties",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
imageUrl: ModelsData.collectibles.kitty3Big,
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "691",
|
||||
name: "KILLABEAR #691",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "bbrz",
|
||||
communityName: "Bearz",
|
||||
communityImage: "https://i.seadn.io/gcs/files/4a875f997063f4f3772190852c1c44f0.png?w=128&auto=format",
|
||||
imageUrl: "https://assets.killabears.com/content/killabears/gif/691-e81f892696a8ae700e0dbc62eb072060679a2046d1ef5eb2671bdb1fad1f68e3.gif",
|
||||
isLoading: true,
|
||||
backgroundColor: "navy"
|
||||
},
|
||||
{
|
||||
uid: "8876",
|
||||
name: "KILLABEAR #2385",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "bbrz",
|
||||
communityName: "Bearz",
|
||||
communityImage: "https://i.seadn.io/gcs/files/4a875f997063f4f3772190852c1c44f0.png?w=128&auto=format",
|
||||
imageUrl: "https://assets.killabears.com/content/killabears/transparent-512/2385-86ba13cc6945ed0aea7c32a363a96be2f218898358745ae07b947452cb7e4e79.png",
|
||||
isLoading: false,
|
||||
backgroundColor: "pink"
|
||||
},
|
||||
{
|
||||
uid: "fp#3195",
|
||||
name: "Frenly Panda #3195",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "fpan",
|
||||
communityName: "Frenly Pandas",
|
||||
communityImage: "https://pbs.twimg.com/profile_images/1599347398769143808/C6qG3RQv_400x400.jpg",
|
||||
imageUrl: "https://i.seadn.io/s/raw/files/59ad1f2e3c5eb5d4b62c06e200076514.png",
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "fp#4297",
|
||||
name: "Frenly Panda #4297",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "fpan",
|
||||
communityName: "Frenly Pandas",
|
||||
communityImage: "https://pbs.twimg.com/profile_images/1599347398769143808/C6qG3RQv_400x400.jpg",
|
||||
imageUrl: "https://i.seadn.io/gae/K4_vmYtXAqU6LTnGDliLtJZc4UPmf9jUlk09_FDbXvSKKyUARyyV9RQEgXdb5bjje5OE9j9ZryC5pzcwBwH7TDOIl8oq7D2tSJ7p",
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "fp#909",
|
||||
name: "Frenly Panda #909",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "fpan",
|
||||
communityName: "Frenly Pandas",
|
||||
communityImage: "https://pbs.twimg.com/profile_images/1599347398769143808/C6qG3RQv_400x400.jpg",
|
||||
imageUrl: "https://i.seadn.io/gae/cR-Bjmb6DsrywCJMOqEBPkkrMHjbTzeRSAKIvLpd7i8ss6raYZ3-doh8oF2z8bJsnmfC1oR3kllz6UxMfFaYAKdXYzXlhfVsDHo6bg",
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "pp21",
|
||||
name: "pepepunk#21",
|
||||
collectionUid: "pepepunks",
|
||||
collectionName: "",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
imageUrl: "https://i.seadn.io/s/raw/files/cfa559bb63e4378f17649c1e3b8f18fe.jpg?auto=format&dpr=1&w=1000",
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
]
|
||||
|
||||
Component.onCompleted: append(data)
|
||||
}
|
|
@ -63,6 +63,7 @@ QtObject {
|
|||
readonly property string custom: Style.png("collectibles/SNT")
|
||||
readonly property string doodles: Style.png("collectibles/Doodles")
|
||||
readonly property string mana: Style.png("collectibles/MANA-token-icon")
|
||||
readonly property string cryptoPunks: Style.png("collectibles/CryptoPunks")
|
||||
}
|
||||
|
||||
readonly property QtObject networks: QtObject {
|
||||
|
|
|
@ -9,6 +9,7 @@ FlatTokensModel 1.0 FlatTokensModel.qml
|
|||
IconModel 1.0 IconModel.qml
|
||||
LinkPreviewModel 1.0 LinkPreviewModel.qml
|
||||
MintedTokensModel 1.0 MintedTokensModel.qml
|
||||
ManageCollectiblesModel 1.0 ManageCollectiblesModel.qml
|
||||
ManageTokensModel 1.0 ManageTokensModel.qml
|
||||
RecipientModel 1.0 RecipientModel.qml
|
||||
SourceOfTokensModel 1.0 SourceOfTokensModel.qml
|
||||
|
|
|
@ -295,7 +295,6 @@ ItemDelegate {
|
|||
}
|
||||
|
||||
Loader {
|
||||
asynchronous: true
|
||||
active: !!root.icon.name || !!root.icon.source
|
||||
visible: active
|
||||
sourceComponent: root.hasIcon ? iconComponent : root.hasImage ? imageComponent : letterIdenticonComponent
|
||||
|
@ -375,6 +374,7 @@ ItemDelegate {
|
|||
width: root.icon.width
|
||||
height: root.icon.height
|
||||
image.source: root.icon.source
|
||||
image.sourceSize: Qt.size(width, height)
|
||||
showLoadingIndicator: true
|
||||
image.fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
|
|
|
@ -142,6 +142,8 @@
|
|||
<file>assets/img/icons/arrow-left.svg</file>
|
||||
<file>assets/img/icons/arrow-right.svg</file>
|
||||
<file>assets/img/icons/arrow-up.svg</file>
|
||||
<file>assets/img/icons/arrow-top.svg</file>
|
||||
<file>assets/img/icons/arrow-bottom.svg</file>
|
||||
<file>assets/img/icons/arrow.svg</file>
|
||||
<file>assets/img/icons/audio.svg</file>
|
||||
<file>assets/img/icons/backspace.svg</file>
|
||||
|
|
|
@ -51,6 +51,7 @@ ManageTokensController::ManageTokensController(QObject* parent)
|
|||
reloadCommunityIds();
|
||||
m_communityTokensModel->setCommunityIds(m_communityIds);
|
||||
m_communityTokensModel->saveCustomSortOrder();
|
||||
m_communityTokensModel->applySort();
|
||||
});
|
||||
m_modelConnectionsInitialized = true;
|
||||
});
|
||||
|
@ -115,6 +116,9 @@ void ManageTokensController::saveSettings()
|
|||
{
|
||||
Q_ASSERT(!m_settingsKey.isEmpty());
|
||||
|
||||
if (m_arrangeByCommunity)
|
||||
m_communityTokensModel->applySort();
|
||||
|
||||
// gather the data to save
|
||||
SerializedTokenData result;
|
||||
for (auto model: {m_regularTokensModel, m_communityTokensModel})
|
||||
|
@ -127,11 +131,11 @@ void ManageTokensController::saveSettings()
|
|||
SerializedTokenData::const_key_value_iterator it = result.constKeyValueBegin();
|
||||
for (auto i = 0; it != result.constKeyValueEnd() && i < result.size(); it++, i++) {
|
||||
m_settings.setArrayIndex(i);
|
||||
const auto tuple = it->second;
|
||||
const auto& [pos, visible, groupId] = it->second;
|
||||
m_settings.setValue(QStringLiteral("symbol"), it->first);
|
||||
m_settings.setValue(QStringLiteral("pos"), std::get<0>(tuple));
|
||||
m_settings.setValue(QStringLiteral("visible"), std::get<1>(tuple));
|
||||
m_settings.setValue(QStringLiteral("groupId"), std::get<2>(tuple));
|
||||
m_settings.setValue(QStringLiteral("pos"), pos);
|
||||
m_settings.setValue(QStringLiteral("visible"), visible);
|
||||
m_settings.setValue(QStringLiteral("groupId"), groupId);
|
||||
}
|
||||
m_settings.endArray();
|
||||
m_settings.endGroup();
|
||||
|
@ -169,7 +173,7 @@ void ManageTokensController::loadSettings()
|
|||
qCWarning(manageTokens) << Q_FUNC_INFO << "Missing symbol while reading tokens settings";
|
||||
continue;
|
||||
}
|
||||
const auto pos = m_settings.value(QStringLiteral("pos"), -1).toInt();
|
||||
const auto pos = m_settings.value(QStringLiteral("pos"), INT_MAX).toInt();
|
||||
const auto visible = m_settings.value(QStringLiteral("visible"), true).toBool();
|
||||
const auto groupId = m_settings.value(QStringLiteral("groupId")).toString();
|
||||
m_settingsData.insert(symbol, {pos, visible, groupId});
|
||||
|
@ -180,7 +184,6 @@ void ManageTokensController::loadSettings()
|
|||
|
||||
void ManageTokensController::revert()
|
||||
{
|
||||
loadSettings();
|
||||
parseSourceModel();
|
||||
}
|
||||
|
||||
|
@ -203,6 +206,7 @@ void ManageTokensController::setSourceModel(QAbstractItemModel* newSourceModel)
|
|||
// clear all the models
|
||||
for (auto model: m_allModels)
|
||||
model->clear();
|
||||
m_settingsData.clear();
|
||||
m_communityIds.clear();
|
||||
m_sourceModel = newSourceModel;
|
||||
emit sourceModelChanged();
|
||||
|
@ -239,9 +243,12 @@ void ManageTokensController::parseSourceModel()
|
|||
model->clear();
|
||||
m_communityIds.clear();
|
||||
|
||||
// load settings
|
||||
loadSettings();
|
||||
|
||||
// read and transform the original data
|
||||
const auto newSize = m_sourceModel->rowCount();
|
||||
qCInfo(manageTokens) << "!!! PARSING" << newSize << "TOKENS";
|
||||
qCDebug(manageTokens) << "!!! PARSING" << newSize << "TOKENS";
|
||||
for (auto i = 0; i < newSize; i++) {
|
||||
addItem(i);
|
||||
}
|
||||
|
@ -259,7 +266,7 @@ void ManageTokensController::parseSourceModel()
|
|||
}
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
qCInfo(manageTokens) << "!!! PARSING SOURCE DATA TOOK" << t.nsecsElapsed()/1'000'000.f << "ms";
|
||||
qCDebug(manageTokens) << "!!! PARSING SOURCE DATA TOOK" << t.nsecsElapsed()/1'000'000.f << "ms";
|
||||
#endif
|
||||
|
||||
emit sourceModelChanged();
|
||||
|
@ -281,16 +288,21 @@ void ManageTokensController::addItem(int index)
|
|||
const auto communityId = dataForIndex(srcIndex, kCommunityIdRoleName).toString();
|
||||
const auto communityName = dataForIndex(srcIndex, kCommunityNameRoleName).toString();
|
||||
const auto visible = m_settingsData.contains(symbol) ? std::get<1>(m_settingsData.value(symbol)) : true;
|
||||
const auto bgColor = dataForIndex(srcIndex, kBackgroundColorRoleName).value<QColor>();
|
||||
const auto collectionUid = dataForIndex(srcIndex, kCollectionUidRoleName).toString();
|
||||
const auto collectionName = dataForIndex(srcIndex, kCollectionNameRoleName).toString();
|
||||
|
||||
TokenData token;
|
||||
token.symbol = symbol;
|
||||
token.name = dataForIndex(srcIndex, kNameRoleName).toString();
|
||||
token.image = dataForIndex(srcIndex, kTokenImageRoleName).toString();
|
||||
if (bgColor.isValid())
|
||||
token.backgroundColor = bgColor;
|
||||
token.communityId = communityId;
|
||||
token.communityName = !communityName.isEmpty() ? communityName : communityId;
|
||||
token.communityImage = dataForIndex(srcIndex, kCommunityImageRoleName).toString();
|
||||
token.collectionUid = dataForIndex(srcIndex, kCollectionUidRoleName).toString();
|
||||
token.collectionName = dataForIndex(srcIndex, kCollectionNameRoleName).toString();
|
||||
token.collectionUid = collectionUid;
|
||||
token.collectionName = !collectionName.isEmpty() ? collectionName : collectionUid;
|
||||
token.balance = dataForIndex(srcIndex, kEnabledNetworkBalanceRoleName);
|
||||
token.currencyBalance = dataForIndex(srcIndex, kEnabledNetworkCurrencyBalanceRoleName);
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ QHash<int, QByteArray> ManageTokensModel::roleNames() const
|
|||
{CurrencyBalanceRole, kEnabledNetworkCurrencyBalanceRoleName},
|
||||
{CustomSortOrderNoRole, kCustomSortOrderNoRoleName},
|
||||
{TokenImageRole, kTokenImageRoleName},
|
||||
{TokenBackgroundColorRole, kBackgroundColorRoleName},
|
||||
};
|
||||
|
||||
return roles;
|
||||
|
@ -142,6 +143,7 @@ QVariant ManageTokensModel::data(const QModelIndex& index, int role) const
|
|||
case CurrencyBalanceRole: return token.currencyBalance;
|
||||
case CustomSortOrderNoRole: return token.customSortOrderNo;
|
||||
case TokenImageRole: return token.image;
|
||||
case TokenBackgroundColorRole: return token.backgroundColor;
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QColor>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(manageTokens)
|
||||
|
||||
|
@ -16,16 +18,18 @@ const auto kCommunityNameRoleName = QByteArrayLiteral("communityName");
|
|||
const auto kCommunityImageRoleName = QByteArrayLiteral("communityImage");
|
||||
const auto kCollectionUidRoleName = QByteArrayLiteral("collectionUid");
|
||||
const auto kCollectionNameRoleName = QByteArrayLiteral("collectionName");
|
||||
const auto kEnabledNetworkBalanceRoleName = QByteArrayLiteral("enabledNetworkBalance");
|
||||
const auto kEnabledNetworkBalanceRoleName = QByteArrayLiteral("enabledNetworkBalance"); // TODO add an extra (separate role) for group->childCount
|
||||
const auto kEnabledNetworkCurrencyBalanceRoleName = QByteArrayLiteral("enabledNetworkCurrencyBalance");
|
||||
const auto kCustomSortOrderNoRoleName = QByteArrayLiteral("customSortOrderNo");
|
||||
const auto kTokenImageRoleName = QByteArrayLiteral("imageUrl");
|
||||
const auto kBackgroundColorRoleName = QByteArrayLiteral("backgroundColor");
|
||||
} // namespace
|
||||
|
||||
struct TokenData {
|
||||
QString symbol, name, communityId, communityName, communityImage, collectionUid, collectionName, image;
|
||||
QColor backgroundColor{Qt::transparent};
|
||||
QVariant balance, currencyBalance;
|
||||
int customSortOrderNo{-1};
|
||||
int customSortOrderNo{INT_MAX};
|
||||
};
|
||||
|
||||
// symbol -> {sortOrder, visible, groupId}
|
||||
|
@ -50,6 +54,7 @@ public:
|
|||
CurrencyBalanceRole,
|
||||
CustomSortOrderNoRole,
|
||||
TokenImageRole,
|
||||
TokenBackgroundColorRole,
|
||||
};
|
||||
Q_ENUM(TokenDataRoles)
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ StatusFlatButton {
|
|||
property bool isGroup
|
||||
property string groupId
|
||||
property bool isCommunityAsset
|
||||
property bool isCollectible
|
||||
|
||||
readonly property bool hideEnabled: model.symbol !== "ETH"
|
||||
readonly property bool menuVisible: menuLoader.active
|
||||
|
@ -38,29 +39,34 @@ StatusFlatButton {
|
|||
|
||||
Loader {
|
||||
id: menuLoader
|
||||
objectName: "manageTokensContextMenuLoader"
|
||||
active: false
|
||||
sourceComponent: StatusMenu {
|
||||
onClosed: menuLoader.active = false
|
||||
|
||||
StatusAction {
|
||||
objectName: "miMoveToTop"
|
||||
enabled: !root.inHidden && root.currentIndex !== 0
|
||||
icon.name: "arrow-top"
|
||||
text: qsTr("Move to top")
|
||||
onTriggered: root.moveRequested(root.currentIndex, 0)
|
||||
}
|
||||
StatusAction {
|
||||
objectName: "miMoveUp"
|
||||
enabled: !root.inHidden && root.currentIndex !== 0
|
||||
icon.name: "arrow-up"
|
||||
text: qsTr("Move up")
|
||||
onTriggered: root.moveRequested(root.currentIndex, root.currentIndex - 1)
|
||||
}
|
||||
StatusAction {
|
||||
objectName: "miMoveDown"
|
||||
enabled: !root.inHidden && root.currentIndex < root.count - 1
|
||||
icon.name: "arrow-down"
|
||||
text: qsTr("Move down")
|
||||
onTriggered: root.moveRequested(root.currentIndex, root.currentIndex + 1)
|
||||
}
|
||||
StatusAction {
|
||||
objectName: "miMoveToBottom"
|
||||
enabled: !root.inHidden && root.currentIndex < root.count - 1
|
||||
icon.name: "arrow-bottom"
|
||||
text: qsTr("Move to bottom")
|
||||
|
@ -71,16 +77,18 @@ StatusFlatButton {
|
|||
|
||||
// any token
|
||||
StatusAction {
|
||||
objectName: "miHideToken"
|
||||
enabled: !root.inHidden && root.hideEnabled && !root.isGroup && !root.isCommunityAsset
|
||||
type: StatusAction.Type.Danger
|
||||
icon.name: "hide"
|
||||
text: qsTr("Hide asset")
|
||||
text: root.isCollectible ? qsTr("Hide collectible") : qsTr("Hide asset")
|
||||
onTriggered: root.showHideRequested(root.currentIndex, false)
|
||||
}
|
||||
StatusAction {
|
||||
objectName: "miShowToken"
|
||||
enabled: root.inHidden
|
||||
icon.name: "show"
|
||||
text: qsTr("Show asset")
|
||||
text: root.isCollectible ? qsTr("Show collectible") : qsTr("Show asset")
|
||||
onTriggered: root.showHideRequested(root.currentIndex, true)
|
||||
}
|
||||
|
||||
|
@ -93,14 +101,16 @@ StatusFlatButton {
|
|||
type: StatusAction.Type.Danger
|
||||
|
||||
StatusAction {
|
||||
text: qsTr("This asset")
|
||||
objectName: "miHideCommunityToken"
|
||||
text: root.isCollectible ? qsTr("This collectible") : qsTr("This asset")
|
||||
onTriggered: {
|
||||
root.showHideRequested(root.currentIndex, false)
|
||||
communitySubmenu.dismiss()
|
||||
}
|
||||
}
|
||||
StatusAction {
|
||||
text: qsTr("All assets from this community")
|
||||
objectName: "miHideAllCommunityTokens"
|
||||
text: root.isCollectible ? qsTr("All collectibles from this community") : qsTr("All assets from this community")
|
||||
onTriggered: {
|
||||
root.showHideGroupRequested(root.groupId, false)
|
||||
communitySubmenu.dismiss()
|
||||
|
@ -110,16 +120,18 @@ StatusFlatButton {
|
|||
|
||||
// token group
|
||||
StatusAction {
|
||||
objectName: "miHideTokenGroup"
|
||||
enabled: !root.inHidden && root.isGroup
|
||||
type: StatusAction.Type.Danger
|
||||
icon.name: "hide"
|
||||
text: qsTr("Hide all assets from this community")
|
||||
text: root.isCollectible ? qsTr("Hide all collectibles from this community") : qsTr("Hide all assets from this community")
|
||||
onTriggered: root.showHideGroupRequested(root.groupId, false)
|
||||
}
|
||||
StatusAction {
|
||||
objectName: "miShowTokenGroup"
|
||||
enabled: root.inHidden && root.groupId
|
||||
icon.name: "show"
|
||||
text: qsTr("Show all assets from this community")
|
||||
text: root.isCollectible ? qsTr("Show all collectibles from this community") : qsTr("Show all assets from this community")
|
||||
onTriggered: root.showHideGroupRequested(root.groupId, true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Components 0.1
|
||||
|
||||
import utils 1.0
|
||||
|
||||
Control {
|
||||
id: root
|
||||
|
||||
property string text
|
||||
property string imageSrc
|
||||
property bool loading
|
||||
|
||||
property Component customBackground: Component {
|
||||
Rectangle {
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
color: Theme.palette.baseColor4
|
||||
radius: 20
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property var loadingComponent: Component { LoadingComponent {} }
|
||||
}
|
||||
|
||||
horizontalPadding: 12
|
||||
verticalPadding: Style.current.halfPadding
|
||||
spacing: 4
|
||||
|
||||
background: Loader {
|
||||
sourceComponent: root.loading ? d.loadingComponent : root.customBackground
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: root.spacing
|
||||
visible: !root.loading
|
||||
StatusRoundedImage {
|
||||
Layout.maximumWidth: visible ? 16 : 0
|
||||
Layout.maximumHeight: visible ? 16 : 0
|
||||
image.source: root.imageSrc
|
||||
visible: !!image.source
|
||||
}
|
||||
StatusBaseText {
|
||||
font.pixelSize: Style.current.tertiaryTextFontSize
|
||||
font.weight: Font.Medium
|
||||
text: root.text
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
import utils 1.0
|
||||
|
||||
DropArea {
|
||||
id: root
|
||||
objectName: "manageTokensDelegate-%1".arg(index)
|
||||
|
||||
// expected roles: symbol, name, communityId, communityName, communityImage, collectionName, imageUrl
|
||||
|
||||
property var controller
|
||||
property int visualIndex: index
|
||||
property alias dragParent: delegate.dragParent
|
||||
property alias dragEnabled: delegate.dragEnabled
|
||||
property alias bgColor: delegate.bgColor
|
||||
property alias topInset: delegate.topInset
|
||||
property alias bottomInset: delegate.bottomInset
|
||||
property bool isGrouped
|
||||
property bool isHidden
|
||||
property int count
|
||||
|
||||
property bool isCollectible
|
||||
|
||||
readonly property alias title: delegate.title
|
||||
|
||||
readonly property var priv: QtObject {
|
||||
id: priv
|
||||
readonly property int iconSize: root.isCollectible ? 44 : 32
|
||||
readonly property int bgRadius: root.isCollectible ? Style.current.radius : iconSize/2
|
||||
}
|
||||
|
||||
ListView.onRemove: SequentialAnimation {
|
||||
PropertyAction { target: root; property: "ListView.delayRemove"; value: true }
|
||||
NumberAnimation { target: root; property: "scale"; to: 0; easing.type: Easing.InOutQuad }
|
||||
PropertyAction { target: root; property: "ListView.delayRemove"; value: false }
|
||||
}
|
||||
|
||||
width: ListView.view.width
|
||||
height: visible ? delegate.height : 0
|
||||
|
||||
onEntered: function(drag) {
|
||||
const from = drag.source.visualIndex
|
||||
const to = delegate.visualIndex
|
||||
if (to === from)
|
||||
return
|
||||
ListView.view.model.moveItem(from, to)
|
||||
drag.accept()
|
||||
}
|
||||
|
||||
StatusDraggableListItem {
|
||||
id: delegate
|
||||
objectName: "draggableDelegate"
|
||||
|
||||
visualIndex: index
|
||||
Drag.keys: root.keys
|
||||
Drag.hotSpot.x: root.width/2
|
||||
Drag.hotSpot.y: root.height/2
|
||||
draggable: true
|
||||
|
||||
width: root.width
|
||||
title: model.name
|
||||
secondaryTitle: root.isCollectible ? (!!model.communityId ? qsTr("Community minted") : model.collectionName || model.symbol) :
|
||||
hovered || menuBtn.menuVisible ? "%1 • %2".arg(LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkBalance))
|
||||
.arg(LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkCurrencyBalance))
|
||||
: LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkBalance)
|
||||
bgRadius: priv.bgRadius
|
||||
hasImage: true
|
||||
icon.source: root.isCollectible ? model.imageUrl : Constants.tokenIcon(model.symbol) // TODO unify via backend model for both assets and collectibles
|
||||
icon.width: priv.iconSize
|
||||
icon.height: priv.iconSize
|
||||
spacing: 12
|
||||
assetBgColor: model.backgroundColor
|
||||
|
||||
actions: [
|
||||
ManageTokensCommunityTag {
|
||||
visible: !!model.communityId && !root.isGrouped
|
||||
text: model.communityName
|
||||
imageSrc: model.communityImage
|
||||
},
|
||||
ManageTokenMenuButton {
|
||||
id: menuBtn
|
||||
objectName: "btnManageTokenMenu-%1".arg(currentIndex)
|
||||
currentIndex: root.visualIndex
|
||||
count: root.count
|
||||
inHidden: root.isHidden
|
||||
groupId: model.communityId
|
||||
isCommunityAsset: !!model.communityId
|
||||
isCollectible: root.isCollectible
|
||||
onMoveRequested: (from, to) => root.ListView.view.model.moveItem(from, to)
|
||||
onShowHideRequested: (index, flag) => isCommunityAsset ? root.controller.showHideCommunityToken(index, flag)
|
||||
: root.controller.showHideRegularToken(index, flag)
|
||||
onShowHideGroupRequested: (groupId, flag) => root.controller.showHideGroup(groupId, flag)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
import utils 1.0
|
||||
|
||||
DropArea {
|
||||
id: root
|
||||
objectName: "manageTokensGroupDelegate-%1".arg(index)
|
||||
|
||||
// expected roles: communityId, communityName, communityImage
|
||||
|
||||
property int visualIndex: index
|
||||
property var controller
|
||||
property bool communityGroupsExpanded
|
||||
property var dragParent
|
||||
property alias dragEnabled: groupedCommunityTokenDelegate.dragEnabled
|
||||
property bool isCollectible
|
||||
|
||||
readonly property string communityId: model.communityId
|
||||
readonly property int childCount: model.enabledNetworkBalance // NB using "balance" as "count" in m_communityTokenGroupsModel
|
||||
readonly property alias title: groupedCommunityTokenDelegate.title
|
||||
|
||||
ListView.onRemove: SequentialAnimation {
|
||||
PropertyAction { target: root; property: "ListView.delayRemove"; value: true }
|
||||
NumberAnimation { target: root; property: "scale"; to: 0; easing.type: Easing.InOutQuad }
|
||||
PropertyAction { target: root; property: "ListView.delayRemove"; value: false }
|
||||
}
|
||||
|
||||
keys: ["x-status-draggable-community-group-item"]
|
||||
width: ListView.view.width
|
||||
height: groupedCommunityTokenDelegate.implicitHeight
|
||||
|
||||
onEntered: function(drag) {
|
||||
const from = drag.source.visualIndex
|
||||
const to = groupedCommunityTokenDelegate.visualIndex
|
||||
if (to === from)
|
||||
return
|
||||
ListView.view.model.moveItem(from, to)
|
||||
drag.accept()
|
||||
}
|
||||
|
||||
StatusDraggableListItem {
|
||||
id: groupedCommunityTokenDelegate
|
||||
width: parent.width
|
||||
height: dragActive ? implicitHeight : parent.height
|
||||
leftPadding: Style.current.halfPadding
|
||||
rightPadding: Style.current.halfPadding
|
||||
bottomPadding: Style.current.halfPadding
|
||||
topPadding: 22
|
||||
draggable: true
|
||||
spacing: 12
|
||||
bgColor: Theme.palette.baseColor4
|
||||
title: model.communityName
|
||||
|
||||
visualIndex: index
|
||||
dragParent: root.dragParent
|
||||
Drag.keys: root.keys
|
||||
Drag.hotSpot.x: root.width/2
|
||||
Drag.hotSpot.y: root.height/2
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 12
|
||||
Layout.rightMargin: 12
|
||||
Layout.bottomMargin: 14
|
||||
spacing: groupedCommunityTokenDelegate.spacing
|
||||
|
||||
StatusIcon {
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
icon: "justify"
|
||||
color: root.dragEnabled ? Theme.palette.baseColor1 : Theme.palette.baseColor2
|
||||
}
|
||||
|
||||
StatusRoundedImage {
|
||||
//radius: groupedCommunityTokenDelegate.bgRadius // TODO different for a collection
|
||||
Layout.preferredWidth: root.isCollectible ? 44 : 32
|
||||
Layout.preferredHeight: root.isCollectible ? 44 : 32
|
||||
image.source: model.communityImage
|
||||
showLoadingIndicator: true
|
||||
image.fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
text: groupedCommunityTokenDelegate.title
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
Layout.leftMargin: -parent.spacing/2
|
||||
text: "• %1".arg(root.isCollectible ? qsTr("%n collectible(s)", "", root.childCount) : qsTr("%n asset(s)", "", root.childCount))
|
||||
elide: Text.ElideRight
|
||||
color: Theme.palette.baseColor1
|
||||
maximumLineCount: 1
|
||||
visible: !root.communityGroupsExpanded
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
ManageTokenMenuButton {
|
||||
objectName: "btnManageTokenMenu-%1".arg(currentIndex)
|
||||
currentIndex: visualIndex
|
||||
count: root.controller.communityTokenGroupsModel.count
|
||||
isGroup: true
|
||||
isCollectible: root.isCollectible
|
||||
groupId: model.communityId
|
||||
onMoveRequested: (from, to) => root.controller.communityTokenGroupsModel.moveItem(from, to) // TODO collection
|
||||
onShowHideGroupRequested: (groupId, flag) => root.controller.showHideGroup(groupId, flag)
|
||||
}
|
||||
}
|
||||
|
||||
StatusListView {
|
||||
objectName: "manageTokensGroupListView"
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
model: root.controller.communityTokensModel
|
||||
interactive: false
|
||||
visible: root.communityGroupsExpanded
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: ManageTokensDelegate {
|
||||
controller: root.controller
|
||||
dragParent: root.dragParent
|
||||
isGrouped: true
|
||||
count: root.childCount
|
||||
dragEnabled: count > 1
|
||||
keys: ["x-status-draggable-community-token-item-%1".arg(model.communityId)]
|
||||
bgColor: Theme.palette.indirectColor4
|
||||
topInset: 2 // tighter "spacing"
|
||||
bottomInset: 2
|
||||
visible: root.communityId === model.communityId
|
||||
isCollectible: root.isCollectible
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,3 +6,6 @@ StatusDateRangePicker 1.0 StatusDateRangePicker.qml
|
|||
ActivityFilterTagItem 1.0 ActivityFilterTagItem.qml
|
||||
SortOrderComboBox 1.0 SortOrderComboBox.qml
|
||||
ManageTokenMenuButton 1.0 ManageTokenMenuButton.qml
|
||||
ManageTokensCommunityTag 1.0 ManageTokensCommunityTag.qml
|
||||
ManageTokensDelegate 1.0 ManageTokensDelegate.qml
|
||||
ManageTokensGroupDelegate 1.0 ManageTokensGroupDelegate.qml
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.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.Popups 0.1
|
||||
import StatusQ.Models 0.1
|
||||
|
||||
import utils 1.0
|
||||
import shared.controls 1.0
|
||||
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
|
||||
Control {
|
||||
id: root
|
||||
|
||||
required property var baseModel
|
||||
|
||||
readonly property bool dirty: d.controller.dirty
|
||||
|
||||
background: null
|
||||
|
||||
function saveSettings() {
|
||||
d.controller.saveSettings();
|
||||
}
|
||||
|
||||
function revert() {
|
||||
d.controller.revert();
|
||||
}
|
||||
|
||||
function clearSettings() {
|
||||
d.controller.clearSettings();
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
property bool collectionGroupsExpanded: true
|
||||
property bool communityGroupsExpanded: true
|
||||
|
||||
readonly property var renamedModel: RolesRenamingModel {
|
||||
sourceModel: root.baseModel
|
||||
|
||||
mapping: [
|
||||
RoleRename {
|
||||
from: "uid"
|
||||
to: "symbol"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
readonly property var controller: ManageTokensController {
|
||||
sourceModel: d.renamedModel
|
||||
arrangeByCommunity: switchArrangeByCommunity.checked
|
||||
settingsKey: "WalletCollectibles"
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: Style.current.padding
|
||||
|
||||
ShapeRectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 2
|
||||
visible: !d.controller.regularTokensModel.count
|
||||
text: qsTr("You’ll be able to manage the display of your collectibles here")
|
||||
}
|
||||
|
||||
// TODO https://github.com/status-im/status-desktop/issues/12703
|
||||
// StatusSwitch {
|
||||
// Layout.alignment: Qt.AlignTrailing
|
||||
// LayoutMirroring.enabled: true
|
||||
// LayoutMirroring.childrenInherit: true
|
||||
// id: switchArrangeByCollection
|
||||
// textColor: Theme.palette.baseColor1
|
||||
// text: qsTr("Arrange by collection (TODO)")
|
||||
// visible: d.controller.regularTokensModel.count
|
||||
// }
|
||||
|
||||
// StatusModalDivider {
|
||||
// Layout.fillWidth: true
|
||||
// Layout.topMargin: -Style.current.halfPadding
|
||||
// visible: switchArrangeByCollection.visible && switchArrangeByCollection.checked
|
||||
// }
|
||||
|
||||
// StatusLinkText {
|
||||
// Layout.alignment: Qt.AlignTrailing
|
||||
// visible: switchArrangeByCollection.visible && switchArrangeByCollection.checked
|
||||
// text: d.collectionGroupsExpanded ? qsTr("Collapse all") : qsTr("Expand all")
|
||||
// normalColor: linkColor
|
||||
// font.weight: Font.Normal
|
||||
// onClicked: d.collectionGroupsExpanded = !d.collectionGroupsExpanded
|
||||
// }
|
||||
|
||||
StatusListView {
|
||||
objectName: "lvRegularTokens"
|
||||
Layout.fillWidth: true
|
||||
model: d.controller.regularTokensModel
|
||||
implicitHeight: contentHeight
|
||||
interactive: false
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: ManageTokensDelegate {
|
||||
isCollectible: true
|
||||
controller: d.controller
|
||||
dragParent: root
|
||||
count: d.controller.regularTokensModel.count
|
||||
dragEnabled: count > 1
|
||||
keys: ["x-status-draggable-token-item"]
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: communityTokensHeader
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
visible: d.controller.communityTokensModel.count
|
||||
StatusBaseText {
|
||||
color: Theme.palette.baseColor1
|
||||
text: qsTr("Community")
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
StatusSwitch {
|
||||
objectName: "switchArrangeByCommunity"
|
||||
LayoutMirroring.enabled: true
|
||||
LayoutMirroring.childrenInherit: true
|
||||
id: switchArrangeByCommunity
|
||||
textColor: Theme.palette.baseColor1
|
||||
text: qsTr("Arrange by community")
|
||||
}
|
||||
}
|
||||
|
||||
StatusModalDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: -Style.current.halfPadding
|
||||
visible: communityTokensHeader.visible && switchArrangeByCommunity.checked
|
||||
}
|
||||
|
||||
StatusLinkText {
|
||||
objectName: "switchCollapseCommunityGroups"
|
||||
Layout.alignment: Qt.AlignTrailing
|
||||
visible: communityTokensHeader.visible && switchArrangeByCommunity.checked
|
||||
text: d.communityGroupsExpanded ? qsTr("Collapse all") : qsTr("Expand all")
|
||||
normalColor: linkColor
|
||||
font.weight: Font.Normal
|
||||
onClicked: d.communityGroupsExpanded = !d.communityGroupsExpanded
|
||||
}
|
||||
|
||||
Loader {
|
||||
objectName: "loaderCommunityTokens"
|
||||
Layout.fillWidth: true
|
||||
active: d.controller.communityTokensModel.count
|
||||
visible: active
|
||||
sourceComponent: switchArrangeByCommunity.checked ? cmpCommunityTokenGroups : cmpCommunityTokens
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
color: Theme.palette.baseColor1
|
||||
text: qsTr("Hidden")
|
||||
visible: d.controller.hiddenTokensModel.count
|
||||
}
|
||||
|
||||
StatusListView {
|
||||
objectName: "lvHiddenTokens"
|
||||
Layout.fillWidth: true
|
||||
model: d.controller.hiddenTokensModel
|
||||
implicitHeight: contentHeight
|
||||
interactive: false
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: ManageTokensDelegate {
|
||||
isCollectible: true
|
||||
controller: d.controller
|
||||
dragParent: root
|
||||
dragEnabled: false
|
||||
keys: ["x-status-draggable-none"]
|
||||
isHidden: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: cmpCommunityTokens
|
||||
StatusListView {
|
||||
objectName: "lvCommunityTokens"
|
||||
model: d.controller.communityTokensModel
|
||||
implicitHeight: contentHeight
|
||||
interactive: false
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: ManageTokensDelegate {
|
||||
isCollectible: true
|
||||
controller: d.controller
|
||||
dragParent: root
|
||||
count: d.controller.communityTokensModel.count
|
||||
dragEnabled: count > 1
|
||||
keys: ["x-status-draggable-community-token-item"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: cmpCommunityTokenGroups
|
||||
StatusListView {
|
||||
objectName: "lvCommunityTokenGroups"
|
||||
model: d.controller.communityTokenGroupsModel
|
||||
implicitHeight: contentHeight
|
||||
interactive: false
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: ManageTokensGroupDelegate {
|
||||
isCollectible: true
|
||||
controller: d.controller
|
||||
dragParent: root
|
||||
dragEnabled: d.controller.communityTokenGroupsModel.count > 1
|
||||
communityGroupsExpanded: d.communityGroupsExpanded
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ import StatusQ.Popups 0.1
|
|||
import StatusQ.Models 0.1
|
||||
|
||||
import utils 1.0
|
||||
import shared.controls 1.0
|
||||
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
|
||||
|
@ -47,213 +46,6 @@ Control {
|
|||
}
|
||||
}
|
||||
|
||||
component CommunityTag: InformationTag {
|
||||
tagPrimaryLabel.font.weight: Font.Medium
|
||||
customBackground: Component {
|
||||
Rectangle {
|
||||
color: Theme.palette.baseColor4
|
||||
radius: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component LocalTokenDelegate: DropArea {
|
||||
id: delegateRoot
|
||||
|
||||
property int visualIndex: index
|
||||
property alias dragEnabled: delegate.dragEnabled
|
||||
property alias bgColor: delegate.bgColor
|
||||
property alias topInset: delegate.topInset
|
||||
property alias bottomInset: delegate.bottomInset
|
||||
property bool isGrouped
|
||||
property bool isHidden
|
||||
property int count
|
||||
|
||||
ListView.onRemove: SequentialAnimation {
|
||||
PropertyAction { target: delegateRoot; property: "ListView.delayRemove"; value: true }
|
||||
NumberAnimation { target: delegateRoot; property: "scale"; to: 0; easing.type: Easing.InOutQuad }
|
||||
PropertyAction { target: delegateRoot; property: "ListView.delayRemove"; value: false }
|
||||
}
|
||||
|
||||
width: ListView.view.width
|
||||
height: visible ? delegate.height : 0
|
||||
|
||||
onEntered: function(drag) {
|
||||
var from = drag.source.visualIndex
|
||||
var to = delegate.visualIndex
|
||||
if (to === from)
|
||||
return
|
||||
//console.warn("!!! DROP from/to", from, to)
|
||||
ListView.view.model.moveItem(from, to)
|
||||
drag.accept()
|
||||
}
|
||||
|
||||
StatusDraggableListItem {
|
||||
id: delegate
|
||||
|
||||
visualIndex: index
|
||||
dragParent: root
|
||||
Drag.keys: delegateRoot.keys
|
||||
draggable: true
|
||||
|
||||
width: delegateRoot.width
|
||||
title: model.name// + " (%1 -> %2)".arg(index).arg(model.customSortOrderNo)
|
||||
secondaryTitle: hovered || menuBtn.menuVisible ? "%1 <b>·</b> %2".arg(LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkBalance))
|
||||
.arg(LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkCurrencyBalance))
|
||||
: LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkBalance)
|
||||
hasImage: true
|
||||
icon.source: model.imageUrl || Constants.tokenIcon(model.symbol)
|
||||
icon.width: 32
|
||||
icon.height: 32
|
||||
spacing: 12
|
||||
|
||||
actions: [
|
||||
CommunityTag {
|
||||
tagPrimaryLabel.text: model.communityName
|
||||
visible: !!model.communityId && !delegateRoot.isGrouped
|
||||
image.source: model.communityImage
|
||||
},
|
||||
ManageTokenMenuButton {
|
||||
id: menuBtn
|
||||
currentIndex: visualIndex
|
||||
count: delegateRoot.count
|
||||
inHidden: delegateRoot.isHidden
|
||||
groupId: model.communityId
|
||||
isCommunityAsset: !!model.communityId
|
||||
onMoveRequested: (from, to) => isCommunityAsset ? d.controller.communityTokensModel.moveItem(from, to)
|
||||
: d.controller.regularTokensModel.moveItem(from, to)
|
||||
onShowHideRequested: (index, flag) => isCommunityAsset ? d.controller.showHideCommunityToken(index, flag)
|
||||
: d.controller.showHideRegularToken(index, flag)
|
||||
onShowHideGroupRequested: (groupId, flag) => d.controller.showHideGroup(groupId, flag)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
component LocalTokenGroupDelegate: DropArea {
|
||||
id: communityDelegateRoot
|
||||
|
||||
property int visualIndex: index
|
||||
readonly property string communityId: model.communityId
|
||||
readonly property int childCount: model.enabledNetworkBalance // NB using "balance" as "count" in m_communityTokenGroupsModel
|
||||
|
||||
ListView.onRemove: SequentialAnimation {
|
||||
PropertyAction { target: communityDelegateRoot; property: "ListView.delayRemove"; value: true }
|
||||
NumberAnimation { target: communityDelegateRoot; property: "scale"; to: 0; easing.type: Easing.InOutQuad }
|
||||
PropertyAction { target: communityDelegateRoot; property: "ListView.delayRemove"; value: false }
|
||||
}
|
||||
|
||||
keys: ["x-status-draggable-community-group-item"]
|
||||
visible: childCount
|
||||
width: ListView.view.width
|
||||
height: visible ? groupedCommunityTokenDelegate.implicitHeight : 0
|
||||
|
||||
onEntered: function(drag) {
|
||||
var from = drag.source.visualIndex
|
||||
var to = groupedCommunityTokenDelegate.visualIndex
|
||||
if (to === from)
|
||||
return
|
||||
//console.warn("!!! DROP GROUP from/to", from, to)
|
||||
ListView.view.model.moveItem(from, to)
|
||||
drag.accept()
|
||||
}
|
||||
|
||||
StatusDraggableListItem {
|
||||
id: groupedCommunityTokenDelegate
|
||||
width: parent.width
|
||||
height: dragActive ? implicitHeight : parent.height
|
||||
leftPadding: Style.current.halfPadding
|
||||
rightPadding: Style.current.halfPadding
|
||||
bottomPadding: Style.current.halfPadding
|
||||
topPadding: 22
|
||||
draggable: true
|
||||
spacing: 12
|
||||
bgColor: Theme.palette.baseColor4
|
||||
|
||||
visualIndex: index
|
||||
dragParent: root
|
||||
Drag.keys: communityDelegateRoot.keys
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 12
|
||||
Layout.rightMargin: 12
|
||||
Layout.bottomMargin: 14
|
||||
spacing: groupedCommunityTokenDelegate.spacing
|
||||
|
||||
StatusIcon {
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
icon: "justify"
|
||||
color: Theme.palette.baseColor1
|
||||
}
|
||||
|
||||
StatusRoundedImage {
|
||||
radius: groupedCommunityTokenDelegate.bgRadius
|
||||
Layout.preferredWidth: 32
|
||||
Layout.preferredHeight: 32
|
||||
image.source: model.communityImage
|
||||
showLoadingIndicator: true
|
||||
image.fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
text: model.communityName// + "(%1 -> %2)".arg(index).arg(model.customSortOrderNo)
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
Layout.leftMargin: -parent.spacing/2
|
||||
text: "<b>·</b> %1".arg(qsTr("%n asset(s)", "", communityDelegateRoot.childCount))
|
||||
elide: Text.ElideRight
|
||||
color: Theme.palette.baseColor1
|
||||
maximumLineCount: 1
|
||||
visible: !d.communityGroupsExpanded
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
ManageTokenMenuButton {
|
||||
currentIndex: visualIndex
|
||||
count: d.controller.communityTokenGroupsModel.count
|
||||
isGroup: true
|
||||
groupId: model.communityId
|
||||
onMoveRequested: (from, to) => d.controller.communityTokenGroupsModel.moveItem(from, to)
|
||||
onShowHideGroupRequested: (groupId, flag) => d.controller.showHideGroup(groupId, flag)
|
||||
}
|
||||
}
|
||||
|
||||
StatusListView {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
model: d.controller.communityTokensModel
|
||||
interactive: false
|
||||
visible: d.communityGroupsExpanded
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: LocalTokenDelegate {
|
||||
isGrouped: true
|
||||
count: communityDelegateRoot.childCount
|
||||
dragEnabled: count > 1
|
||||
keys: ["x-status-draggable-community-token-item-%1".arg(model.communityId)]
|
||||
bgColor: Theme.palette.indirectColor4
|
||||
topInset: 2 // tighter "spacing"
|
||||
bottomInset: 2
|
||||
visible: communityDelegateRoot.communityId === model.communityId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: Style.current.padding
|
||||
|
||||
|
@ -267,7 +59,9 @@ Control {
|
|||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: LocalTokenDelegate {
|
||||
delegate: ManageTokensDelegate {
|
||||
controller: d.controller
|
||||
dragParent: root
|
||||
count: d.controller.regularTokensModel.count
|
||||
dragEnabled: count > 1
|
||||
keys: ["x-status-draggable-token-item"]
|
||||
|
@ -281,7 +75,7 @@ Control {
|
|||
visible: d.controller.communityTokensModel.count
|
||||
StatusBaseText {
|
||||
color: Theme.palette.baseColor1
|
||||
text: qsTr("Community")// + " -> %1".arg(switchArrangeByCommunity.checked ? d.controller.communityTokenGroupsModel.count : d.controller.communityTokensModel.count)
|
||||
text: qsTr("Community")
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
StatusSwitch {
|
||||
|
@ -319,7 +113,7 @@ Control {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
color: Theme.palette.baseColor1
|
||||
text: qsTr("Hidden")// + " -> %1".arg(d.controller.hiddenTokensModel.count)
|
||||
text: qsTr("Hidden")
|
||||
visible: d.controller.hiddenTokensModel.count
|
||||
}
|
||||
|
||||
|
@ -333,7 +127,9 @@ Control {
|
|||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: LocalTokenDelegate {
|
||||
delegate: ManageTokensDelegate {
|
||||
controller: d.controller
|
||||
dragParent: root
|
||||
dragEnabled: false
|
||||
keys: ["x-status-draggable-none"]
|
||||
isHidden: true
|
||||
|
@ -352,7 +148,9 @@ Control {
|
|||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: LocalTokenDelegate {
|
||||
delegate: ManageTokensDelegate {
|
||||
controller: d.controller
|
||||
dragParent: root
|
||||
count: d.controller.communityTokensModel.count
|
||||
dragEnabled: count > 1
|
||||
keys: ["x-status-draggable-community-token-item"]
|
||||
|
@ -372,7 +170,12 @@ Control {
|
|||
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
delegate: LocalTokenGroupDelegate {}
|
||||
delegate: ManageTokensGroupDelegate {
|
||||
controller: d.controller
|
||||
dragParent: root
|
||||
dragEnabled: d.controller.communityTokenGroupsModel.count > 1
|
||||
communityGroupsExpanded: d.communityGroupsExpanded
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,3 +3,4 @@ WalletTxProgressBlock 1.0 WalletTxProgressBlock.qml
|
|||
WalletNftPreview 1.0 WalletNftPreview.qml
|
||||
ActivityFilterPanel 1.0 ActivityFilterPanel.qml
|
||||
ManageTokensPanel 1.0 ManageTokensPanel.qml
|
||||
ManageCollectiblesPanel 1.0 ManageCollectiblesPanel.qml
|
||||
|
|
Loading…
Reference in New Issue