feat(ProfileShowcase): Implement profile showcase collectibles (#13103)

* feat(ProfileShowcase): Show token balences in the profile showcase

* feat: support new tokens & collectible identification

* feat: add collectibles to profile showcase preferences

* feat: dispaly collectibles for a contact

* fix: review fixes & tokens code moved to separated PR
This commit is contained in:
Mikhail Rogachev 2024-01-25 21:43:36 +04:00 committed by GitHub
parent 9e4db718b4
commit 2abfe0fa0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 332 additions and 131 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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")

View File

@ -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

View File

@ -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,

View File

@ -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}"

View File

@ -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.} =

View File

@ -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()

View File

@ -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]) =

View File

@ -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()

View File

@ -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)

View File

@ -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())

View File

@ -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
}]

View File

@ -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,6 +96,7 @@ proc getWalletAccounts*(self: Service): seq[WalletAccountDto] =
result.add(acc)
continue
result.add(kp.accounts)
if not excludeWatchOnly:
result.add(toSeq(self.watchOnlyAccounts.values))
result.sort(walletAccountsCmp)

View File

@ -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")

View File

@ -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")

View File

@ -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

View File

@ -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) {

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 9b7eec0edb650d4b1300c6edaaf0c82f1bf64233
Subproject commit fb98ee93ceaacddce77aaf9df605c6a8ba3fda74