feat(token mgmt): update main wallet view layout with community assets
- update the AssetsView.qml view and delegates according to the latest design - add AssetsView to Storybook - add new section for Community Assets - (re)use the community badge with tooltip and link action to take the user to the respective community - add Community Assets info icon + popup - create context menu for token delegates with actions (Send/Receive/Manage tokens/Hide) - add confirmation popups when hiding a single or all community tokens - emit a toast bubble after hiding the token(s) - plus related controller/backend methods for handling the settings-related actions - some smaller fixes/cleanups Fixes #12369 Fixes #12372
This commit is contained in:
parent
8e0db2e666
commit
3b60506460
|
@ -0,0 +1,56 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
|
||||
import mainui 1.0
|
||||
import utils 1.0
|
||||
|
||||
import shared.views 1.0
|
||||
|
||||
import Storybook 1.0
|
||||
import Models 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
|
||||
Logs { id: logs }
|
||||
|
||||
orientation: Qt.Horizontal
|
||||
|
||||
ManageTokensModel {
|
||||
id: assetsModel
|
||||
}
|
||||
|
||||
Popups {
|
||||
popupParent: root
|
||||
rootStore: QtObject {}
|
||||
communityTokensStore: QtObject {}
|
||||
}
|
||||
|
||||
AssetsView {
|
||||
id: assetsView
|
||||
SplitView.preferredWidth: 600
|
||||
SplitView.fillHeight: true
|
||||
assets: assetsModel
|
||||
onAssetClicked: logs.logEvent("onAssetClicked", ["token"], [token.symbol, token.communityId])
|
||||
onSendRequested: logs.logEvent("onSendRequested", ["symbol"], arguments)
|
||||
onReceiveRequested: logs.logEvent("onReceiveRequested", ["symbol"], arguments)
|
||||
onSwitchToCommunityRequested: logs.logEvent("onSwitchToCommunityRequested", ["communityId"], arguments)
|
||||
onManageTokensRequested: logs.logEvent("onManageTokensRequested")
|
||||
}
|
||||
|
||||
LogsAndControlsPanel {
|
||||
id: logsAndControlsPanel
|
||||
|
||||
SplitView.minimumWidth: 150
|
||||
SplitView.preferredWidth: 250
|
||||
|
||||
logsView.logText: logs.logText
|
||||
}
|
||||
}
|
||||
|
||||
// category: Views
|
||||
// https://www.figma.com/file/FkFClTCYKf83RJWoifWgoX/Wallet-v2?type=design&node-id=17159-67977&mode=design&t=s5EXsh6Vi4nTNYUh-0
|
||||
// https://www.figma.com/file/FkFClTCYKf83RJWoifWgoX/Wallet-v2?type=design&node-id=17171-285559&mode=design&t=s5EXsh6Vi4nTNYUh-0
|
|
@ -44,6 +44,11 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {
|
||||
amount: 10.37,
|
||||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
communityId: "ddls",
|
||||
communityName: "Doodles",
|
||||
communityImage: ModelsData.collectibles.doodles // FIXME backend
|
||||
|
@ -166,6 +171,11 @@ ListModel {
|
|||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
currencyPrice: {
|
||||
amount: 1480.113406237,
|
||||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
changePct24hour: -3.51,
|
||||
communityId: "",
|
||||
communityName: "",
|
||||
|
@ -185,15 +195,21 @@ ListModel {
|
|||
enabledNetworkBalance: ({
|
||||
displayDecimals: true,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 324343.3,
|
||||
amount: 0,
|
||||
symbol: "SNT"
|
||||
}),
|
||||
enabledNetworkCurrencyBalance: ({
|
||||
displayDecimals: 4,
|
||||
stripTrailingZeroes: true,
|
||||
amount: 2.333321323400,
|
||||
amount: 0,
|
||||
symbol: "EUR"
|
||||
}),
|
||||
currencyPrice: {
|
||||
amount: 1.40627,
|
||||
symbol: "EUR",
|
||||
displayDecimals: 2
|
||||
},
|
||||
changePct24hour: 1.3,
|
||||
symbol: "SNT",
|
||||
name: "Status",
|
||||
communityId: "",
|
||||
|
|
|
@ -2,4 +2,5 @@ import QtQuick 2.15
|
|||
|
||||
QtObject {
|
||||
property var blockchainNetworksDown: []
|
||||
property bool sendBuyBridgeEnabled: true
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ QtObject {
|
|||
property var currentCurrency
|
||||
property bool neverAskAboutUnfurlingAgain: false
|
||||
|
||||
property var currencyStore
|
||||
property var currencyStore: CurrenciesStore {}
|
||||
property var history
|
||||
|
||||
property var getNetworkIcon
|
||||
|
@ -37,4 +37,8 @@ QtObject {
|
|||
console.log("STUB: setNeverAskAboutUnfurlingAgain:", value)
|
||||
neverAskAboutUnfurlingAgain = value
|
||||
}
|
||||
|
||||
function getHistoricalDataForToken(symbol, currency) {
|
||||
console.log("STUB: getHistoricalDataForToken:", symbol, currency)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,11 @@ public:
|
|||
Q_INVOKABLE QVariant get(QAbstractItemModel *model, int row,
|
||||
const QString &roleName) const;
|
||||
|
||||
Q_INVOKABLE QVariantList getAll(QAbstractItemModel* model,
|
||||
const QString& roleName,
|
||||
const QString& filterRoleName,
|
||||
const QVariant& filterValue) const;
|
||||
|
||||
Q_INVOKABLE bool contains(QAbstractItemModel *model, const QString &roleName, const QVariant &value, int mode = Qt::CaseSensitive) const;
|
||||
|
||||
///< performs a strict check whether @lhs and @rhs arrays (QList<T>) contain the same elements;
|
||||
|
|
|
@ -116,6 +116,7 @@ Row {
|
|||
id: textLayout
|
||||
width: !iconOrImage.active ? parent.width :
|
||||
parent.width - iconOrImage.width - parent.spacing
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Row {
|
||||
id: headerTitleRow
|
||||
width: parent.width
|
||||
|
|
|
@ -60,6 +60,32 @@ QVariant ModelUtilsInternal::get(QAbstractItemModel *model,
|
|||
return {};
|
||||
}
|
||||
|
||||
QVariantList ModelUtilsInternal::getAll(QAbstractItemModel* model,
|
||||
const QString& roleName,
|
||||
const QString& filterRoleName,
|
||||
const QVariant& filterValue) const
|
||||
{
|
||||
if (!model || filterValue.isNull())
|
||||
return {};
|
||||
|
||||
const auto role = roleByName(model, roleName);
|
||||
if (role == -1)
|
||||
return {};
|
||||
|
||||
const auto filterRole = roleByName(model, filterRoleName);
|
||||
if (filterRole == -1)
|
||||
return {};
|
||||
|
||||
QVariantList result;
|
||||
const auto size = model->rowCount();
|
||||
for (auto i = 0; i < size; i++) {
|
||||
const auto srcIndex = model->index(i, 0);
|
||||
if (srcIndex.data(filterRole) == filterValue)
|
||||
result.append(srcIndex.data(role));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ModelUtilsInternal::contains(QAbstractItemModel* model,
|
||||
const QString& roleName,
|
||||
const QVariant& value,
|
||||
|
|
|
@ -110,7 +110,7 @@ QHash<int, QByteArray> RolesRenamingModel::roleNames() const
|
|||
return {};
|
||||
}
|
||||
|
||||
if (renameMap.size()) {
|
||||
if (!renameMap.isEmpty()) {
|
||||
qWarning().nospace()
|
||||
<< "RolesRenamingModel: specified source roles not found: "
|
||||
<< renameMap.keys() << "!";
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "managetokenscontroller.h"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QMutableHashIterator>
|
||||
|
||||
ManageTokensController::ManageTokensController(QObject* parent)
|
||||
: QObject(parent)
|
||||
|
@ -112,18 +113,24 @@ void ManageTokensController::showHideGroup(const QString& groupId, bool flag)
|
|||
rebuildCommunityTokenGroupsModel();
|
||||
}
|
||||
|
||||
void ManageTokensController::saveSettings()
|
||||
void ManageTokensController::saveSettings(bool reuseCurrent)
|
||||
{
|
||||
Q_ASSERT(!m_settingsKey.isEmpty());
|
||||
|
||||
setSettingsDirty(true);
|
||||
|
||||
if (m_arrangeByCommunity)
|
||||
m_communityTokensModel->applySort();
|
||||
|
||||
// gather the data to save
|
||||
SerializedTokenData result;
|
||||
for (auto model: {m_regularTokensModel, m_communityTokensModel})
|
||||
result.insert(model->save());
|
||||
result.insert(m_hiddenTokensModel->save(false));
|
||||
if (reuseCurrent) {
|
||||
result = m_settingsData;
|
||||
} else {
|
||||
for(auto model : {m_regularTokensModel, m_communityTokensModel})
|
||||
result.insert(model->save());
|
||||
result.insert(m_hiddenTokensModel->save(false));
|
||||
}
|
||||
|
||||
// save to QSettings
|
||||
m_settings.beginGroup(settingsGroupName());
|
||||
|
@ -144,6 +151,8 @@ void ManageTokensController::saveSettings()
|
|||
// unset dirty
|
||||
for (auto model: m_allModels)
|
||||
model->setDirty(false);
|
||||
|
||||
setSettingsDirty(false);
|
||||
}
|
||||
|
||||
void ManageTokensController::clearSettings()
|
||||
|
@ -182,6 +191,13 @@ void ManageTokensController::loadSettings()
|
|||
m_settings.endGroup();
|
||||
}
|
||||
|
||||
void ManageTokensController::setSettingsDirty(bool dirty)
|
||||
{
|
||||
if (m_settingsDirty == dirty) return;
|
||||
m_settingsDirty = dirty;
|
||||
emit settingsDirtyChanged(m_settingsDirty);
|
||||
}
|
||||
|
||||
void ManageTokensController::revert()
|
||||
{
|
||||
parseSourceModel();
|
||||
|
@ -199,6 +215,40 @@ bool ManageTokensController::hasSettings() const
|
|||
return !groups.isEmpty() && groups.contains(settingsGroupName());
|
||||
}
|
||||
|
||||
void ManageTokensController::settingsHideToken(const QString& symbol)
|
||||
{
|
||||
if (m_settingsData.contains(symbol)) { // find or create the settings entry
|
||||
auto [pos, visible, group] = m_settingsData.value(symbol);
|
||||
m_settingsData.remove(symbol); // remove all
|
||||
m_settingsData.insert(symbol, {pos, false, group});
|
||||
} else {
|
||||
m_settingsData.insert(symbol, {0, false, QString()});
|
||||
}
|
||||
|
||||
saveSettings(true);
|
||||
}
|
||||
|
||||
void ManageTokensController::settingsHideCommunityTokens(const QString& communityId, const QStringList& symbols)
|
||||
{
|
||||
QMutableHashIterator<QString, std::tuple<int, bool, QString>> i(m_settingsData);
|
||||
bool found = false;
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
const auto groupID = std::get<2>(i.value());
|
||||
if (groupID == communityId) {
|
||||
found = true;
|
||||
i.setValue({0, false, communityId});
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
for (const auto& symbol: symbols)
|
||||
m_settingsData.insert(symbol, {0, false, communityId});
|
||||
}
|
||||
|
||||
saveSettings(true);
|
||||
}
|
||||
|
||||
bool ManageTokensController::lessThan(const QString& lhsSymbol, const QString& rhsSymbol) const
|
||||
{
|
||||
int leftPos, rightPos;
|
||||
|
@ -216,7 +266,7 @@ bool ManageTokensController::lessThan(const QString& lhsSymbol, const QString& r
|
|||
|
||||
bool ManageTokensController::filterAcceptsSymbol(const QString& symbol) const
|
||||
{
|
||||
const auto& [pos, visible, groupId] = m_settingsData.value(symbol, {INT_MAX, false, QString()});
|
||||
const auto& [pos, visible, groupId] = m_settingsData.value(symbol, {INT_MAX, true, QString()});
|
||||
return visible;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@ class ManageTokensController : public QObject, public QQmlParserStatus
|
|||
Q_INTERFACES(QQmlParserStatus)
|
||||
|
||||
// input properties
|
||||
Q_PROPERTY(QAbstractItemModel* sourceModel READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged FINAL REQUIRED)
|
||||
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)
|
||||
Q_PROPERTY(bool arrangeByCommunity READ arrangeByCommunity WRITE setArrangeByCommunity NOTIFY arrangeByCommunityChanged FINAL) // TODO persist in settings
|
||||
|
||||
// output properties
|
||||
Q_PROPERTY(QAbstractItemModel* regularTokensModel READ regularTokensModel CONSTANT FINAL)
|
||||
|
@ -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 settingsDirty READ settingsDirty NOTIFY settingsDirtyChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit ManageTokensController(QObject* parent = nullptr);
|
||||
|
@ -33,11 +34,15 @@ public:
|
|||
Q_INVOKABLE void showHideCommunityToken(int row, bool flag);
|
||||
Q_INVOKABLE void showHideGroup(const QString& groupId, bool flag);
|
||||
|
||||
Q_INVOKABLE void saveSettings();
|
||||
Q_INVOKABLE void loadSettings();
|
||||
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);
|
||||
|
||||
Q_INVOKABLE bool lessThan(const QString& lhsSymbol, const QString& rhsSymbol) const;
|
||||
Q_INVOKABLE bool filterAcceptsSymbol(const QString& symbol) const;
|
||||
|
||||
|
@ -50,6 +55,7 @@ signals:
|
|||
void dirtyChanged();
|
||||
void arrangeByCommunityChanged();
|
||||
void settingsKeyChanged();
|
||||
void settingsDirtyChanged(bool dirty);
|
||||
|
||||
private:
|
||||
QAbstractItemModel* m_sourceModel{nullptr};
|
||||
|
@ -60,16 +66,16 @@ private:
|
|||
void addItem(int index);
|
||||
|
||||
ManageTokensModel* m_regularTokensModel{nullptr};
|
||||
QAbstractItemModel* regularTokensModel() const { return m_regularTokensModel; };
|
||||
QAbstractItemModel* regularTokensModel() const { return m_regularTokensModel; }
|
||||
|
||||
ManageTokensModel* m_communityTokensModel{nullptr};
|
||||
QAbstractItemModel* communityTokensModel() const { return m_communityTokensModel; };
|
||||
QAbstractItemModel* communityTokensModel() const { return m_communityTokensModel; }
|
||||
|
||||
ManageTokensModel* m_communityTokenGroupsModel{nullptr};
|
||||
QAbstractItemModel* communityTokenGroupsModel() const { return m_communityTokenGroupsModel; };
|
||||
QAbstractItemModel* communityTokenGroupsModel() const { return m_communityTokenGroupsModel; }
|
||||
|
||||
ManageTokensModel* m_hiddenTokensModel{nullptr};
|
||||
QAbstractItemModel* hiddenTokensModel() const { return m_hiddenTokensModel; };
|
||||
QAbstractItemModel* hiddenTokensModel() const { return m_hiddenTokensModel; }
|
||||
|
||||
bool dirty() const;
|
||||
|
||||
|
@ -88,8 +94,11 @@ private:
|
|||
QString settingsGroupName() const;
|
||||
void setSettingsKey(const QString& newSettingsKey);
|
||||
QSettings m_settings;
|
||||
void loadSettings();
|
||||
SerializedTokenData m_settingsData; // symbol -> {sortOrder, visible, groupId}
|
||||
|
||||
bool m_settingsDirty{false};
|
||||
bool settingsDirty() const { return m_settingsDirty; }
|
||||
void setSettingsDirty(bool dirty);
|
||||
|
||||
bool m_modelConnectionsInitialized{false};
|
||||
};
|
||||
|
|
|
@ -63,7 +63,7 @@ SettingsContentBase {
|
|||
onSaveChangesClicked: {
|
||||
manageTokensView.saveChanges()
|
||||
Global.displayToastMessage(
|
||||
qsTr("Your new custom asset order has been applied to your %1", "Go to Wallet")
|
||||
qsTr("Your new custom token order has been applied to your %1", "Go to Wallet")
|
||||
.arg(`<a style="text-decoration:none" href="#${Constants.appSection.wallet}">` + qsTr("Wallet", "Go to Wallet") + "</a>"),
|
||||
"",
|
||||
"checkmark-circle",
|
||||
|
|
|
@ -23,7 +23,7 @@ ColumnLayout {
|
|||
return false
|
||||
if (tabBar.currentIndex > d.collectiblesTabIndex)
|
||||
return false
|
||||
if (tabBar.currentIndex === d.collectiblesTabIndex && baseCollectiblesModel.isFetching)
|
||||
if (tabBar.currentIndex === d.collectiblesTabIndex && baseWalletCollectiblesModel.isFetching)
|
||||
return false
|
||||
return loader.item && loader.item.dirty
|
||||
}
|
||||
|
@ -51,14 +51,14 @@ ColumnLayout {
|
|||
if (tabBar.currentIndex !== collectiblesTabIndex)
|
||||
return
|
||||
// If there is no more items to load or we're already fetching, return
|
||||
if (!root.baseCollectiblesModel.hasMore || root.baseCollectiblesModel.isFetching)
|
||||
if (!root.baseWalletCollectiblesModel.hasMore || root.baseWalletCollectiblesModel.isFetching)
|
||||
return
|
||||
root.baseCollectiblesModel.loadMore()
|
||||
root.baseWalletCollectiblesModel.loadMore()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.baseCollectiblesModel
|
||||
target: root.baseWalletCollectiblesModel
|
||||
function onHasMoreChanged() {
|
||||
d.checkLoadMoreCollectibles()
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ Item {
|
|||
function resetView() {
|
||||
stack.currentIndex = 0
|
||||
root.currentTabIndex = 0
|
||||
historyView.resetView()
|
||||
if (walletTabBar.currentIndex === 2)
|
||||
mainViewLoader.item.resetView()
|
||||
}
|
||||
|
||||
function resetStack() {
|
||||
|
@ -94,7 +95,6 @@ Item {
|
|||
StatusTabBar {
|
||||
id: walletTabBar
|
||||
objectName: "rightSideWalletTabBar"
|
||||
horizontalPadding: Style.current.padding
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
|
||||
|
@ -116,41 +116,67 @@ Item {
|
|||
RootStore.setCurrentViewedHoldingType(walletTabBar.currentIndex === 1 ? Constants.TokenType.ERC721 : Constants.TokenType.ERC20)
|
||||
}
|
||||
}
|
||||
StackLayout {
|
||||
Loader {
|
||||
id: mainViewLoader
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
Layout.bottomMargin: Style.current.padding
|
||||
currentIndex: walletTabBar.currentIndex
|
||||
sourceComponent: {
|
||||
switch (walletTabBar.currentIndex) {
|
||||
case 0: return assetsView
|
||||
case 1: return collectiblesView
|
||||
case 2: return historyView
|
||||
}
|
||||
}
|
||||
active: visible
|
||||
|
||||
AssetsView {
|
||||
assets: RootStore.assets
|
||||
networkConnectionStore: root.networkConnectionStore
|
||||
assetDetailsLaunched: stack.currentIndex === 2
|
||||
onAssetClicked: {
|
||||
assetDetailView.token = token
|
||||
RootStore.setCurrentViewedHolding(token.symbol, Constants.TokenType.ERC20)
|
||||
stack.currentIndex = 2
|
||||
Component {
|
||||
id: assetsView
|
||||
AssetsView {
|
||||
assets: RootStore.assets
|
||||
overview: RootStore.overview
|
||||
networkConnectionStore: root.networkConnectionStore
|
||||
assetDetailsLaunched: stack.currentIndex === 2
|
||||
onAssetClicked: {
|
||||
assetDetailView.token = token
|
||||
RootStore.setCurrentViewedHolding(token.symbol, Constants.TokenType.ERC20)
|
||||
stack.currentIndex = 2
|
||||
}
|
||||
onSendRequested: (symbol) => {
|
||||
root.sendModal.preSelectedSendType = Constants.SendType.Transfer
|
||||
root.sendModal.preSelectedHoldingID = symbol
|
||||
root.sendModal.preSelectedHoldingType = Constants.TokenType.ERC20
|
||||
root.sendModal.onlyAssets = true
|
||||
root.sendModal.open()
|
||||
}
|
||||
onReceiveRequested: (symbol) => root.launchShareAddressModal()
|
||||
onSwitchToCommunityRequested: (communityId) => Global.switchToCommunity(communityId)
|
||||
onManageTokensRequested: Global.changeAppSectionBySectionType(Constants.appSection.profile, Constants.settingsSubsection.wallet)
|
||||
}
|
||||
}
|
||||
CollectiblesView {
|
||||
collectiblesModel: RootStore.collectiblesStore.ownedCollectibles
|
||||
onCollectibleClicked: {
|
||||
RootStore.collectiblesStore.getDetailedCollectible(chainId, contractAddress, tokenId)
|
||||
RootStore.setCurrentViewedHolding(uid, Constants.TokenType.ERC721)
|
||||
stack.currentIndex = 1
|
||||
Component {
|
||||
id: collectiblesView
|
||||
CollectiblesView {
|
||||
collectiblesModel: RootStore.collectiblesStore.ownedCollectibles
|
||||
onCollectibleClicked: {
|
||||
RootStore.collectiblesStore.getDetailedCollectible(chainId, contractAddress, tokenId)
|
||||
RootStore.setCurrentViewedHolding(uid, Constants.TokenType.ERC721)
|
||||
stack.currentIndex = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
HistoryView {
|
||||
Component {
|
||||
id: historyView
|
||||
overview: RootStore.overview
|
||||
showAllAccounts: root.showAllAccounts
|
||||
sendModal: root.sendModal
|
||||
onLaunchTransactionDetail: function (entry, entryIndex) {
|
||||
transactionDetailView.transactionIndex = entryIndex
|
||||
transactionDetailView.transaction = entry
|
||||
|
||||
stack.currentIndex = 3
|
||||
HistoryView {
|
||||
overview: RootStore.overview
|
||||
showAllAccounts: root.showAllAccounts
|
||||
sendModal: root.sendModal
|
||||
onLaunchTransactionDetail: function (entry, entryIndex) {
|
||||
transactionDetailView.transactionIndex = entryIndex
|
||||
transactionDetailView.transaction = entry
|
||||
stack.currentIndex = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick 2.15
|
||||
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import utils 1.0
|
||||
|
||||
|
@ -15,15 +10,18 @@ TokenDelegate {
|
|||
title: Constants.dummyText
|
||||
subTitle: Constants.dummyText
|
||||
asset.name: Constants.dummyText
|
||||
|
||||
currencyBalance.text: Constants.dummyText
|
||||
currencyBalance.loading: true
|
||||
change24HourPercentage.text: Constants.dummyText
|
||||
change24Hour.text: Constants.dummyText
|
||||
localeCurrencyBalance.text: Constants.dummyText
|
||||
change24HourPercentage.loading: true
|
||||
currencyPrice.text: Constants.dummyText
|
||||
currencyPrice.loading: true
|
||||
|
||||
statusListItemSubTitle.loading: true
|
||||
statusListItemTitle.loading: true
|
||||
statusListItemIcon.loading: true
|
||||
change24HourPercentage.loading: true
|
||||
change24Hour.loading: true
|
||||
localeCurrencyBalance.loading: true
|
||||
|
||||
textColor: Theme.palette.baseColor1
|
||||
enabled: false
|
||||
}
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import AppLayouts.Wallet.controls 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
StatusListItem {
|
||||
id: root
|
||||
|
||||
property alias localeCurrencyBalance: localeCurrencyBalance
|
||||
property alias change24Hour: change24HourText
|
||||
// expected roles: name, symbol, enabledNetworkBalance, enabledNetworkCurrencyBalance, currencyPrice, changePct24hour, communityId, communityName, communityImage
|
||||
|
||||
property alias currencyBalance: currencyBalance
|
||||
property alias change24HourPercentage: change24HourPercentageText
|
||||
property alias currencyPrice: currencyPrice
|
||||
|
||||
property string currentCurrencySymbol
|
||||
property string textColor: {
|
||||
|
@ -33,12 +36,26 @@ StatusListItem {
|
|||
property string errorTooltipText_1
|
||||
property string errorTooltipText_2
|
||||
|
||||
readonly property bool isCommunityToken: !!modelData && !!modelData.communityId
|
||||
readonly property string symbolUrl: !!modelData && modelData.symbol ? Constants.tokenIcon(modelData.symbol, false) : ""
|
||||
readonly property string upDownTriangle: {
|
||||
if (!modelData)
|
||||
return ""
|
||||
if (modelData.changePct24hour < 0)
|
||||
return "▾"
|
||||
if (modelData.changePct24hour > 0)
|
||||
return "▴"
|
||||
return ""
|
||||
}
|
||||
|
||||
signal switchToCommunityRequested(string communityId)
|
||||
|
||||
title: modelData ? modelData.name : ""
|
||||
subTitle: LocaleUtils.currencyAmountToLocaleString(modelData.enabledNetworkBalance)
|
||||
asset.name: symbolUrl
|
||||
asset.isImage: true
|
||||
asset.width: 32
|
||||
asset.height: 32
|
||||
errorIcon.tooltip.maxWidth: 300
|
||||
|
||||
statusListItemTitleIcons.sourceComponent: StatusFlatRoundButton {
|
||||
|
@ -55,7 +72,7 @@ StatusListItem {
|
|||
|
||||
components: [
|
||||
Column {
|
||||
id: valueColumn
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
StatusFlatRoundButton {
|
||||
id: errorIcon
|
||||
width: 14
|
||||
|
@ -69,32 +86,49 @@ StatusListItem {
|
|||
visible: !!tooltip.text
|
||||
}
|
||||
StatusTextWithLoadingState {
|
||||
id: localeCurrencyBalance
|
||||
id: currencyBalance
|
||||
anchors.right: parent.right
|
||||
font.pixelSize: 15
|
||||
text: modelData ? LocaleUtils.currencyAmountToLocaleString(modelData.enabledNetworkCurrencyBalance) : ""
|
||||
visible: !errorIcon.visible
|
||||
visible: !errorIcon.visible && !root.isCommunityToken
|
||||
}
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 8
|
||||
visible: !errorIcon.visible
|
||||
anchors.right: parent.right
|
||||
spacing: 6
|
||||
visible: !errorIcon.visible && !root.isCommunityToken
|
||||
StatusTextWithLoadingState {
|
||||
id: change24HourText
|
||||
font.pixelSize: 15
|
||||
id: change24HourPercentageText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
customColor: root.textColor
|
||||
text: modelData ? LocaleUtils.currencyAmountToLocaleString(modelData.currencyPrice) : ""
|
||||
font.pixelSize: 13
|
||||
text: modelData && modelData.changePct24hour !== undefined ? "%1 %2%".arg(root.upDownTriangle).arg(LocaleUtils.numberToLocaleString(modelData.changePct24hour, 2))
|
||||
: "---"
|
||||
}
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 1
|
||||
height: change24HourText.implicitHeight
|
||||
height: 12
|
||||
color: Theme.palette.directColor9
|
||||
}
|
||||
StatusTextWithLoadingState {
|
||||
id: change24HourPercentageText
|
||||
font.pixelSize: 15
|
||||
id: currencyPrice
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
customColor: root.textColor
|
||||
text: modelData && modelData.changePct24hour !== "" ? "%1%".arg(LocaleUtils.numberToLocaleString(modelData.changePct24hour, 2)) : "---"
|
||||
font.pixelSize: 13
|
||||
text: modelData ? LocaleUtils.currencyAmountToLocaleString(modelData.currencyPrice) : ""
|
||||
}
|
||||
}
|
||||
ManageTokensCommunityTag {
|
||||
anchors.right: parent.right
|
||||
text: modelData.communityName
|
||||
imageSrc: modelData.communityImage
|
||||
visible: root.isCommunityToken
|
||||
StatusToolTip {
|
||||
text: qsTr("This token was minted by the %1 community").arg(modelData.communityName)
|
||||
visible: parent.hovered
|
||||
}
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onSingleTapped: root.switchToCommunityRequested(modelData.communityId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +136,7 @@ StatusListItem {
|
|||
|
||||
states: [
|
||||
State {
|
||||
name: "unkownToken"
|
||||
name: "unknownToken"
|
||||
when: !root.symbolUrl
|
||||
PropertyChanges {
|
||||
target: root.asset
|
||||
|
@ -111,6 +145,5 @@ StatusListItem {
|
|||
name: !!modelData && modelData.symbol ? modelData.symbol : ""
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ QtObject {
|
|||
readonly property bool marketValuesCache: walletSectionAssets.hasMarketValuesCache
|
||||
|
||||
readonly property var blockchainNetworksDown: !!networkConnectionModule.blockchainNetworkConnection.chainIds ? networkConnectionModule.blockchainNetworkConnection.chainIds.split(";") : []
|
||||
readonly property bool atleastOneBlockchainNetworkAvailable: blockchainNetworksDown.length < networksModule.all.count
|
||||
readonly property bool atleastOneBlockchainNetworkAvailable: blockchainNetworksDown.length < networksModule.all.count
|
||||
|
||||
readonly property bool sendBuyBridgeEnabled: localAppSettings.testEnvironment || (isOnline &&
|
||||
(!networkConnectionModule.blockchainNetworkConnection.completelyDown && atleastOneBlockchainNetworkAvailable) &&
|
||||
|
@ -30,17 +30,17 @@ QtObject {
|
|||
networkConnectionModule.marketValuesNetworkConnection.completelyDown ?
|
||||
qsTr("Requires CryptoCompare or CoinGecko, both of which are currently unavailable"): ""
|
||||
|
||||
readonly property bool notOnlineWithNoCache: !isOnline && !walletSectionAssets.hasBalanceCache && !walletSectionAssets.hasMarketValuesCache
|
||||
readonly property bool notOnlineWithNoCache: !isOnline && !balanceCache && !marketValuesCache
|
||||
readonly property string notOnlineWithNoCacheText: qsTr("Internet connection lost. Data could not be retrieved.")
|
||||
|
||||
readonly property bool noBlockchainConnectionAndNoCache: networkConnectionModule.blockchainNetworkConnection.completelyDown && !walletSectionAssets.hasBalanceCache
|
||||
readonly property bool noBlockchainConnectionAndNoCache: networkConnectionModule.blockchainNetworkConnection.completelyDown && !balanceCache
|
||||
readonly property string noBlockchainConnectionAndNoCacheText: qsTr("Token balances are fetched from Pocket Network (POKT) and Infura which are both curently unavailable")
|
||||
|
||||
readonly property bool noMarketConnectionAndNoCache: networkConnectionModule.marketValuesNetworkConnection.completelyDown && !walletSectionAssets.hasMarketValuesCache
|
||||
readonly property bool noMarketConnectionAndNoCache: networkConnectionModule.marketValuesNetworkConnection.completelyDown && !marketValuesCache
|
||||
readonly property string noMarketConnectionAndNoCacheText: qsTr("Market values are fetched from CryptoCompare and CoinGecko which are both currently unavailable")
|
||||
|
||||
readonly property bool noBlockchainAndMarketConnectionAndNoCache: noBlockchainConnectionAndNoCache && noMarketConnectionAndNoCache
|
||||
readonly property string noBlockchainAndMarketConnectionAndNoCacheText: qsTr("Market values and token balances use CryptoCompare/CoinGecko and POKT/Infura which are all currently unavailable.")
|
||||
readonly property string noBlockchainAndMarketConnectionAndNoCacheText: qsTr("Market values and token balances use CryptoCompare/CoinGecko and POKT/Infura which are all currently unavailable.")
|
||||
|
||||
readonly property bool accountBalanceNotAvailable: notOnlineWithNoCache || noBlockchainConnectionAndNoCache || noMarketConnectionAndNoCache
|
||||
readonly property string accountBalanceNotAvailableText: !isOnline ? notOnlineWithNoCacheText :
|
||||
|
@ -48,15 +48,15 @@ QtObject {
|
|||
networkConnectionModule.blockchainNetworkConnection.completelyDown ? noBlockchainConnectionAndNoCacheText :
|
||||
networkConnectionModule.marketValuesNetworkConnection.completelyDown ? noBlockchainAndMarketConnectionAndNoCacheText : ""
|
||||
|
||||
readonly property bool noTokenBalanceAvailable: networkConnectionStore.notOnlineWithNoCache || networkConnectionStore.noBlockchainConnectionAndNoCache
|
||||
readonly property bool noTokenBalanceAvailable: notOnlineWithNoCache || noBlockchainConnectionAndNoCache
|
||||
|
||||
readonly property bool ensNetworkAvailable: !blockchainNetworksDown.includes(profileSectionModule.ensUsernamesModule.chainId.toString())
|
||||
readonly property string ensNetworkUnavailableText: qsTr("Requires POKT/Infura for %1, which is currently unavailable").arg( networksModule.all.getNetworkFullName(profileSectionModule.ensUsernamesModule.chainId))
|
||||
readonly property string ensNetworkUnavailableText: qsTr("Requires POKT/Infura for %1, which is currently unavailable").arg(networksModule.all.getNetworkFullName(profileSectionModule.ensUsernamesModule.chainId))
|
||||
readonly property bool stickersNetworkAvailable: !blockchainNetworksDown.includes(stickersModule.getChainIdForStickers().toString())
|
||||
readonly property string stickersNetworkUnavailableText: qsTr("Requires POKT/Infura for %1, which is currently unavailable").arg( networksModule.all.getNetworkFullName(stickersModule.getChainIdForStickers()))
|
||||
readonly property string stickersNetworkUnavailableText: qsTr("Requires POKT/Infura for %1, which is currently unavailable").arg(networksModule.all.getNetworkFullName(stickersModule.getChainIdForStickers()))
|
||||
|
||||
function getBlockchainNetworkDownTextForToken(balances) {
|
||||
if(!!balances && !networkConnectionModule.blockchainNetworkConnection.completelyDown && !networkConnectionStore.notOnlineWithNoCache) {
|
||||
if(!!balances && !networkConnectionModule.blockchainNetworkConnection.completelyDown && !notOnlineWithNoCache) {
|
||||
let chainIdsDown = []
|
||||
for (var i =0; i<balances.count; i++) {
|
||||
let chainId = balances.rowData(i, "chainId")
|
||||
|
@ -73,8 +73,8 @@ QtObject {
|
|||
}
|
||||
|
||||
function getMarketNetworkDownText() {
|
||||
if(networkConnectionStore.notOnlineWithNoCache)
|
||||
return networkConnectionStore.notOnlineWithNoCacheText
|
||||
if(notOnlineWithNoCache)
|
||||
return notOnlineWithNoCacheText
|
||||
else if(noBlockchainAndMarketConnectionAndNoCache)
|
||||
return noBlockchainAndMarketConnectionAndNoCacheText
|
||||
else if(noMarketConnectionAndNoCache)
|
||||
|
@ -87,7 +87,7 @@ QtObject {
|
|||
let jointChainIdString = ""
|
||||
for (const chain of chainIdsDown) {
|
||||
jointChainIdString = (!!jointChainIdString) ? jointChainIdString + " & " : jointChainIdString
|
||||
jointChainIdString += networksModule.all.getNetworkFullName(parseInt(chain))
|
||||
jointChainIdString += networksModule.all.getNetworkFullName(parseInt(chain))
|
||||
}
|
||||
return jointChainIdString
|
||||
}
|
||||
|
|
|
@ -1,88 +1,340 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.14
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Popups.Dialog 0.1
|
||||
import StatusQ.Models 0.1
|
||||
import StatusQ.Internal 0.1
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import "../stores"
|
||||
import shared.stores 1.0
|
||||
import shared.controls 1.0
|
||||
import shared.popups 1.0
|
||||
|
||||
Item {
|
||||
StatusScrollView {
|
||||
id: root
|
||||
|
||||
property var assets
|
||||
// expected roles: name, symbol, enabledNetworkBalance, enabledNetworkCurrencyBalance, currencyPrice, changePct24hour, communityId, communityName, communityImage
|
||||
required property var assets
|
||||
|
||||
property var networkConnectionStore
|
||||
property var overview
|
||||
property bool assetDetailsLaunched: false
|
||||
|
||||
signal assetClicked(var token)
|
||||
signal sendRequested(string symbol)
|
||||
signal receiveRequested(string symbol)
|
||||
signal switchToCommunityRequested(string communityId)
|
||||
signal manageTokensRequested()
|
||||
|
||||
contentWidth: availableWidth
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property int selectedAssetIndex: -1
|
||||
}
|
||||
|
||||
height: assetListView.height
|
||||
readonly property bool isCustomView: d.controller.hasSettings // TODO add respect other predefined orders (#12517)
|
||||
|
||||
StatusListView {
|
||||
id: assetListView
|
||||
objectName: "assetViewStatusListView"
|
||||
anchors.fill: parent
|
||||
model: !!assets ? assets : null
|
||||
reuseItems: true
|
||||
delegate: delegateLoader
|
||||
}
|
||||
function symbolIsVisible(symbol, balance) {
|
||||
if (symbol === "ETH") // always visible
|
||||
return true
|
||||
if (!d.controller.filterAcceptsSymbol(symbol)) // explicitely hidden
|
||||
return false
|
||||
if (symbol === "SNT" || symbol === "DAI") // visible by default
|
||||
return true
|
||||
return !!balance && !!balance.amount // visible with non-zero balance
|
||||
}
|
||||
|
||||
Component {
|
||||
id: delegateLoader
|
||||
Loader {
|
||||
property var modelData: model
|
||||
property int index: index
|
||||
width: ListView.view.width
|
||||
sourceComponent: loading ? loadingTokenDelegate: tokenDelegate
|
||||
readonly property var regularAssetsModel: SortFilterProxyModel {
|
||||
sourceModel: root.assets
|
||||
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
expression: {
|
||||
d.controller.settingsDirty
|
||||
return d.symbolIsVisible(model.symbol, model.enabledNetworkBalance) && !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.enabledNetworkBalance) && !!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"
|
||||
}
|
||||
|
||||
function hideAllCommunityTokens(communityId) {
|
||||
const tokenSymbols = ModelUtils.getAll(communityAssetsModel, "symbol", "communityId", communityId)
|
||||
d.controller.settingsHideCommunityTokens(communityId, tokenSymbols)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: loadingTokenDelegate
|
||||
LoadingTokenDelegate {
|
||||
objectName: "AssetView_LoadingTokenDelegate_" + index
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
width: root.availableWidth
|
||||
spacing: 0
|
||||
|
||||
Component {
|
||||
id: tokenDelegate
|
||||
TokenDelegate {
|
||||
objectName: "AssetView_TokenListItem_" + (!!modelData ? modelData.symbol : "")
|
||||
readonly property string balance: !!modelData ? "%1".arg(modelData.enabledNetworkBalance.amount) : "" // Needed for the tests
|
||||
errorTooltipText_1: !!modelData && !! networkConnectionStore ? networkConnectionStore.getBlockchainNetworkDownTextForToken(modelData.balances) : ""
|
||||
errorTooltipText_2: !!networkConnectionStore ? networkConnectionStore.getMarketNetworkDownText() : ""
|
||||
subTitle: {
|
||||
if (!modelData) {
|
||||
return ""
|
||||
}
|
||||
if (networkConnectionStore && networkConnectionStore.noTokenBalanceAvailable) {
|
||||
return ""
|
||||
}
|
||||
return LocaleUtils.currencyAmountToLocaleString(modelData.enabledNetworkBalance)
|
||||
|
||||
StatusListView {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
interactive: false
|
||||
objectName: "assetViewStatusListView"
|
||||
model: d.regularAssetsModel
|
||||
delegate: delegateLoader
|
||||
}
|
||||
|
||||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.current.padding
|
||||
Layout.bottomMargin: Style.current.halfPadding
|
||||
visible: d.hasCommunityAssets
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.current.padding
|
||||
Layout.rightMargin: Style.current.smallPadding
|
||||
Layout.bottomMargin: 4
|
||||
visible: d.hasCommunityAssets
|
||||
StatusBaseText {
|
||||
text: qsTr("Community assets")
|
||||
color: Theme.palette.baseColor1
|
||||
}
|
||||
errorMode: !!networkConnectionStore ? networkConnectionStore.noBlockchainConnectionAndNoCache && !networkConnectionStore.noMarketConnectionAndNoCache : false
|
||||
errorIcon.tooltip.text: !!networkConnectionStore ? networkConnectionStore.noBlockchainConnectionAndNoCacheText : ""
|
||||
onClicked: {
|
||||
RootStore.getHistoricalDataForToken(modelData.symbol, RootStore.currencyStore.currentCurrency)
|
||||
d.selectedAssetIndex = index
|
||||
assetClicked(modelData)
|
||||
Item { Layout.fillWidth: true }
|
||||
StatusFlatButton {
|
||||
Layout.preferredWidth: 32
|
||||
Layout.preferredHeight: 32
|
||||
icon.name: "info"
|
||||
textColor: Theme.palette.baseColor1
|
||||
horizontalPadding: 0
|
||||
verticalPadding: 0
|
||||
onClicked: Global.openPopup(communityInfoPopupCmp)
|
||||
}
|
||||
Component.onCompleted: {
|
||||
// on Model reset if the detail view is shown, update the data in background.
|
||||
if(root.assetDetailsLaunched && index === d.selectedAssetIndex)
|
||||
assetClicked(modelData)
|
||||
}
|
||||
|
||||
StatusListView {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
interactive: false
|
||||
objectName: "communityAssetViewStatusListView"
|
||||
model: d.communityAssetsModel
|
||||
delegate: delegateLoader
|
||||
}
|
||||
|
||||
Component {
|
||||
id: delegateLoader
|
||||
Loader {
|
||||
property var modelData: model
|
||||
property int index: index
|
||||
width: ListView.view.width
|
||||
sourceComponent: model.loading ? loadingTokenDelegate: tokenDelegate
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: loadingTokenDelegate
|
||||
LoadingTokenDelegate {
|
||||
objectName: "AssetView_LoadingTokenDelegate_" + index
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tokenDelegate
|
||||
TokenDelegate {
|
||||
objectName: "AssetView_TokenListItem_" + (!!modelData ? modelData.symbol : "")
|
||||
readonly property string balance: !!modelData ? "%1".arg(modelData.enabledNetworkBalance.amount) : "" // Needed for the tests
|
||||
errorTooltipText_1: !!modelData && !!networkConnectionStore ? networkConnectionStore.getBlockchainNetworkDownTextForToken(modelData.balances) : ""
|
||||
errorTooltipText_2: !!networkConnectionStore ? networkConnectionStore.getMarketNetworkDownText() : ""
|
||||
subTitle: {
|
||||
if (!modelData) {
|
||||
return ""
|
||||
}
|
||||
if (networkConnectionStore && networkConnectionStore.noTokenBalanceAvailable) {
|
||||
return ""
|
||||
}
|
||||
return LocaleUtils.currencyAmountToLocaleString(modelData.enabledNetworkBalance)
|
||||
}
|
||||
errorMode: !!networkConnectionStore ? networkConnectionStore.noBlockchainConnectionAndNoCache && !networkConnectionStore.noMarketConnectionAndNoCache : false
|
||||
errorIcon.tooltip.text: !!networkConnectionStore ? networkConnectionStore.noBlockchainConnectionAndNoCacheText : ""
|
||||
onClicked: (itemId, mouse) => {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
RootStore.getHistoricalDataForToken(modelData.symbol, RootStore.currencyStore.currentCurrency)
|
||||
d.selectedAssetIndex = index
|
||||
assetClicked(modelData)
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
Global.openMenu(tokenContextMenu, this,
|
||||
{symbol: modelData.symbol, assetName: modelData.name, assetImage: symbolUrl,
|
||||
communityId: modelData.communityId, communityName: modelData.communityName, communityImage: modelData.communityImage})
|
||||
}
|
||||
}
|
||||
onSwitchToCommunityRequested: root.switchToCommunityRequested(communityId)
|
||||
Component.onCompleted: {
|
||||
// on Model reset if the detail view is shown, update the data in background.
|
||||
if(root.assetDetailsLaunched && index === d.selectedAssetIndex)
|
||||
assetClicked(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: tokenContextMenu
|
||||
StatusMenu {
|
||||
onClosed: destroy()
|
||||
|
||||
property string symbol
|
||||
property string assetName
|
||||
property string assetImage
|
||||
property string communityId
|
||||
property string communityName
|
||||
property string communityImage
|
||||
|
||||
StatusAction {
|
||||
enabled: root.networkConnectionStore.sendBuyBridgeEnabled && !root.overview.isWatchOnlyAccount && root.overview.canSend
|
||||
icon.name: "send"
|
||||
text: qsTr("Send")
|
||||
onTriggered: root.sendRequested(symbol)
|
||||
}
|
||||
StatusAction {
|
||||
icon.name: "receive"
|
||||
text: qsTr("Receive")
|
||||
onTriggered: root.receiveRequested(symbol)
|
||||
}
|
||||
StatusMenuSeparator {}
|
||||
StatusAction {
|
||||
icon.name: "settings"
|
||||
text: qsTr("Manage tokens")
|
||||
onTriggered: root.manageTokensRequested()
|
||||
}
|
||||
StatusAction {
|
||||
enabled: symbol !== "ETH"
|
||||
type: StatusAction.Type.Danger
|
||||
icon.name: "hide"
|
||||
text: qsTr("Hide asset")
|
||||
onTriggered: Global.openPopup(confirmHideAssetPopup, {symbol, assetName, assetImage, communityId})
|
||||
}
|
||||
StatusAction {
|
||||
enabled: !!communityId
|
||||
type: StatusAction.Type.Danger
|
||||
icon.name: "hide"
|
||||
text: qsTr("Hide all assets from this community")
|
||||
onTriggered: Global.openPopup(confirmHideCommunityAssetsPopup, {communityId, communityName, communityImage})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: communityInfoPopupCmp
|
||||
StatusDialog {
|
||||
destroyOnClose: true
|
||||
title: qsTr("What are community assets?")
|
||||
standardButtons: Dialog.Ok
|
||||
width: 520
|
||||
contentItem: StatusBaseText {
|
||||
wrapMode: Text.Wrap
|
||||
text: qsTr("Community assets are assets that have been minted by a community. As these assets cannot be verified, always double check their origin and validity before interacting with them. If in doubt, ask a trusted member or admin of the relevant community.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: confirmHideAssetPopup
|
||||
ConfirmationDialog {
|
||||
property string symbol
|
||||
property string assetName
|
||||
property string assetImage
|
||||
property string communityId
|
||||
|
||||
readonly property string formattedName: assetName + (communityId ? " (" + qsTr("community asset") + ")" : "")
|
||||
|
||||
width: 520
|
||||
destroyOnClose: true
|
||||
confirmButtonLabel: qsTr("Hide %1").arg(assetName)
|
||||
cancelBtnType: ""
|
||||
showCancelButton: true
|
||||
headerSettings.title: qsTr("Hide %1").arg(formattedName)
|
||||
headerSettings.asset.name: assetImage
|
||||
confirmationText: qsTr("Are you sure you want to hide %1? You will no longer see or be able to interact with this asset anywhere inside Status.").arg(formattedName)
|
||||
onCancelButtonClicked: close()
|
||||
onConfirmButtonClicked: {
|
||||
d.controller.settingsHideToken(symbol)
|
||||
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>"),
|
||||
"",
|
||||
"checkmark-circle",
|
||||
false,
|
||||
Constants.ephemeralNotificationType.success,
|
||||
""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: confirmHideCommunityAssetsPopup
|
||||
ConfirmationDialog {
|
||||
property string communityId
|
||||
property string communityName
|
||||
property string communityImage
|
||||
|
||||
width: 520
|
||||
destroyOnClose: true
|
||||
confirmButtonLabel: qsTr("Hide all assets minted by this community")
|
||||
cancelBtnType: ""
|
||||
showCancelButton: true
|
||||
headerSettings.title: qsTr("Hide %1 community assets").arg(communityName)
|
||||
headerSettings.asset.name: communityImage
|
||||
confirmationText: qsTr("Are you sure you want to hide all community assets minted by %1? You will no longer see or be able to interact with these assets anywhere inside Status.").arg(communityName)
|
||||
onCancelButtonClicked: close()
|
||||
onConfirmButtonClicked: {
|
||||
d.hideAllCommunityTokens(communityId)
|
||||
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>"),
|
||||
"",
|
||||
"checkmark-circle",
|
||||
false,
|
||||
Constants.ephemeralNotificationType.success,
|
||||
""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue