feat(wallet) save/load collectibles user handled state in DB
Add a separation layer for save/load/clear to ManageTokensModel so that we can save/load from external sources. The separate layer is composed of JSON as protocol, a set of signals and slots for interface. The implementation forwards data to current QSettings for storybook and nim controllers for the app. Updates #13313, #13312
This commit is contained in:
parent
f45a39bfcf
commit
26542970ee
|
@ -32,6 +32,10 @@ QtObject:
|
|||
proc updateCollectiblePreferences*(self: View, collectiblePreferencesJson: string) {.slot.} =
|
||||
self.delegate.updateCollectiblePreferences(collectiblePreferencesJson)
|
||||
|
||||
proc clearCollectiblePreferences*(self: View) {.slot.} =
|
||||
# There is no requirements of clearing the preferences yet but controller is expected to expose it
|
||||
discard
|
||||
|
||||
proc getCollectiblePreferencesJson(self: View): QVariant {.slot.} =
|
||||
let preferences = self.delegate.getCollectiblePreferencesJson()
|
||||
return newQVariant(preferences)
|
||||
|
|
|
@ -87,14 +87,14 @@ type
|
|||
contractAddress*: string
|
||||
owners*: seq[CollectibleOwner]
|
||||
|
||||
# see status-go/services/wallet/collectibles/service.go CollectibleDataType
|
||||
# Mirrors status-go/multiaccounts/settings_wallet/database.go CollectiblePreferencesType
|
||||
CollectiblePreferencesItemType* {.pure.} = enum
|
||||
NonCommunityCollectible = 1,
|
||||
CommunityCollectible,
|
||||
Collection,
|
||||
NonCommunityCollectible = 1,
|
||||
CommunityCollectible,
|
||||
Collection,
|
||||
Community
|
||||
|
||||
# Mirrors services/wallet/thirdparty/collectible_types.go CollectibleContractOwnership
|
||||
# Mirrors status-go/multiaccounts/settings_wallet/database.go CollectiblePreferences
|
||||
CollectiblePreferences* = ref object of RootObj
|
||||
itemType* {.serializedFieldName("type").}: CollectiblePreferencesItemType
|
||||
key* {.serializedFieldName("key").}: string
|
||||
|
|
|
@ -97,6 +97,12 @@ SplitView {
|
|||
controller: ManageTokensController {
|
||||
sourceModel: d.walletAssetStore.groupedAccountAssetsModel
|
||||
settingsKey: "WalletAssets"
|
||||
serializeAsCollectibles: false
|
||||
|
||||
onRequestSaveSettings: (jsonData) => saveToQSettings(jsonData)
|
||||
onRequestLoadSettings: loadFromQSettings()
|
||||
onRequestClearSettings: clearQSettings()
|
||||
|
||||
onTokenHidden: (symbol, name) => Global.displayToastMessage(
|
||||
qsTr("%1 (%2) was successfully hidden").arg(name).arg(symbol), "", "checkmark-circle",
|
||||
false, Constants.ephemeralNotificationType.success, "")
|
||||
|
|
|
@ -82,6 +82,12 @@ SplitView {
|
|||
controller: ManageTokensController {
|
||||
sourceModel: renamedModel
|
||||
settingsKey: "WalletCollectibles"
|
||||
serializeAsCollectibles: true
|
||||
|
||||
onRequestSaveSettings: (jsonData) => saveToQSettings(jsonData)
|
||||
onRequestLoadSettings: loadFromQSettings()
|
||||
onRequestClearSettings: clearQSettings()
|
||||
|
||||
onTokenHidden: (symbol, name) => Global.displayToastMessage(
|
||||
qsTr("%1 was successfully hidden").arg(name), "", "checkmark-circle",
|
||||
false, Constants.ephemeralNotificationType.success, "")
|
||||
|
|
|
@ -50,6 +50,11 @@ SplitView {
|
|||
controller: ManageTokensController {
|
||||
sourceModel: ctrlEmptyModel.checked ? null : walletAssetStore.groupedAccountAssetsModel
|
||||
settingsKey: "WalletAssets"
|
||||
serializeAsCollectibles: false
|
||||
|
||||
onRequestSaveSettings: (jsonData) => saveToQSettings(jsonData)
|
||||
onRequestLoadSettings: loadFromQSettings()
|
||||
onRequestClearSettings: clearQSettings()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,11 @@ SplitView {
|
|||
controller: ManageTokensController {
|
||||
sourceModel: renamedModel
|
||||
settingsKey: "WalletCollectibles"
|
||||
serializeAsCollectibles: true
|
||||
|
||||
onRequestSaveSettings: (jsonData) => saveToQSettings(jsonData)
|
||||
onRequestLoadSettings: loadFromQSettings()
|
||||
onRequestClearSettings: clearQSettings()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,12 +44,22 @@ SplitView {
|
|||
id: assetsController
|
||||
sourceModel: ctrlEmptyModel.checked ? null : walletAssetStore.groupedAccountAssetsModel
|
||||
settingsKey: "WalletAssets"
|
||||
serializeAsCollectibles: false
|
||||
|
||||
onRequestSaveSettings: (jsonData) => saveToQSettings(jsonData)
|
||||
onRequestLoadSettings: loadFromQSettings()
|
||||
onRequestClearSettings: clearQSettings()
|
||||
}
|
||||
|
||||
ManageTokensController {
|
||||
id: collectiblesController
|
||||
sourceModel: ctrlEmptyModel.checked ? null : renamedModel
|
||||
settingsKey: "WalletCollectibles"
|
||||
serializeAsCollectibles: true
|
||||
|
||||
onRequestSaveSettings: (jsonData) => saveToQSettings(jsonData)
|
||||
onRequestLoadSettings: loadFromQSettings()
|
||||
onRequestClearSettings: clearQSettings()
|
||||
}
|
||||
|
||||
ManageHiddenPanel {
|
||||
|
|
|
@ -37,10 +37,20 @@ Item {
|
|||
controller: ManageTokensController {
|
||||
sourceModel: renamedModel
|
||||
settingsKey: "WalletCollectibles"
|
||||
serializeAsCollectibles: true
|
||||
|
||||
onRequestSaveSettings: (jsonData) => saveToQSettings(jsonData)
|
||||
onRequestLoadSettings: loadFromQSettings()
|
||||
onRequestClearSettings: clearQSettings()
|
||||
|
||||
onCommunityTokenGroupHidden: (communityName) => Global.displayToastMessage(
|
||||
qsTr("%1 community collectibles successfully hidden").arg(communityName), "", "checkmark-circle",
|
||||
false, Constants.ephemeralNotificationType.success, "")
|
||||
}
|
||||
|
||||
function clearSettings() {
|
||||
controller.clearQSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,8 @@ add_library(StatusQ SHARED
|
|||
src/wallet/managetokenscontroller.h
|
||||
src/wallet/managetokensmodel.cpp
|
||||
src/wallet/managetokensmodel.h
|
||||
src/wallet/tokendata.cpp
|
||||
src/wallet/tokendata.h
|
||||
)
|
||||
|
||||
target_compile_features(StatusQ PRIVATE cxx_std_17)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "managetokenscontroller.h"
|
||||
|
||||
#include <tuple>
|
||||
#include "tokendata.h"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QMutableHashIterator>
|
||||
|
@ -26,30 +26,38 @@ ManageTokensController::ManageTokensController(QObject* parent)
|
|||
}
|
||||
if (m_modelConnectionsInitialized)
|
||||
return;
|
||||
connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) {
|
||||
connect(m_sourceModel,
|
||||
&QAbstractItemModel::rowsInserted,
|
||||
this,
|
||||
[this](const QModelIndex& parent, int first, int last) {
|
||||
#ifdef QT_DEBUG
|
||||
QElapsedTimer t;
|
||||
t.start();
|
||||
qCDebug(manageTokens) << "!!! ADDING" << last-first+1 << "NEW TOKENS";
|
||||
QElapsedTimer t;
|
||||
t.start();
|
||||
qCDebug(manageTokens) << "!!! ADDING" << last - first + 1 << "NEW TOKENS";
|
||||
#endif
|
||||
for (int i = first; i <= last; i++)
|
||||
addItem(i);
|
||||
for (int i = first; i <= last; i++)
|
||||
addItem(i);
|
||||
|
||||
rebuildCommunityTokenGroupsModel();
|
||||
rebuildHiddenCommunityTokenGroupsModel();
|
||||
rebuildCollectionGroupsModel();
|
||||
rebuildHiddenCollectionGroupsModel();
|
||||
rebuildCommunityTokenGroupsModel();
|
||||
rebuildHiddenCommunityTokenGroupsModel();
|
||||
rebuildCollectionGroupsModel();
|
||||
rebuildHiddenCollectionGroupsModel();
|
||||
|
||||
for (auto model: m_allModels) {
|
||||
model->applySort();
|
||||
model->saveCustomSortOrder();
|
||||
}
|
||||
for (auto model : m_allModels) {
|
||||
model->applySort();
|
||||
model->saveCustomSortOrder();
|
||||
}
|
||||
#ifdef QT_DEBUG
|
||||
qCDebug(manageTokens) << "!!! ADDING NEW SOURCE DATA TOOK" << t.nsecsElapsed()/1'000'000.f << "ms";
|
||||
qCDebug(manageTokens)
|
||||
<< "!!! ADDING NEW SOURCE DATA TOOK" << t.nsecsElapsed() / 1'000'000.f << "ms";
|
||||
#endif
|
||||
});
|
||||
connect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &ManageTokensController::parseSourceModel);
|
||||
connect(m_sourceModel, &QAbstractItemModel::dataChanged, this, &ManageTokensController::parseSourceModel); // NB at this point we don't know in which submodel the item is
|
||||
connect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &ManageTokensController::requestLoadSettings);
|
||||
connect(m_sourceModel,
|
||||
&QAbstractItemModel::dataChanged,
|
||||
this,
|
||||
&ManageTokensController::requestLoadSettings); // NB at this point we don't know in
|
||||
// which submodel the item is
|
||||
m_modelConnectionsInitialized = true;
|
||||
});
|
||||
}
|
||||
|
@ -69,7 +77,7 @@ void ManageTokensController::showHideRegularToken(const QString& symbol, bool fl
|
|||
emit tokenHidden(shownItem->symbol, shownItem->name);
|
||||
}
|
||||
}
|
||||
saveSettings();
|
||||
requestSaveSettings(serializeSettingsAsJson());
|
||||
}
|
||||
|
||||
void ManageTokensController::showHideCommunityToken(const QString& symbol, bool flag)
|
||||
|
@ -90,7 +98,7 @@ void ManageTokensController::showHideCommunityToken(const QString& symbol, bool
|
|||
m_communityTokensModel->saveCustomSortOrder();
|
||||
rebuildCommunityTokenGroupsModel();
|
||||
rebuildHiddenCommunityTokenGroupsModel();
|
||||
saveSettings();
|
||||
requestSaveSettings(serializeSettingsAsJson());
|
||||
}
|
||||
|
||||
void ManageTokensController::showHideGroup(const QString& groupId, bool flag)
|
||||
|
@ -98,7 +106,7 @@ void ManageTokensController::showHideGroup(const QString& groupId, bool flag)
|
|||
if (flag) { // show
|
||||
const auto tokens = m_hiddenTokensModel->takeAllItems(groupId);
|
||||
if (!tokens.isEmpty()) {
|
||||
for (const auto& token: tokens) {
|
||||
for (const auto& token : tokens) {
|
||||
m_communityTokensModel->addItem(token);
|
||||
}
|
||||
emit communityTokenGroupShown(tokens.constFirst().communityName);
|
||||
|
@ -109,7 +117,7 @@ void ManageTokensController::showHideGroup(const QString& groupId, bool flag)
|
|||
} else { // hide
|
||||
const auto tokens = m_communityTokensModel->takeAllItems(groupId);
|
||||
if (!tokens.isEmpty()) {
|
||||
for (const auto& token: tokens) {
|
||||
for (const auto& token : tokens) {
|
||||
m_hiddenTokensModel->addItem(token, false /*prepend*/);
|
||||
}
|
||||
emit communityTokenGroupHidden(tokens.constFirst().communityName);
|
||||
|
@ -122,7 +130,7 @@ void ManageTokensController::showHideGroup(const QString& groupId, bool flag)
|
|||
rebuildCommunityTokenGroupsModel();
|
||||
m_communityTokenGroupsModel->applySort();
|
||||
rebuildHiddenCommunityTokenGroupsModel();
|
||||
saveSettings();
|
||||
requestSaveSettings(serializeSettingsAsJson());
|
||||
}
|
||||
|
||||
void ManageTokensController::showHideCollectionGroup(const QString& groupId, bool flag)
|
||||
|
@ -130,7 +138,7 @@ void ManageTokensController::showHideCollectionGroup(const QString& groupId, boo
|
|||
if (flag) { // show
|
||||
const auto tokens = m_hiddenTokensModel->takeAllItems(groupId);
|
||||
if (!tokens.isEmpty()) {
|
||||
for (const auto& token: tokens) {
|
||||
for (const auto& token : tokens) {
|
||||
m_regularTokensModel->addItem(token);
|
||||
}
|
||||
emit collectionTokenGroupShown(tokens.constFirst().collectionName);
|
||||
|
@ -141,7 +149,7 @@ void ManageTokensController::showHideCollectionGroup(const QString& groupId, boo
|
|||
} else { // hide
|
||||
const auto tokens = m_regularTokensModel->takeAllItems(groupId);
|
||||
if (!tokens.isEmpty()) {
|
||||
for (const auto& token: tokens) {
|
||||
for (const auto& token : tokens) {
|
||||
m_hiddenTokensModel->addItem(token, false /*prepend*/);
|
||||
}
|
||||
emit collectionTokenGroupHidden(tokens.constFirst().collectionName);
|
||||
|
@ -154,71 +162,28 @@ void ManageTokensController::showHideCollectionGroup(const QString& groupId, boo
|
|||
rebuildCollectionGroupsModel();
|
||||
m_collectionGroupsModel->applySort();
|
||||
rebuildHiddenCollectionGroupsModel();
|
||||
saveSettings();
|
||||
requestSaveSettings(serializeSettingsAsJson());
|
||||
}
|
||||
|
||||
void ManageTokensController::saveSettings()
|
||||
void ManageTokensController::saveToQSettings(const QString& json)
|
||||
{
|
||||
Q_ASSERT(!m_settingsKey.isEmpty());
|
||||
|
||||
setSettingsDirty(true);
|
||||
|
||||
// gather the data to save
|
||||
SerializedTokenData result;
|
||||
const auto resultCount = m_regularTokensModel->rowCount() + m_communityTokensModel->rowCount() + m_hiddenTokensModel->rowCount() +
|
||||
(m_arrangeByCommunity ? m_communityTokenGroupsModel->rowCount() : 0) +
|
||||
(m_arrangeByCollection ? m_collectionGroupsModel->rowCount() : 0);
|
||||
result.reserve(resultCount);
|
||||
|
||||
for(auto model : {m_regularTokensModel, m_communityTokensModel})
|
||||
result.insert(model->save());
|
||||
if (m_arrangeByCommunity)
|
||||
result.insert(m_communityTokenGroupsModel->save());
|
||||
if (m_arrangeByCollection)
|
||||
result.insert(m_collectionGroupsModel->save());
|
||||
result.insert(m_hiddenTokensModel->save(false));
|
||||
savingStarted();
|
||||
|
||||
// save to QSettings
|
||||
m_settings.beginGroup(settingsGroupName());
|
||||
|
||||
// arrange by
|
||||
m_settings.setValue(QStringLiteral("ArrangeByCommunity"), m_arrangeByCommunity);
|
||||
m_settings.setValue(QStringLiteral("ArrangeByCollection"), m_arrangeByCollection);
|
||||
|
||||
// data
|
||||
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++) {
|
||||
m_settings.setArrayIndex(i);
|
||||
const auto& [pos, visible, groupId, isCommunityGroup, isCollectionGroup] = it->second;
|
||||
m_settings.setValue(QStringLiteral("symbol"), it->first);
|
||||
m_settings.setValue(QStringLiteral("pos"), pos);
|
||||
m_settings.setValue(QStringLiteral("visible"), visible);
|
||||
m_settings.setValue(QStringLiteral("groupId"), groupId);
|
||||
m_settings.setValue(QStringLiteral("isCommunityGroup"), isCommunityGroup);
|
||||
m_settings.setValue(QStringLiteral("isCollectionGroup"), isCollectionGroup);
|
||||
}
|
||||
m_settings.endArray();
|
||||
|
||||
// hidden groups
|
||||
m_settings.setValue(QStringLiteral("HiddenCommunityGroups"), hiddenCommunityGroups());
|
||||
m_settings.setValue(QStringLiteral("HiddenCollectionGroups"), hiddenCollectionGroups());
|
||||
m_settings.setValue(m_settingsKey, json);
|
||||
|
||||
m_settings.endGroup();
|
||||
m_settings.sync();
|
||||
|
||||
// unset dirty
|
||||
for (auto model: m_allModels)
|
||||
model->setDirty(false);
|
||||
|
||||
loadSettingsData(true); // reload positions and visibility
|
||||
|
||||
incRevision();
|
||||
|
||||
setSettingsDirty(false);
|
||||
savingFinished();
|
||||
}
|
||||
|
||||
void ManageTokensController::clearSettings()
|
||||
void ManageTokensController::clearQSettings()
|
||||
{
|
||||
Q_ASSERT(!m_settingsKey.isEmpty());
|
||||
|
||||
|
@ -231,73 +196,24 @@ void ManageTokensController::clearSettings()
|
|||
emit settingsDirtyChanged(false);
|
||||
}
|
||||
|
||||
void ManageTokensController::loadSettingsData(bool withGroup)
|
||||
{
|
||||
SerializedTokenData result;
|
||||
|
||||
if (withGroup)
|
||||
m_settings.beginGroup(settingsGroupName());
|
||||
|
||||
const auto size = m_settings.beginReadArray(m_settingsKey);
|
||||
for (auto i = 0; i < size; i++) {
|
||||
m_settings.setArrayIndex(i);
|
||||
const auto symbol = m_settings.value(QStringLiteral("symbol")).toString();
|
||||
if (symbol.isEmpty()) {
|
||||
qCDebug(manageTokens) << Q_FUNC_INFO << "Missing symbol while reading tokens settings";
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
const auto isCommunityGroup = m_settings.value(QStringLiteral("isCommunityGroup"), false).toBool();
|
||||
const auto isCollectionGroup = m_settings.value(QStringLiteral("isCollectionGroup"), false).toBool();
|
||||
result.insert(symbol, {pos, visible, groupId, isCommunityGroup, isCollectionGroup});
|
||||
}
|
||||
m_settings.endArray();
|
||||
|
||||
if (withGroup)
|
||||
m_settings.endGroup();
|
||||
|
||||
if (result != m_settingsData)
|
||||
m_settingsData = result;
|
||||
}
|
||||
|
||||
void ManageTokensController::loadSettings()
|
||||
void ManageTokensController::loadFromQSettings()
|
||||
{
|
||||
Q_ASSERT(!m_settingsKey.isEmpty());
|
||||
|
||||
setSettingsDirty(true);
|
||||
m_settingsData.clear();
|
||||
loadingStarted();
|
||||
|
||||
// load from QSettings
|
||||
m_settings.beginGroup(settingsGroupName());
|
||||
|
||||
loadSettingsData();
|
||||
|
||||
// hidden groups
|
||||
const auto groups = m_settings.value(QStringLiteral("HiddenCommunityGroups")).toStringList();
|
||||
if (!groups.isEmpty()) {
|
||||
m_hiddenCommunityGroups = {groups.constBegin(), groups.constEnd()};
|
||||
emit hiddenCommunityGroupsChanged();
|
||||
}
|
||||
const auto collections = m_settings.value(QStringLiteral("HiddenCollectionGroups")).toStringList();
|
||||
if (!collections.isEmpty()) {
|
||||
m_hiddenCollectionGroups = {collections.constBegin(), collections.constEnd()};
|
||||
emit hiddenCollectionGroupsChanged();
|
||||
}
|
||||
|
||||
// arrange by
|
||||
setArrangeByCommunity(m_settings.value(QStringLiteral("ArrangeByCommunity"), false).toBool());
|
||||
setArrangeByCollection(m_settings.value(QStringLiteral("ArrangeByCollection"), false).toBool());
|
||||
|
||||
const auto jsonData = m_settings.value(m_settingsKey).toString();
|
||||
m_settings.endGroup();
|
||||
|
||||
setSettingsDirty(false);
|
||||
loadingFinished(jsonData);
|
||||
}
|
||||
|
||||
void ManageTokensController::setSettingsDirty(bool dirty)
|
||||
{
|
||||
if (m_settingsDirty == dirty) return;
|
||||
if (m_settingsDirty == dirty)
|
||||
return;
|
||||
m_settingsDirty = dirty;
|
||||
emit settingsDirtyChanged(m_settingsDirty);
|
||||
}
|
||||
|
@ -318,9 +234,81 @@ QStringList ManageTokensController::hiddenCollectionGroups() const
|
|||
return {m_hiddenCollectionGroups.constBegin(), m_hiddenCollectionGroups.constEnd()};
|
||||
}
|
||||
|
||||
void ManageTokensController::revert()
|
||||
void ManageTokensController::revert() { requestLoadSettings(); }
|
||||
|
||||
void ManageTokensController::savingStarted()
|
||||
{
|
||||
setSettingsDirty(true); // save to QSettings
|
||||
m_settings.beginGroup(settingsGroupName());
|
||||
|
||||
m_settings.setValue(QStringLiteral("ArrangeByCommunity"), m_arrangeByCommunity);
|
||||
m_settings.setValue(QStringLiteral("ArrangeByCollection"), m_arrangeByCollection);
|
||||
|
||||
m_settings.endGroup();
|
||||
}
|
||||
|
||||
void ManageTokensController::savingFinished()
|
||||
{
|
||||
// unset dirty
|
||||
for (auto model : m_allModels)
|
||||
model->setDirty(false);
|
||||
|
||||
incRevision();
|
||||
|
||||
setSettingsDirty(false);
|
||||
}
|
||||
|
||||
void ManageTokensController::loadingStarted()
|
||||
{
|
||||
setSettingsDirty(true);
|
||||
m_settingsData.clear();
|
||||
|
||||
m_settings.beginGroup(settingsGroupName());
|
||||
|
||||
// hidden groups
|
||||
const auto groups = m_settings.value(QStringLiteral("HiddenCommunityGroups")).toStringList();
|
||||
if (!groups.isEmpty()) {
|
||||
m_hiddenCommunityGroups = {groups.constBegin(), groups.constEnd()};
|
||||
emit hiddenCommunityGroupsChanged();
|
||||
}
|
||||
const auto collections = m_settings.value(QStringLiteral("HiddenCollectionGroups")).toStringList();
|
||||
if (!collections.isEmpty()) {
|
||||
m_hiddenCollectionGroups = {collections.constBegin(), collections.constEnd()};
|
||||
emit hiddenCollectionGroupsChanged();
|
||||
}
|
||||
|
||||
// arrange by
|
||||
setArrangeByCommunity(m_settings.value(QStringLiteral("ArrangeByCommunity"), false).toBool());
|
||||
setArrangeByCollection(m_settings.value(QStringLiteral("ArrangeByCollection"), false).toBool());
|
||||
|
||||
m_settings.endGroup();
|
||||
}
|
||||
|
||||
void ManageTokensController::loadingFinished(const QString& jsonData)
|
||||
{
|
||||
if (!jsonData.isEmpty()) {
|
||||
auto result = tokenOrdersFromJson(jsonData, m_serializeAsCollectibles);
|
||||
if (result != m_settingsData) {
|
||||
m_settingsData = result;
|
||||
}
|
||||
}
|
||||
|
||||
parseSourceModel();
|
||||
setSettingsDirty(false);
|
||||
}
|
||||
|
||||
QString ManageTokensController::serializeSettingsAsJson()
|
||||
{
|
||||
SerializedTokenData result;
|
||||
for (auto model : {m_regularTokensModel, m_communityTokensModel})
|
||||
result.insert(model->save());
|
||||
if (m_arrangeByCommunity)
|
||||
result.insert(m_communityTokenGroupsModel->save(true /* visible */, true /* itemsAreGroups */));
|
||||
if (m_arrangeByCollection)
|
||||
result.insert(m_collectionGroupsModel->save(true /* visible */, true /* itemsAreGroups */));
|
||||
result.insert(m_hiddenTokensModel->save(false));
|
||||
auto json = tokenOrdersToJson(result, m_serializeAsCollectibles);
|
||||
return json;
|
||||
}
|
||||
|
||||
QString ManageTokensController::settingsGroupName() const
|
||||
|
@ -337,26 +325,12 @@ bool ManageTokensController::hasSettings() const
|
|||
|
||||
int ManageTokensController::compareTokens(const QString& lhsSymbol, const QString& rhsSymbol) const
|
||||
{
|
||||
constexpr auto defaultVal = std::make_tuple(INT_MAX, false, QLatin1String(), false, false);
|
||||
|
||||
int leftPos, rightPos;
|
||||
bool leftVisible, rightVisible;
|
||||
QString leftGroup, rightGroup;
|
||||
bool leftIsCommunityGroup, rightIsCommunityGroup, leftIsCollectionGroup, rightIsCollectionGroup;
|
||||
|
||||
std::tie(leftPos, leftVisible, leftGroup, leftIsCommunityGroup, leftIsCollectionGroup) = m_settingsData.value(lhsSymbol, defaultVal);
|
||||
std::tie(rightPos, rightVisible, rightGroup, rightIsCommunityGroup, rightIsCollectionGroup) = m_settingsData.value(rhsSymbol, defaultVal);
|
||||
|
||||
// check grouped position
|
||||
if (((m_arrangeByCommunity && leftIsCommunityGroup && rightIsCommunityGroup)
|
||||
|| (m_arrangeByCollection && leftIsCollectionGroup && rightIsCollectionGroup))) {
|
||||
leftPos = std::get<0>(m_settingsData.value(leftGroup, defaultVal));
|
||||
rightPos = std::get<0>(m_settingsData.value(rightGroup, defaultVal));
|
||||
}
|
||||
const auto left = m_settingsData.value(lhsSymbol, TokenOrder());
|
||||
const auto right = m_settingsData.value(rhsSymbol, TokenOrder());
|
||||
|
||||
// check if visible
|
||||
leftPos = leftVisible ? leftPos : INT_MAX;
|
||||
rightPos = rightVisible ? rightPos : INT_MAX;
|
||||
auto leftPos = left.visible ? left.sortOrder : undefinedTokenOrder;
|
||||
auto rightPos = right.visible ? right.sortOrder : undefinedTokenOrder;
|
||||
|
||||
if (leftPos < rightPos)
|
||||
return -1;
|
||||
|
@ -367,9 +341,13 @@ int ManageTokensController::compareTokens(const QString& lhsSymbol, const QStrin
|
|||
|
||||
bool ManageTokensController::filterAcceptsSymbol(const QString& symbol) const
|
||||
{
|
||||
if (symbol.isEmpty()) return true;
|
||||
if (symbol.isEmpty())
|
||||
return true;
|
||||
|
||||
return std::get<1>(m_settingsData.value(symbol, {INT_MAX, true, QString(), false, false}));
|
||||
if (!m_settingsData.contains(symbol)) {
|
||||
return true;
|
||||
}
|
||||
return m_settingsData.value(symbol).visible;
|
||||
}
|
||||
|
||||
void ManageTokensController::classBegin()
|
||||
|
@ -377,19 +355,17 @@ void ManageTokensController::classBegin()
|
|||
// empty on purpose
|
||||
}
|
||||
|
||||
void ManageTokensController::componentComplete()
|
||||
{
|
||||
loadSettings();
|
||||
}
|
||||
void ManageTokensController::componentComplete() { requestLoadSettings(); }
|
||||
|
||||
void ManageTokensController::setSourceModel(QAbstractItemModel* newSourceModel)
|
||||
{
|
||||
if(m_sourceModel == newSourceModel) return;
|
||||
if (m_sourceModel == newSourceModel)
|
||||
return;
|
||||
|
||||
if(!newSourceModel) {
|
||||
if (!newSourceModel) {
|
||||
disconnect(sourceModel());
|
||||
// clear all the models
|
||||
for (auto model: m_allModels)
|
||||
for (auto model : m_allModels)
|
||||
model->clear();
|
||||
m_settingsData.clear();
|
||||
m_hiddenCommunityGroups.clear();
|
||||
|
@ -402,14 +378,15 @@ void ManageTokensController::setSourceModel(QAbstractItemModel* newSourceModel)
|
|||
|
||||
m_sourceModel = newSourceModel;
|
||||
|
||||
connect(m_sourceModel, &QAbstractItemModel::modelReset, this, &ManageTokensController::parseSourceModel);
|
||||
connect(m_sourceModel, &QAbstractItemModel::modelReset, this, &ManageTokensController::requestLoadSettings);
|
||||
|
||||
if (m_sourceModel && m_sourceModel->roleNames().isEmpty()) { // workaround for when a model has no roles and roles are added when the model is populated (ListModel)
|
||||
if (m_sourceModel && m_sourceModel->roleNames().isEmpty()) { // workaround for when a model has no roles and roles
|
||||
// are added when the model is populated (ListModel)
|
||||
// QTBUG-57971
|
||||
connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &ManageTokensController::parseSourceModel);
|
||||
connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &ManageTokensController::requestLoadSettings);
|
||||
return;
|
||||
} else {
|
||||
parseSourceModel();
|
||||
requestLoadSettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,7 +395,7 @@ void ManageTokensController::parseSourceModel()
|
|||
if (!m_sourceModel)
|
||||
return;
|
||||
|
||||
disconnect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &ManageTokensController::parseSourceModel);
|
||||
disconnect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &ManageTokensController::requestLoadSettings);
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
QElapsedTimer t;
|
||||
|
@ -426,12 +403,9 @@ void ManageTokensController::parseSourceModel()
|
|||
#endif
|
||||
|
||||
// clear all the models
|
||||
for (auto model: m_allModels)
|
||||
for (auto model : m_allModels)
|
||||
model->clear();
|
||||
|
||||
// load settings
|
||||
loadSettings();
|
||||
|
||||
// read and transform the original data
|
||||
const auto newSize = m_sourceModel->rowCount();
|
||||
qCDebug(manageTokens) << "!!! PARSING" << newSize << "TOKENS";
|
||||
|
@ -448,13 +422,13 @@ void ManageTokensController::parseSourceModel()
|
|||
rebuildHiddenCollectionGroupsModel();
|
||||
|
||||
// (pre)sort
|
||||
for (auto model: m_allModels) {
|
||||
for (auto model : m_allModels) {
|
||||
model->applySort();
|
||||
model->setDirty(false);
|
||||
}
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
qCDebug(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();
|
||||
|
@ -464,7 +438,7 @@ void ManageTokensController::addItem(int index)
|
|||
{
|
||||
const auto sourceRoleNames = m_sourceModel->roleNames();
|
||||
|
||||
const auto dataForIndex = [&](const QModelIndex &idx, const QByteArray& rolename) -> QVariant {
|
||||
const auto dataForIndex = [&](const QModelIndex& idx, const QByteArray& rolename) -> QVariant {
|
||||
const auto key = sourceRoleNames.key(rolename, -1);
|
||||
if (key == -1)
|
||||
return {};
|
||||
|
@ -475,7 +449,7 @@ void ManageTokensController::addItem(int index)
|
|||
const auto symbol = dataForIndex(srcIndex, kSymbolRoleName).toString();
|
||||
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 visible = m_settingsData.contains(symbol) ? m_settingsData.value(symbol).visible : true;
|
||||
const auto bgColor = dataForIndex(srcIndex, kBackgroundColorRoleName).value<QColor>();
|
||||
const auto collectionUid = dataForIndex(srcIndex, kCollectionUidRoleName).toString();
|
||||
|
||||
|
@ -497,8 +471,8 @@ void ManageTokensController::addItem(int index)
|
|||
token.decimals = dataForIndex(srcIndex, kDecimalsRoleName);
|
||||
token.marketDetails = dataForIndex(srcIndex, kMarketDetailsRoleName);
|
||||
|
||||
token.customSortOrderNo = m_settingsData.contains(symbol) ? std::get<0>(m_settingsData.value(symbol))
|
||||
: (visible ? INT_MAX : 0); // append/prepend
|
||||
token.customSortOrderNo = m_settingsData.contains(symbol) ? m_settingsData.value(symbol).sortOrder
|
||||
: (visible ? undefinedTokenOrder : 0); // append/prepend
|
||||
|
||||
if (!visible)
|
||||
m_hiddenTokensModel->addItem(token, /*append*/ false);
|
||||
|
@ -510,19 +484,15 @@ void ManageTokensController::addItem(int index)
|
|||
|
||||
bool ManageTokensController::dirty() const
|
||||
{
|
||||
return std::any_of(m_allModels.cbegin(), m_allModels.cend(), [](auto model) {
|
||||
return model->dirty();
|
||||
});
|
||||
return std::any_of(m_allModels.cbegin(), m_allModels.cend(), [](auto model) { return model->dirty(); });
|
||||
}
|
||||
|
||||
bool ManageTokensController::arrangeByCommunity() const
|
||||
{
|
||||
return m_arrangeByCommunity;
|
||||
}
|
||||
bool ManageTokensController::arrangeByCommunity() const { return m_arrangeByCommunity; }
|
||||
|
||||
void ManageTokensController::setArrangeByCommunity(bool newArrangeByCommunity)
|
||||
{
|
||||
if(m_arrangeByCommunity == newArrangeByCommunity) return;
|
||||
if (m_arrangeByCommunity == newArrangeByCommunity)
|
||||
return;
|
||||
m_arrangeByCommunity = newArrangeByCommunity;
|
||||
if (m_arrangeByCommunity) {
|
||||
rebuildCommunityTokenGroupsModel();
|
||||
|
@ -532,14 +502,12 @@ void ManageTokensController::setArrangeByCommunity(bool newArrangeByCommunity)
|
|||
emit arrangeByCommunityChanged();
|
||||
}
|
||||
|
||||
bool ManageTokensController::arrangeByCollection() const
|
||||
{
|
||||
return m_arrangeByCollection;
|
||||
}
|
||||
bool ManageTokensController::arrangeByCollection() const { return m_arrangeByCollection; }
|
||||
|
||||
void ManageTokensController::setArrangeByCollection(bool newArrangeByCollection)
|
||||
{
|
||||
if(m_arrangeByCollection == newArrangeByCollection) return;
|
||||
if (m_arrangeByCollection == newArrangeByCollection)
|
||||
return;
|
||||
m_arrangeByCollection = newArrangeByCollection;
|
||||
if (m_arrangeByCollection) {
|
||||
rebuildCollectionGroupsModel();
|
||||
|
@ -570,7 +538,7 @@ void ManageTokensController::rebuildCommunityTokenGroupsModel()
|
|||
tokenGroup.balance = 1;
|
||||
|
||||
if (m_settingsData.contains(communityId)) {
|
||||
tokenGroup.customSortOrderNo = std::get<0>(m_settingsData.value(communityId));
|
||||
tokenGroup.customSortOrderNo = m_settingsData.value(communityId).sortOrder;
|
||||
}
|
||||
|
||||
result.append(tokenGroup);
|
||||
|
@ -587,7 +555,7 @@ void ManageTokensController::rebuildCommunityTokenGroupsModel()
|
|||
}
|
||||
|
||||
m_communityTokenGroupsModel->clear();
|
||||
for (const auto& group: std::as_const(result))
|
||||
for (const auto& group : std::as_const(result))
|
||||
m_communityTokenGroupsModel->addItem(group);
|
||||
|
||||
qCDebug(manageTokens) << "!!! GROUPS MODEL REBUILT WITH GROUPS:" << communityIds;
|
||||
|
@ -604,7 +572,8 @@ void ManageTokensController::rebuildHiddenCommunityTokenGroupsModel()
|
|||
const auto communityId = communityToken.communityId;
|
||||
if (communityId.isEmpty())
|
||||
continue;
|
||||
if (!communityIds.contains(communityId) && m_hiddenCommunityGroups.contains(communityId)) { // insert into groups
|
||||
if (!communityIds.contains(communityId) &&
|
||||
m_hiddenCommunityGroups.contains(communityId)) { // insert into groups
|
||||
communityIds.append(communityId);
|
||||
|
||||
TokenData tokenGroup;
|
||||
|
@ -628,7 +597,7 @@ void ManageTokensController::rebuildHiddenCommunityTokenGroupsModel()
|
|||
}
|
||||
|
||||
m_hiddenCommunityTokenGroupsModel->clear();
|
||||
for (const auto& group: std::as_const(result))
|
||||
for (const auto& group : std::as_const(result))
|
||||
m_hiddenCommunityTokenGroupsModel->addItem(group);
|
||||
|
||||
qCDebug(manageTokens) << "!!! HIDDEN GROUPS MODEL REBUILT WITH GROUPS:" << communityIds;
|
||||
|
@ -647,7 +616,8 @@ void ManageTokensController::rebuildCollectionGroupsModel()
|
|||
if (!collectionIds.contains(collectionId)) { // insert into groups
|
||||
collectionIds.append(collectionId);
|
||||
|
||||
const auto collectionName = !collectionToken.collectionName.isEmpty() ? collectionToken.collectionName : collectionToken.name;
|
||||
const auto collectionName =
|
||||
!collectionToken.collectionName.isEmpty() ? collectionToken.collectionName : collectionToken.name;
|
||||
|
||||
TokenData tokenGroup;
|
||||
tokenGroup.symbol = collectionId;
|
||||
|
@ -659,7 +629,7 @@ void ManageTokensController::rebuildCollectionGroupsModel()
|
|||
tokenGroup.balance = 1;
|
||||
|
||||
if (m_settingsData.contains(collectionId)) {
|
||||
tokenGroup.customSortOrderNo = std::get<0>(m_settingsData.value(collectionId));
|
||||
tokenGroup.customSortOrderNo = m_settingsData.value(collectionId).sortOrder;
|
||||
}
|
||||
|
||||
result.append(tokenGroup);
|
||||
|
@ -676,7 +646,7 @@ void ManageTokensController::rebuildCollectionGroupsModel()
|
|||
}
|
||||
|
||||
m_collectionGroupsModel->clear();
|
||||
for (const auto& group: std::as_const(result))
|
||||
for (const auto& group : std::as_const(result))
|
||||
m_collectionGroupsModel->addItem(group);
|
||||
|
||||
qCDebug(manageTokens) << "!!! COLLECTION MODEL REBUILT WITH GROUPS:" << collectionIds;
|
||||
|
@ -692,10 +662,12 @@ void ManageTokensController::rebuildHiddenCollectionGroupsModel()
|
|||
const auto& collectionToken = m_hiddenTokensModel->itemAt(i);
|
||||
const auto collectionId = collectionToken.collectionUid;
|
||||
const auto isSelfCollection = collectionToken.isSelfCollection;
|
||||
if (!collectionIds.contains(collectionId) && m_hiddenCollectionGroups.contains(collectionId)) { // insert into groups
|
||||
if (!collectionIds.contains(collectionId) &&
|
||||
m_hiddenCollectionGroups.contains(collectionId)) { // insert into groups
|
||||
collectionIds.append(collectionId);
|
||||
|
||||
const auto collectionName = !collectionToken.collectionName.isEmpty() ? collectionToken.collectionName : collectionToken.name;
|
||||
const auto collectionName =
|
||||
!collectionToken.collectionName.isEmpty() ? collectionToken.collectionName : collectionToken.name;
|
||||
|
||||
TokenData tokenGroup;
|
||||
tokenGroup.symbol = collectionId;
|
||||
|
@ -719,16 +691,13 @@ void ManageTokensController::rebuildHiddenCollectionGroupsModel()
|
|||
}
|
||||
|
||||
m_hiddenCollectionGroupsModel->clear();
|
||||
for (const auto& group: std::as_const(result))
|
||||
for (const auto& group : std::as_const(result))
|
||||
m_hiddenCollectionGroupsModel->addItem(group);
|
||||
|
||||
qCDebug(manageTokens) << "!!! HIDDEN COLLECTION GROUPS MODEL REBUILT WITH GROUPS:" << collectionIds;
|
||||
}
|
||||
|
||||
QString ManageTokensController::settingsKey() const
|
||||
{
|
||||
return m_settingsKey;
|
||||
}
|
||||
QString ManageTokensController::settingsKey() const { return m_settingsKey; }
|
||||
|
||||
void ManageTokensController::setSettingsKey(const QString& newSettingsKey)
|
||||
{
|
||||
|
@ -737,3 +706,13 @@ void ManageTokensController::setSettingsKey(const QString& newSettingsKey)
|
|||
m_settingsKey = newSettingsKey;
|
||||
emit settingsKeyChanged();
|
||||
}
|
||||
|
||||
bool ManageTokensController::serializeAsCollectibles() const { return m_serializeAsCollectibles; }
|
||||
|
||||
void ManageTokensController::setSerializeAsCollectibles(const bool newSerializeAsCollectibles)
|
||||
{
|
||||
if (m_serializeAsCollectibles == newSerializeAsCollectibles)
|
||||
return;
|
||||
m_serializeAsCollectibles = newSerializeAsCollectibles;
|
||||
emit serializeAsCollectiblesChanged();
|
||||
}
|
|
@ -8,6 +8,12 @@
|
|||
|
||||
class QAbstractItemModel;
|
||||
|
||||
/// @brief Controller for managing visibility and order for all kind of tokens and groups.
|
||||
///
|
||||
/// There is an "abstraction" layer for saving data to different mediums and is controlled form QML.
|
||||
/// The QML implementation forwards data to current QSettings for storybook and nim controllers for the app.
|
||||
/// @see request* signals for triggering actions and start/finish methods for notifying about the process.
|
||||
/// @see *QSettings related methods for saving and loading data in user profile settings.
|
||||
class ManageTokensController : public QObject, public QQmlParserStatus
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -16,6 +22,7 @@ class ManageTokensController : public QObject, public QQmlParserStatus
|
|||
// input properties
|
||||
Q_PROPERTY(QAbstractItemModel* sourceModel READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged FINAL)
|
||||
Q_PROPERTY(QString settingsKey READ settingsKey WRITE setSettingsKey NOTIFY settingsKeyChanged FINAL REQUIRED)
|
||||
Q_PROPERTY(bool serializeAsCollectibles READ serializeAsCollectibles WRITE setSerializeAsCollectibles NOTIFY serializeAsCollectiblesChanged FINAL REQUIRED)
|
||||
|
||||
Q_PROPERTY(bool arrangeByCommunity READ arrangeByCommunity WRITE setArrangeByCommunity NOTIFY arrangeByCommunityChanged FINAL)
|
||||
Q_PROPERTY(bool arrangeByCollection READ arrangeByCollection WRITE setArrangeByCollection NOTIFY arrangeByCollectionChanged FINAL)
|
||||
|
@ -45,11 +52,19 @@ public:
|
|||
Q_INVOKABLE void showHideGroup(const QString& groupId, bool flag);
|
||||
Q_INVOKABLE void showHideCollectionGroup(const QString& groupId, bool flag);
|
||||
|
||||
Q_INVOKABLE void loadSettings();
|
||||
Q_INVOKABLE void saveSettings();
|
||||
Q_INVOKABLE void clearSettings();
|
||||
Q_INVOKABLE void loadFromQSettings();
|
||||
Q_INVOKABLE void saveToQSettings(const QString& json);
|
||||
Q_INVOKABLE void clearQSettings();
|
||||
Q_INVOKABLE void revert();
|
||||
|
||||
/// required to be called before the saving is started
|
||||
Q_INVOKABLE void savingStarted();
|
||||
Q_INVOKABLE void savingFinished();
|
||||
Q_INVOKABLE void loadingStarted();
|
||||
Q_INVOKABLE void loadingFinished(const QString& jsonData);
|
||||
|
||||
Q_INVOKABLE QString serializeSettingsAsJson();
|
||||
|
||||
Q_INVOKABLE int compareTokens(const QString& lhsSymbol, const QString& rhsSymbol) const;
|
||||
Q_INVOKABLE bool filterAcceptsSymbol(const QString& symbol) const;
|
||||
|
||||
|
@ -64,6 +79,7 @@ signals:
|
|||
void arrangeByCollectionChanged();
|
||||
void settingsKeyChanged();
|
||||
void settingsDirtyChanged(bool dirty);
|
||||
void serializeAsCollectiblesChanged();
|
||||
|
||||
void tokenHidden(const QString& symbol, const QString& name);
|
||||
void tokenShown(const QString& symbol, const QString& name);
|
||||
|
@ -77,6 +93,17 @@ signals:
|
|||
|
||||
void revisionChanged();
|
||||
|
||||
/// Emitted when the settings are requested to be saved.
|
||||
/// Receiver requires to call savingStarted and savingFinished to notify about the saving process.
|
||||
/// @param jsonData serialized json data
|
||||
void requestSaveSettings(const QString& jsonData);
|
||||
/// Emitted when the settings are requested to be loaded. Client should call loadSettings as a response.
|
||||
/// Receiver requires to call loadingStarted and loadingFinished to notify about the loading process.
|
||||
void requestLoadSettings();
|
||||
/// @brief Emitted when the settings are requested to be cleared.
|
||||
/// Receiver requires to call loadingStarted and loadingFinished to notify about the loading process.
|
||||
void requestClearSettings();
|
||||
|
||||
private:
|
||||
QAbstractItemModel* m_sourceModel{nullptr};
|
||||
QAbstractItemModel* sourceModel() const { return m_sourceModel; }
|
||||
|
@ -128,6 +155,11 @@ private:
|
|||
QString settingsKey() const;
|
||||
QString settingsGroupName() const;
|
||||
void setSettingsKey(const QString& newSettingsKey);
|
||||
|
||||
bool m_serializeAsCollectibles{false};
|
||||
bool serializeAsCollectibles() const;
|
||||
void setSerializeAsCollectibles(const bool newSerializeAsCollectibles);
|
||||
|
||||
QSettings m_settings;
|
||||
SerializedTokenData m_settingsData; // symbol -> {sortOrder, visible, groupId, isCommunityGroup, isCollectionGroup}
|
||||
bool hasSettings() const;
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
Q_LOGGING_CATEGORY(manageTokens, "status.models.manageTokens", QtInfoMsg)
|
||||
|
||||
ManageTokensModel::ManageTokensModel(QObject* parent)
|
||||
: QAbstractListModel(parent)
|
||||
ManageTokensModel::ManageTokensModel(QObject* parent) : QAbstractListModel(parent)
|
||||
{
|
||||
connect(this, &QAbstractItemModel::rowsInserted, this, &ManageTokensModel::countChanged);
|
||||
connect(this, &QAbstractItemModel::rowsRemoved, this, &ManageTokensModel::countChanged);
|
||||
|
@ -40,9 +39,8 @@ void ManageTokensModel::addItem(const TokenData& item, bool append)
|
|||
|
||||
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 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())
|
||||
|
@ -60,7 +58,7 @@ QList<TokenData> ManageTokensModel::takeAllItems(const QString& groupId)
|
|||
QList<int> indexesToRemove;
|
||||
|
||||
for (int i = 0; i < m_data.count(); i++) {
|
||||
const auto &token = m_data.at(i);
|
||||
const auto& token = m_data.at(i);
|
||||
if (token.communityId == groupId || token.collectionUid == groupId) {
|
||||
result.append(token);
|
||||
indexesToRemove.append(i);
|
||||
|
@ -68,7 +66,7 @@ QList<TokenData> ManageTokensModel::takeAllItems(const QString& groupId)
|
|||
}
|
||||
|
||||
QList<int>::reverse_iterator its;
|
||||
for(its = indexesToRemove.rbegin(); its != indexesToRemove.rend(); ++its) {
|
||||
for (its = indexesToRemove.rbegin(); its != indexesToRemove.rend(); ++its) {
|
||||
const auto row = *its;
|
||||
beginRemoveRows({}, row, row);
|
||||
m_data.removeAt(row);
|
||||
|
@ -86,7 +84,7 @@ void ManageTokensModel::clear()
|
|||
setDirty(false);
|
||||
}
|
||||
|
||||
SerializedTokenData ManageTokensModel::save(bool isVisible)
|
||||
SerializedTokenData ManageTokensModel::save(bool isVisible, bool itemsAreGroups)
|
||||
{
|
||||
saveCustomSortOrder();
|
||||
const auto size = rowCount();
|
||||
|
@ -96,21 +94,25 @@ SerializedTokenData ManageTokensModel::save(bool isVisible)
|
|||
const auto& token = itemAt(i);
|
||||
const auto isCommunityGroup = !token.communityId.isEmpty();
|
||||
const auto isCollectionGroup = !token.collectionUid.isEmpty();
|
||||
const auto groupId = isCommunityGroup ? token.communityId : isCollectionGroup ? token.collectionUid : QString();
|
||||
result.insert(token.symbol, {i, isVisible, groupId, isCommunityGroup, isCollectionGroup});
|
||||
result.insert(token.symbol,
|
||||
TokenOrder{token.symbol,
|
||||
i,
|
||||
isVisible,
|
||||
isCommunityGroup,
|
||||
token.communityId,
|
||||
isCollectionGroup,
|
||||
token.collectionUid,
|
||||
tokenDataToCollectiblePreferencesItemType(token, isCommunityGroup, itemsAreGroups)});
|
||||
}
|
||||
setDirty(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
int ManageTokensModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
int ManageTokensModel::rowCount(const QModelIndex& parent) const { return m_data.size(); }
|
||||
|
||||
QHash<int, QByteArray> ManageTokensModel::roleNames() const
|
||||
{
|
||||
static const QHash<int, QByteArray> roles {
|
||||
static const QHash<int, QByteArray> roles{
|
||||
{SymbolRole, kSymbolRoleName},
|
||||
{NameRole, kNameRoleName},
|
||||
{CommunityIdRole, kCommunityIdRoleName},
|
||||
|
@ -134,42 +136,57 @@ QHash<int, QByteArray> ManageTokensModel::roleNames() const
|
|||
|
||||
QVariant ManageTokensModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::ParentIsInvalid))
|
||||
if (!checkIndex(index,
|
||||
QAbstractItemModel::CheckIndexOption::IndexIsValid |
|
||||
QAbstractItemModel::CheckIndexOption::ParentIsInvalid))
|
||||
return {};
|
||||
|
||||
const auto& token = m_data.at(index.row());
|
||||
|
||||
switch(static_cast<TokenDataRoles>(role))
|
||||
{
|
||||
case SymbolRole: return token.symbol;
|
||||
case NameRole: return token.name;
|
||||
case CommunityIdRole: return token.communityId;
|
||||
case CommunityNameRole: return token.communityName;
|
||||
case CommunityImageRole: return token.communityImage;
|
||||
case CollectionUidRole: return token.collectionUid;
|
||||
case CollectionNameRole: return token.collectionName;
|
||||
case BalanceRole: return token.balance;
|
||||
case CurrencyBalanceRole: return token.currencyBalance;
|
||||
case CustomSortOrderNoRole: return token.customSortOrderNo;
|
||||
case TokenImageRole: return token.image;
|
||||
case TokenBackgroundColorRole: return token.backgroundColor;
|
||||
case TokenBalancesRole: return token.balances;
|
||||
case TokenDecimalsRole: return token.decimals;
|
||||
case TokenMarketDetailsRole: return token.marketDetails;
|
||||
case IsSelfCollectionRole: return token.isSelfCollection;
|
||||
switch (static_cast<TokenDataRoles>(role)) {
|
||||
case SymbolRole:
|
||||
return token.symbol;
|
||||
case NameRole:
|
||||
return token.name;
|
||||
case CommunityIdRole:
|
||||
return token.communityId;
|
||||
case CommunityNameRole:
|
||||
return token.communityName;
|
||||
case CommunityImageRole:
|
||||
return token.communityImage;
|
||||
case CollectionUidRole:
|
||||
return token.collectionUid;
|
||||
case CollectionNameRole:
|
||||
return token.collectionName;
|
||||
case BalanceRole:
|
||||
return token.balance;
|
||||
case CurrencyBalanceRole:
|
||||
return token.currencyBalance;
|
||||
case CustomSortOrderNoRole:
|
||||
return token.customSortOrderNo;
|
||||
case TokenImageRole:
|
||||
return token.image;
|
||||
case TokenBackgroundColorRole:
|
||||
return token.backgroundColor;
|
||||
case TokenBalancesRole:
|
||||
return token.balances;
|
||||
case TokenDecimalsRole:
|
||||
return token.decimals;
|
||||
case TokenMarketDetailsRole:
|
||||
return token.marketDetails;
|
||||
case IsSelfCollectionRole:
|
||||
return token.isSelfCollection;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ManageTokensModel::dirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
bool ManageTokensModel::dirty() const { return m_dirty; }
|
||||
|
||||
void ManageTokensModel::setDirty(bool flag)
|
||||
{
|
||||
if (m_dirty == flag) return;
|
||||
if (m_dirty == flag)
|
||||
return;
|
||||
m_dirty = flag;
|
||||
emit dirtyChanged();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "tokendata.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QColor>
|
||||
#include <QLoggingCategory>
|
||||
|
@ -30,18 +32,6 @@ const auto kIsSelfCollectionRoleName = QByteArrayLiteral("isSelfCollection");
|
|||
// TODO add communityPrivilegesLevel for collectibles
|
||||
} // namespace
|
||||
|
||||
struct TokenData {
|
||||
QString symbol, name, communityId, communityName, communityImage, collectionUid, collectionName, image;
|
||||
QColor backgroundColor{Qt::transparent};
|
||||
QVariant balance, currencyBalance;
|
||||
QVariant balances, marketDetails, decimals;
|
||||
int customSortOrderNo{INT_MAX};
|
||||
bool isSelfCollection{false};
|
||||
};
|
||||
|
||||
// symbol -> {sortOrder, visible, groupId, isCommunityGroup, isCollectionGroup}
|
||||
using SerializedTokenData = QHash<QString, std::tuple<int, bool, QString, bool, bool>>;
|
||||
|
||||
class ManageTokensModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -78,7 +68,7 @@ public:
|
|||
QList<TokenData> takeAllItems(const QString& groupId);
|
||||
void clear();
|
||||
|
||||
SerializedTokenData save(bool isVisible = true);
|
||||
SerializedTokenData save(bool isVisible = true, bool itemsAreGroups = false);
|
||||
|
||||
bool dirty() const;
|
||||
void setDirty(bool flag);
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
#include "tokendata.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QList>
|
||||
|
||||
CollectiblePreferencesItemType tokenDataToCollectiblePreferencesItemType(const TokenData& token, bool isCommunity, bool itemsAreGroups)
|
||||
{
|
||||
if (itemsAreGroups) {
|
||||
if (isCommunity) {
|
||||
return CollectiblePreferencesItemType::Community;
|
||||
} else {
|
||||
return CollectiblePreferencesItemType::Collection;
|
||||
}
|
||||
} else {
|
||||
if (isCommunity) {
|
||||
return CollectiblePreferencesItemType::CommunityCollectible;
|
||||
} else {
|
||||
return CollectiblePreferencesItemType::NonCommunityCollectible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TokenOrder::TokenOrder() : sortOrder(undefinedTokenOrder) {}
|
||||
|
||||
TokenOrder::TokenOrder(const QString& symbol,
|
||||
int sortOrder,
|
||||
bool visible,
|
||||
bool isCommunityGroup,
|
||||
const QString& communityId,
|
||||
bool isCollectionGroup,
|
||||
const QString& collectionUid,
|
||||
CollectiblePreferencesItemType type)
|
||||
: symbol(symbol)
|
||||
, sortOrder(sortOrder)
|
||||
, visible(visible)
|
||||
, isCommunityGroup(isCommunityGroup)
|
||||
, communityId(communityId)
|
||||
, isCollectionGroup(isCollectionGroup)
|
||||
, collectionUid(collectionUid)
|
||||
, type(type)
|
||||
{
|
||||
}
|
||||
|
||||
/// reverse of \c tokenOrdersFromJson
|
||||
///
|
||||
/// for protocol structure, see:
|
||||
/// \see CollectiblePreferences in src/backend/collectibles_types.nim
|
||||
/// \see TokenPreferences in src/backend/backend.nim
|
||||
QString tokenOrdersToJson(const SerializedTokenData& dataList, bool areCollectible)
|
||||
{
|
||||
QJsonArray jsonArray;
|
||||
for (const TokenOrder& data : dataList) {
|
||||
QJsonObject obj;
|
||||
obj["key"] = data.symbol;
|
||||
obj["position"] = data.sortOrder;
|
||||
obj["visible"] = data.visible;
|
||||
if (data.isCommunityGroup) {
|
||||
obj["isCommunityGroup"] = true;
|
||||
obj["communityId"] = data.communityId;
|
||||
}
|
||||
if (data.isCollectionGroup) {
|
||||
obj["isCollectionGroup"] = true;
|
||||
obj["collectionUid"] = data.collectionUid;
|
||||
}
|
||||
|
||||
if (areCollectible) {
|
||||
// see CollectiblePreferences in src/backend/collectibles_types.nim
|
||||
// type cover separation of groups and collectibles
|
||||
obj["type"] = static_cast<int>(data.type);
|
||||
} else { // is asset
|
||||
// see TokenPreferences in src/backend/backend.nim
|
||||
// TODO #13312: handle "groupPosition" for asset
|
||||
}
|
||||
jsonArray.append(obj);
|
||||
}
|
||||
|
||||
QJsonDocument doc(jsonArray);
|
||||
QString json_string = doc.toJson(QJsonDocument::Compact);
|
||||
|
||||
return json_string;
|
||||
}
|
||||
|
||||
/// reverse of \c tokenOrdersToJson
|
||||
///
|
||||
/// for protocol structure, see:
|
||||
/// \see CollectiblePreferences in src/backend/collectibles_types.nim
|
||||
/// \see TokenPreferences in src/backend/backend.nim
|
||||
SerializedTokenData tokenOrdersFromJson(const QString& json_string, bool areCollectibles)
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json_string.toUtf8());
|
||||
QJsonArray jsonArray = doc.array();
|
||||
|
||||
SerializedTokenData dataList;
|
||||
for (const QJsonValue& value : jsonArray) {
|
||||
QJsonObject obj = value.toObject();
|
||||
TokenOrder data;
|
||||
|
||||
data.symbol = obj["key"].toString();
|
||||
data.sortOrder = obj["position"].toInt();
|
||||
data.visible = obj["visible"].toBool();
|
||||
if (obj.contains("isCommunityGroup")) {
|
||||
data.isCommunityGroup = obj["isCommunityGroup"].toBool();
|
||||
data.communityId = obj["communityId"].toString();
|
||||
}
|
||||
if (obj.contains("isCollectionGroup")) {
|
||||
data.isCollectionGroup = obj["isCollectionGroup"].toBool();
|
||||
data.collectionUid = obj["collectionUid"].toString();
|
||||
}
|
||||
|
||||
if (areCollectibles) {
|
||||
// see CollectiblePreferences in src/backend/collectibles_types.nim
|
||||
data.type = static_cast<CollectiblePreferencesItemType>(obj["type"].toInt());
|
||||
} else { // is asset
|
||||
// see TokenPreferences in src/backend/backend.nim
|
||||
// TODO #13312: handle "groupPosition" for assets
|
||||
}
|
||||
|
||||
dataList.insert(data.symbol, data);
|
||||
}
|
||||
|
||||
return dataList;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
static const auto undefinedTokenOrder = INT_MAX;
|
||||
|
||||
// Generic structure representing an asset, collectible, collection or community token
|
||||
struct TokenData {
|
||||
QString symbol, name, communityId, communityName, communityImage, collectionUid, collectionName, image;
|
||||
QColor backgroundColor{Qt::transparent};
|
||||
QVariant balance, currencyBalance;
|
||||
QVariant balances, marketDetails, decimals;
|
||||
int customSortOrderNo{undefinedTokenOrder};
|
||||
bool isSelfCollection{false};
|
||||
};
|
||||
|
||||
// mirrors CollectiblePreferencesItemType from src/backend/collectibles_types.nim
|
||||
enum class CollectiblePreferencesItemType { NonCommunityCollectible = 1, CommunityCollectible, Collection, Community };
|
||||
|
||||
CollectiblePreferencesItemType tokenDataToCollectiblePreferencesItemType(const TokenData& tokenData, bool isCommunity, bool itemsAreGroups);
|
||||
|
||||
struct TokenOrder {
|
||||
QString symbol;
|
||||
int sortOrder;
|
||||
bool visible;
|
||||
bool isCommunityGroup;
|
||||
QString communityId;
|
||||
bool isCollectionGroup;
|
||||
QString collectionUid;
|
||||
/// covers separation of groups (collection or community) and collectibles (regular or community)
|
||||
CollectiblePreferencesItemType type;
|
||||
|
||||
// Defines a default TokenOrder, order is not set (undefinedTokenOrder) and visible is false
|
||||
TokenOrder();
|
||||
TokenOrder(const QString& symbol,
|
||||
int sortOrder,
|
||||
bool visible,
|
||||
bool isCommunityGroup,
|
||||
const QString& communityId,
|
||||
bool isCollectionGroup,
|
||||
const QString& collectionUid,
|
||||
CollectiblePreferencesItemType type);
|
||||
|
||||
bool operator==(const TokenOrder& rhs) const
|
||||
{
|
||||
return symbol == rhs.symbol && sortOrder == rhs.sortOrder && visible == rhs.visible &&
|
||||
isCommunityGroup == rhs.isCommunityGroup && (!isCommunityGroup || communityId == rhs.communityId) &&
|
||||
isCollectionGroup == rhs.isCollectionGroup && (!isCollectionGroup || collectionUid == rhs.collectionUid) && type == rhs.type;
|
||||
}
|
||||
|
||||
QString getGroupId() const { return !communityId.isEmpty() ? communityId : collectionUid; }
|
||||
};
|
||||
|
||||
using SerializedTokenData = QHash<QString, TokenOrder>;
|
||||
|
||||
QString tokenOrdersToJson(const SerializedTokenData& data, bool areCollectibles);
|
||||
SerializedTokenData tokenOrdersFromJson(const QString& json_string, bool areCollectibles);
|
|
@ -22,7 +22,8 @@ DoubleFlickableWithFolding {
|
|||
property var getCurrentCurrencyAmount: function(balance) {}
|
||||
|
||||
function saveSettings() {
|
||||
root.controller.saveSettings();
|
||||
let jsonSettings = root.controller.serializeSettingsAsJson()
|
||||
root.controller.requestSaveSettings(jsonSettings);
|
||||
}
|
||||
|
||||
function revert() {
|
||||
|
@ -30,7 +31,7 @@ DoubleFlickableWithFolding {
|
|||
}
|
||||
|
||||
function clearSettings() {
|
||||
root.controller.clearSettings();
|
||||
root.controller.requestClearSettings()
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
|
|
@ -19,7 +19,8 @@ DoubleFlickableWithFolding {
|
|||
readonly property bool hasSettings: root.controller.hasSettings
|
||||
|
||||
function saveSettings() {
|
||||
root.controller.saveSettings();
|
||||
let jsonSettings = root.controller.serializeSettingsAsJson()
|
||||
root.controller.requestSaveSettings(jsonSettings)
|
||||
}
|
||||
|
||||
function revert() {
|
||||
|
@ -27,7 +28,7 @@ DoubleFlickableWithFolding {
|
|||
}
|
||||
|
||||
function clearSettings() {
|
||||
root.controller.clearSettings();
|
||||
root.controller.requestClearSettings()
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
|
|
@ -31,8 +31,8 @@ Control {
|
|||
background: null
|
||||
|
||||
function clearSettings() {
|
||||
root.assetsController.clearSettings();
|
||||
root.collectiblesController.clearSettings();
|
||||
root.assetsController.requestClearSettings();
|
||||
root.collectiblesController.requestClearSettings();
|
||||
}
|
||||
|
||||
QtObject {
|
||||
|
|
|
@ -29,6 +29,24 @@ QtObject {
|
|||
readonly property var collectiblesController: ManageTokensController {
|
||||
sourceModel: allCollectiblesModel
|
||||
settingsKey: "WalletCollectibles"
|
||||
serializeAsCollectibles: true
|
||||
|
||||
onRequestSaveSettings: (jsonData) => {
|
||||
savingStarted()
|
||||
_allCollectiblesModule.updateCollectiblePreferences(jsonData)
|
||||
savingFinished()
|
||||
}
|
||||
onRequestLoadSettings: {
|
||||
loadingStarted()
|
||||
let jsonData = _allCollectiblesModule.getCollectiblePreferencesJson()
|
||||
loadingFinished(jsonData)
|
||||
}
|
||||
onRequestClearSettings: {
|
||||
savingStarted()
|
||||
_allCollectiblesModule.clearCollectiblePreferences()
|
||||
savingFinished()
|
||||
}
|
||||
|
||||
onCommunityTokenGroupHidden: (communityName) => Global.displayToastMessage(
|
||||
qsTr("%1 community collectibles successfully hidden").arg(communityName), "", "checkmark-circle",
|
||||
false, Constants.ephemeralNotificationType.success, "")
|
||||
|
|
|
@ -18,6 +18,25 @@ QtObject {
|
|||
readonly property var assetsController: ManageTokensController {
|
||||
sourceModel: groupedAccountAssetsModel
|
||||
settingsKey: "WalletAssets"
|
||||
serializeAsCollectibles: false
|
||||
|
||||
// TODO #13312: call the assets controller for all events
|
||||
onRequestSaveSettings: (jsonData) => {
|
||||
// savingStarted()
|
||||
saveToQSettings(jsonData)
|
||||
// savingFinished()
|
||||
}
|
||||
onRequestLoadSettings: {
|
||||
// loadingStarted()
|
||||
loadFromQSettings()
|
||||
// loadingFinished()
|
||||
}
|
||||
onRequestClearSettings: {
|
||||
// savingStarted()
|
||||
clearQSettings()
|
||||
// savingFinished()
|
||||
}
|
||||
|
||||
onCommunityTokenGroupHidden: (communityName) => Global.displayToastMessage(
|
||||
qsTr("%1 community assets successfully hidden").arg(communityName), "", "checkmark-circle",
|
||||
false, Constants.ephemeralNotificationType.success, "")
|
||||
|
|
Loading…
Reference in New Issue