diff --git a/src/app/modules/main/profile_section/module.nim b/src/app/modules/main/profile_section/module.nim index 7d77d22725..ee892fb7fd 100644 --- a/src/app/modules/main/profile_section/module.nim +++ b/src/app/modules/main/profile_section/module.nim @@ -94,7 +94,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface, result.controller = controller.newController(result) result.moduleLoaded = false - result.profileModule = profile_module.newModule(result, events, profileService, settingsService, communityService, walletAccountService) + result.profileModule = profile_module.newModule(result, events, profileService, settingsService, communityService, walletAccountService, networkService) result.contactsModule = contacts_module.newModule(result, events, contactsService, chatService) result.languageModule = language_module.newModule(result, events, languageService) result.privacyModule = privacy_module.newModule(result, events, settingsService, keychainService, privacyService, generalService) diff --git a/src/app/modules/main/profile_section/profile/controller.nim b/src/app/modules/main/profile_section/profile/controller.nim index 0af595ba7e..5d82d24510 100644 --- a/src/app/modules/main/profile_section/profile/controller.nim +++ b/src/app/modules/main/profile_section/profile/controller.nim @@ -1,3 +1,4 @@ +import sugar, sequtils import io_interface import app/global/app_signals @@ -6,6 +7,7 @@ import app_service/service/profile/service as profile_service import app_service/service/settings/service as settings_service import app_service/service/community/service as community_service import app_service/service/wallet_account/service as wallet_account_service +import app_service/service/network/service as network_service import app_service/common/social_links import app_service/common/types @@ -21,6 +23,7 @@ type settingsService: settings_service.Service communityService: community_service.Service walletAccountService: wallet_account_service.Service + networkService: network_service.Service proc newController*( delegate: io_interface.AccessInterface, @@ -28,7 +31,8 @@ proc newController*( profileService: profile_service.Service, settingsService: settings_service.Service, communityService: community_service.Service, - walletAccountService: wallet_account_service.Service): Controller = + walletAccountService: wallet_account_service.Service, + networkService: network_service.Service): Controller = result = Controller() result.delegate = delegate result.events = events @@ -36,6 +40,7 @@ proc newController*( result.settingsService = settingsService result.communityService = communityService result.walletAccountService = walletAccountService + result.networkService = networkService proc delete*(self: Controller) = discard @@ -81,9 +86,18 @@ proc getCommunityById*(self: Controller, id: string): CommunityDto = proc getAccountByAddress*(self: Controller, address: string): WalletAccountDto = return self.walletAccountService.getAccountByAddress(address) +proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] = + return self.walletAccountService.getWalletAccounts(true) + proc getTokensByAddresses*(self: Controller, addresses: seq[string]): seq[WalletTokenDto] = return self.walletAccountService.getTokensByAddresses(addresses) +proc getChainIds*(self: Controller): seq[int] = + return self.networkService.getNetworks().map(n => n.chainId) + +proc getEnabledChainIds*(self: Controller): seq[int] = + return self.networkService.getNetworks().filter(n => n.enabled).map(n => n.chainId) + proc setSocialLinks*(self: Controller, links: SocialLinks) = self.settingsService.setSocialLinks(links) diff --git a/src/app/modules/main/profile_section/profile/io_interface.nim b/src/app/modules/main/profile_section/profile/io_interface.nim index b1d00f4d29..a639fed9d0 100644 --- a/src/app/modules/main/profile_section/profile/io_interface.nim +++ b/src/app/modules/main/profile_section/profile/io_interface.nim @@ -26,6 +26,9 @@ method isLoaded*(self: AccessInterface): bool {.base.} = method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} = raise newException(ValueError, "No implementation available") +method getCollectiblesModel*(self: AccessInterface): QVariant {.base.} = + raise newException(ValueError, "No implementation available") + method storeIdentityImage*(self: AccessInterface, imageUrl: string, aX: int, aY: int, bX: int, bY: int) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/profile_section/profile/models/profile_preferences_asset_item.nim b/src/app/modules/main/profile_section/profile/models/profile_preferences_asset_item.nim index eee201e608..c7d2a62310 100644 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_asset_item.nim +++ b/src/app/modules/main/profile_section/profile/models/profile_preferences_asset_item.nim @@ -2,7 +2,6 @@ import json, strutils, stint, json_serialization, tables import profile_preferences_base_item -import app_service/service/wallet_account/dto/account_dto import app_service/service/profile/dto/profile_showcase_preferences import app/modules/shared_models/currency_amount @@ -14,13 +13,17 @@ import backend/helpers/token type ProfileShowcaseAssetItem* = ref object of ProfileShowcaseBaseItem + contractAddress*: string + communityId*: string + chainId*: int symbol*: string name*: string enabledNetworkBalance*: CurrencyAmount color*: string decimals*: int -proc initProfileShowcaseAssetItem*(token: WalletTokenDto, visibility: ProfileShowcaseVisibility, order: int): ProfileShowcaseAssetItem = + +proc initProfileShowcaseVerifiedToken*(token: WalletTokenDto, visibility: ProfileShowcaseVisibility, order: int): ProfileShowcaseAssetItem = result = ProfileShowcaseAssetItem() result.showcaseVisibility = visibility @@ -32,6 +35,8 @@ proc initProfileShowcaseAssetItem*(token: WalletTokenDto, visibility: ProfileSho result.color = token.color result.decimals = token.decimals + # TODO: initProfileShowcaseUnverifiedToken + proc toProfileShowcaseAssetItem*(jsonObj: JsonNode): ProfileShowcaseAssetItem = result = ProfileShowcaseAssetItem() @@ -42,6 +47,8 @@ proc toProfileShowcaseAssetItem*(jsonObj: JsonNode): ProfileShowcaseAssetItem = visibilityInt <= ord(high(ProfileShowcaseVisibility)))): result.showcaseVisibility = ProfileShowcaseVisibility(visibilityInt) + discard jsonObj.getProp("address", result.contractAddress) + discard jsonObj.getProp("communityId", result.communityId) discard jsonObj.getProp("symbol", result.symbol) discard jsonObj.getProp("name", result.name) discard jsonObj.getProp("color", result.color) @@ -49,21 +56,17 @@ proc toProfileShowcaseAssetItem*(jsonObj: JsonNode): ProfileShowcaseAssetItem = result.enabledNetworkBalance = newCurrencyAmount(jsonObj{"enabledNetworkBalance"}.getFloat, result.symbol, result.decimals, false) -proc toShowcasePreferenceItem*(self: ProfileShowcaseAssetItem): ProfileShowcaseAssetPreference = - result = ProfileShowcaseAssetPreference() +proc toShowcaseVerifiedTokenPreference*(self: ProfileShowcaseAssetItem): ProfileShowcaseVerifiedTokenPreference = + result = ProfileShowcaseVerifiedTokenPreference() result.symbol = self.symbol result.showcaseVisibility = self.showcaseVisibility result.order = self.order -proc symbol*(self: ProfileShowcaseAssetItem): string {.inline.} = - self.symbol +proc toShowcaseUnverifiedTokenPreference*(self: ProfileShowcaseAssetItem): ProfileShowcaseUnverifiedTokenPreference = + result = ProfileShowcaseUnverifiedTokenPreference() -proc name*(self: ProfileShowcaseAssetItem): string {.inline.} = - self.name - -proc enabledNetworkBalance*(self: ProfileShowcaseAssetItem): CurrencyAmount {.inline.} = - self.enabledNetworkBalance - -proc color*(self: ProfileShowcaseAssetItem): string {.inline.} = - self.color + result.contractAddress = self.contractAddress + result.chainId = self.chainId + result.showcaseVisibility = self.showcaseVisibility + result.order = self.order diff --git a/src/app/modules/main/profile_section/profile/models/profile_preferences_assets_model.nim b/src/app/modules/main/profile_section/profile/models/profile_preferences_assets_model.nim index 2fe17f8bd6..d56ac6464e 100644 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_assets_model.nim +++ b/src/app/modules/main/profile_section/profile/models/profile_preferences_assets_model.nim @@ -8,6 +8,8 @@ type ShowcaseVisibility = UserRole + 1 Order + Address + CommunityId Symbol Name EnabledNetworkBalance @@ -52,6 +54,8 @@ QtObject: ModelRole.ShowcaseVisibility.int: "showcaseVisibility", ModelRole.Order.int: "order", + ModelRole.Address.int: "address", + ModelRole.CommunityId.int: "communityId", ModelRole.Symbol.int: "symbol", ModelRole.Name.int: "name", ModelRole.EnabledNetworkBalance.int: "enabledNetworkBalance", @@ -74,6 +78,10 @@ QtObject: result = newQVariant(item.showcaseVisibility.int) of ModelRole.Order: result = newQVariant(item.order) + of ModelRole.Address: + result = newQVariant(item.contractAddress) + of ModelRole.CommunityId: + result = newQVariant(item.communityId) of ModelRole.Symbol: result = newQVariant(item.symbol) of ModelRole.Name: @@ -120,6 +128,8 @@ QtObject: self.dataChanged(index, index, @[ ModelRole.ShowcaseVisibility.int, ModelRole.Order.int, + ModelRole.Address.int, + ModelRole.CommunityId.int, ModelRole.Symbol.int, ModelRole.Name.int, ModelRole.EnabledNetworkBalance.int, diff --git a/src/app/modules/main/profile_section/profile/models/profile_preferences_collectible_item.nim b/src/app/modules/main/profile_section/profile/models/profile_preferences_collectible_item.nim index 7f2c95d7fd..1ab4dc80b1 100644 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_collectible_item.nim +++ b/src/app/modules/main/profile_section/profile/models/profile_preferences_collectible_item.nim @@ -1,19 +1,38 @@ -import json, strutils, stint, json_serialization, tables +import json, strutils, strformat, stint, json_serialization, tables import profile_preferences_base_item import app_service/service/profile/dto/profile_showcase_preferences +import app/modules/shared_models/collectibles_entry include app_service/common/json_utils include app_service/common/utils type ProfileShowcaseCollectibleItem* = ref object of ProfileShowcaseBaseItem - uid*: string + chainId*: int + tokenId*: string + contractAddress*: string + communityId*: string name*: string collectionName*: string imageUrl*: string backgroundColor*: string + loading*: bool + +proc initProfileShowcaseCollectibleItem*(collectible: CollectiblesEntry, visibility: ProfileShowcaseVisibility, order: int): ProfileShowcaseCollectibleItem = + result = ProfileShowcaseCollectibleItem() + result.contractAddress = collectible.getContractAddress() + result.chainId = collectible.getChainID() + result.tokenId = collectible.getTokenIDAsString() + result.communityId = collectible.getCommunityId() + result.name = collectible.getName() + result.collectionName = collectible.getCollectionName() + result.imageUrl = collectible.getImageURL() + result.backgroundColor = collectible.getBackgroundColor() + result.showcaseVisibility = visibility + result.order = order + result.loading = false proc toProfileShowcaseCollectibleItem*(jsonObj: JsonNode): ProfileShowcaseCollectibleItem = result = ProfileShowcaseCollectibleItem() @@ -25,7 +44,10 @@ proc toProfileShowcaseCollectibleItem*(jsonObj: JsonNode): ProfileShowcaseCollec visibilityInt <= ord(high(ProfileShowcaseVisibility)))): result.showcaseVisibility = ProfileShowcaseVisibility(visibilityInt) - discard jsonObj.getProp("uid", result.uid) + discard jsonObj.getProp("chainId", result.chainId) + discard jsonObj.getProp("tokenId", result.tokenId) + discard jsonObj.getProp("contractAddress", result.contractAddress) + discard jsonObj.getProp("communityId", result.communityId) discard jsonObj.getProp("name", result.name) discard jsonObj.getProp("collectionName", result.collectionName) discard jsonObj.getProp("imageUrl", result.imageUrl) @@ -34,18 +56,13 @@ proc toProfileShowcaseCollectibleItem*(jsonObj: JsonNode): ProfileShowcaseCollec proc toShowcasePreferenceItem*(self: ProfileShowcaseCollectibleItem): ProfileShowcaseCollectiblePreference = result = ProfileShowcaseCollectiblePreference() - result.uid = self.uid + result.chainId = self.chainId + result.tokenId = self.tokenId + result.contractAddress = self.contractAddress + result.communityId = self.communityId result.showcaseVisibility = self.showcaseVisibility result.order = self.order -proc name*(self: ProfileShowcaseCollectibleItem): string {.inline.} = - self.name - -proc collectionName*(self: ProfileShowcaseCollectibleItem): string {.inline.} = - self.collectionName - -proc imageUrl*(self: ProfileShowcaseCollectibleItem): string {.inline.} = - self.imageUrl - -proc backgroundColor*(self: ProfileShowcaseCollectibleItem): string {.inline.} = - self.backgroundColor +# NOTE: should be same as CollectiblesEntry::getID +proc getID*(self: ProfileShowcaseCollectibleItem): string = + return fmt"{self.chainId}+{self.contractAddress}+{self.tokenId}" \ No newline at end of file diff --git a/src/app/modules/main/profile_section/profile/models/profile_preferences_collectibles_model.nim b/src/app/modules/main/profile_section/profile/models/profile_preferences_collectibles_model.nim index 5e946598bd..cf89537305 100644 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_collectibles_model.nim +++ b/src/app/modules/main/profile_section/profile/models/profile_preferences_collectibles_model.nim @@ -5,14 +5,19 @@ import app_service/service/profile/dto/profile_showcase_preferences type ModelRole {.pure.} = enum - ShowcaseVisibility = UserRole + 1 - Order - - Uid + Uid = UserRole + 1, + ChainId + ContractAddress + TokenId Name - CollectionName ImageUrl BackgroundColor + CollectionName + IsLoading + CommunityId + + ShowcaseVisibility + Order QtObject: type @@ -49,14 +54,19 @@ QtObject: method roleNames(self: ProfileShowcaseCollectiblesModel): Table[int, string] = { - ModelRole.ShowcaseVisibility.int: "showcaseVisibility", - ModelRole.Order.int: "order", - - ModelRole.Uid.int: "uid", + ModelRole.Uid.int:"uid", + ModelRole.ChainId.int: "chainId", + ModelRole.ContractAddress.int: "contractAddress", + ModelRole.TokenId.int: "tokenId", ModelRole.Name.int: "name", - ModelRole.CollectionName.int: "collectionName", ModelRole.ImageUrl.int: "imageUrl", ModelRole.BackgroundColor.int: "backgroundColor", + ModelRole.CollectionName.int: "collectionName", + ModelRole.IsLoading.int:"isLoading", + ModelRole.CommunityId.int: "communityId", + + ModelRole.ShowcaseVisibility.int: "showcaseVisibility", + ModelRole.Order.int: "order", }.toTable method data(self: ProfileShowcaseCollectiblesModel, index: QModelIndex, role: int): QVariant = @@ -70,24 +80,35 @@ QtObject: let enumRole = role.ModelRole case enumRole: - of ModelRole.ShowcaseVisibility: - result = newQVariant(item.showcaseVisibility.int) - of ModelRole.Order: - result = newQVariant(item.order) of ModelRole.Uid: - result = newQVariant(item.uid) + result = newQVariant(item.getID()) + of ModelRole.ChainId: + result = newQVariant(item.chainId) + of ModelRole.ContractAddress: + result = newQVariant(item.contractAddress) + of ModelRole.TokenId: + result = newQVariant(item.tokenId) of ModelRole.Name: result = newQVariant(item.name) - of ModelRole.CollectionName: - result = newQVariant(item.collectionName) of ModelRole.ImageUrl: result = newQVariant(item.imageUrl) of ModelRole.BackgroundColor: result = newQVariant(item.backgroundColor) + of ModelRole.CollectionName: + result = newQVariant(item.collectionName) + of ModelRole.IsLoading: + result = newQVariant(item.loading) + of ModelRole.CommunityId: + result = newQVariant(item.communityId) + + of ModelRole.ShowcaseVisibility: + result = newQVariant(item.showcaseVisibility.int) + of ModelRole.Order: + result = newQVariant(item.order) proc findIndexForCollectible(self: ProfileShowcaseCollectiblesModel, uid: string): int = for i in 0 ..< self.items.len: - if (self.items[i].uid == uid): + if (self.items[i].getID() == uid): return i return -1 @@ -109,7 +130,7 @@ QtObject: self.baseModelFilterConditionsMayHaveChanged() proc upsertItemImpl(self: ProfileShowcaseCollectiblesModel, item: ProfileShowcaseCollectibleItem) = - let ind = self.findIndexForCollectible(item.uid) + let ind = self.findIndexForCollectible(item.getID()) if ind == -1: self.appendItem(item) else: @@ -120,11 +141,15 @@ QtObject: self.dataChanged(index, index, @[ ModelRole.ShowcaseVisibility.int, ModelRole.Order.int, - ModelRole.Uid.int, + ModelRole.ChainId.int, + ModelRole.TokenId.int, + ModelRole.ContractAddress.int, + ModelRole.CommunityId.int, ModelRole.Name.int, ModelRole.CollectionName.int, ModelRole.ImageUrl.int, ModelRole.BackgroundColor.int, + ModelRole.IsLoading.int ]) proc upsertItemJson(self: ProfileShowcaseCollectiblesModel, itemJson: string) {.slot.} = diff --git a/src/app/modules/main/profile_section/profile/module.nim b/src/app/modules/main/profile_section/profile/module.nim index 21ec264391..d73d3ce11a 100644 --- a/src/app/modules/main/profile_section/profile/module.nim +++ b/src/app/modules/main/profile_section/profile/module.nim @@ -9,18 +9,23 @@ import app_service/service/profile/service as profile_service import app_service/service/settings/service as settings_service import app_service/service/community/service as community_service import app_service/service/wallet_account/service as wallet_account_service +import app_service/service/network/service as network_service import app_service/service/profile/dto/profile_showcase import app_service/service/profile/dto/profile_showcase_preferences import app_service/common/social_links import app/modules/shared_models/social_links_model import app/modules/shared_models/social_link_item +import app/modules/shared_modules/collectibles/controller as collectiblesc +import app/modules/shared_models/collectibles_entry import models/profile_preferences_community_item import models/profile_preferences_account_item import models/profile_preferences_collectible_item import models/profile_preferences_asset_item +import backend/collectibles as backend_collectibles + export io_interface logScope: @@ -29,7 +34,8 @@ logScope: type Module* = ref object of io_interface.AccessInterface delegate: delegate_interface.AccessInterface - controller: Controller + controller: controller.Controller + collectiblesController: collectiblesc.Controller view: View viewVariant: QVariant moduleLoaded: bool @@ -41,18 +47,26 @@ proc newModule*( profileService: profile_service.Service, settingsService: settings_service.Service, communityService: community_service.Service, - walletAccountService: wallet_account_service.Service): Module = + walletAccountService: wallet_account_service.Service, + networkService: network_service.Service): Module = result = Module() result.delegate = delegate result.view = view.newView(result) result.viewVariant = newQVariant(result.view) - result.controller = controller.newController(result, events, profileService, settingsService, communityService, walletAccountService) + result.controller = controller.newController(result, events, profileService, settingsService, communityService, walletAccountService, networkService) + result.collectiblesController = collectiblesc.newController( + requestId = int32(backend_collectibles.CollectiblesRequestID.ProfileShowcase), + loadType = collectiblesc.LoadType.AutoLoadSingleUpdate, + networkService = networkService, + events = events + ) result.moduleLoaded = false method delete*(self: Module) = self.view.delete self.viewVariant.delete self.controller.delete + self.collectiblesController.delete method load*(self: Module) = self.controller.init() @@ -64,6 +78,9 @@ method isLoaded*(self: Module): bool = method getModuleAsVariant*(self: Module): QVariant = return self.viewVariant +method getCollectiblesModel*(self: Module): QVariant = + return self.collectiblesController.getModelAsVariant() + proc updateSocialLinks(self: Module, socialLinks: SocialLinks) = var socialLinkItems = toSocialLinkItems(socialLinks) self.view.socialLinksSaved(socialLinkItems) @@ -118,11 +135,22 @@ method storeProfileShowcasePreferences(self: Module, if acc.showcaseVisibility != ProfileShowcaseVisibility.ToNoOne: revealedAddresses.add(acc.address) + var verifiedTokens: seq[ProfileShowcaseVerifiedTokenPreference] = @[] + var unverifiedTokens: seq[ProfileShowcaseUnverifiedTokenPreference] = @[] + + for asset in assets: + # TODO: more obvious way to check if it is verified or not + if asset.communityId == "": + verifiedTokens.add(asset.toShowcaseVerifiedTokenPreference()) + else: + unverifiedTokens.add(asset.toShowcaseUnverifiedTokenPreference()) + self.controller.storeProfileShowcasePreferences(ProfileShowcasePreferencesDto( communities: communities.map(item => item.toShowcasePreferenceItem()), accounts: accounts.map(item => item.toShowcasePreferenceItem()), collectibles: collectibles.map(item => item.toShowcasePreferenceItem()), - assets: assets.map(item => item.toShowcasePreferenceItem()), + verifiedTokens: verifiedTokens, + unverifiedTokens: unverifiedTokens ), revealedAddresses ) @@ -150,80 +178,100 @@ method updateProfileShowcase(self: Module, profileShowcase: ProfileShowcaseDto) if self.presentedPublicKey != profileShowcase.contactId: return + # Communities for a contact var profileCommunityItems: seq[ProfileShowcaseCommunityItem] = @[] - var profileAccountItems: seq[ProfileShowcaseAccountItem] = @[] - var profileAssetItems: seq[ProfileShowcaseAssetItem] = @[] - - for communityEntry in profileShowcase.communities: - let community = self.controller.getCommunityById(communityEntry.communityId) + for communityProfile in profileShowcase.communities: + let community = self.controller.getCommunityById(communityProfile.communityId) if community.id == "": # Fetch the community, however, we do not the shard info, so hopefully we can fetch it - self.controller.requestCommunityInfo(communityEntry.communityId, shard = nil) + self.controller.requestCommunityInfo(communityProfile.communityId, shard = nil) profileCommunityItems.add(initProfileShowcaseCommunityLoadingItem( - communityEntry.communityId, ProfileShowcaseVisibility.ToEveryone, communityEntry.order)) + communityProfile.communityId, ProfileShowcaseVisibility.ToEveryone, communityProfile.order)) else: profileCommunityItems.add(initProfileShowcaseCommunityItem( - community, ProfileShowcaseVisibility.ToEveryone, communityEntry.order)) + community, ProfileShowcaseVisibility.ToEveryone, communityProfile.order)) self.view.updateProfileShowcaseCommunities(profileCommunityItems) - var addresses: seq[string] = @[] + # Accounts for a contact, reuse addresses for collectibles and token balances + var profileAccountItems: seq[ProfileShowcaseAccountItem] = @[] + var accountAddresses: seq[string] = @[] for account in profileShowcase.accounts: profileAccountItems.add(initProfileShowcaseAccountItem( - account.address, - account.name, - account.emoji, - account.colorId, - ProfileShowcaseVisibility.ToEveryone, - account.order - )) - addresses.add(account.address) - - for assetEntry in profileShowcase.assets: - for token in self.controller.getTokensByAddresses(addresses): - if assetEntry.symbol == token.symbol: - profileAssetItems.add(initProfileShowcaseAssetItem(token, ProfileShowcaseVisibility.ToEveryone, assetEntry.order)) - + account.address, account.name, account.emoji, account.colorId, + ProfileShowcaseVisibility.ToEveryone, account.order)) + accountAddresses.add(account.address) self.view.updateProfileShowcaseAccounts(profileAccountItems) + + # Collectibles for a contact + let chainIds = self.controller.getChainIds() + self.collectiblesController.setFilterAddressesAndChains(accountAddresses, chainIds) + + var profileCollectibleItems: seq[ProfileShowcaseCollectibleItem] = @[] + for collectibleProfile in profileShowcase.collectibles: + let collectible = self.collectiblesController.getItemForData(collectibleProfile.tokenId, collectibleProfile.contractAddress, collectibleProfile.chainId) + if collectible != nil: + profileCollectibleItems.add(initProfileShowcaseCollectibleItem( + collectible, ProfileShowcaseVisibility.ToEveryone, collectibleProfile.order)) + self.view.updateProfileShowcaseCollectibles(profileCollectibleItems) + + # Verified tokens for a contact + var profileAssetItems: seq[ProfileShowcaseAssetItem] = @[] + for tokenProfile in profileShowcase.verifiedTokens: + # NOTE: not yet working for external wallet accounts + for token in self.controller.getTokensByAddresses(accountAddresses): + if tokenProfile.symbol == token.symbol: + profileAssetItems.add(initProfileShowcaseVerifiedToken(token, ProfileShowcaseVisibility.ToEveryone, tokenProfile.order)) + + # TODO: Unverified tokens for a contact self.view.updateProfileShowcaseAssets(profileAssetItems) - # TODO: collectibles, need wallet api to fetch collectible by uid method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowcasePreferencesDto) = if self.presentedPublicKey != singletonInstance.userProfile.getPubKey(): return var profileCommunityItems: seq[ProfileShowcaseCommunityItem] = @[] - var profileAccountItems: seq[ProfileShowcaseAccountItem] = @[] - var profileAssetItems: seq[ProfileShowcaseAssetItem] = @[] - - for communityEntry in preferences.communities: - let community = self.controller.getCommunityById(communityEntry.communityId) + for communityProfile in preferences.communities: + let community = self.controller.getCommunityById(communityProfile.communityId) if community.id == "": - warn "Unknown community added to our own profile showcase" , communityId = communityEntry.communityId + warn "Unknown community added to our own profile showcase" , communityId = communityProfile.communityId else: profileCommunityItems.add(initProfileShowcaseCommunityItem( - community, communityEntry.showcaseVisibility, communityEntry.order)) + community, communityProfile.showcaseVisibility, communityProfile.order)) self.view.updateProfileShowcaseCommunities(profileCommunityItems) - var addresses: seq[string] = @[] + # For profile preferences we are using all the addresses for colletibles and token balances + # TODO: add wallet accounts model instance here to remove QML dependency from the wallet module + let accountAddresses = self.controller.getWalletAccounts().map(acc => acc.address) # filter(acc => acc.walletType != WalletTypeWatch). + + # Accounts profile preferences + var profileAccountItems: seq[ProfileShowcaseAccountItem] = @[] for account in preferences.accounts: profileAccountItems.add(initProfileShowcaseAccountItem( - account.address, - account.name, - account.emoji, - account.colorId, - account.showcaseVisibility, - account.order - )) - addresses.add(account.address) - - for assetEntry in preferences.assets: - for token in self.controller.getTokensByAddresses(addresses): - if assetEntry.symbol == token.symbol: - profileAssetItems.add(initProfileShowcaseAssetItem(token, assetEntry.showcaseVisibility, assetEntry.order)) - + account.address, account.name, account.emoji, account.colorId, + account.showcaseVisibility, account.order)) self.view.updateProfileShowcaseAccounts(profileAccountItems) + + # Collectibles profile preferences + let chainIds = self.controller.getChainIds() + self.collectiblesController.setFilterAddressesAndChains(accountAddresses, chainIds) + + var profileCollectibleItems: seq[ProfileShowcaseCollectibleItem] = @[] + for collectibleProfile in preferences.collectibles: + let collectible = self.collectiblesController.getItemForData(collectibleProfile.tokenId, collectibleProfile.contractAddress, collectibleProfile.chainId) + if collectible != nil: + profileCollectibleItems.add(initProfileShowcaseCollectibleItem( + collectible, collectibleProfile.showcaseVisibility, collectibleProfile.order)) + self.view.updateProfileShowcaseCollectibles(profileCollectibleItems) + + # TODO: Verified tokens preferences + var profileAssetItems: seq[ProfileShowcaseAssetItem] = @[] + for tokenProfile in preferences.verifiedTokens: + for token in self.controller.getTokensByAddresses(accountAddresses): + if tokenProfile.symbol == token.symbol: + profileAssetItems.add(initProfileShowcaseVerifiedToken(token, tokenProfile.showcaseVisibility, tokenProfile.order)) + + # TODO: Unverified tokens preferences self.view.updateProfileShowcaseAssets(profileAssetItems) - # TODO: collectibles, need wallet api to fetch collectible by uid method onCommunitiesUpdated*(self: Module, communities: seq[CommunityDto]) = var profileCommunityItems = self.view.getProfileShowcaseCommunities() diff --git a/src/app/modules/main/profile_section/profile/view.nim b/src/app/modules/main/profile_section/profile/view.nim index 317501df0a..251572b098 100644 --- a/src/app/modules/main/profile_section/profile/view.nim +++ b/src/app/modules/main/profile_section/profile/view.nim @@ -174,6 +174,12 @@ QtObject: proc emitBioChangedSignal*(self: View) = self.bioChanged() + proc getCollectiblesModel(self: View): QVariant {.slot.} = + return self.delegate.getCollectiblesModel() + + QtProperty[QVariant] collectiblesModel: + read = getCollectiblesModel + proc getProfileShowcaseCommunitiesModel(self: View): QVariant {.slot.} = return self.profileShowcaseCommunitiesModelVariant @@ -227,7 +233,7 @@ QtObject: proc updateProfileShowcaseAccounts*(self: View, accounts: seq[ProfileShowcaseAccountItem]) = self.profileShowcaseAccountsModel.reset(accounts.sorted((a, b) => cmp(a.order, b.order), SortOrder.Ascending)) - proc updateProfileShowcaseCollectibless*(self: View, collectibles: seq[ProfileShowcaseCollectibleItem]) = + proc updateProfileShowcaseCollectibles*(self: View, collectibles: seq[ProfileShowcaseCollectibleItem]) = self.profileShowcaseCollectiblesModel.reset(collectibles.sorted((a, b) => cmp(a.order, b.order), SortOrder.Ascending)) proc updateProfileShowcaseAssets*(self: View, assets: seq[ProfileShowcaseAssetItem]) = diff --git a/src/app/modules/shared_models/collectibles_model.nim b/src/app/modules/shared_models/collectibles_model.nim index 8940f49320..cdc05fd098 100644 --- a/src/app/modules/shared_models/collectibles_model.nim +++ b/src/app/modules/shared_models/collectibles_model.nim @@ -332,6 +332,12 @@ QtObject: proc getItems*(self: Model): seq[CollectiblesEntry] = return self.items + proc getItemById*(self: Model, id: string): CollectiblesEntry = + for item in self.items: + if(cmpIgnoreCase(item.getID(), id) == 0): + return item + return nil + proc setItems*(self: Model, newItems: seq[CollectiblesEntry], offset: int, hasMore: bool) = if offset == 0: self.removeCollectibleItems() diff --git a/src/app/modules/shared_modules/collectibles/controller.nim b/src/app/modules/shared_modules/collectibles/controller.nim index 23b94a2ca4..ff3ba5efe3 100644 --- a/src/app/modules/shared_modules/collectibles/controller.nim +++ b/src/app/modules/shared_modules/collectibles/controller.nim @@ -301,3 +301,10 @@ QtObject: self.filter = filter self.resetModel() + + proc getActivityToken*(self: Controller, id: string): backend_activity.Token = + return self.model.getActivityToken(id) + + proc getItemForData*(self: Controller, tokenId: string, tokenAddress: string, chainId: int): CollectiblesEntry = + let uid = self.model.getUidForData(tokenId, tokenAddress, chainId) + return self.model.getItemById(uid) diff --git a/src/app_service/service/profile/dto/profile_showcase.nim b/src/app_service/service/profile/dto/profile_showcase.nim index a879caee36..75be29fa65 100644 --- a/src/app_service/service/profile/dto/profile_showcase.nim +++ b/src/app_service/service/profile/dto/profile_showcase.nim @@ -14,19 +14,29 @@ type ProfileShowcaseAccount* = ref object of RootObj order*: int type ProfileShowcaseCollectible* = ref object of RootObj - uid*: string + contractAddress*: string + chainId*: int + tokenId*: string + communityId*: string + accountAddress*: string order*: int -type ProfileShowcaseAsset* = ref object of RootObj +type ProfileShowcaseVerifiedToken* = ref object of RootObj symbol*: string order*: int +type ProfileShowcaseUnverifiedToken* = ref object of RootObj + contractAddress*: string + chainId*: int + order*: int + type ProfileShowcaseDto* = ref object of RootObj contactId*: string communities*: seq[ProfileShowcaseCommunity] accounts*: seq[ProfileShowcaseAccount] collectibles*: seq[ProfileShowcaseCollectible] - assets*: seq[ProfileShowcaseAsset] + verifiedTokens*: seq[ProfileShowcaseVerifiedToken] + unverifiedTokens*: seq[ProfileShowcaseUnverifiedToken] proc toProfileShowcaseCommunity*(jsonObj: JsonNode): ProfileShowcaseCommunity = result = ProfileShowcaseCommunity() @@ -43,14 +53,24 @@ proc toProfileShowcaseAccount*(jsonObj: JsonNode): ProfileShowcaseAccount = proc toProfileShowcaseCollectible*(jsonObj: JsonNode): ProfileShowcaseCollectible = result = ProfileShowcaseCollectible() - discard jsonObj.getProp("uid", result.uid) + discard jsonObj.getProp("chainId", result.chainId) + discard jsonObj.getProp("tokenId", result.tokenId) + discard jsonObj.getProp("contractAddress", result.contractAddress) + discard jsonObj.getProp("communityId", result.communityId) + discard jsonObj.getProp("accountAddress", result.accountAddress) discard jsonObj.getProp("order", result.order) -proc toProfileShowcaseAsset*(jsonObj: JsonNode): ProfileShowcaseAsset = - result = ProfileShowcaseAsset() +proc toProfileShowcaseVerifiedToken*(jsonObj: JsonNode): ProfileShowcaseVerifiedToken = + result = ProfileShowcaseVerifiedToken() discard jsonObj.getProp("symbol", result.symbol) discard jsonObj.getProp("order", result.order) +proc toProfileShowcaseUnverifiedToken*(jsonObj: JsonNode): ProfileShowcaseUnverifiedToken = + result = ProfileShowcaseUnverifiedToken() + discard jsonObj.getProp("contractAddress", result.contractAddress) + discard jsonObj.getProp("chainId", result.chainId) + discard jsonObj.getProp("order", result.order) + proc toProfileShowcaseDto*(jsonObj: JsonNode): ProfileShowcaseDto = result = ProfileShowcaseDto() @@ -62,5 +82,7 @@ proc toProfileShowcaseDto*(jsonObj: JsonNode): ProfileShowcaseDto = result.accounts.add(jsonMsg.toProfileShowcaseAccount()) for jsonMsg in jsonObj["collectibles"]: result.collectibles.add(jsonMsg.toProfileShowcaseCollectible()) - for jsonMsg in jsonObj["assets"]: - result.assets.add(jsonMsg.toProfileShowcaseAsset()) + for jsonMsg in jsonObj["verifiedTokens"]: + result.verifiedTokens.add(jsonMsg.toProfileShowcaseVerifiedToken()) + for jsonMsg in jsonObj["unverifiedTokens"]: + result.unverifiedTokens.add(jsonMsg.toProfileShowcaseUnverifiedToken()) diff --git a/src/app_service/service/profile/dto/profile_showcase_preferences.nim b/src/app_service/service/profile/dto/profile_showcase_preferences.nim index 1f72326086..d0c4dae5b2 100644 --- a/src/app_service/service/profile/dto/profile_showcase_preferences.nim +++ b/src/app_service/service/profile/dto/profile_showcase_preferences.nim @@ -23,20 +23,31 @@ type ProfileShowcaseAccountPreference* = ref object of RootObj order*: int type ProfileShowcaseCollectiblePreference* = ref object of RootObj - uid*: string + contractAddress*: string + chainId*: int + tokenId*: string + communityId*: string + accountAddress*: string showcaseVisibility*: ProfileShowcaseVisibility order*: int -type ProfileShowcaseAssetPreference* = ref object of RootObj +type ProfileShowcaseVerifiedTokenPreference* = ref object of RootObj symbol*: string showcaseVisibility*: ProfileShowcaseVisibility order*: int +type ProfileShowcaseUnverifiedTokenPreference* = ref object of RootObj + contractAddress*: string + chainId*: int + showcaseVisibility*: ProfileShowcaseVisibility + order*: int + type ProfileShowcasePreferencesDto* = ref object of RootObj communities*: seq[ProfileShowcaseCommunityPreference] accounts*: seq[ProfileShowcaseAccountPreference] collectibles*: seq[ProfileShowcaseCollectiblePreference] - assets*: seq[ProfileShowcaseAssetPreference] + verifiedTokens*: seq[ProfileShowcaseVerifiedTokenPreference] + unverifiedTokens*: seq[ProfileShowcaseUnverifiedTokenPreference] proc toProfileShowcaseVisibility*(jsonObj: JsonNode): ProfileShowcaseVisibility = var visibilityInt: int @@ -80,30 +91,53 @@ proc toJsonNode*(self: ProfileShowcaseAccountPreference): JsonNode = proc toProfileShowcaseCollectiblePreference*(jsonObj: JsonNode): ProfileShowcaseCollectiblePreference = result = ProfileShowcaseCollectiblePreference() - discard jsonObj.getProp("uid", result.uid) + discard jsonObj.getProp("chainId", result.chainId) + discard jsonObj.getProp("tokenId", result.tokenId) + discard jsonObj.getProp("contractAddress", result.contractAddress) + discard jsonObj.getProp("communityId", result.communityId) + discard jsonObj.getProp("accountAddress", result.accountAddress) discard jsonObj.getProp("order", result.order) result.showcaseVisibility = jsonObj.toProfileShowcaseVisibility() proc toJsonNode*(self: ProfileShowcaseCollectiblePreference): JsonNode = %* { - "uid": self.uid, + "chainId": self.chainId, + "tokenId": self.tokenId, + "contractAddress": self.contractAddress, + "communityId": self.communityId, + "accountAddress": self.accountAddress, "showcaseVisibility": self.showcaseVisibility.int, "order": self.order, } -proc toProfileShowcaseAssetPreference*(jsonObj: JsonNode): ProfileShowcaseAssetPreference = - result = ProfileShowcaseAssetPreference() +proc toProfileShowcaseVerifiedTokenPreference*(jsonObj: JsonNode): ProfileShowcaseVerifiedTokenPreference = + result = ProfileShowcaseVerifiedTokenPreference() discard jsonObj.getProp("symbol", result.symbol) discard jsonObj.getProp("order", result.order) result.showcaseVisibility = jsonObj.toProfileShowcaseVisibility() -proc toJsonNode*(self: ProfileShowcaseAssetPreference): JsonNode = +proc toJsonNode*(self: ProfileShowcaseVerifiedTokenPreference): JsonNode = %* { "symbol": self.symbol, "showcaseVisibility": self.showcaseVisibility.int, "order": self.order, } +proc toProfileShowcaseUnverifiedTokenPreference*(jsonObj: JsonNode): ProfileShowcaseUnverifiedTokenPreference = + result = ProfileShowcaseUnverifiedTokenPreference() + discard jsonObj.getProp("contractAddress", result.contractAddress) + discard jsonObj.getProp("chainId", result.chainId) + discard jsonObj.getProp("order", result.order) + result.showcaseVisibility = jsonObj.toProfileShowcaseVisibility() + +proc toJsonNode*(self: ProfileShowcaseUnverifiedTokenPreference): JsonNode = + %* { + "contractAddress": self.contractAddress, + "chainId": self.chainId, + "showcaseVisibility": self.showcaseVisibility.int, + "order": self.order, + } + proc toProfileShowcasePreferencesDto*(jsonObj: JsonNode): ProfileShowcasePreferencesDto = result = ProfileShowcasePreferencesDto() @@ -113,18 +147,22 @@ proc toProfileShowcasePreferencesDto*(jsonObj: JsonNode): ProfileShowcasePrefere result.accounts.add(jsonMsg.toProfileShowcaseAccountPreference()) for jsonMsg in jsonObj["collectibles"]: result.collectibles.add(jsonMsg.toProfileShowcaseCollectiblePreference()) - for jsonMsg in jsonObj["assets"]: - result.assets.add(jsonMsg.toProfileShowcaseAssetPreference()) + for jsonMsg in jsonObj["verifiedTokens"]: + result.verifiedTokens.add(jsonMsg.toProfileShowcaseVerifiedTokenPreference()) + for jsonMsg in jsonObj["unverifiedTokens"]: + result.unverifiedTokens.add(jsonMsg.toProfileShowcaseUnverifiedTokenPreference()) proc toJsonNode*(self: ProfileShowcasePreferencesDto): JsonNode = let communities = self.communities.map(entry => entry.toJsonNode()) let accounts = self.accounts.map(entry => entry.toJsonNode()) let collectibles = self.collectibles.map(entry => entry.toJsonNode()) - let assets = self.assets.map(entry => entry.toJsonNode()) + let verifiedTokens = self.verifiedTokens.map(entry => entry.toJsonNode()) + let unverifiedTokens = self.unverifiedTokens.map(entry => entry.toJsonNode()) return %*[{ "communities": communities, "accounts": accounts, "collectibles": collectibles, - "assets": assets, + "verifiedTokens": verifiedTokens, + "unverifiedTokens": unverifiedTokens }] diff --git a/src/app_service/service/wallet_account/service_account.nim b/src/app_service/service/wallet_account/service_account.nim index 7adc58c14f..3932bc58fc 100644 --- a/src/app_service/service/wallet_account/service_account.nim +++ b/src/app_service/service/wallet_account/service_account.nim @@ -87,7 +87,7 @@ proc getAccountsByAddresses*(self: Service, addresses: seq[string]): seq[WalletA continue result.add(acc) -proc getWalletAccounts*(self: Service): seq[WalletAccountDto] = +proc getWalletAccounts*(self: Service, excludeWatchOnly: bool = false): seq[WalletAccountDto] = for _, kp in self.keypairs: if kp.keypairType == KeypairTypeProfile: for acc in kp.accounts: @@ -96,7 +96,8 @@ proc getWalletAccounts*(self: Service): seq[WalletAccountDto] = result.add(acc) continue result.add(kp.accounts) - result.add(toSeq(self.watchOnlyAccounts.values)) + if not excludeWatchOnly: + result.add(toSeq(self.watchOnlyAccounts.values)) result.sort(walletAccountsCmp) proc getWalletAddresses*(self: Service): seq[string] = diff --git a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAssetsPanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAssetsPanel.qml index 4aceb423b6..d8f447c259 100644 --- a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAssetsPanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseAssetsPanel.qml @@ -10,7 +10,7 @@ ProfileShowcasePanel { property var formatCurrencyAmount: function(amount, symbol){} keyRole: "symbol" - roleNames: ["symbol", "name", "enabledNetworkBalance", "decimals"].concat(showcaseRoles) + roleNames: ["symbol", "name", "address", "communityId", "enabledNetworkBalance", "decimals"].concat(showcaseRoles) filterFunc: (modelData) => modelData.symbol !== "" && !showcaseModel.hasItemInShowcase(modelData.symbol) hiddenPlaceholderBanner: qsTr("Assets here will show on your profile") showcasePlaceholderBanner: qsTr("Assets here will be hidden from your profile") diff --git a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseCollectiblesPanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseCollectiblesPanel.qml index bdfa9a168b..926517bb9e 100644 --- a/ui/app/AppLayouts/Profile/panels/ProfileShowcaseCollectiblesPanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ProfileShowcaseCollectiblesPanel.qml @@ -8,7 +8,7 @@ ProfileShowcasePanel { id: root keyRole: "uid" - roleNames: ["uid", "name", "collectionName", "backgroundColor", "imageUrl"].concat(showcaseRoles) + roleNames: ["uid", "chainId", "tokenId", "contractAddress", "communityId", "name", "collectionName", "backgroundColor", "imageUrl"].concat(showcaseRoles) filterFunc: (modelData) => !showcaseModel.hasItemInShowcase(modelData.uid) hiddenPlaceholderBanner: qsTr("Collectibles here will show on your profile") showcasePlaceholderBanner: qsTr("Collectibles here will be hidden from your profile") diff --git a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml index 4bac3d3b61..9687de9675 100644 --- a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml @@ -29,6 +29,8 @@ QtObject { readonly property bool isWalletEnabled: Global.appIsReady? mainModule.sectionsModel.getItemEnabledBySectionType(Constants.appSection.wallet) : true + readonly property var collectiblesModel: profileModule.collectiblesModel + readonly property var profileShowcaseCommunitiesModel: profileModule.profileShowcaseCommunitiesModel readonly property var profileShowcaseAccountsModel: profileModule.profileShowcaseAccountsModel readonly property var profileShowcaseCollectiblesModel: profileModule.profileShowcaseCollectiblesModel diff --git a/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml b/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml index fd38e33c5a..aaca64c1be 100644 --- a/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml +++ b/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml @@ -203,7 +203,6 @@ ColumnLayout { StatusTabButton { width: implicitWidth text: qsTr("Collectibles") - enabled: false // TODO: implement collectibles nim part } StatusTabButton { @@ -240,7 +239,7 @@ ColumnLayout { id: profileShowcaseCollectiblesPanel Layout.minimumHeight: implicitHeight Layout.maximumHeight: implicitHeight - baseModel: root.walletStore.collectibles + baseModel: root.profileStore.collectiblesModel showcaseModel: root.profileStore.profileShowcaseCollectiblesModel onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true } @@ -249,7 +248,7 @@ ColumnLayout { id: profileShowcaseAssetsPanel Layout.minimumHeight: implicitHeight Layout.maximumHeight: implicitHeight - baseModel: root.walletAssetsStore.groupedAccountAssetsModel + baseModel: root.walletAssetsStore.groupedAccountAssetsModel // TODO: instantiate an assets model in profile module showcaseModel: root.profileStore.profileShowcaseAssetsModel onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true formatCurrencyAmount: function(amount, symbol) { diff --git a/vendor/status-go b/vendor/status-go index 9b7eec0edb..fb98ee93ce 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit 9b7eec0edb650d4b1300c6edaaf0c82f1bf64233 +Subproject commit fb98ee93ceaacddce77aaf9df605c6a8ba3fda74