(wallet) implement sorting for assets/collectibles views
- add the sort combobox to assets/collectibles main wallet view pages - preserve the current view settings - add the possibility to navigate/drill down into wallet settings (sub)subsection - some other minor changes/fixes Note: currently assets can't be sorted by "1W change" and collectibles by "Date added" due to missing backend for these Fixes #12517 Fixes #12518
This commit is contained in:
parent
e24e3d734c
commit
fe3b442155
|
@ -34,6 +34,7 @@ SplitView {
|
|||
SplitView.preferredWidth: 600
|
||||
SplitView.fillHeight: true
|
||||
assets: assetsModel
|
||||
filterVisible: ctrlFilterVisible.checked
|
||||
onAssetClicked: logs.logEvent("onAssetClicked", ["token"], [token.symbol, token.communityId])
|
||||
onSendRequested: logs.logEvent("onSendRequested", ["symbol"], arguments)
|
||||
onReceiveRequested: logs.logEvent("onReceiveRequested", ["symbol"], arguments)
|
||||
|
@ -48,6 +49,14 @@ SplitView {
|
|||
SplitView.preferredWidth: 250
|
||||
|
||||
logsView.logText: logs.logText
|
||||
|
||||
ColumnLayout {
|
||||
Switch {
|
||||
id: ctrlFilterVisible
|
||||
text: "Filter visible"
|
||||
checked: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ SplitView {
|
|||
SplitView.preferredWidth: 600
|
||||
SplitView.fillHeight: true
|
||||
collectiblesModel: ctrlEmptyModel.checked ? emptyModel : collectiblesModel
|
||||
filterVisible: ctrlFilterVisible.checked
|
||||
onCollectibleClicked: logs.logEvent("onCollectibleClicked", ["chainId", "contractAddress", "tokenId", "uid"], arguments)
|
||||
onSendRequested: logs.logEvent("onSendRequested", ["symbol"], arguments)
|
||||
onReceiveRequested: logs.logEvent("onReceiveRequested", ["symbol"], arguments)
|
||||
|
@ -56,6 +57,11 @@ SplitView {
|
|||
logsView.logText: logs.logText
|
||||
|
||||
ColumnLayout {
|
||||
Switch {
|
||||
id: ctrlFilterVisible
|
||||
text: "Filter visible"
|
||||
checked: true
|
||||
}
|
||||
Switch {
|
||||
id: ctrlEmptyModel
|
||||
text: "Empty model"
|
||||
|
@ -67,3 +73,4 @@ SplitView {
|
|||
// category: Views
|
||||
// https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?type=design&node-id=19558-95270&mode=design&t=ShZOuMRfiIIl2aR8-0
|
||||
// https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?type=design&node-id=19558-96427&mode=design&t=ShZOuMRfiIIl2aR8-0
|
||||
// https://www.figma.com/file/FkFClTCYKf83RJWoifWgoX/Wallet-v2?node-id=19087%3A293357&mode=dev
|
||||
|
|
|
@ -47,6 +47,11 @@ SplitView {
|
|||
text: "Dirty: %1".arg(showcasePanel.dirty ? "true" : "false")
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Has saved settings: %1".arg(showcasePanel.hasSettings ? "true" : "false")
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Save"
|
||||
onClicked: showcasePanel.saveSettings()
|
||||
|
@ -67,6 +72,7 @@ SplitView {
|
|||
}
|
||||
|
||||
Button {
|
||||
enabled: showcasePanel.hasSettings
|
||||
text: "Clear settings"
|
||||
onClicked: showcasePanel.clearSettings()
|
||||
}
|
||||
|
|
|
@ -50,6 +50,11 @@ SplitView {
|
|||
text: "Dirty: %1".arg(showcasePanel.dirty ? "true" : "false")
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Has saved settings: %1".arg(showcasePanel.hasSettings ? "true" : "false")
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Save"
|
||||
onClicked: showcasePanel.saveSettings()
|
||||
|
@ -71,6 +76,7 @@ SplitView {
|
|||
}
|
||||
|
||||
Button {
|
||||
enabled: showcasePanel.hasSettings
|
||||
text: "Clear settings"
|
||||
onClicked: showcasePanel.clearSettings()
|
||||
}
|
||||
|
|
|
@ -44,11 +44,7 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {
|
||||
amount: 10.37,
|
||||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {},
|
||||
communityId: "ddls",
|
||||
communityName: "Doodles",
|
||||
communityImage: ModelsData.collectibles.doodles // FIXME backend
|
||||
|
@ -65,6 +61,7 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {},
|
||||
communityId: "sox",
|
||||
communityName: "Socks",
|
||||
communityImage: ModelsData.icons.socks
|
||||
|
@ -81,17 +78,22 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {
|
||||
amount: 0.25,
|
||||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
changePct24hour: -2.1,
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
communityImage: ""
|
||||
},
|
||||
{
|
||||
name: "Ave Maria",
|
||||
symbol: "AAVE",
|
||||
name: "Request",
|
||||
symbol: "REQ",
|
||||
enabledNetworkBalance: {
|
||||
amount: 23.3,
|
||||
symbol: "AAVE",
|
||||
amount: 0.00005,
|
||||
symbol: "REQ",
|
||||
displayDecimals: 2
|
||||
},
|
||||
enabledNetworkCurrencyBalance: {
|
||||
|
@ -99,6 +101,11 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {
|
||||
amount: 0.1000001,
|
||||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
changePct24hour: 4.56,
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
|
@ -116,6 +123,11 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {
|
||||
amount: 0.000752089,
|
||||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
changePct24hour: -11.6789,
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
|
@ -134,6 +146,11 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {
|
||||
amount: 0.937718773,
|
||||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
changePct24hour: 0,
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
|
@ -152,6 +169,7 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {},
|
||||
changePct24hour: -1,
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
|
@ -161,13 +179,13 @@ ListModel {
|
|||
name: "Ethereum",
|
||||
symbol: "ETH",
|
||||
enabledNetworkBalance: {
|
||||
amount: 0.12345,
|
||||
amount: 0.123456789,
|
||||
symbol: "ETH",
|
||||
displayDecimals: 8,
|
||||
stripTrailingZeroes: true
|
||||
},
|
||||
enabledNetworkCurrencyBalance: {
|
||||
amount: 182.72,
|
||||
amount: 182.73004849,
|
||||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
|
@ -186,6 +204,7 @@ ListModel {
|
|||
symbol: "InvisibleSYM",
|
||||
enabledNetworkBalance: {},
|
||||
enabledNetworkCurrencyBalance: {},
|
||||
currencyPrice: {},
|
||||
changePct24hour: NaN,
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
|
@ -193,7 +212,7 @@ ListModel {
|
|||
},
|
||||
{
|
||||
enabledNetworkBalance: ({
|
||||
displayDecimals: true,
|
||||
displayDecimals: 4,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 0,
|
||||
symbol: "SNT"
|
||||
|
@ -201,7 +220,7 @@ ListModel {
|
|||
enabledNetworkCurrencyBalance: ({
|
||||
displayDecimals: 4,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 0,
|
||||
amount: 0.,
|
||||
symbol: "EUR"
|
||||
}),
|
||||
currencyPrice: {
|
||||
|
@ -228,6 +247,7 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {},
|
||||
communityId: "ddls",
|
||||
communityName: "Doodles",
|
||||
communityImage: ModelsData.collectibles.doodles
|
||||
|
@ -244,6 +264,7 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {},
|
||||
communityId: "ast",
|
||||
communityName: "Astafarians",
|
||||
communityImage: ModelsData.icons.dribble
|
||||
|
|
|
@ -78,11 +78,9 @@ QQmlListProperty<RoleRename> RolesRenamingModel::mapping()
|
|||
|
||||
QHash<int, QByteArray> RolesRenamingModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles = sourceModel()
|
||||
? sourceModel()->roleNames()
|
||||
: QHash<int, QByteArray>{};
|
||||
const auto roles = sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>{};
|
||||
|
||||
if (roles.empty())
|
||||
if (roles.isEmpty())
|
||||
return roles;
|
||||
|
||||
QHash<QString, RoleRename*> renameMap;
|
||||
|
|
|
@ -23,7 +23,7 @@ QVariant SubmodelProxyModel::data(const QModelIndex &index, int role) const
|
|||
? creationContext : m_delegateModel->engine()->rootContext();
|
||||
|
||||
auto context = new QQmlContext(parentContext, parentContext);
|
||||
context->setContextProperty("submodel", submodel);
|
||||
context->setContextProperty(QStringLiteral("submodel"), submodel);
|
||||
|
||||
QObject* instance = m_delegateModel->create(context);
|
||||
QQmlEngine::setObjectOwnership(instance, QQmlEngine::JavaScriptOwnership);
|
||||
|
|
|
@ -164,12 +164,15 @@ void ManageTokensController::clearSettings()
|
|||
m_settings.remove(QString());
|
||||
m_settings.endGroup();
|
||||
m_settings.sync();
|
||||
|
||||
emit settingsDirtyChanged(false);
|
||||
}
|
||||
|
||||
void ManageTokensController::loadSettings()
|
||||
{
|
||||
Q_ASSERT(!m_settingsKey.isEmpty());
|
||||
|
||||
setSettingsDirty(true);
|
||||
m_settingsData.clear();
|
||||
|
||||
// load from QSettings
|
||||
|
@ -189,6 +192,7 @@ void ManageTokensController::loadSettings()
|
|||
}
|
||||
m_settings.endArray();
|
||||
m_settings.endGroup();
|
||||
setSettingsDirty(false);
|
||||
}
|
||||
|
||||
void ManageTokensController::setSettingsDirty(bool dirty)
|
||||
|
@ -212,7 +216,7 @@ bool ManageTokensController::hasSettings() const
|
|||
{
|
||||
Q_ASSERT(!m_settingsKey.isEmpty());
|
||||
const auto groups = m_settings.childGroups();
|
||||
return !groups.isEmpty() && groups.contains(settingsGroupName());
|
||||
return groups.contains(settingsGroupName());
|
||||
}
|
||||
|
||||
void ManageTokensController::settingsHideToken(const QString& symbol)
|
||||
|
|
|
@ -25,6 +25,7 @@ class ManageTokensController : public QObject, public QQmlParserStatus
|
|||
Q_PROPERTY(QAbstractItemModel* communityTokenGroupsModel READ communityTokenGroupsModel CONSTANT FINAL)
|
||||
Q_PROPERTY(QAbstractItemModel* hiddenTokensModel READ hiddenTokensModel CONSTANT FINAL)
|
||||
Q_PROPERTY(bool dirty READ dirty NOTIFY dirtyChanged FINAL)
|
||||
Q_PROPERTY(bool hasSettings READ hasSettings NOTIFY settingsDirtyChanged FINAL)
|
||||
Q_PROPERTY(bool settingsDirty READ settingsDirty NOTIFY settingsDirtyChanged FINAL)
|
||||
|
||||
public:
|
||||
|
@ -38,7 +39,6 @@ public:
|
|||
Q_INVOKABLE void saveSettings(bool reuseCurrent = false);
|
||||
Q_INVOKABLE void clearSettings();
|
||||
Q_INVOKABLE void revert();
|
||||
Q_INVOKABLE bool hasSettings() const;
|
||||
|
||||
Q_INVOKABLE void settingsHideToken(const QString& symbol);
|
||||
Q_INVOKABLE void settingsHideCommunityTokens(const QString& communityId, const QStringList& symbols);
|
||||
|
@ -95,6 +95,7 @@ private:
|
|||
void setSettingsKey(const QString& newSettingsKey);
|
||||
QSettings m_settings;
|
||||
SerializedTokenData m_settingsData; // symbol -> {sortOrder, visible, groupId}
|
||||
bool hasSettings() const;
|
||||
|
||||
bool m_settingsDirty{false};
|
||||
bool settingsDirty() const { return m_settingsDirty; }
|
||||
|
|
|
@ -54,6 +54,7 @@ StatusSectionLayout {
|
|||
keycardView.item.handleBackAction()
|
||||
break;
|
||||
}
|
||||
Global.settingsSubSubsection = -1
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
|
|
@ -2,6 +2,7 @@ import QtQuick 2.15
|
|||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.13
|
||||
import QtGraphicalEffects 1.13
|
||||
import QtQml 2.15
|
||||
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
|
@ -88,6 +89,14 @@ SettingsContentBase {
|
|||
accountView.height
|
||||
currentIndex: mainViewIndex
|
||||
|
||||
Binding on currentIndex {
|
||||
value: root.manageTokensViewIndex
|
||||
when: Global.settingsSubSubsection === Constants.walletSettingsSubsection.manageAssets ||
|
||||
Global.settingsSubSubsection === Constants.walletSettingsSubsection.manageCollectibles ||
|
||||
Global.settingsSubSubsection === Constants.walletSettingsSubsection.manageTokenLists
|
||||
restoreMode: Binding.RestoreNone
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
root.rootStore.backButtonName = ""
|
||||
root.sectionTitle = root.walletSectionTitle
|
||||
|
@ -257,6 +266,23 @@ SettingsContentBase {
|
|||
// TODO concat proxy model to include community collectibles (#12519)
|
||||
return RootStore.collectiblesStore.ownedCollectibles
|
||||
}
|
||||
|
||||
Binding on currentIndex {
|
||||
value: {
|
||||
switch (Global.settingsSubSubsection) {
|
||||
case Constants.walletSettingsSubsection.manageAssets:
|
||||
return 0
|
||||
case Constants.walletSettingsSubsection.manageCollectibles:
|
||||
return 1
|
||||
case Constants.walletSettingsSubsection.manageTokenLists:
|
||||
return 2
|
||||
}
|
||||
}
|
||||
when: Global.settingsSubSubsection === Constants.walletSettingsSubsection.manageAssets ||
|
||||
Global.settingsSubSubsection === Constants.walletSettingsSubsection.manageCollectibles ||
|
||||
Global.settingsSubSubsection === Constants.walletSettingsSubsection.manageTokenLists
|
||||
restoreMode: Binding.RestoreNone
|
||||
}
|
||||
}
|
||||
|
||||
DappPermissionsView {
|
||||
|
|
|
@ -18,6 +18,8 @@ ColumnLayout {
|
|||
required property var baseWalletAssetsModel
|
||||
required property var baseWalletCollectiblesModel
|
||||
|
||||
property alias currentIndex: tabBar.currentIndex
|
||||
|
||||
readonly property bool dirty: {
|
||||
if (!loader.item)
|
||||
return false
|
||||
|
|
|
@ -197,6 +197,7 @@ Item {
|
|||
Component {
|
||||
id: receiveModalComponent
|
||||
ReceiveModal {
|
||||
destroyOnClose: true
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,79 +13,71 @@ import utils 1.0
|
|||
ComboBox {
|
||||
id: root
|
||||
|
||||
property int sortOrder: Qt.DescendingOrder
|
||||
readonly property string currentSortRoleName: d.currentSortRoleName
|
||||
// expected model role names: text, value (enum TokenOrder), sortRoleName, icon (optional)
|
||||
// text === "---" denotes a separator
|
||||
|
||||
property bool hasCustomOrderDefined
|
||||
|
||||
property int currentSortOrder: Qt.DescendingOrder
|
||||
readonly property string currentSortRoleName: root.currentIndex !== -1 ? root.model[root.currentIndex].sortRoleName : ""
|
||||
|
||||
signal createOrEditRequested()
|
||||
|
||||
model: d.predefinedSortModel
|
||||
textRole: "text"
|
||||
valueRole: "value"
|
||||
displayText: !d.isCustomSortOrder ? "%1 %2".arg(currentText).arg(sortOrder === Qt.DescendingOrder ? "↓" : "↑")
|
||||
: currentText
|
||||
|
||||
Component.onCompleted: currentIndex = indexOfValue(SortOrderComboBox.TokenOrderCustom)
|
||||
displayText: root.currentValue === SortOrderComboBox.TokenOrderCustom ? currentText
|
||||
: "%1 %2".arg(currentText).arg(currentSortOrder === Qt.DescendingOrder ? "↓" : "↑")
|
||||
|
||||
onActivated: {
|
||||
if (index === indexOfValue(SortOrderComboBox.TokenOrderCreateCustom)) { // restore the previous sort role and signal we want create/edit
|
||||
currentIndex = d.currentIndex
|
||||
root.createOrEditRequested()
|
||||
} else {
|
||||
if (d.currentIndex === index) // just keep the same sort role and flip the up/down
|
||||
currentSortOrder = currentSortOrder === Qt.AscendingOrder ? Qt.DescendingOrder : Qt.AscendingOrder
|
||||
|
||||
// update internal index
|
||||
d.currentIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
d.currentIndex = root.currentIndex // sync with settings which might arrive from the outside
|
||||
}
|
||||
|
||||
enum TokenOrder {
|
||||
TokenOrderNone = 0,
|
||||
TokenOrderCustom,
|
||||
TokenOrderValue,
|
||||
TokenOrderBalance,
|
||||
TokenOrder1WChange,
|
||||
TokenOrderAlpha
|
||||
TokenOrderCurrencyBalance, // FIAT value of asset balance (enabledNetworkCurrencyBalance)
|
||||
TokenOrderBalance, // Number of tokens (enabledNetworkBalance)
|
||||
TokenOrderCurrencyPrice, // Value per token in FIAT (currencyPrice)
|
||||
TokenOrder1WChange, // Level of change in asset balance value (in FIAT) comp. to 7 days earlier
|
||||
TokenOrderAlpha, // Alphabetic by asset name (name)
|
||||
TokenOrderDateAdded, // Date added descending (newest first)
|
||||
TokenOrderGroupName, // Collection or Community name
|
||||
TokenOrderCustom, // Custom (user created) order
|
||||
TokenOrderCreateCustom // special menu entry to create/edit the custom sort order
|
||||
}
|
||||
|
||||
horizontalPadding: 12
|
||||
verticalPadding: 8
|
||||
spacing: 8
|
||||
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
|
||||
|
||||
// // models
|
||||
// readonly property SortFilterProxyModel tokensModel: SortFilterProxyModel {
|
||||
// sourceModel: root.baseModel
|
||||
// proxyRoles: [
|
||||
// ExpressionRole {
|
||||
// name: "currentBalance"
|
||||
// expression: model.enabledNetworkBalance.amount
|
||||
// },
|
||||
// ExpressionRole {
|
||||
// name: "currentCurrencyBalance"
|
||||
// expression: model.enabledNetworkCurrencyBalance.amount
|
||||
// }
|
||||
// ]
|
||||
// sorters: RoleSorter {
|
||||
// roleName: cmbTokenOrder.currentSortRoleName
|
||||
// sortOrder: cmbTokenOrder.sortOrder
|
||||
// enabled: !d.isCustomSortOrder
|
||||
// }
|
||||
// filters: ValueFilter {
|
||||
// roleName: "visibleForNetworkWithPositiveBalance"
|
||||
// value: true
|
||||
// }
|
||||
// }
|
||||
|
||||
readonly property var predefinedSortModel: [
|
||||
{ value: SortOrderComboBox.TokenOrderValue, text: qsTr("Token value"), icon: "token-sale", sortRoleName: "currentCurrencyBalance" }, // custom SFPM ExpressionRole
|
||||
{ value: SortOrderComboBox.TokenOrderBalance, text: qsTr("Token balance"), icon: "wallet", sortRoleName: "currentBalance" }, // custom SFPM ExpressionRole
|
||||
{ value: SortOrderComboBox.TokenOrder1WChange, text: qsTr("1W change"), icon: "time", sortRoleName: "changePct24hour" }, // FIXME changePct1Week role missing in backend!!!
|
||||
{ value: SortOrderComboBox.TokenOrderAlpha, text: qsTr("Alphabetic"), icon: "bold", sortRoleName: "name" },
|
||||
{ value: SortOrderComboBox.TokenOrderNone, text: "---", icon: "", sortRoleName: "" },
|
||||
{ value: SortOrderComboBox.TokenOrderCustom, text: qsTr("Custom order"), icon: "exchange", sortRoleName: "" }
|
||||
]
|
||||
readonly property string currentSortRoleName: root.currentIndex !== -1 ? d.predefinedSortModel[root.currentIndex].sortRoleName : ""
|
||||
readonly property bool isCustomSortOrder: root.currentValue === SortOrderComboBox.TokenOrderCustom
|
||||
property int currentIndex: 0
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
border.width: 1
|
||||
border.color: Theme.palette.directColor7
|
||||
radius: 8
|
||||
radius: Style.current.radius
|
||||
color: root.down ? Theme.palette.baseColor2 : "transparent"
|
||||
HoverHandler {
|
||||
cursorShape: root.enabled ? Qt.PointingHandCursor : undefined
|
||||
|
@ -116,16 +108,15 @@ ComboBox {
|
|||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
|
||||
y: root.height + 4
|
||||
|
||||
implicitWidth: root.width
|
||||
margins: 8
|
||||
implicitWidth: 290
|
||||
margins: Style.current.halfPadding
|
||||
|
||||
padding: 1
|
||||
verticalPadding: 8
|
||||
verticalPadding: Style.current.halfPadding
|
||||
|
||||
background: Rectangle {
|
||||
color: Theme.palette.statusSelect.menuItemBackgroundColor
|
||||
radius: 8
|
||||
border.color: Theme.palette.baseColor2
|
||||
radius: Style.current.radius
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
horizontalOffset: 0
|
||||
|
@ -138,6 +129,7 @@ ComboBox {
|
|||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: 0
|
||||
StatusBaseText {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: d.defaultDelegateHeight
|
||||
|
@ -164,20 +156,18 @@ ComboBox {
|
|||
spacing: root.spacing
|
||||
|
||||
StatusIcon {
|
||||
Layout.preferredWidth: 16
|
||||
Layout.preferredHeight: 16
|
||||
visible: !!icon
|
||||
icon: iconName
|
||||
color: root.enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
|
||||
width: 16
|
||||
height: 16
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
text: menuText
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
color: root.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
|
||||
color: isEditAction ? Theme.palette.primaryColor1 : root.enabled ? Theme.palette.directColor1 : Theme.palette.baseColor1
|
||||
font.pixelSize: root.font.pixelSize
|
||||
font.weight: root.currentIndex === menuIndex ? Font.DemiBold : Font.Normal
|
||||
}
|
||||
|
@ -185,7 +175,7 @@ ComboBox {
|
|||
Item { Layout.fillWidth: true }
|
||||
|
||||
Row {
|
||||
visible: !isCustomOrder
|
||||
visible: showUpDownArrows
|
||||
spacing: 4
|
||||
StatusFlatRoundButton {
|
||||
radius: 6
|
||||
|
@ -195,11 +185,12 @@ ComboBox {
|
|||
icon.width: 18
|
||||
icon.height: 18
|
||||
opacity: root.highlightedIndex === menuIndex || highlighted // not "visible, we want the item to stay put
|
||||
highlighted: root.currentIndex === menuIndex && root.sortOrder === Qt.AscendingOrder
|
||||
highlighted: root.currentIndex === menuIndex && root.currentSortOrder === Qt.AscendingOrder
|
||||
onClicked: {
|
||||
if (root.currentIndex !== menuIndex)
|
||||
root.currentIndex = menuIndex
|
||||
root.sortOrder = Qt.AscendingOrder
|
||||
d.currentIndex = menuIndex
|
||||
root.currentSortOrder = Qt.AscendingOrder
|
||||
root.popup.close()
|
||||
}
|
||||
}
|
||||
|
@ -211,11 +202,12 @@ ComboBox {
|
|||
icon.width: 18
|
||||
icon.height: 18
|
||||
opacity: root.highlightedIndex === menuIndex || highlighted // not "visible, we want the item to stay put
|
||||
highlighted: root.currentIndex === menuIndex && root.sortOrder === Qt.DescendingOrder
|
||||
highlighted: root.currentIndex === menuIndex && root.currentSortOrder === Qt.DescendingOrder
|
||||
onClicked: {
|
||||
if (root.currentIndex !== menuIndex)
|
||||
root.currentIndex = menuIndex
|
||||
root.sortOrder = Qt.DescendingOrder
|
||||
d.currentIndex = menuIndex
|
||||
root.currentSortOrder = Qt.DescendingOrder
|
||||
root.popup.close()
|
||||
}
|
||||
}
|
||||
|
@ -234,9 +226,15 @@ ComboBox {
|
|||
readonly property bool isSeparator: text === "---"
|
||||
|
||||
id: menuDelegate
|
||||
width: root.width
|
||||
width: ListView.view.width
|
||||
highlighted: root.highlightedIndex === index
|
||||
enabled: !isSeparator
|
||||
visible: {
|
||||
if (modelData["value"] === SortOrderComboBox.TokenOrderCustom) // hide "Custom order" menu entry if none defined
|
||||
return root.hasCustomOrderDefined
|
||||
return true
|
||||
}
|
||||
height: visible ? implicitHeight : 0
|
||||
leftPadding: isSeparator ? 0 : 14
|
||||
rightPadding: isSeparator ? 0 : 8
|
||||
verticalPadding: isSeparator ? 2 : 5
|
||||
|
@ -264,9 +262,9 @@ ComboBox {
|
|||
readonly property int menuIndex: menuDelegate.index
|
||||
readonly property string menuText: menuDelegate.text
|
||||
readonly property string iconName: menuDelegate.icon.name
|
||||
readonly property bool isCustomOrder: !menuDelegate.modelData["sortRoleName"]
|
||||
readonly property bool showUpDownArrows: menuDelegate.modelData["sortRoleName"] !== ""
|
||||
readonly property bool isEditAction: modelData["value"] === SortOrderComboBox.TokenOrderCreateCustom
|
||||
sourceComponent: menuDelegate.isSeparator ? separatorMenuComponent : regularMenuComponent
|
||||
}
|
||||
onClicked: root.currentIndex = index
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ Control {
|
|||
required property var baseModel
|
||||
|
||||
readonly property bool dirty: d.controller.dirty
|
||||
readonly property bool hasSettings: d.controller.hasSettings
|
||||
|
||||
background: null
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ Control {
|
|||
required property var baseModel
|
||||
|
||||
readonly property bool dirty: d.controller.dirty
|
||||
readonly property bool hasSettings: d.controller.hasSettings
|
||||
|
||||
background: null
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ Item {
|
|||
QtObject {
|
||||
id: d
|
||||
property var marketValueStore : RootStore.marketValueStore
|
||||
readonly property string symbol: root.token ? root.token.symbol : ""
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
@ -286,8 +287,8 @@ Item {
|
|||
}
|
||||
|
||||
Connections {
|
||||
target: token
|
||||
function onSymbolChanged() { graphDetail.updateBalanceStore() }
|
||||
target: d
|
||||
function onSymbolChanged() { if (d.symbol) graphDetail.updateBalanceStore() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
import Qt.labs.settings 1.1
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core 0.1
|
||||
|
@ -19,14 +20,16 @@ import shared.popups 1.0
|
|||
import utils 1.0
|
||||
|
||||
import AppLayouts.Wallet.views.collectibles 1.0
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
StatusScrollView {
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
required property var collectiblesModel
|
||||
property bool sendEnabled: true
|
||||
property bool filterVisible
|
||||
|
||||
signal collectibleClicked(int chainId, string contractAddress, string tokenId, string uid)
|
||||
signal sendRequested(string symbol)
|
||||
|
@ -34,6 +37,8 @@ StatusScrollView {
|
|||
signal switchToCommunityRequested(string communityId)
|
||||
signal manageTokensRequested()
|
||||
|
||||
spacing: 0
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
|
@ -41,11 +46,7 @@ StatusScrollView {
|
|||
readonly property int communityCellHeight: 242
|
||||
readonly property int cellWidth: 176
|
||||
|
||||
readonly property bool isCustomView: d.controller.hasSettings // TODO add respect other predefined orders (#12517)
|
||||
|
||||
function symbolIsVisible(symbol) {
|
||||
return d.controller.filterAcceptsSymbol(symbol)
|
||||
}
|
||||
readonly property bool isCustomView: cmbTokenOrder.currentValue === SortOrderComboBox.TokenOrderCustom
|
||||
|
||||
readonly property var renamedModel: RolesRenamingModel {
|
||||
sourceModel: root.collectiblesModel
|
||||
|
@ -58,86 +59,126 @@ StatusScrollView {
|
|||
]
|
||||
}
|
||||
|
||||
readonly property var regularCollectiblesModel: SortFilterProxyModel {
|
||||
sourceModel: d.renamedModel
|
||||
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.symbolIsVisible(model.symbol) && !model.communityId
|
||||
}
|
||||
}
|
||||
// TODO add other sort/filter using ManageTokensController (#12517)
|
||||
]
|
||||
sorters: [
|
||||
RoleSorter {
|
||||
roleName: "name"
|
||||
enabled: !d.isCustomView
|
||||
},
|
||||
ExpressionSorter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.controller.lessThan(modelLeft.symbol, modelRight.symbol)
|
||||
}
|
||||
enabled: d.isCustomView
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
readonly property var communityCollectiblesModel: SortFilterProxyModel {
|
||||
sourceModel: d.renamedModel
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.symbolIsVisible(model.symbol) && !!model.communityId
|
||||
}
|
||||
}
|
||||
// TODO add other sort/filter using ManageTokensController (#12517)
|
||||
]
|
||||
sorters: [
|
||||
RoleSorter {
|
||||
roleName: "name"
|
||||
enabled: !d.isCustomView
|
||||
},
|
||||
ExpressionSorter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.controller.lessThan(modelLeft.symbol, modelRight.symbol)
|
||||
}
|
||||
enabled: d.isCustomView
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
readonly property bool hasCollectibles: d.regularCollectiblesModel.count
|
||||
readonly property bool hasCommunityCollectibles: d.communityCollectiblesModel.count
|
||||
readonly property bool hasCollectibles: regularCollectiblesView.count
|
||||
readonly property bool hasCommunityCollectibles: communityCollectiblesView.count
|
||||
|
||||
readonly property var controller: ManageTokensController {
|
||||
settingsKey: "WalletCollectibles"
|
||||
}
|
||||
|
||||
function hideAllCommunityTokens(communityId) {
|
||||
const tokenSymbols = ModelUtils.getAll(communityCollectiblesModel, "symbol", "communityId", communityId)
|
||||
const tokenSymbols = ModelUtils.getAll(communityCollectiblesView.model, "symbol", "communityId", communityId)
|
||||
d.controller.settingsHideCommunityTokens(communityId, tokenSymbols)
|
||||
}
|
||||
}
|
||||
|
||||
component CustomSFPM: SortFilterProxyModel {
|
||||
id: customFilter
|
||||
property bool isCommunity
|
||||
|
||||
sourceModel: d.renamedModel
|
||||
proxyRoles: JoinRole {
|
||||
name: "groupName"
|
||||
roleNames: ["collectionName", "communityName"]
|
||||
}
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.controller.filterAcceptsSymbol(model.symbol) && (customFilter.isCommunity ? !!model.communityId : !model.communityId)
|
||||
}
|
||||
}
|
||||
]
|
||||
sorters: [
|
||||
ExpressionSorter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.controller.lessThan(modelLeft.symbol, modelRight.symbol)
|
||||
}
|
||||
enabled: d.isCustomView
|
||||
},
|
||||
RoleSorter {
|
||||
roleName: cmbTokenOrder.currentSortRoleName
|
||||
sortOrder: cmbTokenOrder.currentSortOrder
|
||||
enabled: !d.isCustomView
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Settings {
|
||||
category: "CollectiblesViewSortSettings"
|
||||
property alias currentSortField: cmbTokenOrder.currentIndex
|
||||
property alias currentSortOrder: cmbTokenOrder.currentSortOrder
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
width: root.availableWidth
|
||||
spacing: 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: root.filterVisible && (d.hasCollectibles || d.hasCommunityCollectibles) ? implicitHeight : 0
|
||||
spacing: 20
|
||||
opacity: Layout.preferredHeight < implicitHeight ? 0 : 1
|
||||
|
||||
Behavior on Layout.preferredHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||
Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
StatusBaseText {
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
text: qsTr("Sort by:")
|
||||
}
|
||||
|
||||
SortOrderComboBox {
|
||||
id: cmbTokenOrder
|
||||
hasCustomOrderDefined: d.controller.hasSettings
|
||||
model: [
|
||||
{ value: SortOrderComboBox.TokenOrderDateAdded, text: qsTr("Date added"), icon: "calendar", sortRoleName: "dateAdded" }, // FIXME sortRoleName #12942
|
||||
{ value: SortOrderComboBox.TokenOrderAlpha, text: qsTr("Collectible name"), icon: "bold", sortRoleName: "name" },
|
||||
{ value: SortOrderComboBox.TokenOrderGroupName, text: qsTr("Collection/community name"), icon: "group", sortRoleName: "groupName" }, // Custom SFPM role communityName || collectionName
|
||||
{ value: SortOrderComboBox.TokenOrderCustom, text: qsTr("Custom order"), icon: "exchange", sortRoleName: "" },
|
||||
{ value: SortOrderComboBox.TokenOrderNone, text: "---", icon: "", sortRoleName: "" }, // separator
|
||||
{ value: SortOrderComboBox.TokenOrderCreateCustom, text: hasCustomOrderDefined ? qsTr("Edit custom order →") : qsTr("Create custom order →"),
|
||||
icon: "", sortRoleName: "" }
|
||||
]
|
||||
onCreateOrEditRequested: {
|
||||
root.manageTokensRequested()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
ShapeRectangle {
|
||||
visible: !d.hasCollectibles && !d.hasCommunityCollectibles
|
||||
Layout.fillWidth: true
|
||||
visible: !d.hasCollectibles && !d.hasCommunityCollectibles
|
||||
text: qsTr("Collectibles will appear here")
|
||||
}
|
||||
|
||||
StatusScrollView {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
leftPadding: 0
|
||||
verticalPadding: 0
|
||||
contentWidth: availableWidth
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
CustomGridView {
|
||||
id: regularCollectiblesView
|
||||
cellHeight: d.cellHeight
|
||||
model: d.regularCollectiblesModel
|
||||
visible: d.hasCollectibles
|
||||
model: CustomSFPM {}
|
||||
}
|
||||
|
||||
StatusDialogDivider {
|
||||
|
@ -170,9 +211,10 @@ StatusScrollView {
|
|||
}
|
||||
|
||||
CustomGridView {
|
||||
id: communityCollectiblesView
|
||||
cellHeight: d.communityCellHeight
|
||||
model: d.communityCollectiblesModel
|
||||
visible: d.hasCommunityCollectibles
|
||||
model: CustomSFPM { isCommunity: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,7 +266,7 @@ StatusScrollView {
|
|||
width: d.cellWidth
|
||||
height: isCommunityCollectible ? d.communityCellHeight : d.cellHeight
|
||||
title: model.name ? model.name : "..."
|
||||
subTitle: model.collectionName ?? ""
|
||||
subTitle: model.collectionName ? model.collectionName : model.collectionUid ? model.collectionUid : ""
|
||||
mediaUrl: model.mediaUrl ?? ""
|
||||
mediaType: model.mediaType ?? ""
|
||||
fallbackImageUrl: model.imageUrl ?? ""
|
||||
|
@ -330,7 +372,7 @@ StatusScrollView {
|
|||
close()
|
||||
Global.displayToastMessage(
|
||||
qsTr("%1 was successfully hidden. You can toggle collectible visibility via %2.").arg(formattedName)
|
||||
.arg(`<a style="text-decoration:none" href="#${Constants.appSection.profile}/${Constants.settingsSubsection.wallet}">` + qsTr("Settings", "Go to Settings") + "</a>"),
|
||||
.arg(`<a style="text-decoration:none" href="#${Constants.appSection.profile}/${Constants.settingsSubsection.wallet}/${Constants.walletSettingsSubsection.manageCollectibles}">` + qsTr("Settings", "Go to Settings") + "</a>"),
|
||||
"",
|
||||
"checkmark-circle",
|
||||
false,
|
||||
|
@ -362,7 +404,7 @@ StatusScrollView {
|
|||
close()
|
||||
Global.displayToastMessage(
|
||||
qsTr("%1 community collectibles were successfully hidden. You can toggle collectible visibility via %2.").arg(communityName)
|
||||
.arg(`<a style="text-decoration:none" href="#${Constants.appSection.profile}/${Constants.settingsSubsection.wallet}">` + qsTr("Settings", "Go to Settings") + "</a>"),
|
||||
.arg(`<a style="text-decoration:none" href="#${Constants.appSection.profile}/${Constants.settingsSubsection.wallet}/${Constants.walletSettingsSubsection.manageCollectibles}">` + qsTr("Settings", "Go to Settings") + "</a>"),
|
||||
"",
|
||||
"checkmark-circle",
|
||||
false,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.13
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
import utils 1.0
|
||||
import shared.controls 1.0
|
||||
|
@ -92,6 +93,8 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
StatusTabBar {
|
||||
id: walletTabBar
|
||||
objectName: "rightSideWalletTabBar"
|
||||
|
@ -116,12 +119,20 @@ Item {
|
|||
RootStore.setCurrentViewedHoldingType(walletTabBar.currentIndex === 1 ? Constants.TokenType.ERC721 : Constants.TokenType.ERC20)
|
||||
}
|
||||
}
|
||||
StatusFlatButton {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
id: filterButton
|
||||
icon.name: "filter"
|
||||
checkable: true
|
||||
icon.color: checked ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
|
||||
Behavior on icon.color { ColorAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||
highlighted: checked
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: mainViewLoader
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
Layout.bottomMargin: Style.current.padding
|
||||
sourceComponent: {
|
||||
switch (walletTabBar.currentIndex) {
|
||||
case 0: return assetsView
|
||||
|
@ -138,6 +149,7 @@ Item {
|
|||
overview: RootStore.overview
|
||||
networkConnectionStore: root.networkConnectionStore
|
||||
assetDetailsLaunched: stack.currentIndex === 2
|
||||
filterVisible: filterButton.checked
|
||||
onAssetClicked: {
|
||||
assetDetailView.token = token
|
||||
RootStore.setCurrentViewedHolding(token.symbol, Constants.TokenType.ERC20)
|
||||
|
@ -152,7 +164,8 @@ Item {
|
|||
}
|
||||
onReceiveRequested: (symbol) => root.launchShareAddressModal()
|
||||
onSwitchToCommunityRequested: (communityId) => Global.switchToCommunity(communityId)
|
||||
onManageTokensRequested: Global.changeAppSectionBySectionType(Constants.appSection.profile, Constants.settingsSubsection.wallet)
|
||||
onManageTokensRequested: Global.changeAppSectionBySectionType(Constants.appSection.profile, Constants.settingsSubsection.wallet,
|
||||
Constants.walletSettingsSubsection.manageAssets)
|
||||
}
|
||||
}
|
||||
Component {
|
||||
|
@ -160,6 +173,7 @@ Item {
|
|||
CollectiblesView {
|
||||
collectiblesModel: RootStore.collectiblesStore.ownedCollectibles
|
||||
sendEnabled: root.networkConnectionStore.sendBuyBridgeEnabled && !RootStore.overview.isWatchOnlyAccount && RootStore.overview.canSend
|
||||
filterVisible: filterButton.checked
|
||||
onCollectibleClicked: {
|
||||
RootStore.collectiblesStore.getDetailedCollectible(chainId, contractAddress, tokenId)
|
||||
RootStore.setCurrentViewedHolding(uid, Constants.TokenType.ERC721)
|
||||
|
@ -174,7 +188,8 @@ Item {
|
|||
}
|
||||
onReceiveRequested: (symbol) => root.launchShareAddressModal()
|
||||
onSwitchToCommunityRequested: (communityId) => Global.switchToCommunity(communityId)
|
||||
onManageTokensRequested: Global.changeAppSectionBySectionType(Constants.appSection.profile, Constants.settingsSubsection.wallet)
|
||||
onManageTokensRequested: Global.changeAppSectionBySectionType(Constants.appSection.profile, Constants.settingsSubsection.wallet,
|
||||
Constants.walletSettingsSubsection.manageCollectibles)
|
||||
}
|
||||
}
|
||||
Component {
|
||||
|
|
|
@ -115,6 +115,7 @@ Item {
|
|||
|
||||
function onActiveSectionChanged() {
|
||||
createChatView.opened = false
|
||||
Global.settingsSubSubsection = -1
|
||||
}
|
||||
|
||||
function onOpenActivityCenter() {
|
||||
|
@ -325,13 +326,14 @@ Item {
|
|||
appMain.rootStore.mainModuleInst.setNthEnabledSectionActive(nthSection)
|
||||
}
|
||||
|
||||
function onAppSectionBySectionTypeChanged(sectionType: int, subsection: int) {
|
||||
function onAppSectionBySectionTypeChanged(sectionType, subsection, settingsSubsection = -1) {
|
||||
if(!appMain.rootStore.mainModuleInst)
|
||||
return
|
||||
|
||||
appMain.rootStore.mainModuleInst.setActiveSectionBySectionType(sectionType)
|
||||
if (sectionType === Constants.appSection.profile) {
|
||||
Global.settingsSubsection = subsection;
|
||||
Global.settingsSubSubsection = settingsSubsection;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -750,7 +752,7 @@ Item {
|
|||
active: appMain.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled
|
||||
delay: false
|
||||
onClicked: Global.openTestnetPopup()
|
||||
onCloseClicked: hide()
|
||||
closeBtnVisible: false
|
||||
}
|
||||
|
||||
ModuleWarning {
|
||||
|
@ -1410,7 +1412,11 @@ Item {
|
|||
id: sendModal
|
||||
active: false
|
||||
|
||||
function open() {
|
||||
function open(address = "") {
|
||||
if (!!address) {
|
||||
preSelectedRecipient = address
|
||||
preSelectedRecipientType = TabAddressSelectorView.Type.Address
|
||||
}
|
||||
this.active = true
|
||||
this.item.open()
|
||||
}
|
||||
|
@ -1626,7 +1632,8 @@ Item {
|
|||
const sectionArgs = link.substring(1).split("/")
|
||||
const section = sectionArgs[0]
|
||||
let subsection = sectionArgs.length > 1 ? sectionArgs[1] : 0
|
||||
Global.changeAppSectionBySectionType(section, subsection)
|
||||
let subsubsection = sectionArgs.length > 2 ? sectionArgs[2] : -1
|
||||
Global.changeAppSectionBySectionType(section, subsection, subsubsection)
|
||||
}
|
||||
else
|
||||
Global.openLink(link)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import Qt.labs.settings 1.1
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
@ -19,7 +20,9 @@ import shared.stores 1.0
|
|||
import shared.controls 1.0
|
||||
import shared.popups 1.0
|
||||
|
||||
StatusScrollView {
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
// expected roles: name, symbol, enabledNetworkBalance, enabledNetworkCurrencyBalance, currencyPrice, changePct24hour, communityId, communityName, communityImage
|
||||
|
@ -28,6 +31,7 @@ StatusScrollView {
|
|||
property var networkConnectionStore
|
||||
property var overview
|
||||
property bool assetDetailsLaunched: false
|
||||
property bool filterVisible
|
||||
|
||||
signal assetClicked(var token)
|
||||
signal sendRequested(string symbol)
|
||||
|
@ -35,15 +39,15 @@ StatusScrollView {
|
|||
signal switchToCommunityRequested(string communityId)
|
||||
signal manageTokensRequested()
|
||||
|
||||
contentWidth: availableWidth
|
||||
spacing: 0
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property int selectedAssetIndex: -1
|
||||
|
||||
readonly property bool isCustomView: d.controller.hasSettings // TODO add respect other predefined orders (#12517)
|
||||
readonly property bool isCustomView: cmbTokenOrder.currentValue === SortOrderComboBox.TokenOrderCustom
|
||||
|
||||
function symbolIsVisible(symbol) {
|
||||
function tokenIsVisible(symbol, currencyBalance) {
|
||||
if (symbol === "ETH") // always visible
|
||||
return true
|
||||
if (!d.controller.filterAcceptsSymbol(symbol)) // explicitely hidden
|
||||
|
@ -51,71 +55,137 @@ StatusScrollView {
|
|||
if (symbol === "SNT" || symbol === "STT" || symbol === "DAI") // visible by default
|
||||
return true
|
||||
// We'll receive the tokens only with non zero balance except for Eth, Dai or SNT/STT
|
||||
return true
|
||||
return !!currencyBalance // TODO handle UI threshold (#12611)
|
||||
}
|
||||
|
||||
readonly property var regularAssetsModel: SortFilterProxyModel {
|
||||
sourceModel: root.assets
|
||||
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.symbolIsVisible(model.symbol) && !model.communityId
|
||||
}
|
||||
}
|
||||
// TODO add other sort/filter using ManageTokensController (#12517)
|
||||
]
|
||||
sorters: ExpressionSorter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.controller.lessThan(modelLeft.symbol, modelRight.symbol)
|
||||
}
|
||||
enabled: d.isCustomView
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var communityAssetsModel: SortFilterProxyModel {
|
||||
sourceModel: root.assets
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.symbolIsVisible(model.symbol) && !!model.communityId
|
||||
}
|
||||
}
|
||||
// TODO add other sort/filter using ManageTokensController (#12517)
|
||||
]
|
||||
sorters: ExpressionSorter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.controller.lessThan(modelLeft.symbol, modelRight.symbol)
|
||||
}
|
||||
enabled: d.isCustomView
|
||||
}
|
||||
}
|
||||
readonly property bool hasCommunityAssets: d.communityAssetsModel.count
|
||||
|
||||
readonly property var controller: ManageTokensController {
|
||||
settingsKey: "WalletAssets"
|
||||
}
|
||||
|
||||
readonly property bool hasCommunityAssets: communityAssetsLV.count
|
||||
|
||||
function hideAllCommunityTokens(communityId) {
|
||||
const tokenSymbols = ModelUtils.getAll(communityAssetsModel, "symbol", "communityId", communityId)
|
||||
const tokenSymbols = ModelUtils.getAll(communityAssetsLV.model, "symbol", "communityId", communityId)
|
||||
d.controller.settingsHideCommunityTokens(communityId, tokenSymbols)
|
||||
}
|
||||
}
|
||||
|
||||
component CustomSFPM: SortFilterProxyModel {
|
||||
id: customFilter
|
||||
property bool isCommunity
|
||||
|
||||
sourceModel: root.assets
|
||||
proxyRoles: [
|
||||
ExpressionRole {
|
||||
name: "currentBalance"
|
||||
expression: model.enabledNetworkBalance.amount
|
||||
},
|
||||
ExpressionRole {
|
||||
name: "currentCurrencyBalance"
|
||||
expression: model.enabledNetworkCurrencyBalance.amount
|
||||
},
|
||||
ExpressionRole {
|
||||
name: "tokenPrice"
|
||||
expression: model.currencyPrice.amount
|
||||
}
|
||||
]
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.tokenIsVisible(model.symbol, model.currentCurrencyBalance) && (customFilter.isCommunity ? !!model.communityId : !model.communityId)
|
||||
}
|
||||
}
|
||||
]
|
||||
sorters: [
|
||||
ExpressionSorter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.controller.lessThan(modelLeft.symbol, modelRight.symbol)
|
||||
}
|
||||
enabled: d.isCustomView
|
||||
},
|
||||
RoleSorter {
|
||||
roleName: cmbTokenOrder.currentSortRoleName
|
||||
sortOrder: cmbTokenOrder.currentSortOrder
|
||||
enabled: !d.isCustomView
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Settings {
|
||||
category: "AssetsViewSortSettings"
|
||||
property alias currentSortField: cmbTokenOrder.currentIndex
|
||||
property alias currentSortOrder: cmbTokenOrder.currentSortOrder
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
width: root.availableWidth
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: root.filterVisible ? implicitHeight : 0
|
||||
spacing: 20
|
||||
opacity: Layout.preferredHeight < implicitHeight ? 0 : 1
|
||||
|
||||
Behavior on Layout.preferredHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||
Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } }
|
||||
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.current.halfPadding
|
||||
|
||||
StatusBaseText {
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
text: qsTr("Sort by:")
|
||||
}
|
||||
|
||||
SortOrderComboBox {
|
||||
id: cmbTokenOrder
|
||||
hasCustomOrderDefined: d.controller.hasSettings
|
||||
model: [
|
||||
{ value: SortOrderComboBox.TokenOrderCurrencyBalance, text: qsTr("Asset balance value"), icon: "token-sale", sortRoleName: "currentCurrencyBalance" }, // custom SFPM ExpressionRole on "enabledNetworkCurrencyBalance" amount
|
||||
{ value: SortOrderComboBox.TokenOrderBalance, text: qsTr("Asset balance"), icon: "channel", sortRoleName: "currentBalance" }, // custom SFPM ExpressionRole on "enabledNetworkBalance" amount
|
||||
{ value: SortOrderComboBox.TokenOrderCurrencyPrice, text: qsTr("Asset value"), icon: "token", sortRoleName: "tokenPrice" }, // custom SFPM ExpressionRole on "currencyPrice" amount
|
||||
{ value: SortOrderComboBox.TokenOrder1WChange, text: qsTr("1d change: balance value"), icon: "history", sortRoleName: "changePct24hour" }, // FIXME changePct1week role missing in backend!!!
|
||||
{ value: SortOrderComboBox.TokenOrderAlpha, text: qsTr("Asset name"), icon: "bold", sortRoleName: "name" },
|
||||
{ value: SortOrderComboBox.TokenOrderCustom, text: qsTr("Custom order"), icon: "exchange", sortRoleName: "" },
|
||||
{ value: SortOrderComboBox.TokenOrderNone, text: "---", icon: "", sortRoleName: "" }, // separator
|
||||
{ value: SortOrderComboBox.TokenOrderCreateCustom, text: hasCustomOrderDefined ? qsTr("Edit custom order →") : qsTr("Create custom order →"),
|
||||
icon: "", sortRoleName: "" }
|
||||
]
|
||||
onCreateOrEditRequested: {
|
||||
root.manageTokensRequested()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
StatusScrollView {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
leftPadding: 0
|
||||
verticalPadding: 0
|
||||
contentWidth: availableWidth
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
StatusListView {
|
||||
id: regularAssetsLV
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
interactive: false
|
||||
objectName: "assetViewStatusListView"
|
||||
model: d.regularAssetsModel
|
||||
model: CustomSFPM {}
|
||||
delegate: delegateLoader
|
||||
}
|
||||
|
||||
|
@ -149,13 +219,16 @@ StatusScrollView {
|
|||
}
|
||||
|
||||
StatusListView {
|
||||
id: communityAssetsLV
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
interactive: false
|
||||
objectName: "communityAssetViewStatusListView"
|
||||
model: d.communityAssetsModel
|
||||
model: CustomSFPM { isCommunity: true }
|
||||
delegate: delegateLoader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: delegateLoader
|
||||
|
@ -188,7 +261,8 @@ StatusScrollView {
|
|||
if (networkConnectionStore && networkConnectionStore.noTokenBalanceAvailable) {
|
||||
return ""
|
||||
}
|
||||
return LocaleUtils.currencyAmountToLocaleString(modelData.enabledNetworkBalance)
|
||||
return "%1 %2".arg(LocaleUtils.stripTrailingZeroes(LocaleUtils.numberToLocaleString(modelData.enabledNetworkBalance.amount, 6), Qt.locale()))
|
||||
.arg(modelData.enabledNetworkBalance.symbol)
|
||||
}
|
||||
errorMode: !!networkConnectionStore ? networkConnectionStore.noBlockchainConnectionAndNoCache && !networkConnectionStore.noMarketConnectionAndNoCache : false
|
||||
errorIcon.tooltip.text: !!networkConnectionStore ? networkConnectionStore.noBlockchainConnectionAndNoCacheText : ""
|
||||
|
@ -196,8 +270,8 @@ StatusScrollView {
|
|||
if (mouse.button === Qt.LeftButton) {
|
||||
RootStore.getHistoricalDataForToken(modelData.symbol, RootStore.currencyStore.currentCurrency)
|
||||
d.selectedAssetIndex = delegateIndex
|
||||
let selectedModel = !!modelData.communityId ? d.communityAssetsModel: d.regularAssetsModel
|
||||
assetClicked(selectedModel.get(delegateIndex))
|
||||
let selectedView = !!modelData.communityId ? communityAssetsLV : regularAssetsLV
|
||||
assetClicked(selectedView.model.get(delegateIndex))
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
Global.openMenu(tokenContextMenu, this,
|
||||
{symbol: modelData.symbol, assetName: modelData.name, assetImage: symbolUrl,
|
||||
|
@ -208,8 +282,8 @@ StatusScrollView {
|
|||
Component.onCompleted: {
|
||||
// on Model reset if the detail view is shown, update the data in background.
|
||||
if(root.assetDetailsLaunched && delegateIndex === d.selectedAssetIndex) {
|
||||
let selectedModel = !!modelData.communityId ? d.communityAssetsModel: d.regularAssetsModel
|
||||
assetClicked(selectedModel.get(delegateIndex))
|
||||
let selectedView = !!modelData.communityId ? communityAssetsLV : regularAssetsLV
|
||||
assetClicked(selectedView.model.get(delegateIndex))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -299,7 +373,7 @@ StatusScrollView {
|
|||
close()
|
||||
Global.displayToastMessage(
|
||||
qsTr("%1 was successfully hidden. You can toggle asset visibility via %2.").arg(formattedName)
|
||||
.arg(`<a style="text-decoration:none" href="#${Constants.appSection.profile}/${Constants.settingsSubsection.wallet}">` + qsTr("Settings", "Go to Settings") + "</a>"),
|
||||
.arg(`<a style="text-decoration:none" href="#${Constants.appSection.profile}/${Constants.settingsSubsection.wallet}/${Constants.walletSettingsSubsection.manageAssets}">` + qsTr("Settings", "Go to Settings") + "</a>"),
|
||||
"",
|
||||
"checkmark-circle",
|
||||
false,
|
||||
|
@ -331,7 +405,7 @@ StatusScrollView {
|
|||
close()
|
||||
Global.displayToastMessage(
|
||||
qsTr("%1 community assets were successfully hidden. You can toggle asset visibility via %2.").arg(communityName)
|
||||
.arg(`<a style="text-decoration:none" href="#${Constants.appSection.profile}/${Constants.settingsSubsection.wallet}">` + qsTr("Settings", "Go to Settings") + "</a>"),
|
||||
.arg(`<a style="text-decoration:none" href="#${Constants.appSection.profile}/${Constants.settingsSubsection.wallet}/${Constants.walletSettingsSubsection.manageAssets}">` + qsTr("Settings", "Go to Settings") + "</a>"),
|
||||
"",
|
||||
"checkmark-circle",
|
||||
false,
|
||||
|
@ -342,4 +416,3 @@ StatusScrollView {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -352,6 +352,14 @@ QtObject {
|
|||
readonly property int backUpSeed: 17
|
||||
}
|
||||
|
||||
readonly property QtObject walletSettingsSubsection: QtObject {
|
||||
readonly property int manageNetworks: 0
|
||||
readonly property int manageAccounts: 1
|
||||
readonly property int manageAssets: 2
|
||||
readonly property int manageCollectibles: 3
|
||||
readonly property int manageTokenLists: 4
|
||||
}
|
||||
|
||||
readonly property QtObject currentUserStatus: QtObject{
|
||||
readonly property int unknown: 0
|
||||
readonly property int automatic: 1
|
||||
|
|
|
@ -9,6 +9,7 @@ QtObject {
|
|||
property var applicationWindow
|
||||
property bool activityPopupOpened: false
|
||||
property int settingsSubsection: Constants.settingsSubsection.profile
|
||||
property int settingsSubSubsection: -1
|
||||
|
||||
property var userProfile
|
||||
property bool appIsReady: false
|
||||
|
@ -62,7 +63,7 @@ QtObject {
|
|||
signal activateDeepLink(string link)
|
||||
|
||||
signal setNthEnabledSectionActive(int nthSection)
|
||||
signal appSectionBySectionTypeChanged(int sectionType, int subsection)
|
||||
signal appSectionBySectionTypeChanged(int sectionType, int subsection, int settingsSubsection)
|
||||
|
||||
signal openSendModal(string address)
|
||||
signal switchToCommunity(string communityId)
|
||||
|
@ -103,8 +104,8 @@ QtObject {
|
|||
root.openDownloadModalRequested(available, version, url);
|
||||
}
|
||||
|
||||
function changeAppSectionBySectionType(sectionType, subsection = 0) {
|
||||
root.appSectionBySectionTypeChanged(sectionType, subsection);
|
||||
function changeAppSectionBySectionType(sectionType, subsection = 0, settingsSubsection = -1) {
|
||||
root.appSectionBySectionTypeChanged(sectionType, subsection, settingsSubsection)
|
||||
}
|
||||
|
||||
function openMenu(menuComponent, menuParent, params = {}, point = undefined) {
|
||||
|
|
Loading…
Reference in New Issue