diff --git a/src/app/modules/main/wallet_section/all_tokens/controller.nim b/src/app/modules/main/wallet_section/all_tokens/controller.nim index da1d992c6c..971b570b80 100644 --- a/src/app/modules/main/wallet_section/all_tokens/controller.nim +++ b/src/app/modules/main/wallet_section/all_tokens/controller.nim @@ -1,5 +1,3 @@ -import json - import ./io_interface import app/core/eventemitter @@ -111,11 +109,11 @@ proc getCommunityTokenDescription*(self: Controller, chainId: int, address: stri proc updateTokenPreferences*(self: Controller, tokenPreferencesJson: string) = self.tokenService.updateTokenPreferences(tokenPreferencesJson) +proc getTokenPreferences*(self: Controller, symbol: string): TokenPreferencesItem = + return self.tokenService.getTokenPreferences(symbol) + proc getTokenPreferencesJson*(self: Controller): string = - let data = self.tokenService.getTokenPreferences() - if data.isNil: - return "[]" - return $data + return self.tokenService.getTokenPreferencesJson() proc getTokenGroupByCommunity*(self: Controller): bool = return self.settingsService.tokenGroupByCommunity() diff --git a/src/app/modules/main/wallet_section/all_tokens/flat_tokens_model.nim b/src/app/modules/main/wallet_section/all_tokens/flat_tokens_model.nim index 0b2771ee8f..bae650feb2 100644 --- a/src/app/modules/main/wallet_section/all_tokens/flat_tokens_model.nim +++ b/src/app/modules/main/wallet_section/all_tokens/flat_tokens_model.nim @@ -31,6 +31,8 @@ type MarketDetails DetailsLoading MarketDetailsLoading + Visible + Position QtObject: type FlatTokensModel* = ref object of QAbstractListModel @@ -81,7 +83,9 @@ QtObject: ModelRole.WebsiteUrl.int:"websiteUrl", ModelRole.MarketDetails.int:"marketDetails", ModelRole.DetailsLoading.int:"detailsLoading", - ModelRole.MarketDetailsLoading.int:"marketDetailsLoading" + ModelRole.MarketDetailsLoading.int:"marketDetailsLoading", + ModelRole.Visible.int:"visible", + ModelRole.Position.int:"position" }.toTable method data(self: FlatTokensModel, index: QModelIndex, role: int): QVariant = @@ -129,6 +133,10 @@ QtObject: result = newQVariant(self.delegate.getTokensDetailsLoading()) of ModelRole.MarketDetailsLoading: result = newQVariant(self.delegate.getTokensMarketValuesLoading()) + of ModelRole.Visible: + result = newQVariant(self.delegate.getTokenPreferences(item.symbol).visible) + of ModelRole.Position: + result = newQVariant(self.delegate.getTokenPreferences(item.symbol).position) proc modelsUpdated*(self: FlatTokensModel) = self.beginResetModel() @@ -170,3 +178,11 @@ QtObject: proc currencyFormatsUpdated*(self: FlatTokensModel) = for marketDetails in self.tokenMarketDetails: marketDetails.updateCurrencyFormat() + + proc tokenPreferencesUpdated*(self: FlatTokensModel) = + if self.delegate.getFlatTokensList().len > 0: + let index = self.createIndex(0, 0, nil) + let lastindex = self.createIndex(self.delegate.getFlatTokensList().len-1, 0, nil) + defer: index.delete + defer: lastindex.delete + self.dataChanged(index, lastindex, @[ModelRole.Visible.int, ModelRole.Position.int]) \ No newline at end of file diff --git a/src/app/modules/main/wallet_section/all_tokens/io_interface.nim b/src/app/modules/main/wallet_section/all_tokens/io_interface.nim index cccb36ba63..f51dbdfd1e 100644 --- a/src/app/modules/main/wallet_section/all_tokens/io_interface.nim +++ b/src/app/modules/main/wallet_section/all_tokens/io_interface.nim @@ -10,6 +10,7 @@ type FlatTokenModelDataSource* = tuple[ getFlatTokensList: proc(): var seq[TokenItem], getTokenDetails: proc(symbol: string): TokenDetailsItem, + getTokenPreferences: proc(symbol: string): TokenPreferencesItem, getCommunityTokenDescription: proc(chainId: int, address: string): string, getTokensDetailsLoading: proc(): bool, getTokensMarketValuesLoading: proc(): bool, @@ -18,6 +19,7 @@ type TokenBySymbolModelDataSource* = tuple[ getTokenBySymbolList: proc(): var seq[TokenBySymbolItem], getTokenDetails: proc(symbol: string): TokenDetailsItem, + getTokenPreferences: proc(symbol: string): TokenPreferencesItem, getCommunityTokenDescription: proc(addressPerChain: seq[AddressPerChain]): string, getTokensDetailsLoading: proc(): bool, getTokensMarketValuesLoading: proc(): bool, diff --git a/src/app/modules/main/wallet_section/all_tokens/module.nim b/src/app/modules/main/wallet_section/all_tokens/module.nim index 7760d3375b..d3e56513e6 100644 --- a/src/app/modules/main/wallet_section/all_tokens/module.nim +++ b/src/app/modules/main/wallet_section/all_tokens/module.nim @@ -70,8 +70,7 @@ method load*(self: Module) = self.events.on(SIGNAL_TOKENS_PRICES_UPDATED) do(e: Args): self.view.tokensMarketValuesUpdated() self.events.on(SIGNAL_TOKEN_PREFERENCES_UPDATED) do(e: Args): - let args = ResultArgs(e) - self.view.tokenPreferencesUpdated(args.success) + self.view.tokenPreferencesUpdated() self.events.on(SIGNAL_COMMUNITY_TOKENS_DETAILS_LOADED) do(e: Args): self.view.tokensDetailsUpdated() @@ -116,6 +115,7 @@ method getFlatTokenModelDataSource*(self: Module): FlatTokenModelDataSource = return ( getFlatTokensList: proc(): var seq[TokenItem] = self.controller.getFlatTokensList(), getTokenDetails: proc(symbol: string): TokenDetailsItem = self.controller.getTokenDetails(symbol), + getTokenPreferences: proc(symbol: string): TokenPreferencesItem = self.controller.getTokenPreferences(symbol), getCommunityTokenDescription: proc(chainId: int, address: string): string = self.controller.getCommunityTokenDescription(chainId, address), getTokensDetailsLoading: proc(): bool = self.controller.getTokensDetailsLoading(), getTokensMarketValuesLoading: proc(): bool = self.controller.getTokensMarketValuesLoading() @@ -125,6 +125,7 @@ method getTokenBySymbolModelDataSource*(self: Module): TokenBySymbolModelDataSou return ( getTokenBySymbolList: proc(): var seq[TokenBySymbolItem] = self.controller.getTokenBySymbolList(), getTokenDetails: proc(symbol: string): TokenDetailsItem = self.controller.getTokenDetails(symbol), + getTokenPreferences: proc(symbol: string): TokenPreferencesItem = self.controller.getTokenPreferences(symbol), getCommunityTokenDescription: proc(addressPerChain: seq[AddressPerChain]): string = self.controller.getCommunityTokenDescription(addressPerChain), getTokensDetailsLoading: proc(): bool = self.controller.getTokensDetailsLoading(), getTokensMarketValuesLoading: proc(): bool = self.controller.getTokensMarketValuesLoading() diff --git a/src/app/modules/main/wallet_section/all_tokens/token_by_symbol_model.nim b/src/app/modules/main/wallet_section/all_tokens/token_by_symbol_model.nim index c6f16fee72..98fb3a2c28 100644 --- a/src/app/modules/main/wallet_section/all_tokens/token_by_symbol_model.nim +++ b/src/app/modules/main/wallet_section/all_tokens/token_by_symbol_model.nim @@ -30,6 +30,8 @@ type MarketDetails DetailsLoading MarketDetailsLoading + Visible + Position QtObject: type TokensBySymbolModel* = ref object of QAbstractListModel @@ -84,6 +86,8 @@ QtObject: ModelRole.MarketDetails.int:"marketDetails", ModelRole.DetailsLoading.int:"detailsLoading", ModelRole.MarketDetailsLoading.int:"marketDetailsLoading", + ModelRole.Visible.int:"visible", + ModelRole.Position.int:"position" }.toTable method data(self: TokensBySymbolModel, index: QModelIndex, role: int): QVariant = @@ -130,6 +134,10 @@ QtObject: result = newQVariant(self.delegate.getTokensDetailsLoading()) of ModelRole.MarketDetailsLoading: result = newQVariant(self.delegate.getTokensMarketValuesLoading()) + of ModelRole.Visible: + result = newQVariant(self.delegate.getTokenPreferences(item.symbol).visible) + of ModelRole.Position: + result = newQVariant(self.delegate.getTokenPreferences(item.symbol).position) proc modelsUpdated*(self: TokensBySymbolModel) = self.beginResetModel() @@ -179,3 +187,11 @@ QtObject: proc currencyFormatsUpdated*(self: TokensBySymbolModel) = for marketDetails in self.tokenMarketDetails: marketDetails.updateCurrencyFormat() + + proc tokenPreferencesUpdated*(self: TokensBySymbolModel) = + if self.delegate.getTokenBySymbolList().len > 0: + let index = self.createIndex(0, 0, nil) + let lastindex = self.createIndex(self.delegate.getTokenBySymbolList().len-1, 0, nil) + defer: index.delete + defer: lastindex.delete + self.dataChanged(index, lastindex, @[ModelRole.Visible.int, ModelRole.Position.int]) \ No newline at end of file diff --git a/src/app/modules/main/wallet_section/all_tokens/view.nim b/src/app/modules/main/wallet_section/all_tokens/view.nim index 951d21298c..b579d40cde 100644 --- a/src/app/modules/main/wallet_section/all_tokens/view.nim +++ b/src/app/modules/main/wallet_section/all_tokens/view.nim @@ -141,7 +141,9 @@ QtObject: self.flatTokensModel.currencyFormatsUpdated() self.tokensBySymbolModel.currencyFormatsUpdated() - proc tokenPreferencesUpdated*(self: View, result: bool) {.signal.} + proc tokenPreferencesUpdated*(self: View) = + self.flatTokensModel.tokenPreferencesUpdated() + self.tokensBySymbolModel.tokenPreferencesUpdated() proc updateTokenPreferences*(self: View, tokenPreferencesJson: string) {.slot.} = self.delegate.updateTokenPreferences(tokenPreferencesJson) diff --git a/src/app_service/service/token/service.nim b/src/app_service/service/token/service.nim index 9688d9e216..8974f9a879 100644 --- a/src/app_service/service/token/service.nim +++ b/src/app_service/service/token/service.nim @@ -60,6 +60,8 @@ QtObject: tokenDetailsTable: Table[string, TokenDetailsItem] tokenMarketValuesTable: Table[string, TokenMarketValuesItem] tokenPriceTable: Table[string, float64] + tokenPreferencesTable: Table[string, TokenPreferencesItem] + tokenPreferencesJson: string tokensDetailsLoading: bool tokensPricesLoading: bool tokensMarketDetailsLoading: bool @@ -69,6 +71,7 @@ QtObject: proc getCurrency*(self: Service): string proc rebuildMarketData*(self: Service) + proc fetchTokenPreferences(self: Service) proc delete*(self: Service) = self.QObject.delete @@ -92,6 +95,7 @@ QtObject: result.tokenDetailsTable = initTable[string, TokenDetailsItem]() result.tokenMarketValuesTable = initTable[string, TokenMarketValuesItem]() result.tokenPriceTable = initTable[string, float64]() + result.tokenPreferencesTable = initTable[string, TokenPreferencesItem]() result.tokensDetailsLoading = true result.tokensPricesLoading = true result.tokensMarketDetailsLoading = true @@ -261,7 +265,9 @@ QtObject: # Callback to process the response of getSupportedTokensList call proc supportedTokensListRetrieved(self: Service, response: string) {.slot.} = # this is emited so that the models can know that the seq it depends on has been updated - defer: self.events.emit(SIGNAL_TOKENS_LIST_UPDATED, Args()) + defer: + self.fetchTokenPreferences() + self.events.emit(SIGNAL_TOKENS_LIST_UPDATED, Args()) try: let parsedJson = response.parseJson var errorString: string @@ -506,30 +512,57 @@ QtObject: self.threadpool.start(arg) # Token Management - proc getTokenPreferences*(self: Service): JsonNode = + proc fetchTokenPreferences(self: Service) = + # this is emited so that the models can notify about token preferences being available + defer: self.events.emit(SIGNAL_TOKEN_PREFERENCES_UPDATED, Args()) + self.tokenPreferencesJson = "[]" try: let response = backend.getTokenPreferences() if not response.error.isNil: - error "status-go error", procName="getTokenPreferences", errCode=response.error.code, errDesription=response.error.message + error "status-go error", procName="fetchTokenPreferences", errCode=response.error.code, errDesription=response.error.message return - return response.result + + if response.result.isNil or response.result.kind != JArray: + return + + self.tokenPreferencesJson = $response.result + for preferences in response.result: + let dto = Json.decode($preferences, TokenPreferencesDto, allowUnknownFields = true) + self.tokenPreferencesTable[dto.key] = TokenPreferencesItem( + key: dto.key, + position: dto.position, + groupPosition: dto.groupPosition, + visible: dto.visible, + communityId: dto.communityId) except Exception as e: - error "error: ", procName="getTokenPreferences", errName=e.name, errDesription=e.msg + error "error: ", procName="fetchTokenPreferences", errName=e.name, errDesription=e.msg + + proc getTokenPreferences*(self: Service, symbol: string): TokenPreferencesItem = + if not self.tokenPreferencesTable.hasKey(symbol): + return TokenPreferencesItem( + key: symbol, + position: high(int), + groupPosition: high(int), + visible: true, + communityId: "" + ) + return self.tokenPreferencesTable[symbol] + + proc getTokenPreferencesJson*(self: Service): string = + if len(self.tokenPreferencesJson) == 0: + self.fetchTokenPreferences() + return self.tokenPreferencesJson proc updateTokenPreferences*(self: Service, tokenPreferencesJson: string) = - var updated = false try: let preferencesJson = parseJson(tokenPreferencesJson) - var tokenPreferences: seq[TokenPreferences] + var tokenPreferences: seq[TokenPreferencesDto] if preferencesJson.kind == JArray: for preferences in preferencesJson: - add(tokenPreferences, fromJson(preferences, TokenPreferences)) - + add(tokenPreferences, Json.decode($preferences, TokenPreferencesDto, allowUnknownFields = false)) let response = backend.updateTokenPreferences(tokenPreferences) if not response.error.isNil: raise newException(CatchableError, response.error.message) - updated = true + self.fetchTokenPreferences() except Exception as e: error "error: ", procName="updateTokenPreferences", errName=e.name, errDesription=e.msg - - self.events.emit(SIGNAL_TOKEN_PREFERENCES_UPDATED, ResultArgs(success: updated)) diff --git a/src/app_service/service/token/service_items.nim b/src/app_service/service/token/service_items.nim index c3abf410e2..158310f753 100644 --- a/src/app_service/service/token/service_items.nim +++ b/src/app_service/service/token/service_items.nim @@ -89,6 +89,23 @@ proc `$`*(self: TokenDetailsItem): string = assetWebsiteUrl: {self.assetWebsiteUrl} ]""" +type + TokenPreferencesItem* = ref object of RootObj + key*: string + position*: int + groupPosition*: int + visible*: bool + communityId*: string + +proc `$`*(self: TokenPreferencesItem): string = + result = fmt"""TokenPreferencesItem[ + key: {self.key}, + position: {self.position}, + groupPosition: {self.groupPosition}, + visible: {self.visible}, + communityId: {self.communityId} + ]""" + type TokenMarketValuesItem* = object marketCap*: float64 diff --git a/src/backend/backend.nim b/src/backend/backend.nim index f5ecf62695..056f4ee950 100644 --- a/src/backend/backend.nim +++ b/src/backend/backend.nim @@ -56,21 +56,13 @@ type activityTypes* {.serializedFieldName("activityTypes").}: seq[int] readType* {.serializedFieldName("readType").}: int - TokenPreferences* = ref object of RootObj + TokenPreferencesDto* = ref object of RootObj key* {.serializedFieldName("key").}: string position* {.serializedFieldName("position").}: int groupPosition* {.serializedFieldName("groupPosition").}: int visible* {.serializedFieldName("visible").}: bool communityId* {.serializedFieldName("communityId").}: string -proc fromJson*(t: JsonNode, T: typedesc[TokenPreferences]): TokenPreferences {.inline.} = - result = TokenPreferences() - discard t.getProp("key", result.key) - discard t.getProp("position", result.position) - discard t.getProp("groupPosition", result.groupPosition) - discard t.getProp("visible", result.visible) - discard t.getProp("communityId", result.communityId) - rpc(clientVersion, "web3"): discard @@ -285,7 +277,7 @@ rpc(moveWalletAccount, "accounts"): toPosition: int rpc(updateTokenPreferences, "accounts"): - preferences: seq[TokenPreferences] + preferences: seq[TokenPreferencesDto] rpc(getTokenPreferences, "accounts"): discard diff --git a/storybook/pages/AssetsViewAdaptorPage.qml b/storybook/pages/AssetsViewAdaptorPage.qml index 405a0e4a7c..0b469f5f6d 100644 --- a/storybook/pages/AssetsViewAdaptorPage.qml +++ b/storybook/pages/AssetsViewAdaptorPage.qml @@ -53,7 +53,9 @@ Item { } }, detailsLoading: false, - image: Qt.resolvedUrl("") + image: Qt.resolvedUrl(""), + position: 1, + visible: true }, { tokensKey: "key_SNT", @@ -92,7 +94,9 @@ Item { } }, detailsLoading: false, - image: Qt.resolvedUrl("") + image: Qt.resolvedUrl(""), + position: 2, + visible: true }, { tokensKey: "key_MYASST", @@ -121,7 +125,9 @@ Item { } }, detailsLoading: false, - image: Constants.tokenIcon("ZRX", false) + image: Constants.tokenIcon("ZRX", false), + position: 5, + visible: true } ] @@ -141,42 +147,9 @@ Item { } } - ManageTokensController { - id: manageTokensController - - sourceModel: listModel - serializeAsCollectibles: false - - onRequestLoadSettings: { - loadingStarted() - - const jsonData = [ - { - "key": "ETH", - "position": 1, - "visible": true - }, - { - "key": "SNT", - "position": 2, - "visible": true - }, - { - "key": "MYASST", - "position": 5, - "visible": true - } - ] - - loadingFinished(JSON.stringify(jsonData)) - } - } - AssetsViewAdaptor { id: adaptor - controller: manageTokensController - chains: chainsSelector.selection accounts: accountsSelector.selection diff --git a/ui/app/AppLayouts/Wallet/views/RightTabView.qml b/ui/app/AppLayouts/Wallet/views/RightTabView.qml index 504176bcdd..24619b5d7a 100644 --- a/ui/app/AppLayouts/Wallet/views/RightTabView.qml +++ b/ui/app/AppLayouts/Wallet/views/RightTabView.qml @@ -174,7 +174,6 @@ RightTabBaseView { } tokensModel: RootStore.walletAssetsStore.groupedAccountAssetsModel - controller: RootStore.walletAssetsStore.assetsController formatBalance: (balance, symbol) => { return LocaleUtils.currencyAmountToLocaleString( diff --git a/ui/imports/shared/views/AssetsViewAdaptor.qml b/ui/imports/shared/views/AssetsViewAdaptor.qml index 967a07856c..6899e37d66 100644 --- a/ui/imports/shared/views/AssetsViewAdaptor.qml +++ b/ui/imports/shared/views/AssetsViewAdaptor.qml @@ -12,10 +12,6 @@ import SortFilterProxyModel 0.2 QObject { id: root - // Controller providing information about visibility and order defined - // by a user (token management) - required property ManageTokensController controller - /** Expected model structure: @@ -35,6 +31,8 @@ QObject { currencyPrice [object] - object holding fiat price details amount [double] - fiat prace of 1 logical unit of cryptocurrency detailsLoading [bool] - indicatator if market details are ready to use + position [int] - custom order position + visible [bool] - token management visiblity flag Community related part (relevant for community minted assets, empty otherwise): @@ -115,15 +113,8 @@ QObject { readonly property real marketPrice: marketDetails.currencyPrice.amount ?? 0 readonly property real marketChangePct24hour: marketDetails.changePct24hour ?? 0 - readonly property int position: { - controller.revision - return controller.order(model.symbol) - } - readonly property bool visible: { - root.controller.revision - - if (!root.controller.filterAcceptsSymbol(model.symbol)) + if (!model.visible) return false if (hasCommunityId) @@ -184,9 +175,10 @@ QObject { expectedRoles: ["tokensKey", "symbol", "image", "balances", "decimals", - "detailsLoading", "marketDetails", "communityId", "communityImage"] + "detailsLoading", "marketDetails", "communityId", "communityImage", + "position", "visible"] exposedRoles: - ["key", "error", "balance", "balanceText", "position", "icon", + ["key", "error", "balance", "balanceText", "icon", "visible", "canBeHidden", "marketDetailsAvailable", "marketDetailsLoading", "marketPrice", "marketChangePct24hour", "communityIcon"] }