mirror of
https://github.com/status-im/status-desktop.git
synced 2025-01-12 15:24:39 +00:00
feat(CollectiblesView): Add combobox/popup with custom filtering options
.. to filter by community or collection name - make the HistoryView own filter button look like the other combos - fix some cosmetic issues for StatusCombo in small/secondary mode - fix StatusBaseInput bg color in dark mode (was invisible) - update CollectiblesViewPage with options to include regular and/or community collectibles Fixes #12969 Fixes #12948
This commit is contained in:
parent
1bd23b027d
commit
e2fa5b756a
@ -12,6 +12,7 @@ import mainui 1.0
|
||||
import utils 1.0
|
||||
|
||||
import shared.views 1.0
|
||||
import shared.stores 1.0
|
||||
|
||||
import Storybook 1.0
|
||||
import Models 1.0
|
||||
@ -53,29 +54,11 @@ SplitView {
|
||||
return supportedAddresses
|
||||
}
|
||||
|
||||
readonly property var currencyStore: QtObject {
|
||||
property string currentCurrency: "USD"
|
||||
function getCurrencyAmount(amount, symbol) {
|
||||
return ({
|
||||
amount: amount,
|
||||
symbol: symbol.toUpperCase(),
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false
|
||||
})
|
||||
}
|
||||
function getCurrentCurrencyAmount(amount) {
|
||||
return ({
|
||||
amount: amount,
|
||||
symbol: "USD",
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false
|
||||
})
|
||||
}
|
||||
}
|
||||
readonly property var currencyStore: CurrenciesStore {}
|
||||
|
||||
readonly property var groupedAccountsAssetsModel: GroupedAccountsAssetsModel {}
|
||||
readonly property var tokensBySymbolModel: TokensBySymbolModel {}
|
||||
readonly property CommunitiesModel communityModel: CommunitiesModel{}
|
||||
readonly property CommunitiesModel communityModel: CommunitiesModel {}
|
||||
|
||||
// Added this here simply because the network and address filtering wont work in Storybook applied in AssetsView
|
||||
readonly property SubmodelProxyModel assetsWithFilteredBalances: SubmodelProxyModel {
|
||||
@ -88,7 +71,7 @@ SplitView {
|
||||
d.networksChainsCurrentlySelected
|
||||
d.addressesSelected
|
||||
return d.networksChainsCurrentlySelected.split(":").includes(chainId+"") &&
|
||||
(!! d.addressesSelected ? d.addressesSelected.toUpperCase() === account.toUpperCase() : true)
|
||||
(!! d.addressesSelected ? d.addressesSelected.toUpperCase() === account.toUpperCase() : true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -185,7 +168,7 @@ SplitView {
|
||||
|
||||
CheckBox {
|
||||
id: loadingCheckbox
|
||||
checked: true
|
||||
checked: false
|
||||
text: "loading"
|
||||
}
|
||||
|
||||
|
@ -23,10 +23,8 @@ SplitView {
|
||||
|
||||
ManageCollectiblesModel {
|
||||
id: collectiblesModel
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: emptyModel
|
||||
includeRegularCollectibles: ctrlIncludeRegularCollectibles.checked
|
||||
includeCommunityCollectibles: ctrlIncludeCommunityCollectibles.checked
|
||||
}
|
||||
|
||||
Popups {
|
||||
@ -39,7 +37,7 @@ SplitView {
|
||||
id: assetsView
|
||||
SplitView.preferredWidth: 600
|
||||
SplitView.fillHeight: true
|
||||
collectiblesModel: ctrlEmptyModel.checked ? emptyModel : collectiblesModel
|
||||
collectiblesModel: collectiblesModel
|
||||
filterVisible: ctrlFilterVisible.checked
|
||||
onCollectibleClicked: logs.logEvent("onCollectibleClicked", ["chainId", "contractAddress", "tokenId", "uid"], arguments)
|
||||
onSendRequested: logs.logEvent("onSendRequested", ["symbol"], arguments)
|
||||
@ -63,8 +61,14 @@ SplitView {
|
||||
checked: true
|
||||
}
|
||||
Switch {
|
||||
id: ctrlEmptyModel
|
||||
text: "Empty model"
|
||||
id: ctrlIncludeRegularCollectibles
|
||||
text: "Regular collectibles"
|
||||
checked: true
|
||||
}
|
||||
Switch {
|
||||
id: ctrlIncludeCommunityCollectibles
|
||||
text: "Community collectibles"
|
||||
checked: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ Item {
|
||||
const lvRegular = findChild(controlUnderTest, "lvRegularTokens")
|
||||
verify(!!lvRegular)
|
||||
const lvRegularCount = lvRegular.count
|
||||
verify(lvRegularCount === 6)
|
||||
verify(lvRegularCount === 7)
|
||||
|
||||
const delegate0 = findChild(lvRegular, "manageTokensDelegate-0")
|
||||
verify(!!delegate0)
|
||||
@ -124,14 +124,14 @@ Item {
|
||||
verify(!!lvCommunityTokenGroups)
|
||||
|
||||
// verify we have 2 community collectible groups
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 3)
|
||||
triggerDelegateMenuAction(lvCommunityTokenGroups, 0, "miHideTokenGroup", true)
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
|
||||
// verify we have one less group
|
||||
waitForItemPolished(lvCommunityTokenGroups)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 1)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
const lvHidden = findChild(controlUnderTest, "lvHiddenTokens")
|
||||
verify(!!lvHidden)
|
||||
tryCompare(lvHidden, "count", 4) // we've just hidden 4 collectibles coming from this group
|
||||
@ -154,8 +154,8 @@ Item {
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
|
||||
// verify we again have 2 community groups, and one less hidden token
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
// verify we again have 3 community groups, and one less hidden token
|
||||
tryCompare(lvCommunityTokenGroups, "count", 3)
|
||||
tryCompare(lvHidden, "count", 3)
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
@ -164,7 +164,7 @@ Item {
|
||||
triggerDelegateMenuAction(lvHidden, 0, "miShowTokenGroup")
|
||||
waitForItemPolished(lvHidden)
|
||||
tryCompare(lvHidden, "count", 0)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 3)
|
||||
|
||||
verify(controlUnderTest.dirty)
|
||||
}
|
||||
@ -209,7 +209,7 @@ Item {
|
||||
const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups")
|
||||
verify(!!lvCommunityTokenGroups)
|
||||
waitForItemPolished(lvCommunityTokenGroups)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 3)
|
||||
|
||||
const group0 = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-0")
|
||||
const title0 = group0.title
|
||||
@ -242,7 +242,7 @@ Item {
|
||||
const lvCommunityTokenGroups = findChild(loaderCommunityTokens, "lvCommunityTokenGroups")
|
||||
verify(!!lvCommunityTokenGroups)
|
||||
waitForItemPolished(lvCommunityTokenGroups)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 2)
|
||||
tryCompare(lvCommunityTokenGroups, "count", 3)
|
||||
|
||||
// get the "Bearz" group at index 1
|
||||
var bearzGroupTokenDelegate = findChild(lvCommunityTokenGroups, "manageTokensGroupDelegate-1")
|
||||
|
@ -4,23 +4,20 @@ import QtQml.Models 2.15
|
||||
import Models 1.0
|
||||
|
||||
ListModel {
|
||||
function randomizeData() {
|
||||
// TODO
|
||||
property bool includeRegularCollectibles: true
|
||||
onIncludeRegularCollectiblesChanged: fillData()
|
||||
property bool includeCommunityCollectibles: true
|
||||
onIncludeCommunityCollectiblesChanged: fillData()
|
||||
|
||||
function fillData() {
|
||||
clear()
|
||||
if (includeRegularCollectibles)
|
||||
append(data)
|
||||
if (includeCommunityCollectibles)
|
||||
append(communityData)
|
||||
}
|
||||
|
||||
readonly property var data: [
|
||||
{
|
||||
uid: "fp#9140",
|
||||
name: "Frenly Panda #9140",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "fpan",
|
||||
communityName: "Frenly Pandas",
|
||||
communityImage: "https://pbs.twimg.com/profile_images/1599347398769143808/C6qG3RQv_400x400.jpg",
|
||||
imageUrl: "https://i.seadn.io/gae/qPfQjj4P1w0xVQXAmQJLmQ4ZtLFAJU6oiH69Lsny82LFbipLAgXhHKrcLBx2U09SmRnzeHY0ygz-3NIb-JegE_hWrZquFeL-qUPXPdw",
|
||||
isLoading: false,
|
||||
backgroundColor: "pink"
|
||||
},
|
||||
{
|
||||
uid: "123",
|
||||
name: "Punx not dead!",
|
||||
@ -28,6 +25,7 @@ ListModel {
|
||||
collectionName: "",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: "",
|
||||
imageUrl: ModelsData.collectibles.cryptoPunks,
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
@ -39,6 +37,7 @@ ListModel {
|
||||
collectionName: "Pepepunks",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: "",
|
||||
imageUrl: "https://i.seadn.io/s/raw/files/ba2811bb5cd0bed67529d69fa92ef5aa.jpg?auto=format&dpr=1&w=1000",
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
@ -50,6 +49,7 @@ ListModel {
|
||||
collectionName: "Kitties",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: "",
|
||||
imageUrl: ModelsData.collectibles.kitty1Big,
|
||||
isLoading: true,
|
||||
backgroundColor: ""
|
||||
@ -61,6 +61,7 @@ ListModel {
|
||||
collectionName: "Kitties",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: "",
|
||||
imageUrl: ModelsData.collectibles.kitty2Big,
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
@ -72,10 +73,50 @@ ListModel {
|
||||
collectionName: "Kitties",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: "",
|
||||
imageUrl: ModelsData.collectibles.kitty3Big,
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "pp21",
|
||||
name: "pepepunk#21",
|
||||
collectionUid: "pepepunks",
|
||||
collectionName: "Pepepunks",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: "",
|
||||
imageUrl: "https://i.seadn.io/s/raw/files/cfa559bb63e4378f17649c1e3b8f18fe.jpg?auto=format&dpr=1&w=1000",
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "lp#666a",
|
||||
name: "Lonely Panda #666",
|
||||
collectionUid: "lpan_collection",
|
||||
collectionName: "Lonely Panda Collection",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: "",
|
||||
imageUrl: "",
|
||||
isLoading: false,
|
||||
backgroundColor: "pink"
|
||||
},
|
||||
]
|
||||
|
||||
readonly property var communityData: [
|
||||
{
|
||||
uid: "fp#9140",
|
||||
name: "Frenly Panda #9140",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "fpan",
|
||||
communityName: "Frenly Pandas",
|
||||
communityImage: "https://pbs.twimg.com/profile_images/1599347398769143808/C6qG3RQv_400x400.jpg",
|
||||
imageUrl: "https://i.seadn.io/gae/qPfQjj4P1w0xVQXAmQJLmQ4ZtLFAJU6oiH69Lsny82LFbipLAgXhHKrcLBx2U09SmRnzeHY0ygz-3NIb-JegE_hWrZquFeL-qUPXPdw",
|
||||
isLoading: false,
|
||||
backgroundColor: "pink"
|
||||
},
|
||||
{
|
||||
uid: "691",
|
||||
name: "KILLABEAR #691",
|
||||
@ -137,17 +178,20 @@ ListModel {
|
||||
backgroundColor: ""
|
||||
},
|
||||
{
|
||||
uid: "pp21",
|
||||
name: "pepepunk#21",
|
||||
collectionUid: "pepepunks",
|
||||
collectionName: "Pepepunks",
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
imageUrl: "https://i.seadn.io/s/raw/files/cfa559bb63e4378f17649c1e3b8f18fe.jpg?auto=format&dpr=1&w=1000",
|
||||
uid: "lb#666",
|
||||
name: "Lonely Bear #666",
|
||||
collectionUid: "",
|
||||
collectionName: "",
|
||||
communityId: "lbear",
|
||||
communityName: "Lonely Bearz Community",
|
||||
communityImage: "",
|
||||
imageUrl: "",
|
||||
isLoading: false,
|
||||
backgroundColor: ""
|
||||
backgroundColor: "pink"
|
||||
},
|
||||
]
|
||||
|
||||
Component.onCompleted: append(data)
|
||||
Component.onCompleted: {
|
||||
fillData()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import QtQuick 2.15
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
readonly property string currentCurrency: "USD"
|
||||
property string currentCurrencySymbol: "$"
|
||||
|
||||
@ -11,4 +13,22 @@ QtObject {
|
||||
function getFiatValue(balance, cryptoSymbol, fiatSymbol) {
|
||||
return balance
|
||||
}
|
||||
|
||||
function getCurrencyAmount(amount, symbol) {
|
||||
return ({
|
||||
amount: amount,
|
||||
symbol: symbol ? symbol.toUpperCase() : root.currentCurrency,
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false
|
||||
})
|
||||
}
|
||||
|
||||
function getCurrentCurrencyAmount(amount) {
|
||||
return ({
|
||||
amount: amount,
|
||||
symbol: root.currentCurrency,
|
||||
displayDecimals: 2,
|
||||
stripTrailingZeroes: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ Item {
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
color: root.showBackground ? Theme.palette.baseColor2 : "transparent"
|
||||
color: root.showBackground ? Theme.palette.statusAppNavBar.backgroundColor : "transparent"
|
||||
radius: 8
|
||||
|
||||
clip: true
|
||||
|
@ -43,6 +43,8 @@ Item {
|
||||
implicitWidth: layout.implicitWidth
|
||||
implicitHeight: layout.implicitHeight
|
||||
|
||||
opacity: enabled ? 1 : 0.3
|
||||
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
ColumnLayout {
|
||||
@ -55,7 +57,6 @@ Item {
|
||||
id: labelItem
|
||||
Layout.fillWidth: true
|
||||
visible: !!text
|
||||
font.pixelSize: 15
|
||||
color: root.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
|
||||
}
|
||||
|
||||
@ -69,7 +70,7 @@ Item {
|
||||
enabled: root.enabled
|
||||
|
||||
font.family: Theme.palette.baseFont.name
|
||||
font.pixelSize: 14
|
||||
font.pixelSize: root.size === StatusComboBox.Size.Large ? Theme.secondaryTextFontSize : 13
|
||||
|
||||
padding: 16
|
||||
spacing: 16
|
||||
@ -112,7 +113,7 @@ Item {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
text: comboBox.displayText
|
||||
color: root.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
|
||||
color: root.type === StatusComboBox.Type.Secondary ? Theme.palette.baseColor1 : Theme.palette.directColor1
|
||||
}
|
||||
|
||||
indicator: StatusIcon {
|
||||
@ -186,7 +187,7 @@ Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 11
|
||||
visible: !!text
|
||||
font.pixelSize: 12
|
||||
font.pixelSize: Theme.tertiaryTextFontSize
|
||||
color: Theme.palette.dangerColor1
|
||||
horizontalAlignment: TextEdit.AlignRight
|
||||
wrapMode: Text.WordWrap
|
||||
|
@ -27,7 +27,7 @@ QtObject {
|
||||
//icon bg
|
||||
property real bgWidth
|
||||
property real bgHeight
|
||||
property int bgRadius
|
||||
property real bgRadius
|
||||
property color bgColor: "transparent"
|
||||
property color bgBorderColor: "transparent"
|
||||
property int bgBorderWidth: 0
|
||||
|
@ -434,7 +434,7 @@ void ConcatModel::initRoles()
|
||||
|
||||
m_nameRoles.reserve(m_expectedRoles.size() + 1);
|
||||
|
||||
for (auto& expectedRoleName : qAsConst(m_expectedRoles))
|
||||
for (const auto& expectedRoleName : qAsConst(m_expectedRoles))
|
||||
m_nameRoles.try_emplace(expectedRoleName.toUtf8(), m_nameRoles.size());
|
||||
|
||||
for (auto sourceModel : qAsConst(m_sources)) {
|
||||
@ -455,7 +455,7 @@ void ConcatModel::initRoles()
|
||||
|
||||
m_roleNames.reserve(m_nameRoles.size());
|
||||
|
||||
for (auto& [name, role] : m_nameRoles)
|
||||
for (const auto& [name, role] : m_nameRoles)
|
||||
m_roleNames.insert(role, name);
|
||||
}
|
||||
|
||||
@ -580,7 +580,7 @@ void ConcatModel::connectModelSlots(int index, QAbstractItemModel *model)
|
||||
emit this->layoutAboutToBeChanged();
|
||||
});
|
||||
|
||||
connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, [this]
|
||||
connect(model, &QAbstractItemModel::layoutChanged, this, [this]
|
||||
{
|
||||
emit this->layoutChanged();
|
||||
});
|
||||
|
@ -6,6 +6,7 @@
|
||||
ManageTokensController::ManageTokensController(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_regularTokensModel(new ManageTokensModel(this))
|
||||
, m_regularTokenGroupsModel(new ManageTokensModel(this))
|
||||
, m_communityTokensModel(new ManageTokensModel(this))
|
||||
, m_communityTokenGroupsModel(new ManageTokensModel(this))
|
||||
, m_hiddenTokensModel(new ManageTokensModel(this))
|
||||
@ -33,6 +34,7 @@ ManageTokensController::ManageTokensController(QObject* parent)
|
||||
m_communityTokensModel->setCommunityIds(m_communityIds);
|
||||
m_communityTokensModel->saveCustomSortOrder();
|
||||
rebuildCommunityTokenGroupsModel();
|
||||
rebuildRegularTokenGroupsModel();
|
||||
#ifdef QT_DEBUG
|
||||
qCInfo(manageTokens) << "!!! ADDING NEW SOURCE DATA TOOK" << t.nsecsElapsed()/1'000'000.f << "ms";
|
||||
#endif
|
||||
@ -270,6 +272,8 @@ bool ManageTokensController::lessThan(const QString& lhsSymbol, const QString& r
|
||||
|
||||
bool ManageTokensController::filterAcceptsSymbol(const QString& symbol) const
|
||||
{
|
||||
if (symbol.isEmpty()) return true;
|
||||
|
||||
const auto& [pos, visible, groupId] = m_settingsData.value(symbol, {INT_MAX, true, QString()});
|
||||
return visible;
|
||||
}
|
||||
@ -345,6 +349,9 @@ void ManageTokensController::parseSourceModel()
|
||||
reloadCommunityIds();
|
||||
m_communityTokensModel->setCommunityIds(m_communityIds);
|
||||
|
||||
// build collections
|
||||
rebuildRegularTokenGroupsModel();
|
||||
|
||||
// (pre)sort
|
||||
for (auto model: m_allModels) {
|
||||
model->applySort();
|
||||
@ -478,6 +485,46 @@ void ManageTokensController::rebuildCommunityTokenGroupsModel()
|
||||
qCDebug(manageTokens) << "!!! GROUPS MODEL REBUILT WITH GROUPS:" << communityIds;
|
||||
}
|
||||
|
||||
void ManageTokensController::rebuildRegularTokenGroupsModel()
|
||||
{
|
||||
QStringList collectionIds;
|
||||
QList<TokenData> result;
|
||||
|
||||
const auto count = m_regularTokensModel->count();
|
||||
for (auto i = 0; i < count; i++) {
|
||||
const auto& collectionToken = m_regularTokensModel->itemAt(i);
|
||||
const auto collectionId = collectionToken.collectionUid;
|
||||
if (collectionId.isEmpty())
|
||||
continue;
|
||||
if (!collectionIds.contains(collectionId)) { // insert into groups
|
||||
collectionIds.append(collectionId);
|
||||
|
||||
TokenData tokenGroup;
|
||||
tokenGroup.collectionUid = collectionId;
|
||||
tokenGroup.collectionName = collectionToken.collectionName;
|
||||
tokenGroup.image = collectionToken.image;
|
||||
tokenGroup.balance = 1;
|
||||
result.append(tokenGroup);
|
||||
} else { // update group's childCount
|
||||
const auto tokenGroup = std::find_if(result.cbegin(), result.cend(), [collectionId](const auto& item) {
|
||||
return collectionId == item.collectionUid;
|
||||
});
|
||||
if (tokenGroup != result.cend()) {
|
||||
const auto row = std::distance(result.cbegin(), tokenGroup);
|
||||
TokenData updTokenGroup = result.takeAt(row);
|
||||
updTokenGroup.balance = updTokenGroup.balance.toInt() + 1;
|
||||
result.insert(row, updTokenGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_regularTokenGroupsModel->clear();
|
||||
for (const auto& group: result)
|
||||
m_regularTokenGroupsModel->addItem(group);
|
||||
|
||||
qCDebug(manageTokens) << "!!! COLLECTION MODEL REBUILT WITH GROUPS:" << collectionIds;
|
||||
}
|
||||
|
||||
QString ManageTokensController::settingsKey() const
|
||||
{
|
||||
return m_settingsKey;
|
||||
|
@ -17,10 +17,11 @@ class ManageTokensController : public QObject, public QQmlParserStatus
|
||||
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 arrangeByCommunity READ arrangeByCommunity WRITE setArrangeByCommunity NOTIFY arrangeByCommunityChanged FINAL) // TODO persist in settings
|
||||
// TODO arrangeByCollection for collectibles
|
||||
|
||||
// output properties
|
||||
Q_PROPERTY(QAbstractItemModel* regularTokensModel READ regularTokensModel CONSTANT FINAL)
|
||||
// TODO regularTokenGroupsModel for grouped (collections of) collectibles?
|
||||
Q_PROPERTY(QAbstractItemModel* regularTokenGroupsModel READ regularTokenGroupsModel CONSTANT FINAL)
|
||||
Q_PROPERTY(QAbstractItemModel* communityTokensModel READ communityTokensModel CONSTANT FINAL)
|
||||
Q_PROPERTY(QAbstractItemModel* communityTokenGroupsModel READ communityTokenGroupsModel CONSTANT FINAL)
|
||||
Q_PROPERTY(QAbstractItemModel* hiddenTokensModel READ hiddenTokensModel CONSTANT FINAL)
|
||||
@ -68,6 +69,9 @@ private:
|
||||
ManageTokensModel* m_regularTokensModel{nullptr};
|
||||
QAbstractItemModel* regularTokensModel() const { return m_regularTokensModel; }
|
||||
|
||||
ManageTokensModel* m_regularTokenGroupsModel{nullptr};
|
||||
QAbstractItemModel* regularTokenGroupsModel() const { return m_regularTokenGroupsModel; }
|
||||
|
||||
ManageTokensModel* m_communityTokensModel{nullptr};
|
||||
QAbstractItemModel* communityTokensModel() const { return m_communityTokensModel; }
|
||||
|
||||
@ -86,8 +90,9 @@ private:
|
||||
QStringList m_communityIds;
|
||||
void reloadCommunityIds();
|
||||
void rebuildCommunityTokenGroupsModel();
|
||||
void rebuildRegularTokenGroupsModel();
|
||||
|
||||
const std::array<ManageTokensModel*, 4> m_allModels {m_regularTokensModel, m_communityTokensModel, m_communityTokenGroupsModel, m_hiddenTokensModel};
|
||||
const std::array<ManageTokensModel*, 5> m_allModels {m_regularTokensModel, m_regularTokenGroupsModel, m_communityTokensModel, m_communityTokenGroupsModel, m_hiddenTokensModel};
|
||||
|
||||
QString m_settingsKey;
|
||||
QString settingsKey() const;
|
||||
|
@ -174,7 +174,8 @@ void ManageTokensModel::saveCustomSortOrder()
|
||||
}
|
||||
m_data[i] = newToken;
|
||||
}
|
||||
emit dataChanged(index(0, 0), index(count - 1, 0), {TokenDataRoles::CustomSortOrderNoRole});
|
||||
if (count > 0)
|
||||
emit dataChanged(index(0, 0), index(count - 1, 0), {TokenDataRoles::CustomSortOrderNoRole});
|
||||
}
|
||||
|
||||
void ManageTokensModel::applySort()
|
||||
|
@ -1598,8 +1598,10 @@ private slots:
|
||||
QSignalSpy layoutChangedSpy(&model, &ConcatModel::layoutChanged);
|
||||
|
||||
emit sourceModel1.model()->layoutAboutToBeChanged();
|
||||
emit sourceModel1.model()->layoutChanged();
|
||||
QCOMPARE(layoutAboutToBeChangedSpy.count(), 1);
|
||||
QCOMPARE(layoutChangedSpy.count(), 0);
|
||||
|
||||
emit sourceModel1.model()->layoutChanged();
|
||||
QCOMPARE(layoutAboutToBeChangedSpy.count(), 1);
|
||||
QCOMPARE(layoutChangedSpy.count(), 1);
|
||||
}
|
||||
|
369
ui/app/AppLayouts/Wallet/controls/FilterComboBox.qml
Normal file
369
ui/app/AppLayouts/Wallet/controls/FilterComboBox.qml
Normal file
@ -0,0 +1,369 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtGraphicalEffects 1.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Popups 0.1
|
||||
|
||||
import utils 1.0
|
||||
import shared.controls 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
ComboBox {
|
||||
id: root
|
||||
|
||||
required property var regularTokensModel // "uncategorized" collectibles (not grouped)
|
||||
required property var regularTokenGroupsModel // collection groups
|
||||
required property var communityTokenGroupsModel // community groups
|
||||
|
||||
property bool hasCommunityGroups
|
||||
|
||||
property alias selectedFilterGroupIds: d.selectedFilterGroupIds
|
||||
readonly property bool hasEnabledFilters: d.selectedFilterGroupIds.length
|
||||
|
||||
function clearFilter() {
|
||||
d.selectedFilterGroupIds = []
|
||||
}
|
||||
|
||||
enabled: d.searchTextLowerCase || d.combinedProxyModel.count || d.uncategorizedModel.count
|
||||
opacity: enabled ? 1 : 0.3
|
||||
|
||||
displayText: qsTr("Collection")
|
||||
|
||||
horizontalPadding: 12
|
||||
verticalPadding: Style.current.halfPadding
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
font.family: Theme.palette.baseFont.name
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
readonly property int defaultDelegateHeight: 34
|
||||
|
||||
readonly property string searchTextLowerCase: searchBox.input.text.toLowerCase()
|
||||
|
||||
readonly property var combinedModel: ConcatModel {
|
||||
sources: [
|
||||
SourceModel {
|
||||
model: root.communityTokenGroupsModel
|
||||
markerRoleValue: "community"
|
||||
},
|
||||
SourceModel {
|
||||
model: root.regularTokenGroupsModel
|
||||
markerRoleValue: "collection"
|
||||
}
|
||||
]
|
||||
|
||||
markerRoleName: "sourceGroup"
|
||||
onRowsRemoved: root.clearFilter() // different underlying model -> uncheck all groups
|
||||
}
|
||||
|
||||
readonly property var combinedProxyModel: SortFilterProxyModel {
|
||||
sourceModel: d.combinedModel
|
||||
proxyRoles: [
|
||||
JoinRole {
|
||||
name: "groupName"
|
||||
roleNames: ["collectionName", "communityName"]
|
||||
separator: ""
|
||||
},
|
||||
JoinRole {
|
||||
name: "groupId"
|
||||
roleNames: ["collectionUid", "communityId"]
|
||||
separator: ""
|
||||
}
|
||||
]
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
enabled: d.searchTextLowerCase !== ""
|
||||
expression: {
|
||||
d.searchTextLowerCase // ensure expression is reevaluated when searchString changes
|
||||
return model.groupName.toLowerCase().includes(d.searchTextLowerCase) || model.groupId.toLowerCase().includes(d.searchTextLowerCase)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
readonly property var uncategorizedModel: SortFilterProxyModel { // regular collectibles with no collection
|
||||
sourceModel: root.regularTokensModel
|
||||
filters: ValueFilter {
|
||||
roleName: "collectionUid"
|
||||
value: ""
|
||||
}
|
||||
onCountChanged: if (!count) d.removeFilter("") // different underlying model -> uncheck
|
||||
}
|
||||
|
||||
property var selectedFilterGroupIds: []
|
||||
readonly property bool allVisuallyChecked: selectedFilterGroupIds.length === 0
|
||||
|
||||
function addFilter(groupId) {
|
||||
if (d.selectedFilterGroupIds.includes(groupId))
|
||||
return
|
||||
const newFilters = d.selectedFilterGroupIds.concat(groupId)
|
||||
d.selectedFilterGroupIds = newFilters
|
||||
}
|
||||
function removeFilter(groupId) {
|
||||
const newFilters = d.selectedFilterGroupIds.filter((filter) => filter !== groupId)
|
||||
d.selectedFilterGroupIds = newFilters
|
||||
}
|
||||
function removeGroupFilters() {
|
||||
const newFilters = d.selectedFilterGroupIds.filter((filter) => filter === "")
|
||||
d.selectedFilterGroupIds = newFilters
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
border.width: 1
|
||||
border.color: Theme.palette.directColor7
|
||||
radius: Style.current.radius
|
||||
color: root.down ? Theme.palette.baseColor2 : "transparent"
|
||||
HoverHandler {
|
||||
cursorShape: root.enabled ? Qt.PointingHandCursor : undefined
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: -6 // badge has an implicit border :/
|
||||
StatusBaseText {
|
||||
leftPadding: root.horizontalPadding
|
||||
rightPadding: root.horizontalPadding
|
||||
font.pixelSize: root.font.pixelSize
|
||||
font.weight: Font.Medium
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
text: root.displayText
|
||||
color: Theme.palette.baseColor1
|
||||
}
|
||||
StatusBadge {
|
||||
Layout.preferredHeight: 16
|
||||
Layout.preferredWidth: 16
|
||||
Layout.rightMargin: Style.current.halfPadding
|
||||
value: d.selectedFilterGroupIds.length
|
||||
visible: root.hasEnabledFilters
|
||||
}
|
||||
}
|
||||
|
||||
indicator: StatusIcon {
|
||||
x: root.mirrored ? root.horizontalPadding : root.width - width - root.horizontalPadding
|
||||
y: root.topPadding + (root.availableHeight - height) / 2
|
||||
width: 16
|
||||
height: width
|
||||
icon: "chevron-down"
|
||||
color: Theme.palette.baseColor1
|
||||
}
|
||||
|
||||
popup: Popup {
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
|
||||
y: root.height + 4
|
||||
|
||||
implicitWidth: 290
|
||||
implicitHeight: Math.min(contentHeight+margins, 380)
|
||||
margins: Style.current.halfPadding
|
||||
|
||||
padding: 0
|
||||
bottomPadding: Style.current.halfPadding
|
||||
|
||||
background: Rectangle {
|
||||
color: Theme.palette.statusSelect.menuItemBackgroundColor
|
||||
radius: Style.current.radius
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
horizontalOffset: 0
|
||||
verticalOffset: 4
|
||||
radius: 12
|
||||
samples: 25
|
||||
spread: 0.2
|
||||
color: Theme.palette.dropShadow
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
SearchBox {
|
||||
id: searchBox
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 12
|
||||
Layout.leftMargin: Style.current.halfPadding
|
||||
Layout.rightMargin: Style.current.halfPadding
|
||||
Layout.bottomMargin: 12
|
||||
minimumHeight: d.defaultDelegateHeight
|
||||
maximumHeight: d.defaultDelegateHeight
|
||||
input.edit.font.pixelSize: root.font.pixelSize
|
||||
input.placeholder.font.pixelSize: root.font.pixelSize
|
||||
input.asset.width: 16
|
||||
input.asset.height: 16
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
placeholderText: qsTr("Collection, community, name or #")
|
||||
}
|
||||
StatusListView {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: contentWidth
|
||||
implicitHeight: contentHeight
|
||||
|
||||
model: d.combinedProxyModel
|
||||
delegate: Item { // NB anything but AbstractButton to prevent auto-closing of the popup
|
||||
width: ListView.view.width
|
||||
implicitHeight: customMenuDelegate.implicitHeight
|
||||
|
||||
CustomItemDelegate {
|
||||
id: customMenuDelegate
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
section.property: "sourceGroup"
|
||||
section.delegate: ColumnLayout {
|
||||
id: sectionDelegate
|
||||
width: ListView.view.width
|
||||
height: d.defaultDelegateHeight
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: Theme.palette.statusListItem.backgroundColor
|
||||
|
||||
StatusBaseText {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.rightMargin: Style.current.padding
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text: section === "community" ? qsTr("Community minted") : root.hasCommunityGroups ? qsTr("Other")
|
||||
: qsTr("Collections")
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Style.current.tertiaryTextFontSize
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
// floating divider
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 4
|
||||
color: sectionDelegate.y <= sectionDelegate.ListView.view.contentY && sectionDelegate.y !== 0 ? Theme.palette.directColor8
|
||||
: Theme.palette.statusListItem.backgroundColor
|
||||
}
|
||||
}
|
||||
section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
|
||||
}
|
||||
StatusMenuSeparator {
|
||||
Layout.fillWidth: true
|
||||
visible: d.uncategorizedModel.count
|
||||
}
|
||||
CustomItemDelegate {
|
||||
Layout.fillWidth: true
|
||||
icon.name: "image"
|
||||
text: qsTr("No collection")
|
||||
count: d.uncategorizedModel.count
|
||||
groupId: ""
|
||||
visible: count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component CustomItemDelegate: CheckDelegate {
|
||||
id: menuDelegate
|
||||
|
||||
property int count: model.enabledNetworkBalance
|
||||
readonly property bool isCommunityGroup: !!model && !!model.communityId
|
||||
property string groupId: model.groupId
|
||||
readonly property string groupImage: !!model ? model.communityImage || model.imageUrl : ""
|
||||
|
||||
highlighted: hovered
|
||||
leftPadding: Style.current.padding
|
||||
rightPadding: 44
|
||||
verticalPadding: 4
|
||||
spacing: root.spacing
|
||||
font: root.font
|
||||
text: model.groupName
|
||||
icon.source: groupImage
|
||||
icon.name: isCommunityGroup ? "group" : "gallery"
|
||||
checked: d.selectedFilterGroupIds.includes(menuDelegate.groupId)
|
||||
onToggled: checked ? d.addFilter(menuDelegate.groupId) : d.removeFilter(menuDelegate.groupId)
|
||||
background: Rectangle {
|
||||
color: menuDelegate.highlighted ? Theme.palette.statusMenu.hoverBackgroundColor : "transparent"
|
||||
HoverHandler {
|
||||
cursorShape: menuDelegate.enabled ? Qt.PointingHandCursor : undefined
|
||||
}
|
||||
}
|
||||
indicator: Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Style.current.padding
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
implicitWidth: 18
|
||||
implicitHeight: implicitWidth
|
||||
radius: 2
|
||||
color: menuDelegate.down || menuDelegate.checkState !== Qt.Checked
|
||||
? Theme.palette.directColor8
|
||||
: Theme.palette.primaryColor1
|
||||
|
||||
StatusIcon {
|
||||
icon: "checkbox"
|
||||
width: 11
|
||||
height: 8
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: 1
|
||||
color: d.allVisuallyChecked ? Theme.palette.baseColor1 : Theme.palette.white
|
||||
visible: menuDelegate.down || menuDelegate.checkState !== Qt.Unchecked || d.allVisuallyChecked
|
||||
}
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
spacing: root.spacing
|
||||
|
||||
Loader {
|
||||
Layout.preferredWidth: 32
|
||||
Layout.preferredHeight: 32
|
||||
|
||||
sourceComponent: !!menuDelegate.groupImage ? roundImage : roundIcon
|
||||
|
||||
Component {
|
||||
id: roundImage
|
||||
StatusRoundedImage {
|
||||
image.source: menuDelegate.icon.source
|
||||
radius: menuDelegate.isCommunityGroup ? width/2 : 6
|
||||
showLoadingIndicator: true
|
||||
image.fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: roundIcon
|
||||
StatusRoundIcon {
|
||||
asset.bgRadius: menuDelegate.isCommunityGroup ? width/2 : 6
|
||||
asset.bgWidth: 16
|
||||
asset.bgHeight: 16
|
||||
asset.bgColor: Theme.palette.primaryColor3
|
||||
asset.width: 16
|
||||
asset.height: 16
|
||||
asset.name: menuDelegate.icon.name
|
||||
asset.color: Theme.palette.primaryColor1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
Layout.fillWidth: true
|
||||
text: menuDelegate.text
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: menuDelegate.font.pixelSize
|
||||
font.weight: menuDelegate.checked ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
StatusBaseText {
|
||||
font.pixelSize: Style.current.tertiaryTextFontSize
|
||||
color: Theme.palette.baseColor1
|
||||
text: menuDelegate.count
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ StatusTxProgressBar 1.0 StatusTxProgressBar.qml
|
||||
StatusDateRangePicker 1.0 StatusDateRangePicker.qml
|
||||
ActivityFilterTagItem 1.0 ActivityFilterTagItem.qml
|
||||
SortOrderComboBox 1.0 SortOrderComboBox.qml
|
||||
FilterComboBox 1.0 FilterComboBox.qml
|
||||
ManageTokenMenuButton 1.0 ManageTokenMenuButton.qml
|
||||
ManageTokensCommunityTag 1.0 ManageTokensCommunityTag.qml
|
||||
ManageTokensDelegate 1.0 ManageTokensDelegate.qml
|
||||
|
@ -31,16 +31,12 @@ Column {
|
||||
|
||||
spacing: 8
|
||||
|
||||
StatusRoundButton {
|
||||
id: filterButton
|
||||
width: 32
|
||||
height: 32
|
||||
icon.name: "filter"
|
||||
border.width: 1
|
||||
border.color: Theme.palette.directColor8
|
||||
type: StatusRoundButton.Type.Tertiary
|
||||
icon.color: Theme.palette.primaryColor1
|
||||
onClicked: {
|
||||
StatusComboBox {
|
||||
height: 34
|
||||
size: StatusComboBox.Size.Small
|
||||
type: StatusComboBox.Type.Secondary
|
||||
control.displayText: qsTr("Filter")
|
||||
control.popup.onOpened: {
|
||||
activityFilterStore.updateStartTimestamp()
|
||||
activityFilterMenu.popup(x, y + height + 4)
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ ColumnLayout {
|
||||
|
||||
readonly property var controller: ManageTokensController {
|
||||
settingsKey: "WalletCollectibles"
|
||||
sourceModel: d.renamedModel
|
||||
}
|
||||
|
||||
function hideAllCommunityTokens(communityId) {
|
||||
@ -87,6 +88,16 @@ ColumnLayout {
|
||||
d.controller.settingsDirty
|
||||
return d.controller.filterAcceptsSymbol(model.symbol) && (customFilter.isCommunity ? !!model.communityId : !model.communityId)
|
||||
}
|
||||
},
|
||||
ExpressionFilter {
|
||||
enabled: customFilter.isCommunity && cmbFilter.hasEnabledFilters
|
||||
expression: cmbFilter.selectedFilterGroupIds.includes(model.communityId) ||
|
||||
(!model.communityId && cmbFilter.selectedFilterGroupIds.includes(""))
|
||||
},
|
||||
ExpressionFilter {
|
||||
enabled: !customFilter.isCommunity && cmbFilter.hasEnabledFilters
|
||||
expression: cmbFilter.selectedFilterGroupIds.includes(model.collectionUid) ||
|
||||
(!model.collectionUid && cmbFilter.selectedFilterGroupIds.includes(""))
|
||||
}
|
||||
]
|
||||
sorters: [
|
||||
@ -109,13 +120,14 @@ ColumnLayout {
|
||||
category: "CollectiblesViewSortSettings"
|
||||
property alias currentSortField: cmbTokenOrder.currentIndex
|
||||
property alias currentSortOrder: cmbTokenOrder.currentSortOrder
|
||||
property alias selectedFilterGroupIds: cmbFilter.selectedFilterGroupIds
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: root.filterVisible && (d.hasCollectibles || d.hasCommunityCollectibles) ? implicitHeight : 0
|
||||
Layout.preferredHeight: root.filterVisible ? implicitHeight : 0
|
||||
spacing: 20
|
||||
opacity: Layout.preferredHeight < implicitHeight ? 0 : 1
|
||||
opacity: root.filterVisible ? 1 : 0
|
||||
|
||||
Behavior on Layout.preferredHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||
Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||
@ -128,6 +140,22 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
FilterComboBox {
|
||||
id: cmbFilter
|
||||
regularTokensModel: d.controller.regularTokensModel
|
||||
regularTokenGroupsModel: d.controller.regularTokenGroupsModel
|
||||
communityTokenGroupsModel: d.controller.communityTokenGroupsModel
|
||||
hasCommunityGroups: d.hasCommunityCollectibles
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredHeight: 34
|
||||
Layout.preferredWidth: 1
|
||||
Layout.leftMargin: 12
|
||||
Layout.rightMargin: 12
|
||||
color: Theme.palette.baseColor2
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
@ -150,6 +178,15 @@ ColumnLayout {
|
||||
root.manageTokensRequested()
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
StatusLinkText {
|
||||
visible: cmbFilter.hasEnabledFilters
|
||||
normalColor: Theme.palette.primaryColor1
|
||||
text: qsTr("Clear filter")
|
||||
onClicked: cmbFilter.clearFilter()
|
||||
}
|
||||
}
|
||||
|
||||
StatusDialogDivider {
|
||||
@ -159,6 +196,7 @@ ColumnLayout {
|
||||
|
||||
ShapeRectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
visible: !d.hasCollectibles && !d.hasCommunityCollectibles
|
||||
text: qsTr("Collectibles will appear here")
|
||||
}
|
||||
@ -185,7 +223,7 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
Layout.bottomMargin: Style.current.halfPadding
|
||||
visible: d.hasCommunityCollectibles
|
||||
visible: d.hasCollectibles && d.hasCommunityCollectibles
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
@ -189,6 +189,7 @@ Item {
|
||||
overview: RootStore.overview
|
||||
showAllAccounts: root.showAllAccounts
|
||||
sendModal: root.sendModal
|
||||
filterVisible: filterButton.checked
|
||||
onLaunchTransactionDetail: function (entry, entryIndex) {
|
||||
transactionDetailView.transactionIndex = entryIndex
|
||||
transactionDetailView.transaction = entry
|
||||
|
@ -110,7 +110,7 @@ StatusListItem {
|
||||
font.pixelSize: 13
|
||||
loading: modelData && modelData.marketDetailsLoading
|
||||
text: modelData && modelData.marketDetails && modelData.marketDetails.changePct24hour !== undefined ? "%1 %2%".arg(root.upDownTriangle).arg(LocaleUtils.numberToLocaleString(modelData.marketDetails.changePct24hour, 2))
|
||||
: "---"
|
||||
: "---"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@ -124,7 +124,7 @@ StatusListItem {
|
||||
customColor: root.textColor
|
||||
font.pixelSize: 13
|
||||
loading: modelData && modelData.marketDetailsLoading
|
||||
text: modelData && modelData.marketDetails ? LocaleUtils.currencyAmountToLocaleString(modelData.marketDetails.currencyPrice) : ""
|
||||
text: modelData && modelData.marketDetails ? LocaleUtils.currencyAmountToLocaleString(modelData.marketDetails.currencyPrice) : ""
|
||||
}
|
||||
}
|
||||
ManageTokensCommunityTag {
|
||||
|
@ -126,6 +126,11 @@ ColumnLayout {
|
||||
expression: model.marketDetails.currencyPrice.amount
|
||||
expectedRoles: ["marketDetails"]
|
||||
},
|
||||
FastExpressionRole {
|
||||
name: "changePct24hour"
|
||||
expression: model.marketDetails.changePct24hour
|
||||
expectedRoles: ["marketDetails"]
|
||||
},
|
||||
FastExpressionRole {
|
||||
name: "isCommunityAsset"
|
||||
expression: !!model.communityId
|
||||
@ -170,7 +175,7 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: root.filterVisible ? implicitHeight : 0
|
||||
spacing: 20
|
||||
opacity: Layout.preferredHeight < implicitHeight ? 0 : 1
|
||||
opacity: root.filterVisible ? 1 : 0
|
||||
|
||||
Behavior on Layout.preferredHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||
Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||
@ -214,38 +219,29 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
StatusScrollView {
|
||||
StatusListView {
|
||||
id: assetsListView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
leftPadding: 0
|
||||
verticalPadding: 0
|
||||
contentWidth: availableWidth
|
||||
|
||||
StatusListView {
|
||||
id: assetsListView
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
interactive: false
|
||||
objectName: "assetViewStatusListView"
|
||||
model: root.areAssetsLoading ? d.loadingItemsCount : d.customSFPM
|
||||
delegate: delegateLoader
|
||||
section {
|
||||
property: "isCommunityAsset"
|
||||
delegate: Loader {
|
||||
width: ListView.view.width
|
||||
required property string section
|
||||
sourceComponent: section === "true" ? sectionDelegate: null
|
||||
}
|
||||
Layout.preferredHeight: contentHeight
|
||||
Layout.fillHeight: true
|
||||
objectName: "assetViewStatusListView"
|
||||
model: root.areAssetsLoading ? d.loadingItemsCount : d.customSFPM
|
||||
delegate: delegateLoader
|
||||
section {
|
||||
property: "isCommunityAsset"
|
||||
delegate: Loader {
|
||||
width: ListView.view.width
|
||||
required property string section
|
||||
sourceComponent: section === "true" ? sectionDelegate : null
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: sectionDelegate
|
||||
ColumnLayout {
|
||||
width: ListView.view.width
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
StatusDialogDivider {
|
||||
@ -282,7 +278,7 @@ ColumnLayout {
|
||||
property var modelData: model
|
||||
property int delegateIndex: index
|
||||
width: ListView.view.width
|
||||
sourceComponent: root.areAssetsLoading ? loadingTokenDelegate: tokenDelegate
|
||||
sourceComponent: root.areAssetsLoading ? loadingTokenDelegate : tokenDelegate
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,7 +293,7 @@ ColumnLayout {
|
||||
id: tokenDelegate
|
||||
TokenDelegate {
|
||||
objectName: "AssetView_TokenListItem_" + (!!modelData ? modelData.symbol : "")
|
||||
readonly property string balance: !!modelData && !!modelData.currentBalance? "%1".arg(modelData.currentBalance) : "" // Needed for the tests
|
||||
readonly property string balance: !!modelData && !!modelData.currentBalance ? "%1".arg(modelData.currentBalance) : "" // Needed for the tests
|
||||
errorTooltipText_1: !!modelData && !!networkConnectionStore ? networkConnectionStore.getBlockchainNetworkDownTextForToken(modelData.balances) : ""
|
||||
errorTooltipText_2: !!networkConnectionStore ? networkConnectionStore.getMarketNetworkDownText() : ""
|
||||
subTitle: {
|
||||
|
@ -30,6 +30,7 @@ ColumnLayout {
|
||||
property var overview
|
||||
property bool showAllAccounts: false
|
||||
property var sendModal
|
||||
property bool filterVisible
|
||||
|
||||
signal launchTransactionDetail(var transaction, int entryIndex)
|
||||
|
||||
@ -43,7 +44,6 @@ ColumnLayout {
|
||||
if (!visible)
|
||||
return
|
||||
|
||||
filterPanelLoader.active = true
|
||||
if (RootStore.transactionActivityStatus.isFilterDirty) {
|
||||
WalletStores.RootStore.currentActivityFiltersStore.applyAllFilters()
|
||||
}
|
||||
@ -101,11 +101,11 @@ ColumnLayout {
|
||||
|
||||
Loader {
|
||||
id: filterPanelLoader
|
||||
active: false
|
||||
active: root.filterVisible && (d.isInitialLoading || transactionListRoot.count > 0 || WalletStores.RootStore.currentActivityFiltersStore.filtersSet)
|
||||
visible: active
|
||||
asynchronous: true
|
||||
Layout.fillWidth: true
|
||||
sourceComponent: ActivityFilterPanel {
|
||||
visible: d.isInitialLoading || transactionListRoot.count > 0 || WalletStores.RootStore.currentActivityFiltersStore.filtersSet
|
||||
activityFilterStore: WalletStores.RootStore.currentActivityFiltersStore
|
||||
store: WalletStores.RootStore
|
||||
hideNoResults: newTransactions.visible
|
||||
|
@ -239,7 +239,7 @@ StatusMenu {
|
||||
|
||||
StatusAction {
|
||||
id: blockMenuItem
|
||||
objectName: blockUser_StatusItem
|
||||
objectName: "blockUser_StatusItem"
|
||||
text: qsTr("Block User")
|
||||
icon.name: "cancel"
|
||||
type: StatusAction.Type.Danger
|
||||
|
Loading…
x
Reference in New Issue
Block a user