diff --git a/src/app/modules/shared_models/collectibles_entry.nim b/src/app/modules/shared_models/collectibles_entry.nim index 7a3272d3a9..a85545c6ab 100644 --- a/src/app/modules/shared_models/collectibles_entry.nim +++ b/src/app/modules/shared_models/collectibles_entry.nim @@ -26,6 +26,9 @@ QtObject: extradata: ExtraData traits: TraitModel ownership: OwnershipModel + generatedId: string + generatedCollectionId: string + proc setup(self: CollectiblesEntry) = self.QObject.setup @@ -45,32 +48,6 @@ QtObject: self.ownership.setItems(ownership) self.setup() - proc newCollectibleDetailsFullEntry*(data: backend.Collectible, extradata: ExtraData): CollectiblesEntry = - new(result, delete) - result.id = data.id - result.setData(data) - result.extradata = extradata - result.setup() - - proc newCollectibleDetailsBasicEntry*(id: backend.CollectibleUniqueID, extradata: ExtraData): CollectiblesEntry = - new(result, delete) - result.id = id - result.extradata = extradata - result.traits = newTraitModel() - result.ownership = newOwnershipModel() - result.setup() - - proc newCollectibleDetailsEmptyEntry*(): CollectiblesEntry = - let id = backend.CollectibleUniqueID( - contractID: backend.ContractID( - chainID: 0, - address: "" - ), - tokenID: stint.u256(0) - ) - let extradata = ExtraData() - return newCollectibleDetailsBasicEntry(id, extradata) - proc `$`*(self: CollectiblesEntry): string = return fmt"""CollectiblesEntry( id:{self.id}, @@ -78,6 +55,8 @@ QtObject: extradata:{self.extradata}, traits:{self.traits}, ownership:{self.ownership}, + generatedId:{self.generatedId}, + generatedCollectionId:{self.generatedCollectionId} )""" proc getCollectibleUniqueID*(self: CollectiblesEntry): backend.CollectibleUniqueID = @@ -130,10 +109,16 @@ QtObject: # Unique ID to identify collectible, generated by us proc getID*(self: CollectiblesEntry): string = + return self.generatedId + + proc generateId*(self: CollectiblesEntry): string = return fmt"{self.getChainId}+{self.getContractAddress}+{self.getTokenID}" # Unique ID to identify collection, generated by us proc getCollectionID*(self: CollectiblesEntry): string = + return self.generatedCollectionId + + proc generateCollectionId*(self: CollectiblesEntry): string = return fmt"{self.getChainId}+{self.getContractAddress}" proc nameChanged*(self: CollectiblesEntry) {.signal.} @@ -359,4 +344,34 @@ QtObject: self.communityColorChanged() self.communityPrivilegesLevelChanged() self.communityImageChanged() - return true \ No newline at end of file + return true + + proc newCollectibleDetailsFullEntry*(data: backend.Collectible, extradata: ExtraData): CollectiblesEntry = + new(result, delete) + result.id = data.id + result.setData(data) + result.extradata = extradata + result.generatedId = result.generateId() + result.generatedCollectionId = result.generateCollectionId() + result.setup() + + proc newCollectibleDetailsBasicEntry*(id: backend.CollectibleUniqueID, extradata: ExtraData): CollectiblesEntry = + new(result, delete) + result.id = id + result.extradata = extradata + result.traits = newTraitModel() + result.ownership = newOwnershipModel() + result.generatedId = result.generateId() + result.generatedCollectionId = result.generateCollectionId() + result.setup() + + proc newCollectibleDetailsEmptyEntry*(): CollectiblesEntry = + let id = backend.CollectibleUniqueID( + contractID: backend.ContractID( + chainID: 0, + address: "" + ), + tokenID: stint.u256(0) + ) + let extradata = ExtraData() + return newCollectibleDetailsBasicEntry(id, extradata) \ No newline at end of file diff --git a/ui/StatusQ/include/StatusQ/fastexpressionsorter.h b/ui/StatusQ/include/StatusQ/fastexpressionsorter.h index e9163b61c2..aa9f081bdc 100644 --- a/ui/StatusQ/include/StatusQ/fastexpressionsorter.h +++ b/ui/StatusQ/include/StatusQ/fastexpressionsorter.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include @@ -14,9 +16,10 @@ class FastExpressionSorter : public qqsfpm::Sorter Q_PROPERTY(QQmlScriptString expression READ expression WRITE setExpression NOTIFY expressionChanged) - Q_PROPERTY(QStringList expectedRoles READ expectedRoles + Q_PROPERTY(QSet expectedRoles READ expectedRoles WRITE setExpectedRoles NOTIFY expectedRolesChanged) public: + using qqsfpm::Sorter::Sorter; const QQmlScriptString& expression() const; @@ -24,16 +27,18 @@ public: void proxyModelCompleted(const qqsfpm::QQmlSortFilterProxyModel& proxyModel) override; - void setExpectedRoles(const QStringList& expectedRoles); - const QStringList& expectedRoles() const; + void setExpectedRoles(const QSet& expectedRoles); + const QSet& expectedRoles() const; + + void queueInvalidate(); + void onInvalidate(); Q_SIGNALS: void expressionChanged(); void expectedRolesChanged(); protected: - int compare(const QModelIndex& sourceLeft, const QModelIndex& sourceRight, - const qqsfpm::QQmlSortFilterProxyModel& proxyModel) const override; + int compare(const QModelIndex& sourceLeft, const QModelIndex& sourceRight, const qqsfpm::QQmlSortFilterProxyModel& proxyModel) const override; private: void updateContext(const qqsfpm::QQmlSortFilterProxyModel& proxyModel); @@ -44,5 +49,10 @@ private: std::unique_ptr m_expression; std::unique_ptr m_context; - QStringList m_expectedRoles; + QSet m_expectedRoles; + + bool m_queuedInvalidate { false }; + + mutable QQmlPropertyMap m_modelLeftMap; + mutable QQmlPropertyMap m_modelRightMap; }; diff --git a/ui/StatusQ/src/fastexpressionsorter.cpp b/ui/StatusQ/src/fastexpressionsorter.cpp index 6cf66f5020..5b55008d9b 100644 --- a/ui/StatusQ/src/fastexpressionsorter.cpp +++ b/ui/StatusQ/src/fastexpressionsorter.cpp @@ -50,12 +50,28 @@ void FastExpressionSorter::setExpression(const QQmlScriptString& scriptString) updateExpression(); emit expressionChanged(); - invalidate(); + queueInvalidate(); +} + +void FastExpressionSorter::queueInvalidate() +{ + if (m_queuedInvalidate) + return; + + m_queuedInvalidate = true; + QMetaObject::invokeMethod(this, &FastExpressionSorter::invalidate, Qt::QueuedConnection); +} + +void FastExpressionSorter::onInvalidate() +{ + m_queuedInvalidate = false; + Sorter::invalidate(); } void FastExpressionSorter::proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel) { updateContext(proxyModel); + Sorter::proxyModelCompleted(proxyModel); } /*! @@ -63,7 +79,7 @@ void FastExpressionSorter::proxyModelCompleted(const QQmlSortFilterProxyModel& p List of role names intended to be available in the expression's context. */ -void FastExpressionSorter::setExpectedRoles(const QStringList& expectedRoles) +void FastExpressionSorter::setExpectedRoles(const QSet& expectedRoles) { if (m_expectedRoles == expectedRoles) return; @@ -71,44 +87,45 @@ void FastExpressionSorter::setExpectedRoles(const QStringList& expectedRoles) m_expectedRoles = expectedRoles; emit expectedRolesChanged(); - invalidate(); + queueInvalidate(); } -const QStringList &FastExpressionSorter::expectedRoles() const +const QSet &FastExpressionSorter::expectedRoles() const { return m_expectedRoles; } -bool evaluateBoolExpression(QQmlExpression& expression) +int evaluateIntExpression(QQmlExpression& expression) { QVariant variantResult = expression.evaluate(); if (expression.hasError()) { qWarning() << expression.error(); - return false; + return -1; } - if (variantResult.canConvert()) - return variantResult.toBool(); + if (variantResult.canConvert()) + return variantResult.toInt(); - qWarning("%s:%i:%i : Can't convert result to bool", + qWarning("%s:%i:%i : Can't convert result to int", expression.sourceFile().toUtf8().data(), expression.lineNumber(), expression.columnNumber()); - return false; + return 0; } + int FastExpressionSorter::compare(const QModelIndex& sourceLeft, - const QModelIndex& sourceRight, - const QQmlSortFilterProxyModel& proxyModel) const + const QModelIndex& sourceRight, + const QQmlSortFilterProxyModel& proxyModel) const { - if (m_scriptString.isEmpty()) - return 0; - QVariantMap modelLeftMap, modelRightMap; + if (m_scriptString.isEmpty() || !m_context || !m_expression) + return false; + + m_expression->setNotifyOnValueChanged(false); + QHash roles = proxyModel.roleNames(); - QQmlContext context(qmlContext(this)); - for (auto it = roles.cbegin(); it != roles.cend(); ++it) { auto role = it.key(); auto name = it.value(); @@ -116,50 +133,42 @@ int FastExpressionSorter::compare(const QModelIndex& sourceLeft, if (!m_expectedRoles.contains(name)) continue; - modelLeftMap.insert(name, proxyModel.sourceData(sourceLeft, role)); - modelRightMap.insert(name, proxyModel.sourceData(sourceRight, role)); + m_modelLeftMap.insert(name, proxyModel.sourceData(sourceLeft, role)); + m_modelRightMap.insert(name, proxyModel.sourceData(sourceRight, role)); } - modelLeftMap.insert(QStringLiteral("index"), sourceLeft.row()); - modelRightMap.insert(QStringLiteral("index"), sourceRight.row()); + m_modelLeftMap.insert(QStringLiteral("index"), sourceLeft.row()); + m_modelRightMap.insert(QStringLiteral("index"), sourceRight.row()); - QQmlExpression expression(m_scriptString, &context); + m_expression->setNotifyOnValueChanged(true); - context.setContextProperty(QStringLiteral("modelLeft"), modelLeftMap); - context.setContextProperty(QStringLiteral("modelRight"), modelRightMap); - - if (evaluateBoolExpression(expression)) - return -1; - - context.setContextProperty(QStringLiteral("modelLeft"), modelRightMap); - context.setContextProperty(QStringLiteral("modelRight"), modelLeftMap); - - if (evaluateBoolExpression(expression)) - return 1; - - return 0; + return evaluateIntExpression(*m_expression); } void FastExpressionSorter::updateContext(const QQmlSortFilterProxyModel& proxyModel) { m_context = std::make_unique(qmlContext(this)); + updateExpression(); - QVariantMap modelLeftMap, modelRightMap; + if (!m_expression) + return; + + m_expression->setNotifyOnValueChanged(false); const auto roleNames = proxyModel.roleNames(); for (const QByteArray& name : roleNames) { if (!m_expectedRoles.contains(name)) continue; - modelLeftMap.insert(name, {}); - modelRightMap.insert(name, {}); + m_modelLeftMap.insert(name, {}); + m_modelRightMap.insert(name, {}); } - modelLeftMap.insert(QStringLiteral("index"), -1); - modelRightMap.insert(QStringLiteral("index"), -1); + m_modelLeftMap.insert(QStringLiteral("index"), -1); + m_modelRightMap.insert(QStringLiteral("index"), -1); - m_context->setContextProperty(QStringLiteral("modelLeft"), modelLeftMap); - m_context->setContextProperty(QStringLiteral("modelRight"), modelRightMap); + m_context->setContextProperty(QStringLiteral("modelLeft"), &m_modelLeftMap); + m_context->setContextProperty(QStringLiteral("modelRight"), &m_modelRightMap); - updateExpression(); + m_expression->setNotifyOnValueChanged(true); } void FastExpressionSorter::updateExpression() @@ -171,7 +180,7 @@ void FastExpressionSorter::updateExpression() m_context.get()); connect(m_expression.get(), &QQmlExpression::valueChanged, this, - &FastExpressionSorter::invalidate); + &FastExpressionSorter::queueInvalidate); m_expression->setNotifyOnValueChanged(true); m_expression->evaluate(); } diff --git a/ui/StatusQ/src/wallet/managetokenscontroller.cpp b/ui/StatusQ/src/wallet/managetokenscontroller.cpp index 17d6d083b5..fde3992ec8 100644 --- a/ui/StatusQ/src/wallet/managetokenscontroller.cpp +++ b/ui/StatusQ/src/wallet/managetokenscontroller.cpp @@ -239,8 +239,7 @@ void ManageTokensController::loadSettings() { Q_ASSERT(!m_settingsKey.isEmpty()); - setSettingsDirty(true); - m_settingsData.clear(); + SerializedTokenData result; // load from QSettings m_settings.beginGroup(settingsGroupName()); @@ -256,7 +255,7 @@ void ManageTokensController::loadSettings() const auto pos = m_settings.value(QStringLiteral("pos"), INT_MAX).toInt(); const auto visible = m_settings.value(QStringLiteral("visible"), true).toBool(); const auto groupId = m_settings.value(QStringLiteral("groupId")).toString(); - m_settingsData.insert(symbol, {pos, visible, groupId}); + result.insert(symbol, {pos, visible, groupId}); } m_settings.endArray(); @@ -277,7 +276,11 @@ void ManageTokensController::loadSettings() setArrangeByCollection(m_settings.value(QStringLiteral("ArrangeByCollection"), false).toBool()); m_settings.endGroup(); - setSettingsDirty(false); + + if (result != m_settingsData) { + m_settingsData = result; + setSettingsDirty(true); + } } void ManageTokensController::setSettingsDirty(bool dirty) @@ -353,7 +356,7 @@ void ManageTokensController::settingsHideGroupTokens(const QString& groupId, con saveSettings(true); } -bool ManageTokensController::lessThan(const QString& lhsSymbol, const QString& rhsSymbol) const +int ManageTokensController::compareTokens(const QString& lhsSymbol, const QString& rhsSymbol) const { int leftPos, rightPos; bool leftVisible, rightVisible; @@ -365,7 +368,11 @@ bool ManageTokensController::lessThan(const QString& lhsSymbol, const QString& r leftPos = leftVisible ? leftPos : INT_MAX; rightPos = rightVisible ? rightPos : INT_MAX; - return leftPos <= rightPos; + if (leftPos < rightPos) + return -1; + if (leftPos > rightPos) + return 1; + return 0; } bool ManageTokensController::filterAcceptsSymbol(const QString& symbol) const diff --git a/ui/StatusQ/src/wallet/managetokenscontroller.h b/ui/StatusQ/src/wallet/managetokenscontroller.h index aea5206ef6..b13b6a0d0c 100644 --- a/ui/StatusQ/src/wallet/managetokenscontroller.h +++ b/ui/StatusQ/src/wallet/managetokenscontroller.h @@ -52,7 +52,7 @@ public: Q_INVOKABLE void settingsHideToken(const QString& symbol); Q_INVOKABLE void settingsHideGroupTokens(const QString& groupId, const QStringList& symbols); - Q_INVOKABLE bool lessThan(const QString& lhsSymbol, const QString& rhsSymbol) const; + Q_INVOKABLE int compareTokens(const QString& lhsSymbol, const QString& rhsSymbol) const; Q_INVOKABLE bool filterAcceptsSymbol(const QString& symbol) const; protected: diff --git a/ui/StatusQ/tests/TestCore/TestModels/tst_FastExpressionSorter.qml b/ui/StatusQ/tests/TestCore/TestModels/tst_FastExpressionSorter.qml index f3a64e9fb8..ffd3c459e7 100644 --- a/ui/StatusQ/tests/TestCore/TestModels/tst_FastExpressionSorter.qml +++ b/ui/StatusQ/tests/TestCore/TestModels/tst_FastExpressionSorter.qml @@ -17,17 +17,21 @@ Item { property int d: 1 property alias sorterEnabled: sorter.enabled + property alias sortingAscending: sorter.ascendingOrder + property alias sorters: testModel.sorters readonly property ListModel source: ListModel { id: listModel - ListElement { a: 1; b: 11; c: 101 } - ListElement { a: 2; b: 12; c: 102 } + ListElement { a: 1; b: 11; c: 100 } + ListElement { a: 2; b: 11; c: 101 } ListElement { a: 3; b: 13; c: 103 } ListElement { a: 4; b: 14; c: 104 } ListElement { a: 5; b: 15; c: 105 } ListElement { a: 6; b: 16; c: 106 } + ListElement { a: 2; b: 12; c: 101 } ListElement { a: 7; b: 17; c: 107 } + ListElement { a: 7; b: 17; c: 108 } } readonly property ModelAccessObserverProxy observer: ModelAccessObserverProxy { @@ -44,28 +48,71 @@ Item { } } - readonly property SortFilterProxyModel model: SortFilterProxyModel { + property SortFilterProxyModel model: SortFilterProxyModel { id: testModel sourceModel: observerProxy - sorters: FastExpressionSorter { - id: sorter + sorters: [sorter] + } - expression: { - return d ? modelLeft.a < modelRight.a - : modelLeft.a > modelRight.a - } + readonly property Component modelWithPriorityComponent: Component { + SortFilterProxyModel { + id: testModelWithPriority - expectedRoles: ["a"] + sourceModel: observerProxy + sorters: [sorter, otherSorter, roleSorter] } } + readonly property FastExpressionSorter sorter: FastExpressionSorter { + id: sorter + + expression: { + if (modelLeft.a < modelRight.a) + return d ? -1 : 1 + else if (modelLeft.a > modelRight.a) + return d ? 1 : -1 + else + return 0 + } + + expectedRoles: ["a"] + } + + readonly property FastExpressionSorter otherSorter: FastExpressionSorter { + id: otherSorter + + expression: { + if (modelLeft.b > modelRight.b) + return -1 + else if (modelLeft.b < modelRight.b) + return 1 + else + return 0 + } + + expectedRoles: ["b"] + } + + readonly property RoleSorter roleSorter: RoleSorter { + id: roleSorter + + roleName: "c" + ascendingOrder: false + } + readonly property SignalSpy rowsRemovedSpy: SignalSpy { target: testModel signalName: "rowsRemoved" } + + readonly property SignalSpy layoutChangedSpy: SignalSpy { + id: layoutChangedSpy + target: testModel + signalName: "layoutChanged" + } } } @@ -76,17 +123,17 @@ Item { const obj = createTemporaryObject(testComponent, root) const count = obj.model.count - compare(count, 7) + compare(count, 9) verify(obj.observer.accessCounter < count * Math.ceil(Math.log2(count)) * 3) compare(obj.observer.accessedRoles.size, 1) compare(obj.model.get(0).a, 1) compare(obj.model.get(1).a, 2) - compare(obj.model.get(6).a, 7) + compare(obj.model.get(7).a, 7) } - function test_filteringAfterContextChange() { + function test_sortingAfterContextChange() { const obj = createTemporaryObject(testComponent, root) const count = obj.model.count @@ -98,9 +145,9 @@ Item { < count * Math.ceil(Math.log2(count)) * 3) compare(obj.observer.accessedRoles.size, 1) - compare(obj.model.get(0).a, 7) - compare(obj.model.get(1).a, 6) - compare(obj.model.get(6).a, 1) + tryVerify(() => obj.model.get(0).a, 7) + tryVerify(() => obj.model.get(1).a, 6) + tryVerify(() => obj.model.get(6).a, 1) } function test_enabled() { @@ -110,7 +157,7 @@ Item { compare(obj.model.get(0).a, 1) compare(obj.model.get(1).a, 2) - compare(obj.model.get(6).a, 7) + compare(obj.model.get(7).a, 7) obj.observer.accessedRoles.clear() obj.observer.accessCounter = 0 @@ -123,8 +170,236 @@ Item { compare(obj.observer.accessedRoles.size, 1) compare(obj.model.get(0).a, 7) - compare(obj.model.get(1).a, 6) - compare(obj.model.get(6).a, 1) + compare(obj.model.get(1).a, 7) + compare(obj.model.get(7).a, 2) + compare(obj.model.get(8).a, 1) + } + + function test_sortingDescending() { + const obj = createTemporaryObject(testComponent, root) + + const count = obj.model.count + + verify(obj.observer.accessCounter + < count * Math.ceil(Math.log2(count)) * 3) + compare(obj.observer.accessedRoles.size, 1) + + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(7).a, 7) + + obj.observer.accessCounter = 0 + + obj.sortingAscending = false + + tryVerify(() => obj.observer.accessCounter + < count * Math.ceil(Math.log2(count)) * 3) + + tryVerify(() => obj.model.get(0).a, 7) + tryVerify(() => obj.model.get(1).a, 6) + tryVerify(() => obj.model.get(7).a, 1) + } + + function test_sortingDescendingAfterEnablingSorting() { + const obj = createTemporaryObject(testComponent, root, { sorterEnabled: false, sortingAscending: false }) + + compare(obj.observer.accessCounter, 0) + compare(obj.observer.accessedRoles.size, 0) + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(7).a, 7) + + obj.observer.accessedRoles.clear() + obj.observer.accessCounter = 0 + + obj.sorterEnabled = true + + const count = obj.model.count + + verify(obj.observer.accessCounter + < count * Math.ceil(Math.log2(count)) * 3) + + compare(obj.observer.accessedRoles.size, 1) + + compare(obj.model.get(0).a, 7) + compare(obj.model.get(1).a, 7) + compare(obj.model.get(8).a, 1) + + obj.observer.accessedRoles.clear() + obj.observer.accessCounter = 0 + + obj.sorterEnabled = false + + verify(obj.observer.accessCounter == 0) + + compare(obj.observer.accessedRoles.size, 0) + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(7).a, 7) + } + + function test_stableSorting() { + const obj = createTemporaryObject(testComponent, root) + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(2).a, 2) + compare(obj.model.get(0).b, 11) + compare(obj.model.get(1).b, 11) + compare(obj.model.get(2).b, 12) + compare(obj.model.get(0).c, 100) + compare(obj.model.get(1).c, 101) + compare(obj.model.get(2).c, 101) + + obj.sortingAscending = false + + compare(obj.model.get(8).a, 1) + compare(obj.model.get(7).a, 2) + compare(obj.model.get(6).a, 2) + compare(obj.model.get(8).b, 11) + compare(obj.model.get(7).b, 12) + compare(obj.model.get(6).b, 11) + compare(obj.model.get(8).c, 100) + compare(obj.model.get(7).c, 101) + compare(obj.model.get(6).c, 101) + + + obj.sortingAscending = true + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(2).a, 2) + compare(obj.model.get(0).b, 11) + compare(obj.model.get(1).b, 11) + compare(obj.model.get(2).b, 12) + compare(obj.model.get(0).c, 100) + compare(obj.model.get(1).c, 101) + compare(obj.model.get(2).c, 101) + + obj.source.append({a: 2, b: 13, c: 101}) + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(2).a, 2) + compare(obj.model.get(3).a, 2) + compare(obj.model.get(0).b, 11) + compare(obj.model.get(1).b, 11) + compare(obj.model.get(2).b, 12) + compare(obj.model.get(3).b, 13) + compare(obj.model.get(0).c, 100) + compare(obj.model.get(1).c, 101) + compare(obj.model.get(2).c, 101) + compare(obj.model.get(3).c, 101) + + obj.sortingAscending = false + + compare(obj.model.get(9).a, 1) + compare(obj.model.get(8).a, 2) + compare(obj.model.get(7).a, 2) + compare(obj.model.get(6).a, 2) + compare(obj.model.get(9).b, 11) + compare(obj.model.get(8).b, 13) + compare(obj.model.get(7).b, 12) + compare(obj.model.get(6).b, 11) + compare(obj.model.get(9).c, 100) + compare(obj.model.get(8).c, 101) + compare(obj.model.get(7).c, 101) + compare(obj.model.get(6).c, 101) + } + + function test_default_stableSorting() { + const obj = createTemporaryObject(testComponent, root, { sorters: [] }) + + obj.model.sortRoleName = "a" + obj.model.ascendingSortOrder = true + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(2).a, 2) + compare(obj.model.get(0).b, 11) + compare(obj.model.get(1).b, 11) + compare(obj.model.get(2).b, 12) + compare(obj.model.get(0).c, 100) + compare(obj.model.get(1).c, 101) + compare(obj.model.get(2).c, 101) + + obj.model.ascendingSortOrder = false + + compare(obj.model.get(8).a, 1) + compare(obj.model.get(7).a, 2) + compare(obj.model.get(6).a, 2) + compare(obj.model.get(8).b, 11) + compare(obj.model.get(7).b, 12) + compare(obj.model.get(6).b, 11) + compare(obj.model.get(8).c, 100) + compare(obj.model.get(7).c, 101) + compare(obj.model.get(6).c, 101) + + + obj.model.ascendingSortOrder = true + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(2).a, 2) + compare(obj.model.get(0).b, 11) + compare(obj.model.get(1).b, 11) + compare(obj.model.get(2).b, 12) + compare(obj.model.get(0).c, 100) + compare(obj.model.get(1).c, 101) + compare(obj.model.get(2).c, 101) + + obj.source.append({a: 2, b: 13, c: 101}) + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(2).a, 2) + compare(obj.model.get(3).a, 2) + compare(obj.model.get(0).b, 11) + compare(obj.model.get(1).b, 11) + compare(obj.model.get(2).b, 12) + compare(obj.model.get(3).b, 13) + compare(obj.model.get(0).c, 100) + compare(obj.model.get(1).c, 101) + compare(obj.model.get(2).c, 101) + compare(obj.model.get(3).c, 101) + + obj.model.ascendingSortOrder = false + + compare(obj.model.get(9).a, 1) + compare(obj.model.get(8).a, 2) + compare(obj.model.get(7).a, 2) + compare(obj.model.get(6).a, 2) + compare(obj.model.get(9).b, 11) + compare(obj.model.get(8).b, 13) + compare(obj.model.get(7).b, 12) + compare(obj.model.get(6).b, 11) + compare(obj.model.get(9).c, 100) + compare(obj.model.get(8).c, 101) + compare(obj.model.get(7).c, 101) + compare(obj.model.get(6).c, 101) + } + + function test_sortWithPriority() { + const obj = createTemporaryObject(testComponent, root) + + obj.model = createTemporaryObject(obj.modelWithPriorityComponent, obj) + + compare(obj.model.get(0).a, 1) + compare(obj.model.get(1).a, 2) + compare(obj.model.get(2).a, 2) + compare(obj.model.get(0).b, 11) + compare(obj.model.get(1).b, 12) // descending "b" + compare(obj.model.get(2).b, 11) + compare(obj.model.get(0).c, 100) + compare(obj.model.get(1).c, 101) + compare(obj.model.get(2).c, 101) + compare(obj.model.get(7).a, 7) + compare(obj.model.get(8).a, 7) + compare(obj.model.get(7).c, 108) // descending "c" + compare(obj.model.get(8).c, 107) } } } diff --git a/ui/app/AppLayouts/Communities/panels/SharedAddressesAccountSelector.qml b/ui/app/AppLayouts/Communities/panels/SharedAddressesAccountSelector.qml index 6a05d5f8e9..ecd247b529 100644 --- a/ui/app/AppLayouts/Communities/panels/SharedAddressesAccountSelector.qml +++ b/ui/app/AppLayouts/Communities/panels/SharedAddressesAccountSelector.qml @@ -102,7 +102,12 @@ StatusListView { } sorters: FastExpressionSorter { expression: { - return modelLeft.enabledNetworkBalance > modelRight.enabledNetworkBalance // descending, biggest first + if (modelLeft.enabledNetworkBalance > modelRight.enabledNetworkBalance) + return -1 // descending, biggest first + else if (modelLeft.enabledNetworkBalance < modelRight.enabledNetworkBalance) + return 1 + else + return 0 } expectedRoles: ["enabledNetworkBalance"] } diff --git a/ui/app/AppLayouts/Wallet/views/CollectiblesView.qml b/ui/app/AppLayouts/Wallet/views/CollectiblesView.qml index 7ea39a6c1f..7a0e1929f0 100644 --- a/ui/app/AppLayouts/Wallet/views/CollectiblesView.qml +++ b/ui/app/AppLayouts/Wallet/views/CollectiblesView.qml @@ -133,7 +133,7 @@ ColumnLayout { FastExpressionSorter { expression: { d.controller.settingsDirty - return d.controller.lessThan(modelLeft.symbol, modelRight.symbol) + return d.controller.compareTokens(modelLeft.symbol, modelRight.symbol) } enabled: d.isCustomView expectedRoles: ["symbol"] diff --git a/ui/app/AppLayouts/Wallet/views/RightTabView.qml b/ui/app/AppLayouts/Wallet/views/RightTabView.qml index 350f4e7165..b4edfe4bee 100644 --- a/ui/app/AppLayouts/Wallet/views/RightTabView.qml +++ b/ui/app/AppLayouts/Wallet/views/RightTabView.qml @@ -131,7 +131,6 @@ RightTabBaseView { case 2: return historyView } } - active: visible Component { id: assetsView diff --git a/ui/imports/shared/views/AssetsView.qml b/ui/imports/shared/views/AssetsView.qml index 8ae6193a98..37240a1a3d 100644 --- a/ui/imports/shared/views/AssetsView.qml +++ b/ui/imports/shared/views/AssetsView.qml @@ -140,7 +140,7 @@ ColumnLayout { FastExpressionSorter { expression: { d.controller.settingsDirty - return d.controller.lessThan(modelLeft.symbol, modelRight.symbol) + return d.controller.compareTokens(modelLeft.symbol, modelRight.symbol) } enabled: d.isCustomView expectedRoles: ["symbol"] @@ -175,6 +175,7 @@ ColumnLayout { Layout.preferredHeight: root.filterVisible ? implicitHeight : 0 spacing: 20 opacity: root.filterVisible ? 1 : 0 + visible: opacity > 0 Behavior on Layout.preferredHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }