performance: Improve the wallet loading time

+ small bug fixes
This commit is contained in:
Alex Jbanca 2024-01-29 21:49:59 +02:00 committed by Alex Jbanca
parent a6abdbeeef
commit a55dcf299e
10 changed files with 428 additions and 107 deletions

View File

@ -26,6 +26,9 @@ QtObject:
extradata: ExtraData extradata: ExtraData
traits: TraitModel traits: TraitModel
ownership: OwnershipModel ownership: OwnershipModel
generatedId: string
generatedCollectionId: string
proc setup(self: CollectiblesEntry) = proc setup(self: CollectiblesEntry) =
self.QObject.setup self.QObject.setup
@ -45,32 +48,6 @@ QtObject:
self.ownership.setItems(ownership) self.ownership.setItems(ownership)
self.setup() 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 = proc `$`*(self: CollectiblesEntry): string =
return fmt"""CollectiblesEntry( return fmt"""CollectiblesEntry(
id:{self.id}, id:{self.id},
@ -78,6 +55,8 @@ QtObject:
extradata:{self.extradata}, extradata:{self.extradata},
traits:{self.traits}, traits:{self.traits},
ownership:{self.ownership}, ownership:{self.ownership},
generatedId:{self.generatedId},
generatedCollectionId:{self.generatedCollectionId}
)""" )"""
proc getCollectibleUniqueID*(self: CollectiblesEntry): backend.CollectibleUniqueID = proc getCollectibleUniqueID*(self: CollectiblesEntry): backend.CollectibleUniqueID =
@ -130,10 +109,16 @@ QtObject:
# Unique ID to identify collectible, generated by us # Unique ID to identify collectible, generated by us
proc getID*(self: CollectiblesEntry): string = proc getID*(self: CollectiblesEntry): string =
return self.generatedId
proc generateId*(self: CollectiblesEntry): string =
return fmt"{self.getChainId}+{self.getContractAddress}+{self.getTokenID}" return fmt"{self.getChainId}+{self.getContractAddress}+{self.getTokenID}"
# Unique ID to identify collection, generated by us # Unique ID to identify collection, generated by us
proc getCollectionID*(self: CollectiblesEntry): string = proc getCollectionID*(self: CollectiblesEntry): string =
return self.generatedCollectionId
proc generateCollectionId*(self: CollectiblesEntry): string =
return fmt"{self.getChainId}+{self.getContractAddress}" return fmt"{self.getChainId}+{self.getContractAddress}"
proc nameChanged*(self: CollectiblesEntry) {.signal.} proc nameChanged*(self: CollectiblesEntry) {.signal.}
@ -360,3 +345,33 @@ QtObject:
self.communityPrivilegesLevelChanged() self.communityPrivilegesLevelChanged()
self.communityImageChanged() self.communityImageChanged()
return true 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)

View File

@ -5,6 +5,8 @@
#include <QQmlContext> #include <QQmlContext>
#include <QQmlExpression> #include <QQmlExpression>
#include <QQmlScriptString> #include <QQmlScriptString>
#include <QSet>
#include <QQmlPropertyMap>
#include <memory> #include <memory>
@ -14,9 +16,10 @@ class FastExpressionSorter : public qqsfpm::Sorter
Q_PROPERTY(QQmlScriptString expression READ expression Q_PROPERTY(QQmlScriptString expression READ expression
WRITE setExpression NOTIFY expressionChanged) WRITE setExpression NOTIFY expressionChanged)
Q_PROPERTY(QStringList expectedRoles READ expectedRoles Q_PROPERTY(QSet<QByteArray> expectedRoles READ expectedRoles
WRITE setExpectedRoles NOTIFY expectedRolesChanged) WRITE setExpectedRoles NOTIFY expectedRolesChanged)
public: public:
using qqsfpm::Sorter::Sorter; using qqsfpm::Sorter::Sorter;
const QQmlScriptString& expression() const; const QQmlScriptString& expression() const;
@ -24,16 +27,18 @@ public:
void proxyModelCompleted(const qqsfpm::QQmlSortFilterProxyModel& proxyModel) override; void proxyModelCompleted(const qqsfpm::QQmlSortFilterProxyModel& proxyModel) override;
void setExpectedRoles(const QStringList& expectedRoles); void setExpectedRoles(const QSet<QByteArray>& expectedRoles);
const QStringList& expectedRoles() const; const QSet<QByteArray>& expectedRoles() const;
void queueInvalidate();
void onInvalidate();
Q_SIGNALS: Q_SIGNALS:
void expressionChanged(); void expressionChanged();
void expectedRolesChanged(); void expectedRolesChanged();
protected: protected:
int compare(const QModelIndex& sourceLeft, const QModelIndex& sourceRight, int compare(const QModelIndex& sourceLeft, const QModelIndex& sourceRight, const qqsfpm::QQmlSortFilterProxyModel& proxyModel) const override;
const qqsfpm::QQmlSortFilterProxyModel& proxyModel) const override;
private: private:
void updateContext(const qqsfpm::QQmlSortFilterProxyModel& proxyModel); void updateContext(const qqsfpm::QQmlSortFilterProxyModel& proxyModel);
@ -44,5 +49,10 @@ private:
std::unique_ptr<QQmlExpression> m_expression; std::unique_ptr<QQmlExpression> m_expression;
std::unique_ptr<QQmlContext> m_context; std::unique_ptr<QQmlContext> m_context;
QStringList m_expectedRoles; QSet<QByteArray> m_expectedRoles;
bool m_queuedInvalidate { false };
mutable QQmlPropertyMap m_modelLeftMap;
mutable QQmlPropertyMap m_modelRightMap;
}; };

View File

@ -50,12 +50,28 @@ void FastExpressionSorter::setExpression(const QQmlScriptString& scriptString)
updateExpression(); updateExpression();
emit expressionChanged(); 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) void FastExpressionSorter::proxyModelCompleted(const QQmlSortFilterProxyModel& proxyModel)
{ {
updateContext(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. List of role names intended to be available in the expression's context.
*/ */
void FastExpressionSorter::setExpectedRoles(const QStringList& expectedRoles) void FastExpressionSorter::setExpectedRoles(const QSet<QByteArray>& expectedRoles)
{ {
if (m_expectedRoles == expectedRoles) if (m_expectedRoles == expectedRoles)
return; return;
@ -71,44 +87,45 @@ void FastExpressionSorter::setExpectedRoles(const QStringList& expectedRoles)
m_expectedRoles = expectedRoles; m_expectedRoles = expectedRoles;
emit expectedRolesChanged(); emit expectedRolesChanged();
invalidate(); queueInvalidate();
} }
const QStringList &FastExpressionSorter::expectedRoles() const const QSet<QByteArray> &FastExpressionSorter::expectedRoles() const
{ {
return m_expectedRoles; return m_expectedRoles;
} }
bool evaluateBoolExpression(QQmlExpression& expression) int evaluateIntExpression(QQmlExpression& expression)
{ {
QVariant variantResult = expression.evaluate(); QVariant variantResult = expression.evaluate();
if (expression.hasError()) { if (expression.hasError()) {
qWarning() << expression.error(); qWarning() << expression.error();
return false; return -1;
} }
if (variantResult.canConvert<bool>()) if (variantResult.canConvert<int>())
return variantResult.toBool(); 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.sourceFile().toUtf8().data(),
expression.lineNumber(), expression.lineNumber(),
expression.columnNumber()); expression.columnNumber());
return false; return 0;
} }
int FastExpressionSorter::compare(const QModelIndex& sourceLeft, int FastExpressionSorter::compare(const QModelIndex& sourceLeft,
const QModelIndex& sourceRight, const QModelIndex& sourceRight,
const QQmlSortFilterProxyModel& proxyModel) const 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<int, QByteArray> roles = proxyModel.roleNames(); QHash<int, QByteArray> roles = proxyModel.roleNames();
QQmlContext context(qmlContext(this));
for (auto it = roles.cbegin(); it != roles.cend(); ++it) { for (auto it = roles.cbegin(); it != roles.cend(); ++it) {
auto role = it.key(); auto role = it.key();
auto name = it.value(); auto name = it.value();
@ -116,50 +133,42 @@ int FastExpressionSorter::compare(const QModelIndex& sourceLeft,
if (!m_expectedRoles.contains(name)) if (!m_expectedRoles.contains(name))
continue; continue;
modelLeftMap.insert(name, proxyModel.sourceData(sourceLeft, role)); m_modelLeftMap.insert(name, proxyModel.sourceData(sourceLeft, role));
modelRightMap.insert(name, proxyModel.sourceData(sourceRight, role)); m_modelRightMap.insert(name, proxyModel.sourceData(sourceRight, role));
} }
modelLeftMap.insert(QStringLiteral("index"), sourceLeft.row()); m_modelLeftMap.insert(QStringLiteral("index"), sourceLeft.row());
modelRightMap.insert(QStringLiteral("index"), sourceRight.row()); m_modelRightMap.insert(QStringLiteral("index"), sourceRight.row());
QQmlExpression expression(m_scriptString, &context); m_expression->setNotifyOnValueChanged(true);
context.setContextProperty(QStringLiteral("modelLeft"), modelLeftMap); return evaluateIntExpression(*m_expression);
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;
} }
void FastExpressionSorter::updateContext(const QQmlSortFilterProxyModel& proxyModel) void FastExpressionSorter::updateContext(const QQmlSortFilterProxyModel& proxyModel)
{ {
m_context = std::make_unique<QQmlContext>(qmlContext(this)); m_context = std::make_unique<QQmlContext>(qmlContext(this));
updateExpression();
QVariantMap modelLeftMap, modelRightMap; if (!m_expression)
return;
m_expression->setNotifyOnValueChanged(false);
const auto roleNames = proxyModel.roleNames(); const auto roleNames = proxyModel.roleNames();
for (const QByteArray& name : roleNames) { for (const QByteArray& name : roleNames) {
if (!m_expectedRoles.contains(name)) if (!m_expectedRoles.contains(name))
continue; continue;
modelLeftMap.insert(name, {}); m_modelLeftMap.insert(name, {});
modelRightMap.insert(name, {}); m_modelRightMap.insert(name, {});
} }
modelLeftMap.insert(QStringLiteral("index"), -1); m_modelLeftMap.insert(QStringLiteral("index"), -1);
modelRightMap.insert(QStringLiteral("index"), -1); m_modelRightMap.insert(QStringLiteral("index"), -1);
m_context->setContextProperty(QStringLiteral("modelLeft"), modelLeftMap); m_context->setContextProperty(QStringLiteral("modelLeft"), &m_modelLeftMap);
m_context->setContextProperty(QStringLiteral("modelRight"), modelRightMap); m_context->setContextProperty(QStringLiteral("modelRight"), &m_modelRightMap);
updateExpression(); m_expression->setNotifyOnValueChanged(true);
} }
void FastExpressionSorter::updateExpression() void FastExpressionSorter::updateExpression()
@ -171,7 +180,7 @@ void FastExpressionSorter::updateExpression()
m_context.get()); m_context.get());
connect(m_expression.get(), &QQmlExpression::valueChanged, this, connect(m_expression.get(), &QQmlExpression::valueChanged, this,
&FastExpressionSorter::invalidate); &FastExpressionSorter::queueInvalidate);
m_expression->setNotifyOnValueChanged(true); m_expression->setNotifyOnValueChanged(true);
m_expression->evaluate(); m_expression->evaluate();
} }

View File

@ -239,8 +239,7 @@ void ManageTokensController::loadSettings()
{ {
Q_ASSERT(!m_settingsKey.isEmpty()); Q_ASSERT(!m_settingsKey.isEmpty());
setSettingsDirty(true); SerializedTokenData result;
m_settingsData.clear();
// load from QSettings // load from QSettings
m_settings.beginGroup(settingsGroupName()); m_settings.beginGroup(settingsGroupName());
@ -256,7 +255,7 @@ void ManageTokensController::loadSettings()
const auto pos = m_settings.value(QStringLiteral("pos"), INT_MAX).toInt(); const auto pos = m_settings.value(QStringLiteral("pos"), INT_MAX).toInt();
const auto visible = m_settings.value(QStringLiteral("visible"), true).toBool(); const auto visible = m_settings.value(QStringLiteral("visible"), true).toBool();
const auto groupId = m_settings.value(QStringLiteral("groupId")).toString(); 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(); m_settings.endArray();
@ -277,7 +276,11 @@ void ManageTokensController::loadSettings()
setArrangeByCollection(m_settings.value(QStringLiteral("ArrangeByCollection"), false).toBool()); setArrangeByCollection(m_settings.value(QStringLiteral("ArrangeByCollection"), false).toBool());
m_settings.endGroup(); m_settings.endGroup();
setSettingsDirty(false);
if (result != m_settingsData) {
m_settingsData = result;
setSettingsDirty(true);
}
} }
void ManageTokensController::setSettingsDirty(bool dirty) void ManageTokensController::setSettingsDirty(bool dirty)
@ -353,7 +356,7 @@ void ManageTokensController::settingsHideGroupTokens(const QString& groupId, con
saveSettings(true); 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; int leftPos, rightPos;
bool leftVisible, rightVisible; bool leftVisible, rightVisible;
@ -365,7 +368,11 @@ bool ManageTokensController::lessThan(const QString& lhsSymbol, const QString& r
leftPos = leftVisible ? leftPos : INT_MAX; leftPos = leftVisible ? leftPos : INT_MAX;
rightPos = rightVisible ? rightPos : 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 bool ManageTokensController::filterAcceptsSymbol(const QString& symbol) const

View File

@ -52,7 +52,7 @@ public:
Q_INVOKABLE void settingsHideToken(const QString& symbol); Q_INVOKABLE void settingsHideToken(const QString& symbol);
Q_INVOKABLE void settingsHideGroupTokens(const QString& groupId, const QStringList& symbols); 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; Q_INVOKABLE bool filterAcceptsSymbol(const QString& symbol) const;
protected: protected:

View File

@ -17,17 +17,21 @@ Item {
property int d: 1 property int d: 1
property alias sorterEnabled: sorter.enabled property alias sorterEnabled: sorter.enabled
property alias sortingAscending: sorter.ascendingOrder
property alias sorters: testModel.sorters
readonly property ListModel source: ListModel { readonly property ListModel source: ListModel {
id: listModel id: listModel
ListElement { a: 1; b: 11; c: 101 } ListElement { a: 1; b: 11; c: 100 }
ListElement { a: 2; b: 12; c: 102 } ListElement { a: 2; b: 11; c: 101 }
ListElement { a: 3; b: 13; c: 103 } ListElement { a: 3; b: 13; c: 103 }
ListElement { a: 4; b: 14; c: 104 } ListElement { a: 4; b: 14; c: 104 }
ListElement { a: 5; b: 15; c: 105 } ListElement { a: 5; b: 15; c: 105 }
ListElement { a: 6; b: 16; c: 106 } 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: 107 }
ListElement { a: 7; b: 17; c: 108 }
} }
readonly property ModelAccessObserverProxy observer: ModelAccessObserverProxy { readonly property ModelAccessObserverProxy observer: ModelAccessObserverProxy {
@ -44,28 +48,71 @@ Item {
} }
} }
readonly property SortFilterProxyModel model: SortFilterProxyModel { property SortFilterProxyModel model: SortFilterProxyModel {
id: testModel id: testModel
sourceModel: observerProxy sourceModel: observerProxy
sorters: FastExpressionSorter { sorters: [sorter]
}
readonly property Component modelWithPriorityComponent: Component {
SortFilterProxyModel {
id: testModelWithPriority
sourceModel: observerProxy
sorters: [sorter, otherSorter, roleSorter]
}
}
readonly property FastExpressionSorter sorter: FastExpressionSorter {
id: sorter id: sorter
expression: { expression: {
return d ? modelLeft.a < modelRight.a if (modelLeft.a < modelRight.a)
: modelLeft.a > modelRight.a return d ? -1 : 1
else if (modelLeft.a > modelRight.a)
return d ? 1 : -1
else
return 0
} }
expectedRoles: ["a"] 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 { readonly property SignalSpy rowsRemovedSpy: SignalSpy {
target: testModel target: testModel
signalName: "rowsRemoved" signalName: "rowsRemoved"
} }
readonly property SignalSpy layoutChangedSpy: SignalSpy {
id: layoutChangedSpy
target: testModel
signalName: "layoutChanged"
}
} }
} }
@ -76,17 +123,17 @@ Item {
const obj = createTemporaryObject(testComponent, root) const obj = createTemporaryObject(testComponent, root)
const count = obj.model.count const count = obj.model.count
compare(count, 7) compare(count, 9)
verify(obj.observer.accessCounter verify(obj.observer.accessCounter
< count * Math.ceil(Math.log2(count)) * 3) < count * Math.ceil(Math.log2(count)) * 3)
compare(obj.observer.accessedRoles.size, 1) compare(obj.observer.accessedRoles.size, 1)
compare(obj.model.get(0).a, 1) compare(obj.model.get(0).a, 1)
compare(obj.model.get(1).a, 2) 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 obj = createTemporaryObject(testComponent, root)
const count = obj.model.count const count = obj.model.count
@ -98,9 +145,9 @@ Item {
< count * Math.ceil(Math.log2(count)) * 3) < count * Math.ceil(Math.log2(count)) * 3)
compare(obj.observer.accessedRoles.size, 1) compare(obj.observer.accessedRoles.size, 1)
compare(obj.model.get(0).a, 7) tryVerify(() => obj.model.get(0).a, 7)
compare(obj.model.get(1).a, 6) tryVerify(() => obj.model.get(1).a, 6)
compare(obj.model.get(6).a, 1) tryVerify(() => obj.model.get(6).a, 1)
} }
function test_enabled() { function test_enabled() {
@ -110,7 +157,7 @@ Item {
compare(obj.model.get(0).a, 1) compare(obj.model.get(0).a, 1)
compare(obj.model.get(1).a, 2) 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.accessedRoles.clear()
obj.observer.accessCounter = 0 obj.observer.accessCounter = 0
@ -123,8 +170,236 @@ Item {
compare(obj.observer.accessedRoles.size, 1) compare(obj.observer.accessedRoles.size, 1)
compare(obj.model.get(0).a, 7) compare(obj.model.get(0).a, 7)
compare(obj.model.get(1).a, 6) compare(obj.model.get(1).a, 7)
compare(obj.model.get(6).a, 1) 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)
} }
} }
} }

View File

@ -102,7 +102,12 @@ StatusListView {
} }
sorters: FastExpressionSorter { sorters: FastExpressionSorter {
expression: { 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"] expectedRoles: ["enabledNetworkBalance"]
} }

View File

@ -133,7 +133,7 @@ ColumnLayout {
FastExpressionSorter { FastExpressionSorter {
expression: { expression: {
d.controller.settingsDirty d.controller.settingsDirty
return d.controller.lessThan(modelLeft.symbol, modelRight.symbol) return d.controller.compareTokens(modelLeft.symbol, modelRight.symbol)
} }
enabled: d.isCustomView enabled: d.isCustomView
expectedRoles: ["symbol"] expectedRoles: ["symbol"]

View File

@ -131,7 +131,6 @@ RightTabBaseView {
case 2: return historyView case 2: return historyView
} }
} }
active: visible
Component { Component {
id: assetsView id: assetsView

View File

@ -140,7 +140,7 @@ ColumnLayout {
FastExpressionSorter { FastExpressionSorter {
expression: { expression: {
d.controller.settingsDirty d.controller.settingsDirty
return d.controller.lessThan(modelLeft.symbol, modelRight.symbol) return d.controller.compareTokens(modelLeft.symbol, modelRight.symbol)
} }
enabled: d.isCustomView enabled: d.isCustomView
expectedRoles: ["symbol"] expectedRoles: ["symbol"]
@ -175,6 +175,7 @@ ColumnLayout {
Layout.preferredHeight: root.filterVisible ? implicitHeight : 0 Layout.preferredHeight: root.filterVisible ? implicitHeight : 0
spacing: 20 spacing: 20
opacity: root.filterVisible ? 1 : 0 opacity: root.filterVisible ? 1 : 0
visible: opacity > 0
Behavior on Layout.preferredHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } Behavior on Layout.preferredHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }