feat: Create the hidden tab (to host both assets and collectibles)

- add new Hidden tab/section to Settings/Wallet/Manage tokens page and
storybook
- extract the controller(s) to ManageTokensView.qml to share them across
the tabs
- updated the grouped UI delegate
- adjust the tests

Fixes #13201
Fixes #13188
This commit is contained in:
Lukáš Tinkl 2024-01-16 17:22:05 +01:00 committed by Lukáš Tinkl
parent 2abfe0fa0c
commit 57b3b254b8
18 changed files with 637 additions and 256 deletions

View File

@ -3,6 +3,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import StatusQ.Core 0.1
import StatusQ.Models 0.1
import utils 1.0
@ -30,7 +31,6 @@ SplitView {
ManageAssetsPanel {
id: showcasePanel
width: 500
baseModel: ctrlEmptyModel.checked ? null : walletAssetStore.groupedAccountAssetsModel
getCurrencyAmount: function (balance, symbol) {
return ({
amount: balance,
@ -47,6 +47,10 @@ SplitView {
stripTrailingZeroes: false
})
}
controller: ManageTokensController {
sourceModel: ctrlEmptyModel.checked ? null : assetsModel
settingsKey: "WalletAssets"
}
}
}

View File

@ -3,6 +3,7 @@ import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import StatusQ 0.1
import StatusQ.Models 0.1
import StatusQ.Core 0.1
import AppLayouts.Wallet.panels 1.0
@ -23,16 +24,28 @@ SplitView {
id: collectiblesModel
}
RolesRenamingModel {
id: renamedModel
sourceModel: ctrlEmptyModel.checked ? null : collectiblesModel
mapping: [
RoleRename {
from: "uid"
to: "symbol"
}
]
}
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml
SplitView.fillWidth: true
SplitView.fillHeight: true
Component.onCompleted: forceActiveFocus()
ManageCollectiblesPanel {
id: showcasePanel
width: 500
baseModel: ctrlEmptyModel.checked ? null : collectiblesModel
controller: ManageTokensController {
sourceModel: renamedModel
settingsKey: "WalletCollectibles"
}
}
}

View File

@ -0,0 +1,107 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Models 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
ManageTokensModel {
id: assetsModel
}
ManageCollectiblesModel {
id: collectiblesModel
}
RolesRenamingModel {
id: renamedModel
sourceModel: collectiblesModel
mapping: [
RoleRename {
from: "uid"
to: "symbol"
}
]
}
ManageTokensController {
id: assetsController
sourceModel: ctrlEmptyModel.checked ? null : assetsModel
settingsKey: "WalletAssets"
}
ManageTokensController {
id: collectiblesController
sourceModel: ctrlEmptyModel.checked ? null : renamedModel
settingsKey: "WalletCollectibles"
}
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml
SplitView.fillWidth: true
SplitView.fillHeight: true
Component.onCompleted: forceActiveFocus()
ManageHiddenPanel {
id: showcasePanel
width: 500
assetsController: assetsController
collectiblesController: collectiblesController
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumWidth: 150
SplitView.preferredWidth: 250
logsView.logText: logs.logText
ColumnLayout {
Label {
Layout.fillWidth: true
text: "Has saved settings: %1".arg(showcasePanel.hasSettings ? "true" : "false")
}
Button {
enabled: showcasePanel.hasSettings
text: "Clear settings"
onClicked: showcasePanel.clearSettings()
}
Switch {
id: ctrlEmptyModel
text: "Empty model"
}
Label {
text: "Hidden community groups:"
}
Label {
text: assetsController.hiddenCommunityGroups.concat(collectiblesController.hiddenCommunityGroups).join()
}
}
}
}
// category: Panels
// https://www.figma.com/file/eM26pyHZUeAwMLviaS1KJn/%E2%9A%99%EF%B8%8F-Wallet-Settings%3A-Manage-Tokens?type=design&node-id=12-126364&mode=design&t=ZqKtOXpYtpReg4oL-0
// https://www.figma.com/file/eM26pyHZUeAwMLviaS1KJn/%E2%9A%99%EF%B8%8F-Wallet-Settings%3A-Manage-Tokens?type=design&node-id=40-127902&mode=design&t=ZqKtOXpYtpReg4oL-0
// https://www.figma.com/file/eM26pyHZUeAwMLviaS1KJn/%E2%9A%99%EF%B8%8F-Wallet-Settings%3A-Manage-Tokens?type=design&node-id=577-130046&mode=design&t=ZqKtOXpYtpReg4oL-0
// https://www.figma.com/file/eM26pyHZUeAwMLviaS1KJn/%E2%9A%99%EF%B8%8F-Wallet-Settings%3A-Manage-Tokens?type=design&node-id=577-151896&mode=design&t=ZqKtOXpYtpReg4oL-0

View File

@ -2,6 +2,9 @@ import QtQuick 2.15
import QtQuick.Controls 2.15
import QtTest 1.15
import StatusQ 0.1
import StatusQ.Models 0.1
import AppLayouts.Wallet.panels 1.0
import Storybook 1.0
@ -17,12 +20,32 @@ Item {
id: collectiblesModel
}
RolesRenamingModel {
id: renamedModel
sourceModel: collectiblesModel
mapping: [
RoleRename {
from: "uid"
to: "symbol"
}
]
}
Component {
id: componentUnderTest
ManageCollectiblesPanel {
id: showcasePanel
width: 500
baseModel: collectiblesModel
controller: ManageTokensController {
sourceModel: renamedModel
settingsKey: "WalletCollectibles"
onTokenHidden: (symbol, name) => Global.displayToastMessage(
qsTr("%1 was successfully hidden.").arg(name), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
onCommunityTokenGroupHidden: (communityName) => Global.displayToastMessage(
qsTr("%1 community collectibles successfully hidden").arg(communityName), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
}
}
}
@ -79,10 +102,6 @@ Item {
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
@ -96,27 +115,8 @@ Item {
// verify the signal to show the notification toast got fired
tryCompare(notificationSpy, "count", 1)
// verify we now have +1 hidden and -1 regular tokens after the "hide" operation
waitForItemPolished(lvHidden)
tryCompare(lvHidden, "count", 1)
// verify we now have -1 regular tokens after the "hide" operation
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)
}
function test_showHideCommunityGroup() {
@ -141,33 +141,6 @@ Item {
// verify we have one less group
waitForItemPolished(lvCommunityTokenGroups)
tryCompare(lvCommunityTokenGroups, "count", 2)
const lvHidden = findChild(controlUnderTest, "lvHiddenTokens")
verify(!!lvHidden)
tryCompare(lvHidden, "count", 4) // we've just hidden 4 collectibles coming from this group
// 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 we again have 3 community groups, and one less hidden token
tryCompare(lvCommunityTokenGroups, "count", 3)
tryCompare(lvHidden, "count", 3)
// 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", 3)
}
function test_dnd() {
@ -264,15 +237,8 @@ Item {
// verify the signal to show the notification toast got fired
tryCompare(notificationSpy, "count", 1)
// 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)
waitForItemPolished(lvCommunityTokenGroups)
triggerDelegateMenuAction(lvCommunityTokenGroups, 1, "miMoveUp", true)
verify(controlUnderTest.dirty)
bearzGroupTokenDelegate = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0")

View File

@ -380,7 +380,6 @@ 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
}

View File

@ -10,6 +10,7 @@ ManageTokensController::ManageTokensController(QObject* parent)
, m_communityTokensModel(new ManageTokensModel(this))
, m_communityTokenGroupsModel(new ManageTokensModel(this))
, m_hiddenTokensModel(new ManageTokensModel(this))
, m_hiddenCommunityTokenGroupsModel(new ManageTokensModel(this))
{
for (auto model : m_allModels) {
connect(model, &ManageTokensModel::dirtyChanged, this, &ManageTokensController::dirtyChanged);
@ -34,6 +35,7 @@ ManageTokensController::ManageTokensController(QObject* parent)
m_communityTokensModel->setCommunityIds(m_communityIds);
m_communityTokensModel->saveCustomSortOrder();
rebuildCommunityTokenGroupsModel();
rebuildHiddenCommunityTokenGroupsModel();
rebuildRegularTokenGroupsModel();
#ifdef QT_DEBUG
qCDebug(manageTokens) << "!!! ADDING NEW SOURCE DATA TOOK" << t.nsecsElapsed()/1'000'000.f << "ms";
@ -59,16 +61,16 @@ ManageTokensController::ManageTokensController(QObject* parent)
});
}
void ManageTokensController::showHideRegularToken(int row, bool flag)
void ManageTokensController::showHideRegularToken(const QString& symbol, bool flag)
{
if (flag) { // show
auto hiddenItem = m_hiddenTokensModel->takeItem(row);
auto hiddenItem = m_hiddenTokensModel->takeItem(symbol);
if (hiddenItem) {
m_regularTokensModel->addItem(*hiddenItem);
emit tokenShown(hiddenItem->symbol, hiddenItem->name);
}
} else { // hide
auto shownItem = m_regularTokensModel->takeItem(row);
auto shownItem = m_regularTokensModel->takeItem(symbol);
if (shownItem) {
m_hiddenTokensModel->addItem(*shownItem, false /*prepend*/);
emit tokenHidden(shownItem->symbol, shownItem->name);
@ -76,10 +78,10 @@ void ManageTokensController::showHideRegularToken(int row, bool flag)
}
}
void ManageTokensController::showHideCommunityToken(int row, bool flag)
void ManageTokensController::showHideCommunityToken(const QString& symbol, bool flag)
{
if (flag) { // show
auto hiddenItem = m_hiddenTokensModel->takeItem(row);
auto hiddenItem = m_hiddenTokensModel->takeItem(symbol);
if (hiddenItem) {
m_communityTokensModel->addItem(*hiddenItem);
if (!m_communityIds.contains(hiddenItem->communityId))
@ -87,7 +89,7 @@ void ManageTokensController::showHideCommunityToken(int row, bool flag)
emit tokenShown(hiddenItem->symbol, hiddenItem->name);
}
} else { // hide
auto shownItem = m_communityTokensModel->takeItem(row);
auto shownItem = m_communityTokensModel->takeItem(symbol);
if (shownItem) {
m_hiddenTokensModel->addItem(*shownItem, false /*prepend*/);
if (!m_communityTokensModel->hasCommunityIdToken(shownItem->communityId))
@ -98,6 +100,7 @@ void ManageTokensController::showHideCommunityToken(int row, bool flag)
m_communityTokensModel->setCommunityIds(m_communityIds);
m_communityTokensModel->saveCustomSortOrder();
rebuildCommunityTokenGroupsModel();
rebuildHiddenCommunityTokenGroupsModel();
}
void ManageTokensController::showHideGroup(const QString& groupId, bool flag)
@ -111,6 +114,9 @@ void ManageTokensController::showHideGroup(const QString& groupId, bool flag)
emit communityTokenGroupShown(tokens.constFirst().communityName);
}
m_communityIds.append(groupId);
if (m_hiddenCommunityGroups.remove(groupId)) {
emit hiddenCommunityGroupsChanged();
}
} else { // hide
const auto tokens = m_communityTokensModel->takeAllItems(groupId);
if (!tokens.isEmpty()) {
@ -120,10 +126,15 @@ void ManageTokensController::showHideGroup(const QString& groupId, bool flag)
emit communityTokenGroupHidden(tokens.constFirst().communityName);
}
m_communityIds.removeAll(groupId);
if (!m_hiddenCommunityGroups.contains(groupId)) {
m_hiddenCommunityGroups.insert(groupId);
emit hiddenCommunityGroupsChanged();
}
}
m_communityTokensModel->setCommunityIds(m_communityIds);
m_communityTokensModel->saveCustomSortOrder();
rebuildCommunityTokenGroupsModel();
rebuildHiddenCommunityTokenGroupsModel();
}
void ManageTokensController::saveSettings(bool reuseCurrent)
@ -147,6 +158,7 @@ void ManageTokensController::saveSettings(bool reuseCurrent)
// save to QSettings
m_settings.beginGroup(settingsGroupName());
m_settings.beginWriteArray(m_settingsKey);
SerializedTokenData::const_key_value_iterator it = result.constKeyValueBegin();
for (auto i = 0; it != result.constKeyValueEnd() && i < result.size(); it++, i++) {
@ -158,6 +170,10 @@ void ManageTokensController::saveSettings(bool reuseCurrent)
m_settings.setValue(QStringLiteral("groupId"), groupId);
}
m_settings.endArray();
// hidden community groups
m_settings.setValue(QStringLiteral("HiddenCommunityGroups"), hiddenCommunityGroups());
m_settings.endGroup();
m_settings.sync();
@ -204,6 +220,14 @@ void ManageTokensController::loadSettings()
m_settingsData.insert(symbol, {pos, visible, groupId});
}
m_settings.endArray();
// hidden community groups
const auto groups = m_settings.value(QStringLiteral("HiddenCommunityGroups")).toStringList();
if (!groups.isEmpty()) {
m_hiddenCommunityGroups = {groups.constBegin(), groups.constEnd()};
emit hiddenCommunityGroupsChanged();
}
m_settings.endGroup();
setSettingsDirty(false);
}
@ -215,6 +239,11 @@ void ManageTokensController::setSettingsDirty(bool dirty)
emit settingsDirtyChanged(m_settingsDirty);
}
QStringList ManageTokensController::hiddenCommunityGroups() const
{
return {m_hiddenCommunityGroups.constBegin(), m_hiddenCommunityGroups.constEnd()};
}
void ManageTokensController::revert()
{
parseSourceModel();
@ -344,6 +373,7 @@ void ManageTokensController::parseSourceModel()
for (auto model: m_allModels)
model->clear();
m_communityIds.clear();
m_hiddenCommunityGroups.clear();
// load settings
loadSettings();
@ -357,6 +387,7 @@ void ManageTokensController::parseSourceModel()
// build community groups model
rebuildCommunityTokenGroupsModel();
rebuildHiddenCommunityTokenGroupsModel();
reloadCommunityIds();
m_communityTokensModel->setCommunityIds(m_communityIds);
@ -485,20 +516,58 @@ void ManageTokensController::rebuildCommunityTokenGroupsModel()
});
if (tokenGroup != result.cend()) {
const auto row = std::distance(result.cbegin(), tokenGroup);
TokenData updTokenGroup = result.takeAt(row);
TokenData& updTokenGroup = result[row];
updTokenGroup.balance = updTokenGroup.balance.toInt() + 1;
result.insert(row, updTokenGroup);
}
}
}
m_communityTokenGroupsModel->clear();
for (const auto& group: result)
for (const auto& group: std::as_const(result))
m_communityTokenGroupsModel->addItem(group);
qCDebug(manageTokens) << "!!! GROUPS MODEL REBUILT WITH GROUPS:" << communityIds;
}
void ManageTokensController::rebuildHiddenCommunityTokenGroupsModel()
{
QStringList communityIds;
QList<TokenData> result;
const auto count = m_hiddenTokensModel->count();
for (auto i = 0; i < count; i++) {
const auto& communityToken = m_hiddenTokensModel->itemAt(i);
const auto communityId = communityToken.communityId;
if (communityId.isEmpty())
continue;
if (!communityIds.contains(communityId) && m_hiddenCommunityGroups.contains(communityId)) { // insert into groups
communityIds.append(communityId);
TokenData tokenGroup;
tokenGroup.communityId = communityId;
tokenGroup.communityName = communityToken.communityName;
tokenGroup.communityImage = communityToken.communityImage;
tokenGroup.balance = 1;
result.append(tokenGroup);
} else { // update group's childCount
const auto tokenGroup = std::find_if(result.cbegin(), result.cend(), [communityId](const auto& item) {
return communityId == item.communityId;
});
if (tokenGroup != result.cend()) {
const auto row = std::distance(result.cbegin(), tokenGroup);
TokenData& updTokenGroup = result[row];
updTokenGroup.balance = updTokenGroup.balance.toInt() + 1;
}
}
}
m_hiddenCommunityTokenGroupsModel->clear();
for (const auto& group: std::as_const(result))
m_hiddenCommunityTokenGroupsModel->addItem(group);
qCDebug(manageTokens) << "!!! HIDDEN GROUPS MODEL REBUILT WITH GROUPS:" << communityIds;
}
void ManageTokensController::rebuildRegularTokenGroupsModel()
{
QStringList collectionIds;
@ -525,15 +594,14 @@ void ManageTokensController::rebuildRegularTokenGroupsModel()
});
if (tokenGroup != result.cend()) {
const auto row = std::distance(result.cbegin(), tokenGroup);
TokenData updTokenGroup = result.takeAt(row);
TokenData& updTokenGroup = result[row];
updTokenGroup.balance = updTokenGroup.balance.toInt() + 1;
result.insert(row, updTokenGroup);
}
}
}
m_regularTokenGroupsModel->clear();
for (const auto& group: result)
for (const auto& group: std::as_const(result))
m_regularTokenGroupsModel->addItem(group);
qCDebug(manageTokens) << "!!! COLLECTION MODEL REBUILT WITH GROUPS:" << collectionIds;

View File

@ -25,6 +25,11 @@ class ManageTokensController : public QObject, public QQmlParserStatus
Q_PROPERTY(QAbstractItemModel* communityTokensModel READ communityTokensModel CONSTANT FINAL)
Q_PROPERTY(QAbstractItemModel* communityTokenGroupsModel READ communityTokenGroupsModel CONSTANT FINAL)
Q_PROPERTY(QAbstractItemModel* hiddenTokensModel READ hiddenTokensModel CONSTANT FINAL)
// TODO track hidden collection groups
Q_PROPERTY(QStringList hiddenCommunityGroups READ hiddenCommunityGroups NOTIFY hiddenCommunityGroupsChanged FINAL)
Q_PROPERTY(QAbstractItemModel* hiddenCommunityTokenGroupsModel READ hiddenCommunityTokenGroupsModel CONSTANT FINAL)
Q_PROPERTY(bool dirty READ dirty NOTIFY dirtyChanged FINAL)
Q_PROPERTY(bool hasSettings READ hasSettings NOTIFY settingsDirtyChanged FINAL)
Q_PROPERTY(bool settingsDirty READ settingsDirty NOTIFY settingsDirtyChanged FINAL)
@ -32,8 +37,8 @@ class ManageTokensController : public QObject, public QQmlParserStatus
public:
explicit ManageTokensController(QObject* parent = nullptr);
Q_INVOKABLE void showHideRegularToken(int row, bool flag);
Q_INVOKABLE void showHideCommunityToken(int row, bool flag);
Q_INVOKABLE void showHideRegularToken(const QString& symbol, bool flag);
Q_INVOKABLE void showHideCommunityToken(const QString& symbol, bool flag);
Q_INVOKABLE void showHideGroup(const QString& groupId, bool flag);
Q_INVOKABLE void loadSettings();
@ -43,6 +48,7 @@ public:
Q_INVOKABLE void settingsHideToken(const QString& symbol);
Q_INVOKABLE void settingsHideCommunityTokens(const QString& communityId, const QStringList& symbols);
// TODO settingHideCollectionTokens
Q_INVOKABLE bool lessThan(const QString& lhsSymbol, const QString& rhsSymbol) const;
Q_INVOKABLE bool filterAcceptsSymbol(const QString& symbol) const;
@ -64,6 +70,8 @@ signals:
void communityTokenGroupShown(const QString& communityName);
// TODO collectionTokenGroupHidden(const QString& collectionName);
void hiddenCommunityGroupsChanged();
private:
QAbstractItemModel* m_sourceModel{nullptr};
QAbstractItemModel* sourceModel() const { return m_sourceModel; }
@ -87,6 +95,9 @@ private:
ManageTokensModel* m_hiddenTokensModel{nullptr};
QAbstractItemModel* hiddenTokensModel() const { return m_hiddenTokensModel; }
ManageTokensModel* m_hiddenCommunityTokenGroupsModel{nullptr};
QAbstractItemModel* hiddenCommunityTokenGroupsModel() const { return m_hiddenCommunityTokenGroupsModel; }
bool dirty() const;
bool m_arrangeByCommunity{false};
@ -96,9 +107,11 @@ private:
QStringList m_communityIds;
void reloadCommunityIds();
void rebuildCommunityTokenGroupsModel();
void rebuildHiddenCommunityTokenGroupsModel();
void rebuildRegularTokenGroupsModel();
const std::array<ManageTokensModel*, 5> m_allModels {m_regularTokensModel, m_regularTokenGroupsModel, m_communityTokensModel, m_communityTokenGroupsModel, m_hiddenTokensModel};
const std::array<ManageTokensModel*, 6> m_allModels {m_regularTokensModel, m_regularTokenGroupsModel, m_communityTokensModel, m_communityTokenGroupsModel, m_hiddenTokensModel,
m_hiddenCommunityTokenGroupsModel};
QString m_settingsKey;
QString settingsKey() const;
@ -113,4 +126,8 @@ private:
void setSettingsDirty(bool dirty);
bool m_modelConnectionsInitialized{false};
// explicitely mass-hidden community asset/collectible groups
QSet<QString> m_hiddenCommunityGroups;
QStringList hiddenCommunityGroups() const;
};

View File

@ -38,8 +38,13 @@ void ManageTokensModel::addItem(const TokenData& item, bool append)
endInsertRows();
}
std::optional<TokenData> ManageTokensModel::takeItem(int row)
std::optional<TokenData> ManageTokensModel::takeItem(const QString& symbol)
{
const auto token = std::find_if(m_data.cbegin(), m_data.cend(), [symbol](const auto& item) {
return symbol == item.symbol;
});
const auto row = std::distance(m_data.cbegin(), token);
if (row < 0 || row >= rowCount())
return {};

View File

@ -71,7 +71,7 @@ public:
Q_INVOKABLE void moveItem(int fromRow, int toRow);
void addItem(const TokenData& item, bool append = true);
std::optional<TokenData> takeItem(int row);
std::optional<TokenData> takeItem(const QString& symbol);
QList<TokenData> takeAllItems(const QString& communityId);
void clear();
@ -85,6 +85,7 @@ public:
int count() const { return rowCount(); }
const TokenData& itemAt(int row) const { return m_data.at(row); }
TokenData& itemAt(int row) { return m_data[row]; }
void setCommunityIds(const QStringList& ids) { m_communityIds = ids; };
bool hasCommunityIdToken(const QString& communityId) const;

View File

@ -2,9 +2,11 @@ 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.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Models 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups.Dialog 0.1
@ -32,7 +34,7 @@ ColumnLayout {
readonly property bool dirty: {
if (!loader.item)
return false
if (tabBar.currentIndex > d.collectiblesTabIndex)
if (tabBar.currentIndex > d.hiddenTabIndex)
return false
// FIXME take advanced settings into account here too (#13178)
if (tabBar.currentIndex === d.collectiblesTabIndex && baseWalletCollectiblesModel.isFetching)
@ -41,14 +43,14 @@ ColumnLayout {
}
function saveChanges() {
if (tabBar.currentIndex > d.collectiblesTabIndex)
if (tabBar.currentIndex > d.hiddenTabIndex)
return
// FIXME save advanced settings (#13178)
loader.item.saveSettings()
}
function resetChanges() {
if (tabBar.currentIndex > d.collectiblesTabIndex)
if (tabBar.currentIndex > d.hiddenTabIndex)
return
loader.item.revert()
}
@ -58,7 +60,52 @@ ColumnLayout {
readonly property int assetsTabIndex: 0
readonly property int collectiblesTabIndex: 1
readonly property int advancedTabIndex: 2
readonly property int hiddenTabIndex: 2
readonly property int advancedTabIndex: 3
// assets
readonly property var assetsController: ManageTokensController {
sourceModel: root.baseWalletAssetsModel
settingsKey: "WalletAssets"
onTokenHidden: (symbol, name) => Global.displayToastMessage(
qsTr("%1 (%2) was successfully hidden").arg(name).arg(symbol), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
onCommunityTokenGroupHidden: (communityName) => Global.displayToastMessage(
qsTr("%1 community assets successfully hidden").arg(communityName), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
onTokenShown: (symbol, name) => Global.displayToastMessage(qsTr("%1 is now visible").arg(name), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
onCommunityTokenGroupShown: (communityName) => Global.displayToastMessage(
qsTr("%1 community assets are now visible").arg(communityName), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
}
// collectibles
readonly property var renamedCollectiblesModel: RolesRenamingModel {
sourceModel: root.baseWalletCollectiblesModel
mapping: [
RoleRename {
from: "uid"
to: "symbol"
}
]
}
readonly property var collectiblesController: ManageTokensController {
sourceModel: d.renamedCollectiblesModel
settingsKey: "WalletCollectibles"
onTokenHidden: (symbol, name) => Global.displayToastMessage(
qsTr("%1 was successfully hidden").arg(name), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
onCommunityTokenGroupHidden: (communityName) => Global.displayToastMessage(
qsTr("%1 community collectibles successfully hidden").arg(communityName), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
onTokenShown: (symbol, name) => Global.displayToastMessage(qsTr("%1 is now visible").arg(name), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
onCommunityTokenGroupShown: (communityName) => Global.displayToastMessage(
qsTr("%1 community collectibles are now visible").arg(communityName), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
}
function checkLoadMoreCollectibles() {
if (tabBar.currentIndex !== collectiblesTabIndex)
@ -91,12 +138,14 @@ ColumnLayout {
width: implicitWidth
text: qsTr("Assets")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Collectibles")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Hidden")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Advanced")
@ -116,6 +165,8 @@ ColumnLayout {
return tokensPanel
case d.collectiblesTabIndex:
return collectiblesPanel
case d.hiddenTabIndex:
return hiddenPanel
case d.advancedTabIndex:
return advancedTab
}
@ -125,24 +176,32 @@ ColumnLayout {
Component {
id: tokensPanel
ManageAssetsPanel {
baseModel: root.baseWalletAssetsModel
getCurrencyAmount: function (balance, symbol) {
return root.getCurrencyAmount(balance, symbol)
}
getCurrentCurrencyAmount: function (balance) {
return root.getCurrentCurrencyAmount(balance)
}
controller: d.assetsController
}
}
Component {
id: collectiblesPanel
ManageCollectiblesPanel {
baseModel: root.baseWalletCollectiblesModel
controller: d.collectiblesController
Component.onCompleted: d.checkLoadMoreCollectibles()
}
}
Component {
id: hiddenPanel
ManageHiddenPanel {
assetsController: d.assetsController
collectiblesController: d.collectiblesController
}
}
Component {
id: advancedTab
ColumnLayout {

View File

@ -23,7 +23,7 @@ StatusFlatButton {
readonly property bool menuVisible: menuLoader.active
signal moveRequested(int from, int to)
signal showHideRequested(int index, bool flag)
signal showHideRequested(string symbol, bool flag)
signal showHideGroupRequested(string groupId, bool flag)
icon.name: "more"
@ -82,14 +82,14 @@ StatusFlatButton {
type: StatusAction.Type.Danger
icon.name: "hide"
text: root.isCollectible ? qsTr("Hide collectible") : qsTr("Hide asset")
onTriggered: root.showHideRequested(root.currentIndex, false)
onTriggered: root.showHideRequested(model.symbol, false)
}
StatusAction {
objectName: "miShowToken"
enabled: root.inHidden
enabled: root.inHidden && !root.isGroup
icon.name: "show"
text: root.isCollectible ? qsTr("Show collectible") : qsTr("Show asset")
onTriggered: root.showHideRequested(root.currentIndex, true)
onTriggered: root.showHideRequested(model.symbol, true)
}
// (hide) community tokens
@ -104,7 +104,7 @@ StatusFlatButton {
objectName: "miHideCommunityToken"
text: root.isCollectible ? qsTr("This collectible") : qsTr("This asset")
onTriggered: {
root.showHideRequested(root.currentIndex, false)
root.showHideRequested(model.symbol, false)
communitySubmenu.dismiss()
}
}

View File

@ -20,7 +20,7 @@ Control {
Rectangle {
border.width: 1
border.color: Theme.palette.baseColor2
color: Theme.palette.baseColor4
color: enabled ? Theme.palette.baseColor4 : Theme.palette.baseColor3
radius: 20
}
}
@ -43,8 +43,10 @@ Control {
visible: !root.loading
StatusSmartIdenticon {
id: identicon
Layout.maximumWidth: visible ? 16 : 0
Layout.maximumHeight: visible ? 16 : 0
Layout.preferredWidth: visible ? 16 : 0
Layout.preferredHeight: visible ? 16 : 0
asset.width: 16
asset.height: 16
asset.isImage: true
visible: !!asset.source
}

View File

@ -1,4 +1,5 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import StatusQ 0.1
@ -24,9 +25,8 @@ DropArea {
property alias topInset: delegate.topInset
property alias bottomInset: delegate.bottomInset
property bool isGrouped
property bool isHidden
property bool isHidden // inside the "Hidden" section
property int count
property bool isCollectible
readonly property alias title: delegate.title
@ -47,7 +47,7 @@ DropArea {
PropertyAction { target: root; property: "ListView.delayRemove"; value: false }
}
width: ListView.view.width
width: ListView.view ? ListView.view.width : 0
height: visible ? delegate.height : 0
onEntered: function(drag) {
@ -87,6 +87,7 @@ DropArea {
actions: [
ManageTokensCommunityTag {
Layout.maximumWidth: delegate.width *.4
visible: !!model.communityId && !root.isGrouped
text: model.communityName
asset.name: model && !!model.communityImage ? model.communityImage : ""
@ -101,11 +102,11 @@ DropArea {
isCommunityAsset: !!model.communityId
isCollectible: root.isCollectible
onMoveRequested: (from, to) => root.ListView.view.model.moveItem(from, to)
onShowHideRequested: function(index, flag) {
onShowHideRequested: function(symbol, flag) {
if (isCommunityAsset)
root.controller.showHideCommunityToken(index, flag)
root.controller.showHideCommunityToken(symbol, flag)
else
root.controller.showHideRegularToken(index, flag)
root.controller.showHideRegularToken(symbol, flag)
root.controller.saveSettings()
}
onShowHideGroupRequested: function(groupId, flag) {

View File

@ -21,6 +21,7 @@ DropArea {
property var dragParent
property alias dragEnabled: groupedCommunityTokenDelegate.dragEnabled
property bool isCollectible
property bool isHidden // inside the "Hidden" section
readonly property string communityId: model.communityId
readonly property int childCount: model.enabledNetworkBalance // NB using "balance" as "count" in m_communityTokenGroupsModel
@ -36,8 +37,8 @@ DropArea {
}
keys: ["x-status-draggable-community-group-item"]
width: ListView.view.width
height: groupedCommunityTokenDelegate.implicitHeight
width: ListView.view ? ListView.view.width : 0
height: visible ? groupedCommunityTokenDelegate.implicitHeight : 0
onEntered: function(drag) {
const from = drag.source.visualIndex
@ -52,10 +53,7 @@ DropArea {
id: groupedCommunityTokenDelegate
width: parent.width
height: dragActive ? implicitHeight : parent.height
leftPadding: Style.current.halfPadding
rightPadding: Style.current.halfPadding
bottomPadding: Style.current.halfPadding
topPadding: 22
horizontalPadding: root.isHidden ? 0 : Style.current.halfPadding
draggable: true
spacing: 12
bgColor: Theme.palette.baseColor4
@ -68,13 +66,12 @@ DropArea {
Drag.hotSpot.y: root.height/2
contentItem: ColumnLayout {
spacing: 0
spacing: 12
RowLayout {
Layout.fillWidth: true
Layout.leftMargin: 12
Layout.rightMargin: 12
Layout.bottomMargin: 14
spacing: groupedCommunityTokenDelegate.spacing
StatusIcon {
@ -100,25 +97,25 @@ DropArea {
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 }
ManageTokensCommunityTag {
text: root.childCount
asset.name: root.isCollectible ? "image" : "token"
asset.isImage: false
asset.color: Theme.palette.baseColor1
enabled: false
}
ManageTokenMenuButton {
objectName: "btnManageTokenMenu-%1".arg(currentIndex)
currentIndex: visualIndex
count: root.controller.communityTokenGroupsModel.count
count: root.controller.communityTokenGroupsModel.count // FIXME collection
isGroup: true
isCollectible: root.isCollectible
groupId: model.communityId
onMoveRequested: (from, to) => root.controller.communityTokenGroupsModel.moveItem(from, to) // TODO collection
inHidden: root.isHidden
onMoveRequested: (from, to) => root.controller.communityTokenGroupsModel.moveItem(from, to) // FIXME collection
onShowHideGroupRequested: function(groupId, flag) {
root.controller.showHideGroup(groupId, flag)
root.controller.saveSettings()
@ -132,7 +129,7 @@ DropArea {
Layout.preferredHeight: contentHeight
model: root.controller.communityTokensModel
interactive: false
visible: root.communityGroupsExpanded
visible: root.communityGroupsExpanded && !root.isHidden
displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }

View File

@ -16,10 +16,10 @@ import AppLayouts.Wallet.controls 1.0
Control {
id: root
required property var baseModel
required property var controller
readonly property bool dirty: d.controller.dirty
readonly property bool hasSettings: d.controller.hasSettings
readonly property bool dirty: root.controller.dirty
readonly property bool hasSettings: root.controller.hasSettings
property var getCurrencyAmount: function (balance, symbol) {}
property var getCurrentCurrencyAmount: function(balance){}
@ -27,33 +27,27 @@ Control {
background: null
function saveSettings() {
d.controller.saveSettings();
root.controller.saveSettings();
}
function revert() {
d.controller.revert();
root.controller.revert();
}
function clearSettings() {
d.controller.clearSettings();
root.controller.clearSettings();
}
QtObject {
id: d
property bool communityGroupsExpanded: true
}
readonly property var controller: ManageTokensController {
sourceModel: root.baseModel
arrangeByCommunity: switchArrangeByCommunity.checked
settingsKey: "WalletAssets"
onTokenHidden: (symbol, name) => Global.displayToastMessage(
qsTr("%1 (%2) was successfully hidden.").arg(name).arg(symbol), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
onCommunityTokenGroupHidden: (communityName) => Global.displayToastMessage(
qsTr("%1 community assets successfully hidden").arg(communityName), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
}
Binding {
target: controller
property: "arrangeByCommunity"
value: switchArrangeByCommunity.checked
}
contentItem: ColumnLayout {
@ -61,7 +55,7 @@ Control {
StatusListView {
Layout.fillWidth: true
model: d.controller.regularTokensModel
model: root.controller.regularTokensModel
implicitHeight: contentHeight
interactive: false
@ -70,9 +64,9 @@ Control {
}
delegate: ManageTokensDelegate {
controller: d.controller
controller: root.controller
dragParent: root
count: d.controller.regularTokensModel.count
count: root.controller.regularTokensModel.count
dragEnabled: count > 1
keys: ["x-status-draggable-token-item"]
getCurrencyAmount: function (balance, symbol) {
@ -88,7 +82,7 @@ Control {
id: communityTokensHeader
Layout.fillWidth: true
Layout.topMargin: Style.current.padding
visible: d.controller.communityTokensModel.count
visible: root.controller.communityTokensModel.count
StatusBaseText {
color: Theme.palette.baseColor1
text: qsTr("Community")
@ -120,49 +114,16 @@ Control {
Loader {
Layout.fillWidth: true
active: d.controller.communityTokensModel.count
active: root.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 {
Layout.fillWidth: true
model: d.controller.hiddenTokensModel
implicitHeight: contentHeight
interactive: false
displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
delegate: ManageTokensDelegate {
controller: d.controller
dragParent: root
dragEnabled: false
keys: ["x-status-draggable-none"]
isHidden: true
getCurrencyAmount: function (balance, symbol) {
return root.getCurrencyAmount(balance, symbol)
}
getCurrentCurrencyAmount: function (balance) {
return root.getCurrentCurrencyAmount(balance)
}
}
}
}
Component {
id: cmpCommunityTokens
StatusListView {
model: d.controller.communityTokensModel
model: root.controller.communityTokensModel
implicitHeight: contentHeight
interactive: false
@ -171,9 +132,9 @@ Control {
}
delegate: ManageTokensDelegate {
controller: d.controller
controller: root.controller
dragParent: root
count: d.controller.communityTokensModel.count
count: root.controller.communityTokensModel.count
dragEnabled: count > 1
keys: ["x-status-draggable-community-token-item"]
getCurrencyAmount: function (balance, symbol) {
@ -189,7 +150,7 @@ Control {
Component {
id: cmpCommunityTokenGroups
StatusListView {
model: d.controller.communityTokenGroupsModel
model: root.controller.communityTokenGroupsModel
implicitHeight: contentHeight
interactive: false
spacing: Style.current.halfPadding
@ -199,9 +160,9 @@ Control {
}
delegate: ManageTokensGroupDelegate {
controller: d.controller
controller: root.controller
dragParent: root
dragEnabled: d.controller.communityTokenGroupsModel.count > 1
dragEnabled: root.controller.communityTokenGroupsModel.count > 1
communityGroupsExpanded: d.communityGroupsExpanded
getCurrencyAmount: function (balance, symbol) {
return root.getCurrencyAmount(balance, symbol)

View File

@ -18,53 +18,36 @@ import AppLayouts.Wallet.controls 1.0
Control {
id: root
required property var baseModel
required property var controller
readonly property bool dirty: d.controller.dirty
readonly property bool hasSettings: d.controller.hasSettings
readonly property bool dirty: root.controller.dirty
readonly property bool hasSettings: root.controller.hasSettings
background: null
function saveSettings() {
d.controller.saveSettings();
root.controller.saveSettings();
}
function revert() {
d.controller.revert();
root.controller.revert();
}
function clearSettings() {
d.controller.clearSettings();
root.controller.clearSettings();
}
QtObject {
id: d
property bool collectionGroupsExpanded: true
//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"
onTokenHidden: (symbol, name) => Global.displayToastMessage(
qsTr("%1 was successfully hidden.").arg(name), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
onCommunityTokenGroupHidden: (communityName) => Global.displayToastMessage(
qsTr("%1 community collectibles successfully hidden").arg(communityName), "", "checkmark-circle",
false, Constants.ephemeralNotificationType.success, "")
}
Binding {
target: controller
property: "arrangeByCommunity"
value: switchArrangeByCommunity.checked
}
contentItem: ColumnLayout {
@ -73,7 +56,7 @@ Control {
ShapeRectangle {
Layout.fillWidth: true
Layout.margins: 2
visible: !d.controller.regularTokensModel.count
visible: !root.controller.regularTokensModel.count
text: qsTr("Youll be able to manage the display of your collectibles here")
}
@ -85,7 +68,7 @@ Control {
// id: switchArrangeByCollection
// textColor: Theme.palette.baseColor1
// text: qsTr("Arrange by collection")
// visible: d.controller.regularTokensModel.count
// visible: root.controller.regularTokensModel.count
// }
// StatusModalDivider {
@ -106,7 +89,7 @@ Control {
StatusListView {
objectName: "lvRegularTokens"
Layout.fillWidth: true
model: d.controller.regularTokensModel
model: root.controller.regularTokensModel
implicitHeight: contentHeight
interactive: false
@ -116,9 +99,9 @@ Control {
delegate: ManageTokensDelegate {
isCollectible: true
controller: d.controller
controller: root.controller
dragParent: root
count: d.controller.regularTokensModel.count
count: root.controller.regularTokensModel.count
dragEnabled: count > 1
keys: ["x-status-draggable-token-item"]
}
@ -128,7 +111,7 @@ Control {
id: communityTokensHeader
Layout.fillWidth: true
Layout.topMargin: Style.current.padding
visible: d.controller.communityTokensModel.count
visible: root.controller.communityTokensModel.count
StatusBaseText {
color: Theme.palette.baseColor1
text: qsTr("Community")
@ -163,46 +146,17 @@ Control {
Loader {
objectName: "loaderCommunityTokens"
Layout.fillWidth: true
active: d.controller.communityTokensModel.count
active: root.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
model: root.controller.communityTokensModel
implicitHeight: contentHeight
interactive: false
@ -212,9 +166,9 @@ Control {
delegate: ManageTokensDelegate {
isCollectible: true
controller: d.controller
controller: root.controller
dragParent: root
count: d.controller.communityTokensModel.count
count: root.controller.communityTokensModel.count
dragEnabled: count > 1
keys: ["x-status-draggable-community-token-item"]
}
@ -225,7 +179,7 @@ Control {
id: cmpCommunityTokenGroups
StatusListView {
objectName: "lvCommunityTokenGroups"
model: d.controller.communityTokenGroupsModel
model: root.controller.communityTokenGroupsModel
implicitHeight: contentHeight
interactive: false
spacing: Style.current.halfPadding
@ -236,9 +190,9 @@ Control {
delegate: ManageTokensGroupDelegate {
isCollectible: true
controller: d.controller
controller: root.controller
dragParent: root
dragEnabled: d.controller.communityTokenGroupsModel.count > 1
dragEnabled: root.controller.communityTokenGroupsModel.count > 1
communityGroupsExpanded: d.communityGroupsExpanded
}
}

View File

@ -0,0 +1,226 @@
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.Models 0.1
import utils 1.0
import shared.controls 1.0
import AppLayouts.Wallet.controls 1.0
import SortFilterProxyModel 0.2
Control {
id: root
required property var assetsController
required property var collectiblesController
readonly property bool dirty: false // never dirty, the "show xxx" actions are immediate
readonly property bool hasSettings: root.assetsController.hasSettings || root.collectiblesController.hasSettings
background: null
function clearSettings() {
root.assetsController.clearSettings();
root.collectiblesController.clearSettings();
}
QtObject {
id: d
property bool assetsExpanded: true
property bool collectiblesExpanded: true
readonly property int assetsCount: root.assetsController.hiddenTokensModel.count + root.assetsController.hiddenCommunityTokenGroupsModel.count
readonly property int collectiblesCount: root.collectiblesController.hiddenTokensModel.count + root.collectiblesController.hiddenCommunityTokenGroupsModel.count // + TODO collection groups
readonly property var filteredHiddenAssets: SortFilterProxyModel {
sourceModel: root.assetsController.hiddenTokensModel
filters: FastExpressionFilter {
expression: {
root.assetsController.hiddenCommunityGroups
return !root.assetsController.hiddenCommunityGroups.includes(model.communityId)
}
expectedRoles: ["communityId"]
}
}
readonly property var filteredHiddenCollectibles: SortFilterProxyModel {
sourceModel: root.collectiblesController.hiddenTokensModel
filters: FastExpressionFilter {
expression: {
root.collectiblesController.hiddenCommunityGroups
return !root.collectiblesController.hiddenCommunityGroups.includes(model.communityId)
}
expectedRoles: ["communityId"]
}
}
readonly property var combinedModel: ConcatModel {
sources: [
SourceModel { // single hidden assets (not belonging to a group)
model: d.filteredHiddenAssets
markerRoleValue: "asset"
},
SourceModel { // community asset groups
model: root.assetsController.hiddenCommunityTokenGroupsModel
markerRoleValue: "assetGroup"
},
SourceModel { // single hidden collectibles (not belonging to a group)
model: d.filteredHiddenCollectibles
markerRoleValue: "collectible"
},
SourceModel { // community collectible groups
model: root.collectiblesController.hiddenCommunityTokenGroupsModel
markerRoleValue: "collectibleGroup"
}
]
markerRoleName: "tokenType"
}
readonly property var sfpm: SortFilterProxyModel {
sourceModel: d.combinedModel
proxyRoles: [
FastExpressionRole {
name: "isCollectible"
expression: model.tokenType.startsWith("collectible")
expectedRoles: "tokenType"
},
FastExpressionRole {
name: "isGroup"
expression: model.tokenType.endsWith("Group")
expectedRoles: "tokenType"
}
// TODO collection
]
// TODO sort by recency/timestamp (newest first)
}
}
component SectionDelegate: Rectangle {
id: sectionDelegate
height: 64
color: Theme.palette.statusListItem.backgroundColor
property bool isCollectible
RowLayout {
anchors.fill: parent
StatusFlatButton {
size: StatusBaseButton.Size.Small
icon.name: checked ? "chevron-down" : "next"
checked: sectionDelegate.isCollectible ? d.collectiblesExpanded : d.assetsExpanded
textColor: Theme.palette.baseColor1
textHoverColor: Theme.palette.directColor1
onToggled: {
if (sectionDelegate.isCollectible)
d.collectiblesExpanded = !d.collectiblesExpanded
else
d.assetsExpanded = !d.assetsExpanded
}
}
StatusBaseText {
Layout.fillWidth: true
text: sectionDelegate.isCollectible ? qsTr("Collectibles") : qsTr("Assets")
elide: Text.ElideRight
}
}
}
component Placeholder: ShapeRectangle {
property bool isCollectible
text: isCollectible ? qsTr("Your hidden collectibles will appear here") : qsTr("Your hidden assets will appear here")
}
Component {
id: tokenDelegate
ManageTokensDelegate {
isCollectible: model.isCollectible
controller: isCollectible ? root.collectiblesController : root.assetsController
dragParent: null
dragEnabled: false
keys: ["x-status-draggable-none"]
isHidden: true
}
}
Component {
id: tokenGroupDelegate
ManageTokensGroupDelegate {
isCollectible: model.isCollectible
controller: isCollectible ? root.collectiblesController : root.assetsController
dragParent: null
dragEnabled: false
keys: ["x-status-draggable-none"]
isHidden: true
}
}
contentItem: ColumnLayout {
spacing: 2 // subtle spacing for the dashed placeholders to be fully visible
ColumnLayout { // no assets placeholder
Layout.fillWidth: true
spacing: 0
visible: !d.assetsCount
SectionDelegate {
Layout.fillWidth: true
}
Placeholder {
Layout.fillWidth: true
visible: d.assetsExpanded
}
}
StatusListView {
Layout.fillWidth: true
implicitHeight: contentHeight
Layout.fillHeight: true
model: d.sfpm
displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
delegate: Loader {
required property var model
required property int index
width: ListView.view.width
height: visible ? 76 : 0
sourceComponent: model.isGroup ? tokenGroupDelegate : tokenDelegate
visible: (!model.isCollectible && d.assetsExpanded) || (model.isCollectible && d.collectiblesExpanded)
}
section.property: "isCollectible"
section.delegate: SectionDelegate {
width: ListView.view.width
isCollectible: section == "true"
}
section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
}
ColumnLayout { // no collectibles placeholder
Layout.fillWidth: true
spacing: 0
visible: !d.collectiblesCount
SectionDelegate {
Layout.fillWidth: true
isCollectible: true
}
Placeholder {
Layout.fillWidth: true
isCollectible: true
visible: d.collectiblesExpanded
}
}
}
}

View File

@ -4,3 +4,4 @@ WalletNftPreview 1.0 WalletNftPreview.qml
ActivityFilterPanel 1.0 ActivityFilterPanel.qml
ManageAssetsPanel 1.0 ManageAssetsPanel.qml
ManageCollectiblesPanel 1.0 ManageCollectiblesPanel.qml
ManageHiddenPanel 1.0 ManageHiddenPanel.qml