diff --git a/src/app/core/signals/remote_signals/messages.nim b/src/app/core/signals/remote_signals/messages.nim index 5701be966d..90118f2422 100644 --- a/src/app/core/signals/remote_signals/messages.nim +++ b/src/app/core/signals/remote_signals/messages.nim @@ -13,7 +13,6 @@ import ../../../../app_service/service/devices/dto/[installation] import ../../../../app_service/service/settings/dto/[settings] import ../../../../app_service/service/saved_address/dto as saved_address_dto import ../../../../app_service/service/wallet_account/dto/[keypair_dto] -import ../../../../app_service/service/profile/dto/[profile_showcase] type MessageSignal* = ref object of Signal bookmarks*: seq[BookmarkDto] @@ -40,7 +39,7 @@ type MessageSignal* = ref object of Signal keypairs*: seq[KeypairDto] watchOnlyAccounts*: seq[WalletAccountDto] accountsPositions*: seq[WalletAccountDto] - updatedProfileShowcases*: seq[ProfileShowcaseDto] + updatedProfileShowcaseContactIDs*: seq[string] type MessageDeliveredSignal* = ref object of Signal chatId*: string @@ -167,8 +166,8 @@ proc fromEvent*(T: type MessageSignal, event: JsonNode): MessageSignal = for jsonAcc in e["accountsPositions"]: signal.accountsPositions.add(jsonAcc.toWalletAccountDto()) - if e.contains("updatedProfileShowcases"): - for jsonProfileShowcase in e["updatedProfileShowcases"]: - signal.updatedProfileShowcases.add(jsonProfileShowcase.toProfileShowcaseDto()) + if e.contains("updatedProfileShowcaseContactIDs"): + for contactId in e["updatedProfileShowcaseContactIDs"]: + signal.updatedProfileShowcaseContactIDs.add(contactId.getStr()) result = signal diff --git a/src/app/modules/main/profile_section/contacts/controller.nim b/src/app/modules/main/profile_section/contacts/controller.nim index 25eeab7cd7..012e7ef4f7 100644 --- a/src/app/modules/main/profile_section/contacts/controller.nim +++ b/src/app/modules/main/profile_section/contacts/controller.nim @@ -1,9 +1,11 @@ +import sugar, sequtils import io_interface import ../../../../core/eventemitter -import ../../../../../app_service/service/contacts/service as contacts_service -import ../../../../../app_service/service/chat/service as chat_service -import ../../../../../app_service/service/message/dto/message as message_dto +import app_service/service/contacts/service as contacts_service +import app_service/service/chat/service as chat_service +import app_service/service/network/service as network_service +import app_service/service/message/dto/message as message_dto type Controller* = ref object of RootObj @@ -11,16 +13,19 @@ type events: EventEmitter contactsService: contacts_service.Service chatService: chat_service.Service + networkService: network_service.Service proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter, contactsService: contacts_service.Service, - chatService: chat_service.Service): Controller = + chatService: chat_service.Service, + networkService: network_service.Service): Controller = result = Controller() result.delegate = delegate result.events = events result.contactsService = contactsService result.chatService = chatService + result.networkService = networkService proc delete*(self: Controller) = discard @@ -90,6 +95,18 @@ proc init*(self: Controller) = let args = ContactInfoRequestArgs(e) self.delegate.onContactInfoRequestFinished(args.publicKey, args.ok) + self.events.on(SIGNAL_CONTACT_PROFILE_SHOWCASE_UPDATED) do(e: Args): + let args = ProfileShowcaseContactIdArgs(e) + self.delegate.onProfileShowcaseUpdated(args.contactId) + + self.events.on(SIGNAL_CONTACT_PROFILE_SHOWCASE_LOADED) do(e: Args): + let args = ProfileShowcaseForContactArgs(e) + self.delegate.loadProfileShowcase(args.profileShowcase, args.validated) + + self.events.on(SIGNAL_CONTACT_SHOWCASE_ACCOUNTS_BY_ADDRESS_FETCHED) do(e: Args): + let args = ProfileShowcaseForContactArgs(e) + self.delegate.onProfileShowcaseAccountsByAddressFetched(args.profileShowcase.accounts) + proc getContacts*(self: Controller, group: ContactsGroup): seq[ContactsDto] = return self.contactsService.getContactsByGroup(group) @@ -180,3 +197,12 @@ proc shareUserUrlWithChatKey*(self: Controller, pubkey: string): string = proc shareUserUrlWithENS*(self: Controller, pubkey: string): string = self.contactsService.shareUserUrlWithENS(pubkey) + +proc requestProfileShowcaseForContact*(self: Controller, contactId: string, validated: bool) = + self.contactsService.requestProfileShowcaseForContact(contactId, validated) + +proc fetchProfileShowcaseAccountsByAddress*(self: Controller, address: string) = + self.contactsService.fetchProfileShowcaseAccountsByAddress(address) + +proc getChainIds*(self: Controller): seq[int] = + self.networkService.getCurrentNetworks().map(n => n.chainId) \ No newline at end of file diff --git a/src/app/modules/main/profile_section/contacts/io_interface.nim b/src/app/modules/main/profile_section/contacts/io_interface.nim index e96d1a42f3..49073876af 100644 --- a/src/app/modules/main/profile_section/contacts/io_interface.nim +++ b/src/app/modules/main/profile_section/contacts/io_interface.nim @@ -2,6 +2,8 @@ import NimQml import ../../../../../app_service/service/contacts/dto/contacts as contacts import ../../../../../app_service/service/contacts/dto/status_update +import app_service/service/contacts/dto/profile_showcase + type AccessInterface* {.pure inheritable.} = ref object of RootObj ## Abstract class for any input/interaction with this module. @@ -138,4 +140,25 @@ method shareUserUrlWithChatKey*(self: AccessInterface, pubkey: string): string { raise newException(ValueError, "No implementation available") method shareUserUrlWithENS*(self: AccessInterface, pubkey: string): string {.base.} = + raise newException(ValueError, "No implementation available") + +method requestProfileShowcase*(self: AccessInterface, publicKey: string) {.base.} = + raise newException(ValueError, "No implementation available") + +method onProfileShowcaseUpdated*(self: AccessInterface, publicKey: string) {.base.} = + raise newException(ValueError, "No implementation available") + +method loadProfileShowcase*(self: AccessInterface, profileShowcase: ProfileShowcaseDto, validated: bool) {.base.} = + raise newException(ValueError, "No implementation available") + +method fetchProfileShowcaseAccountsByAddress*(self: AccessInterface, address: string) {.base.} = + raise newException(ValueError, "No implementation available") + +method onProfileShowcaseAccountsByAddressFetched*(self: AccessInterface, accounts: seq[ProfileShowcaseAccount]) {.base.} = + raise newException(ValueError, "No implementation available") + +method getShowcaseCollectiblesModel*(self: AccessInterface): QVariant {.base.} = + raise newException(ValueError, "No implementation available") + +method isShowcaseForAContactLoading*(self: AccessInterface): bool {.base.} = raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/main/profile_section/contacts/models/showcase_contact_accounts_model.nim b/src/app/modules/main/profile_section/contacts/models/showcase_contact_accounts_model.nim new file mode 100644 index 0000000000..70814cc975 --- /dev/null +++ b/src/app/modules/main/profile_section/contacts/models/showcase_contact_accounts_model.nim @@ -0,0 +1,78 @@ +import NimQml, tables, strutils, sequtils, json + +type + ShowcaseContactAccountItem* = object of RootObj + address*: string + name*: string + emoji*: string + colorId*: string + showcasePosition*: int + +type + ModelRole {.pure.} = enum + Address + Name + Emoji + ColorId + ShowcasePosition + +QtObject: + type + ShowcaseContactAccountModel* = ref object of QAbstractListModel + items: seq[ShowcaseContactAccountItem] + + proc delete(self: ShowcaseContactAccountModel) = + self.items = @[] + self.QAbstractListModel.delete + + proc setup(self: ShowcaseContactAccountModel) = + self.QAbstractListModel.setup + + proc newShowcaseContactAccountModel*(): ShowcaseContactAccountModel = + new(result, delete) + result.setup + + proc items*(self: ShowcaseContactAccountModel): seq[ShowcaseContactAccountItem] = + self.items + + method rowCount(self: ShowcaseContactAccountModel, index: QModelIndex = nil): int = + return self.items.len + + method roleNames(self: ShowcaseContactAccountModel): Table[int, string] = + { + ModelRole.Address.int: "address", + ModelRole.Name.int: "name", + ModelRole.Emoji.int: "emoji", + ModelRole.ColorId.int: "colorId", + ModelRole.ShowcasePosition.int: "showcasePosition", + }.toTable + + method data(self: ShowcaseContactAccountModel, index: QModelIndex, role: int): QVariant = + if (not index.isValid): + return + + if (index.row < 0 or index.row >= self.items.len): + return + + let item = self.items[index.row] + let enumRole = role.ModelRole + + case enumRole: + of ModelRole.Address: + result = newQVariant(item.address) + of ModelRole.Name: + result = newQVariant(item.name) + of ModelRole.Emoji: + result = newQVariant(item.emoji) + of ModelRole.ColorId: + result = newQVariant(item.colorId) + of ModelRole.ShowcasePosition: + result = newQVariant(item.showcasePosition) + + proc setItems*(self: ShowcaseContactAccountModel, items: seq[ShowcaseContactAccountItem]) = + self.beginResetModel() + self.items = items + self.endResetModel() + + proc clear*(self: ShowcaseContactAccountModel) {.slot.} = + self.setItems(@[]) diff --git a/src/app/modules/main/profile_section/contacts/models/showcase_contact_generic_model.nim b/src/app/modules/main/profile_section/contacts/models/showcase_contact_generic_model.nim new file mode 100644 index 0000000000..66e181a063 --- /dev/null +++ b/src/app/modules/main/profile_section/contacts/models/showcase_contact_generic_model.nim @@ -0,0 +1,63 @@ +import NimQml, tables, strutils, sequtils, json + +type + ShowcaseContactGenericItem* = object of RootObj + showcaseKey*: string + showcasePosition*: int + +type + ModelRole {.pure.} = enum + ShowcaseKey + ShowcasePosition + +QtObject: + type + ShowcaseContactGenericModel* = ref object of QAbstractListModel + items: seq[ShowcaseContactGenericItem] + + proc delete(self: ShowcaseContactGenericModel) = + self.items = @[] + self.QAbstractListModel.delete + + proc setup(self: ShowcaseContactGenericModel) = + self.QAbstractListModel.setup + + proc newShowcaseContactGenericModel*(): ShowcaseContactGenericModel = + new(result, delete) + result.setup + + proc items*(self: ShowcaseContactGenericModel): seq[ShowcaseContactGenericItem] = + self.items + + method rowCount(self: ShowcaseContactGenericModel, index: QModelIndex = nil): int = + return self.items.len + + method roleNames(self: ShowcaseContactGenericModel): Table[int, string] = + { + ModelRole.ShowcaseKey.int: "showcaseKey", + ModelRole.ShowcasePosition.int: "showcasePosition", + }.toTable + + method data(self: ShowcaseContactGenericModel, index: QModelIndex, role: int): QVariant = + if (not index.isValid): + return + + if (index.row < 0 or index.row >= self.items.len): + return + + let item = self.items[index.row] + let enumRole = role.ModelRole + + case enumRole: + of ModelRole.ShowcaseKey: + result = newQVariant(item.showcaseKey) + of ModelRole.ShowcasePosition: + result = newQVariant(item.showcasePosition) + + proc setItems*(self: ShowcaseContactGenericModel, items: seq[ShowcaseContactGenericItem]) = + self.beginResetModel() + self.items = items + self.endResetModel() + + proc clear*(self: ShowcaseContactGenericModel) {.slot.} = + self.setItems(@[]) diff --git a/src/app/modules/main/profile_section/contacts/models/showcase_contact_social_links_model.nim b/src/app/modules/main/profile_section/contacts/models/showcase_contact_social_links_model.nim new file mode 100644 index 0000000000..27e41be707 --- /dev/null +++ b/src/app/modules/main/profile_section/contacts/models/showcase_contact_social_links_model.nim @@ -0,0 +1,68 @@ +import NimQml, tables, strutils, sequtils, json + +type + ShowcaseContactSocialLinkItem* = object of RootObj + url*: string + text*: string + showcasePosition*: int + +type + ModelRole {.pure.} = enum + Url + Text + ShowcasePosition + +QtObject: + type + ShowcaseContactSocialLinkModel* = ref object of QAbstractListModel + items: seq[ShowcaseContactSocialLinkItem] + + proc delete(self: ShowcaseContactSocialLinkModel) = + self.items = @[] + self.QAbstractListModel.delete + + proc setup(self: ShowcaseContactSocialLinkModel) = + self.QAbstractListModel.setup + + proc newShowcaseContactSocialLinkModel*(): ShowcaseContactSocialLinkModel = + new(result, delete) + result.setup + + proc items*(self: ShowcaseContactSocialLinkModel): seq[ShowcaseContactSocialLinkItem] = + self.items + + method rowCount(self: ShowcaseContactSocialLinkModel, index: QModelIndex = nil): int = + return self.items.len + + method roleNames(self: ShowcaseContactSocialLinkModel): Table[int, string] = + { + ModelRole.Url.int: "url", + ModelRole.Text.int: "text", + ModelRole.ShowcasePosition.int: "showcasePosition", + }.toTable + + method data(self: ShowcaseContactSocialLinkModel, index: QModelIndex, role: int): QVariant = + if (not index.isValid): + return + + if (index.row < 0 or index.row >= self.items.len): + return + + let item = self.items[index.row] + let enumRole = role.ModelRole + + case enumRole: + of ModelRole.Url: + result = newQVariant(item.url) + of ModelRole.Text: + result = newQVariant(item.text) + of ModelRole.ShowcasePosition: + result = newQVariant(item.showcasePosition) + + proc setItems*(self: ShowcaseContactSocialLinkModel, items: seq[ShowcaseContactSocialLinkItem]) = + self.beginResetModel() + self.items = items + self.endResetModel() + + proc clear*(self: ShowcaseContactSocialLinkModel) {.slot.} = + self.setItems(@[]) diff --git a/src/app/modules/main/profile_section/contacts/module.nim b/src/app/modules/main/profile_section/contacts/module.nim index bb7b9beace..4edb12a47f 100644 --- a/src/app/modules/main/profile_section/contacts/module.nim +++ b/src/app/modules/main/profile_section/contacts/module.nim @@ -7,38 +7,66 @@ import ../io_interface as delegate_interface import ../../../../global/global_singleton import ../../../../core/eventemitter -import ../../../../../app_service/common/types -import ../../../../../app_service/service/contacts/dto/contacts as contacts_dto -import ../../../../../app_service/service/contacts/service as contacts_service -import ../../../../../app_service/service/chat/service as chat_service +import app_service/common/types +import app_service/service/contacts/dto/contacts as contacts_dto +import app_service/service/contacts/service as contacts_service +import app_service/service/chat/service as chat_service +import app_service/service/network/service as network_service + +import app/modules/shared_modules/collectibles/controller as collectiblesc +import backend/collectibles as backend_collectibles +import app_service/service/contacts/dto/profile_showcase + +import models/showcase_contact_generic_model +import models/showcase_contact_accounts_model +import models/showcase_contact_social_links_model export io_interface +const COLLECTIBLES_CACHE_AGE_SECONDS = 60 + logScope: topics = "profile-section-contacts-module" 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 + showcasePublicKey: string + showcaseForAContactLoading: bool proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, contactsService: contacts_service.Service, - chatService: chat_service.Service): + chatService: chat_service.Service, + networkService: network_service.Service): Module = result = Module() result.delegate = delegate result.view = newView(result) result.viewVariant = newQVariant(result.view) - result.controller = controller.newController(result, events, contactsService, chatService) + result.controller = controller.newController(result, events, contactsService, chatService, networkService) + result.collectiblesController = collectiblesc.newController( + requestId = int32(backend_collectibles.CollectiblesRequestID.ProfileShowcase), + loadType = collectiblesc.LoadType.AutoLoadSingleUpdate, + networkService = networkService, + events = events, + fetchCriteria = backend_collectibles.FetchCriteria( + fetchType: backend_collectibles.FetchType.FetchIfCacheOld, + maxCacheAgeSeconds: COLLECTIBLES_CACHE_AGE_SECONDS + ) + ) result.moduleLoaded = false + result.showcaseForAContactLoading = false method delete*(self: Module) = self.view.delete + self.viewVariant.delete + self.collectiblesController.delete proc createItemFromPublicKey(self: Module, publicKey: string): UserItem = let contactDetails = self.controller.getContactDetails(publicKey) @@ -303,3 +331,98 @@ method shareUserUrlWithChatKey*(self: Module, pubkey: string): string = method shareUserUrlWithENS*(self: Module, pubkey: string): string = return self.controller.shareUserUrlWithENS(pubkey) + +# Profile showcase for a contanct related stuff +method requestProfileShowcase*(self: Module, publicKey: string) = + if self.showcasePublicKey != publicKey: + self.view.clearShowcaseModels() + self.showcasePublicKey = publicKey + self.showcaseForAContactLoading = true + self.view.emitShowcaseForAContactLoadingChangedSignal() + + self.controller.requestProfileShowcaseForContact(publicKey, false) + +method onProfileShowcaseUpdated(self: Module, publicKey: string) = + if self.showcasePublicKey == publicKey: + self.controller.requestProfileShowcaseForContact(publicKey, true) + +method loadProfileShowcase(self: Module, profileShowcase: ProfileShowcaseDto, validated: bool) = + if self.showcasePublicKey != profileShowcase.contactId: + warn "Got profile showcase for wrong contact id" + return + + var communityItems: seq[ShowcaseContactGenericItem] = @[] + for community in profileShowcase.communities: + if not validated or community.membershipStatus == ProfileShowcaseMembershipStatus.ProvenMember: + communityItems.add(ShowcaseContactGenericItem( + showcaseKey: community.communityId, + showcasePosition: community.order + )) + self.view.loadProfileShowcaseContactCommunities(communityItems) + + var accountItems: seq[ShowcaseContactAccountItem] = @[] + var accountAddresses: seq[string] = @[] + for account in profileShowcase.accounts: + accountItems.add(ShowcaseContactAccountItem( + address: account.address, + name: account.name, + emoji: account.emoji, + colorId: account.colorId, + showcasePosition: account.order + )) + accountAddresses.add(account.address) + self.view.loadProfileShowcaseContactAccounts(accountItems) + + var collectibleItems: seq[ShowcaseContactGenericItem] = @[] + var collectibleChainIds: seq[int] = @[] + for collectible in profileShowcase.collectibles: + collectibleItems.add(ShowcaseContactGenericItem( + showcaseKey: collectible.toCombinedCollectibleId(), + showcasePosition: collectible.order + )) + collectibleChainIds.add(collectible.chainId) + self.view.loadProfileShowcaseContactCollectibles(collectibleItems) + + var assetItems: seq[ShowcaseContactGenericItem] = @[] + for token in profileShowcase.verifiedTokens: + assetItems.add(ShowcaseContactGenericItem( + showcaseKey: token.symbol, + showcasePosition: token.order + )) + for token in profileShowcase.unverifiedTokens: + assetItems.add(ShowcaseContactGenericItem( + showcaseKey: token.toCombinedTokenId(), + showcasePosition: token.order + )) + self.view.loadProfileShowcaseContactAssets(assetItems) + + var socialLinkItems: seq[ShowcaseContactSocialLinkItem] = @[] + for socialLink in profileShowcase.socialLinks: + socialLinkItems.add(ShowcaseContactSocialLinkItem( + url: socialLink.url, + text: socialLink.text, + showcasePosition: socialLink.order + )) + self.view.loadProfileShowcaseContactSocialLinks(socialLinkItems) + + if validated: + self.showcaseForAContactLoading = false + self.view.emitShowcaseForAContactLoadingChangedSignal() + else: + # NOTE: this implementation does not respect testnet setting + # to fix use SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED and getChainIds() to intersect with collectibleChainIds + self.collectiblesController.setFilterAddressesAndChains(accountAddresses, collectibleChainIds) + self.controller.requestProfileShowcaseForContact(self.showcasePublicKey, true) + +method fetchProfileShowcaseAccountsByAddress*(self: Module, address: string) = + self.controller.fetchProfileShowcaseAccountsByAddress(address) + +method onProfileShowcaseAccountsByAddressFetched*(self: Module, accounts: seq[ProfileShowcaseAccount]) = + let jsonObj = % accounts + self.view.emitProfileShowcaseAccountsByAddressFetchedSignal($jsonObj) + +method getShowcaseCollectiblesModel*(self: Module): QVariant = + return self.collectiblesController.getModelAsVariant() + +method isShowcaseForAContactLoading*(self: Module): bool = + return self.showcaseForAContactLoading \ No newline at end of file diff --git a/src/app/modules/main/profile_section/contacts/view.nim b/src/app/modules/main/profile_section/contacts/view.nim index afe02eb5ed..8b67f2ef70 100644 --- a/src/app/modules/main/profile_section/contacts/view.nim +++ b/src/app/modules/main/profile_section/contacts/view.nim @@ -3,6 +3,10 @@ import NimQml import ../../../shared_models/user_model import ./io_interface +import models/showcase_contact_generic_model +import models/showcase_contact_accounts_model +import models/showcase_contact_social_links_model + QtObject: type View* = ref object of QObject @@ -20,6 +24,17 @@ QtObject: # receivedButRejectedContactRequestsModelVariant: QVariant # sentButRejectedContactRequestsModel: Model # sentButRejectedContactRequestsModelVariant: QVariant + showcaseContactCommunitiesModel: ShowcaseContactGenericModel + showcaseContactCommunitiesModelVariant: QVariant + showcaseContactAccountsModel: ShowcaseContactAccountModel + showcaseContactAccountsModelVariant: QVariant + showcaseContactCollectiblesModel: ShowcaseContactGenericModel + showcaseContactCollectiblesModelVariant: QVariant + showcaseContactAssetsModel: ShowcaseContactGenericModel + showcaseContactAssetsModelVariant: QVariant + showcaseContactSocialLinksModel: ShowcaseContactSocialLinkModel + showcaseContactSocialLinksModelVariant: QVariant + proc delete*(self: View) = self.myMutualContactsModel.delete @@ -35,6 +50,16 @@ QtObject: # self.receivedButRejectedContactRequestsModelVariant.delete # self.sentButRejectedContactRequestsModelVariant.delete # self.sentButRejectedContactRequestsModel.delete + self.showcaseContactCommunitiesModel.delete + self.showcaseContactCommunitiesModelVariant.delete + self.showcaseContactAccountsModel.delete + self.showcaseContactAccountsModelVariant.delete + self.showcaseContactCollectiblesModel.delete + self.showcaseContactCollectiblesModelVariant.delete + self.showcaseContactAssetsModel.delete + self.showcaseContactAssetsModelVariant.delete + self.showcaseContactSocialLinksModel.delete + self.showcaseContactSocialLinksModelVariant.delete self.QObject.delete proc newView*(delegate: io_interface.AccessInterface): View = @@ -54,6 +79,16 @@ QtObject: # result.receivedButRejectedContactRequestsModelVariant = newQVariant(result.receivedButRejectedContactRequestsModel) # result.sentButRejectedContactRequestsModel = newModel() # result.sentButRejectedContactRequestsModelVariant = newQVariant(result.sentButRejectedContactRequestsModel) + result.showcaseContactCommunitiesModel = newShowcaseContactGenericModel() + result.showcaseContactCommunitiesModelVariant = newQVariant(result.showcaseContactCommunitiesModel) + result.showcaseContactAccountsModel = newShowcaseContactAccountModel() + result.showcaseContactAccountsModelVariant = newQVariant(result.showcaseContactAccountsModel) + result.showcaseContactCollectiblesModel = newShowcaseContactGenericModel() + result.showcaseContactCollectiblesModelVariant = newQVariant(result.showcaseContactCollectiblesModel) + result.showcaseContactAssetsModel = newShowcaseContactGenericModel() + result.showcaseContactAssetsModelVariant = newQVariant(result.showcaseContactAssetsModel) + result.showcaseContactSocialLinksModel = newShowcaseContactSocialLinkModel() + result.showcaseContactSocialLinksModelVariant = newQVariant(result.showcaseContactSocialLinksModel) proc load*(self: View) = self.delegate.viewDidLoad() @@ -204,4 +239,79 @@ QtObject: self.delegate.requestContactInfo(publicKey) proc onContactInfoRequestFinished*(self: View, publicKey: string, ok: bool) {.slot.} = - self.contactInfoRequestFinished(publicKey, ok) \ No newline at end of file + self.contactInfoRequestFinished(publicKey, ok) + + # Showcase models for a contact + proc getShowcaseContactCommunitiesModel(self: View): QVariant {.slot.} = + return self.showcaseContactCommunitiesModelVariant + QtProperty[QVariant] showcaseContactCommunitiesModel: + read = getShowcaseContactCommunitiesModel + + proc getShowcaseContactAccountsModel(self: View): QVariant {.slot.} = + return self.showcaseContactAccountsModelVariant + QtProperty[QVariant] showcaseContactAccountsModel: + read = getShowcaseContactAccountsModel + + proc getShowcaseContactCollectiblesModel(self: View): QVariant {.slot.} = + return self.showcaseContactCollectiblesModelVariant + QtProperty[QVariant] showcaseContactCollectiblesModel: + read = getShowcaseContactCollectiblesModel + + proc getShowcaseContactAssetsModel(self: View): QVariant {.slot.} = + return self.showcaseContactAssetsModelVariant + QtProperty[QVariant] showcaseContactAssetsModel: + read = getShowcaseContactAssetsModel + + proc getShowcaseContactSocialLinksModel(self: View): QVariant {.slot.} = + return self.showcaseContactSocialLinksModelVariant + QtProperty[QVariant] showcaseContactSocialLinksModel: + read = getShowcaseContactSocialLinksModel + + # Support models for showcase for a contact + proc showcaseCollectiblesModelChanged*(self: View) {.signal.} + proc getShowcaseCollectiblesModel(self: View): QVariant {.slot.} = + return self.delegate.getShowcaseCollectiblesModel() + QtProperty[QVariant] showcaseCollectiblesModel: + read = getShowcaseCollectiblesModel + notify = showcaseCollectiblesModelChanged + + proc showcaseForAContactLoadingChanged*(self: View) {.signal.} + proc emitShowcaseForAContactLoadingChangedSignal*(self: View) = + self.showcaseForAContactLoadingChanged() + proc isShowcaseForAContactLoading*(self: View): bool {.signal.} = + return self.delegate.isShowcaseForAContactLoading() + QtProperty[QVariant] showcaseForAContactLoading: + read = isShowcaseForAContactLoading + notify = showcaseForAContactLoadingChanged + + proc fetchProfileShowcaseAccountsByAddress*(self: View, address: string) {.slot.} = + self.delegate.fetchProfileShowcaseAccountsByAddress(address) + + proc profileShowcaseAccountsByAddressFetched*(self: View, accounts: string) {.signal.} + proc emitProfileShowcaseAccountsByAddressFetchedSignal*(self: View, accounts: string) = + self.profileShowcaseAccountsByAddressFetched(accounts) + + proc requestProfileShowcase(self: View, publicKey: string) {.slot.} = + self.delegate.requestProfileShowcase(publicKey) + + proc clearShowcaseModels*(self: View) {.slot.} = + self.showcaseContactCommunitiesModel.clear() + self.showcaseContactAccountsModel.clear() + self.showcaseContactCollectiblesModel.clear() + self.showcaseContactAssetsModel.clear() + self.showcaseContactSocialLinksModel.clear() + + proc loadProfileShowcaseContactCommunities*(self: View, items: seq[ShowcaseContactGenericItem]) = + self.showcaseContactCommunitiesModel.setItems(items) + + proc loadProfileShowcaseContactAccounts*(self: View, items: seq[ShowcaseContactAccountItem]) = + self.showcaseContactAccountsModel.setItems(items) + + proc loadProfileShowcaseContactCollectibles*(self: View, items: seq[ShowcaseContactGenericItem]) = + self.showcaseContactCollectiblesModel.setItems(items) + + proc loadProfileShowcaseContactAssets*(self: View, items: seq[ShowcaseContactGenericItem]) = + self.showcaseContactAssetsModel.setItems(items) + + proc loadProfileShowcaseContactSocialLinks*(self: View, items: seq[ShowcaseContactSocialLinkItem]) = + self.showcaseContactSocialLinksModel.setItems(items) diff --git a/src/app/modules/main/profile_section/module.nim b/src/app/modules/main/profile_section/module.nim index a2d5e93832..f86080998c 100644 --- a/src/app/modules/main/profile_section/module.nim +++ b/src/app/modules/main/profile_section/module.nim @@ -96,8 +96,8 @@ 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, networkService, tokenService) - result.contactsModule = contacts_module.newModule(result, events, contactsService, chatService) + result.profileModule = profile_module.newModule(result, events, profileService, settingsService, communityService, walletAccountService, tokenService) + result.contactsModule = contacts_module.newModule(result, events, contactsService, chatService, networkService) result.languageModule = language_module.newModule(result, events, languageService) result.privacyModule = privacy_module.newModule(result, events, settingsService, keychainService, privacyService, generalService) result.aboutModule = about_module.newModule(result, events, aboutService) diff --git a/src/app/modules/main/profile_section/profile/controller.nim b/src/app/modules/main/profile_section/profile/controller.nim index ebf6c938cd..a927dfa115 100644 --- a/src/app/modules/main/profile_section/profile/controller.nim +++ b/src/app/modules/main/profile_section/profile/controller.nim @@ -1,4 +1,3 @@ -import sugar, sequtils import io_interface import app/global/app_signals @@ -7,7 +6,6 @@ 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/token/service as token_service import app_service/common/social_links import app_service/common/types @@ -22,7 +20,6 @@ type settingsService: settings_service.Service communityService: community_service.Service walletAccountService: wallet_account_service.Service - networkService: network_service.Service tokenService: token_service.Service proc newController*( @@ -32,7 +29,6 @@ proc newController*( settingsService: settings_service.Service, communityService: community_service.Service, walletAccountService: wallet_account_service.Service, - networkService: network_service.Service, tokenService: token_service.Service): Controller = result = Controller() result.delegate = delegate @@ -41,7 +37,6 @@ proc newController*( result.settingsService = settingsService result.communityService = communityService result.walletAccountService = walletAccountService - result.networkService = networkService result.tokenService = tokenService proc delete*(self: Controller) = @@ -64,21 +59,9 @@ proc init*(self: Controller) = self.events.on(SIGNAL_PROFILE_SHOWCASE_PREFERENCES_SAVE_FAILED) do(e: Args): self.delegate.onProfileShowcasePreferencesSaveFailed() - self.events.on(SIGNAL_PROFILE_SHOWCASE_PREFERENCES_UPDATED) do(e: Args): + self.events.on(SIGNAL_PROFILE_SHOWCASE_PREFERENCES_LOADED) do(e: Args): let args = ProfileShowcasePreferencesArgs(e) - self.delegate.updateProfileShowcasePreferences(args.preferences) - - self.events.on(SIGNAL_PROFILE_SHOWCASE_FOR_CONTACT_UPDATED) do(e: Args): - let args = ProfileShowcaseForContactArgs(e) - self.delegate.updateProfileShowcase(args.profileShowcase) - - self.events.on(SIGNAL_PROFILE_SHOWCASE_ACCOUNTS_BY_ADDRESS_FETCHED) do(e: Args): - let args = ProfileShowcaseForContactArgs(e) - self.delegate.onProfileShowcaseAccountsByAddressFetched(args.profileShowcase.accounts) - - self.events.on(SIGNAL_COMMUNITIES_UPDATE) do(e: Args): - let args = CommunitiesArgs(e) - self.delegate.onCommunitiesUpdated(args.communities) + self.delegate.loadProfileShowcasePreferences(args.preferences) proc storeIdentityImage*(self: Controller, address: string, image: string, aX: int, aY: int, bX: int, bY: int): bool = len(self.profileService.storeIdentityImage(address, image, aX, aY, bX, bY)) > 0 @@ -101,9 +84,6 @@ proc getAccountByAddress*(self: Controller, address: string): WalletAccountDto = proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] = self.walletAccountService.getWalletAccounts(true) -proc getChainIds*(self: Controller): seq[int] = - self.networkService.getCurrentNetworks().map(n => n.chainId) - proc setSocialLinks*(self: Controller, links: SocialLinks) = self.settingsService.setSocialLinks(links) @@ -113,19 +93,13 @@ proc getBio*(self: Controller): string = proc setBio*(self: Controller, bio: string): bool = self.settingsService.saveBio(bio) -proc storeProfileShowcasePreferences*(self: Controller, preferences: ProfileShowcasePreferencesDto, revealedAddresses: seq[string]) = +proc saveProfileShowcasePreferences*(self: Controller, preferences: ProfileShowcasePreferencesDto, revealedAddresses: seq[string]) = self.profileService.saveProfileShowcasePreferences(preferences) self.events.emit(MARK_WALLET_ADDRESSES_AS_SHOWN, WalletAddressesArgs(addresses: revealedAddresses)) proc requestProfileShowcasePreferences*(self: Controller) = self.profileService.requestProfileShowcasePreferences() -proc requestProfileShowcaseForContact*(self: Controller, contactId: string) = - self.profileService.requestProfileShowcaseForContact(contactId) - -proc fetchProfileShowcaseAccountsByAddress*(self: Controller, address: string) = - self.profileService.fetchProfileShowcaseAccountsByAddress(address) - proc getProfileShowcaseSocialLinksLimit*(self: Controller): int = self.profileService.getProfileShowcaseSocialLinksLimit() 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 cf36f2d7ad..9598f38117 100644 --- a/src/app/modules/main/profile_section/profile/io_interface.nim +++ b/src/app/modules/main/profile_section/profile/io_interface.nim @@ -1,14 +1,7 @@ import NimQml import app_service/common/social_links -import app_service/service/profile/dto/profile_showcase import app_service/service/profile/dto/profile_showcase_preferences -import app_service/service/community/dto/community - -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 models/profile_save_data @@ -28,9 +21,6 @@ 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 getBio*(self: AccessInterface): string {.base.} = raise newException(ValueError, "No implementation available") @@ -67,38 +57,13 @@ method getProfileShowcaseSocialLinksLimit*(self: AccessInterface): int {.base.} method getProfileShowcaseEntriesLimit*(self: AccessInterface): int {.base.} = raise newException(ValueError, "No implementation available") -method storeProfileShowcasePreferences*(self: AccessInterface, - communities: seq[ProfileShowcaseCommunityItem], - accounts: seq[ProfileShowcaseAccountItem], - collectibles: seq[ProfileShowcaseCollectibleItem], - assets: seq[ProfileShowcaseAssetItem]) {.base.} = - raise newException(ValueError, "No implementation available") - method requestProfileShowcasePreferences*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") method setIsFirstShowcaseInteraction*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method requestProfileShowcase*(self: AccessInterface, publicKey: string) {.base.} = - raise newException(ValueError, "No implementation available") - -method fetchProfileShowcaseAccountsByAddress*(self: AccessInterface, address: string) {.base.} = - raise newException(ValueError, "No implementation available") - -method onProfileShowcaseAccountsByAddressFetched*(self: AccessInterface, accounts: seq[ProfileShowcaseAccount]) {.base.} = - raise newException(ValueError, "No implementation available") - -method updateProfileShowcase*(self: AccessInterface, profileShowcase: ProfileShowcaseDto) {.base.} = - raise newException(ValueError, "No implementation available") - -method updateProfileShowcasePreferences*(self: AccessInterface, preferences: ProfileShowcasePreferencesDto) {.base.} = - raise newException(ValueError, "No implementation available") - -method onContactDetailsUpdated*(self: AccessInterface, contactId: string) {.base.} = - raise newException(ValueError, "No implementation available") - -method onCommunitiesUpdated*(self: AccessInterface, communities: seq[CommunityDto]) {.base.} = +method loadProfileShowcasePreferences*(self: AccessInterface, preferences: ProfileShowcasePreferencesDto) {.base.} = raise newException(ValueError, "No implementation available") # View Delegate Interface diff --git a/src/app/modules/main/profile_section/profile/models/profile_preferences_account_item.nim b/src/app/modules/main/profile_section/profile/models/profile_preferences_account_item.nim deleted file mode 100644 index d85a2af686..0000000000 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_account_item.nim +++ /dev/null @@ -1,68 +0,0 @@ -import json, strutils, stint, json_serialization, tables - -import profile_preferences_base_item - -import app_service/service/profile/dto/profile_showcase_preferences - -include app_service/common/json_utils -include app_service/common/utils - -type - ProfileShowcaseAccountItem* = ref object of ProfileShowcaseBaseItem - address*: string - name*: string - emoji*: string - colorId*: string - -proc initProfileShowcaseAccountItem*( - address: string, - name: string, - emoji: string, - colorId: string, - visibility: ProfileShowcaseVisibility, - order: int): ProfileShowcaseAccountItem = - result = ProfileShowcaseAccountItem() - - result.address = address - result.name = name - result.emoji = emoji - result.colorId = colorId - result.showcaseVisibility = visibility - result.order = order - -proc toProfileShowcaseAccountItem*(jsonObj: JsonNode): ProfileShowcaseAccountItem = - result = ProfileShowcaseAccountItem() - - discard jsonObj.getProp("address", result.address) - discard jsonObj.getProp("name", result.name) - discard jsonObj.getProp("emoji", result.emoji) - discard jsonObj.getProp("colorId", result.colorId) - - discard jsonObj.getProp("order", result.order) - var visibilityInt: int - if (jsonObj.getProp("showcaseVisibility", visibilityInt) and - (visibilityInt >= ord(low(ProfileShowcaseVisibility)) and - visibilityInt <= ord(high(ProfileShowcaseVisibility)))): - result.showcaseVisibility = ProfileShowcaseVisibility(visibilityInt) - -proc toShowcasePreferenceItem*(self: ProfileShowcaseAccountItem): ProfileShowcaseAccountPreference = - result = ProfileShowcaseAccountPreference() - - result.address = self.address - result.showcaseVisibility = self.showcaseVisibility - result.order = self.order - -proc name*(self: ProfileShowcaseAccountItem): string {.inline.} = - self.name - -proc address*(self: ProfileShowcaseAccountItem): string {.inline.} = - self.address - -proc walletType*(self: ProfileShowcaseAccountItem): string {.inline.} = - self.walletType - -proc emoji*(self: ProfileShowcaseAccountItem): string {.inline.} = - self.emoji - -proc colorId*(self: ProfileShowcaseAccountItem): string {.inline.} = - self.colorId diff --git a/src/app/modules/main/profile_section/profile/models/profile_preferences_accounts_model.nim b/src/app/modules/main/profile_section/profile/models/profile_preferences_accounts_model.nim deleted file mode 100644 index d241e35407..0000000000 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_accounts_model.nim +++ /dev/null @@ -1,209 +0,0 @@ -import NimQml, tables, strutils, sequtils, json - -import profile_preferences_account_item -import app_service/service/profile/dto/profile_showcase_preferences - -type - ModelRole {.pure.} = enum - ShowcaseVisibility = UserRole + 1 - Order - - Address - Name - Emoji - ColorId - -QtObject: - type - ProfileShowcaseAccountsModel* = ref object of QAbstractListModel - items: seq[ProfileShowcaseAccountItem] - - proc delete(self: ProfileShowcaseAccountsModel) = - self.items = @[] - self.QAbstractListModel.delete - - proc setup(self: ProfileShowcaseAccountsModel) = - self.QAbstractListModel.setup - - proc newProfileShowcaseAccountsModel*(): ProfileShowcaseAccountsModel = - new(result, delete) - result.setup - - proc countChanged(self: ProfileShowcaseAccountsModel) {.signal.} - proc getCount(self: ProfileShowcaseAccountsModel): int {.slot.} = - self.items.len - QtProperty[int] count: - read = getCount - notify = countChanged - - proc hiddenCountChanged(self: ProfileShowcaseAccountsModel) {.signal.} - proc getHiddenCount(self: ProfileShowcaseAccountsModel): int {.slot.} = - result = 0 - for i, item in self.items: - if item.showcaseVisibility == ProfileShowcaseVisibility.ToNoOne: - result += 1 - QtProperty[int] hiddenCount: - read = getHiddenCount - notify = hiddenCountChanged - - proc recalcOrder(self: ProfileShowcaseAccountsModel) = - for order, item in self.items: - item.order = order - - proc items*(self: ProfileShowcaseAccountsModel): seq[ProfileShowcaseAccountItem] = - self.items - - method rowCount(self: ProfileShowcaseAccountsModel, index: QModelIndex = nil): int = - return self.items.len - - method roleNames(self: ProfileShowcaseAccountsModel): Table[int, string] = - { - ModelRole.ShowcaseVisibility.int: "showcaseVisibility", - ModelRole.Order.int: "order", - - ModelRole.Address.int: "address", - ModelRole.Name.int: "name", - ModelRole.Emoji.int: "emoji", - ModelRole.ColorId.int: "colorId", - }.toTable - - method data(self: ProfileShowcaseAccountsModel, index: QModelIndex, role: int): QVariant = - if (not index.isValid): - return - - if (index.row < 0 or index.row >= self.items.len): - return - - let item = self.items[index.row] - let enumRole = role.ModelRole - - case enumRole: - of ModelRole.ShowcaseVisibility: - result = newQVariant(item.showcaseVisibility.int) - of ModelRole.Order: - result = newQVariant(item.order) - of ModelRole.Address: - result = newQVariant(item.address) - of ModelRole.Name: - result = newQVariant(item.name) - of ModelRole.Emoji: - result = newQVariant(item.emoji) - of ModelRole.ColorId: - result = newQVariant(item.colorId) - - proc findIndexForAccount(self: ProfileShowcaseAccountsModel, address: string): int = - for index in 0 ..< self.items.len: - if (self.items[index].address == address): - return index - return -1 - - proc hasItemInShowcase*(self: ProfileShowcaseAccountsModel, address: string): bool {.slot.} = - let ind = self.findIndexForAccount(address) - if ind == -1: - return false - return self.items[ind].showcaseVisibility != ProfileShowcaseVisibility.ToNoOne - - proc baseModelFilterConditionsMayHaveChanged*(self: ProfileShowcaseAccountsModel) {.signal.} - - proc appendItem*(self: ProfileShowcaseAccountsModel, item: ProfileShowcaseAccountItem) = - let parentModelIndex = newQModelIndex() - defer: parentModelIndex.delete - self.beginInsertRows(parentModelIndex, self.items.len, self.items.len) - self.items.add(item) - self.endInsertRows() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItemImpl(self: ProfileShowcaseAccountsModel, item: ProfileShowcaseAccountItem) = - let ind = self.findIndexForAccount(item.address) - if ind == -1: - self.appendItem(item) - else: - self.items[ind] = item - - let index = self.createIndex(ind, 0, nil) - defer: index.delete - self.dataChanged(index, index) - self.hiddenCountChanged() - - proc upsertItemJson(self: ProfileShowcaseAccountsModel, itemJson: string) {.slot.} = - self.upsertItemImpl(itemJson.parseJson.toProfileShowcaseAccountItem()) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItem*(self: ProfileShowcaseAccountsModel, item: ProfileShowcaseAccountItem) = - self.upsertItemImpl(item) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItems*(self: ProfileShowcaseAccountsModel, items: seq[ProfileShowcaseAccountItem]) = - for item in items: - self.upsertItemImpl(item) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc reset*(self: ProfileShowcaseAccountsModel, items: seq[ProfileShowcaseAccountItem]) = - self.beginResetModel() - self.items = items - self.endResetModel() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc clear*(self: ProfileShowcaseAccountsModel) {.slot.} = - self.reset(@[]) - - proc remove*(self: ProfileShowcaseAccountsModel, index: int) {.slot.} = - if index < 0 or index >= self.items.len: - return - - let parentModelIndex = newQModelIndex() - defer: parentModelIndex.delete - self.beginRemoveRows(parentModelIndex, index, index) - self.items.delete(index) - self.endRemoveRows() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc removeEntry*(self: ProfileShowcaseAccountsModel, address: string) {.slot.} = - let ind = self.findIndexForAccount(address) - if ind != -1: - self.remove(ind) - - proc move*(self: ProfileShowcaseAccountsModel, fromRow: int, toRow: int, dummyCount: int = 1) {.slot.} = - if fromRow < 0 or fromRow >= self.items.len: - return - - let sourceIndex = newQModelIndex() - defer: sourceIndex.delete - let destIndex = newQModelIndex() - defer: destIndex.delete - - var destRow = toRow - if toRow > fromRow: - inc(destRow) - - self.beginMoveRows(sourceIndex, fromRow, fromRow, destIndex, destRow) - let item = self.items[fromRow] - self.items.delete(fromRow) - self.items.insert(@[item], toRow) - self.recalcOrder() - self.endMoveRows() - - proc setVisibilityByIndex*(self: ProfileShowcaseAccountsModel, ind: int, visibility: int) {.slot.} = - if (visibility >= ord(low(ProfileShowcaseVisibility)) and - visibility <= ord(high(ProfileShowcaseVisibility)) and - ind >= 0 and ind < self.items.len): - self.items[ind].showcaseVisibility = ProfileShowcaseVisibility(visibility) - let index = self.createIndex(ind, 0, nil) - defer: index.delete - self.dataChanged(index, index, @[ModelRole.ShowcaseVisibility.int]) - self.baseModelFilterConditionsMayHaveChanged() - self.hiddenCountChanged() - - proc setVisibility*(self: ProfileShowcaseAccountsModel, address: string, visibility: int) {.slot.} = - let index = self.findIndexForAccount(address) - if index != -1: - self.setVisibilityByIndex(index, visibility) 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 deleted file mode 100644 index 5566a88cac..0000000000 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_asset_item.nim +++ /dev/null @@ -1,68 +0,0 @@ -import json, strutils, stint, json_serialization, tables - -import profile_preferences_base_item - -import app_service/service/profile/dto/profile_showcase_preferences -import app_service/service/token/service_items - -import app/modules/shared_models/currency_amount - -include app_service/common/json_utils -include app_service/common/utils - -type - ProfileShowcaseAssetItem* = ref object of ProfileShowcaseBaseItem - contractAddress*: string - communityId*: string - chainId*: int - symbol*: string - name*: string - enabledNetworkBalance*: CurrencyAmount - decimals*: int - - -proc initProfileShowcaseVerifiedToken*(token: TokenBySymbolItem, visibility: ProfileShowcaseVisibility, order: int): ProfileShowcaseAssetItem = - result = ProfileShowcaseAssetItem() - - result.showcaseVisibility = visibility - result.order = order - - result.symbol = token.symbol - result.name = token.name - result.enabledNetworkBalance = newCurrencyAmount() - result.decimals = token.decimals - - # TODO: initProfileShowcaseUnverifiedToken - -proc toProfileShowcaseAssetItem*(jsonObj: JsonNode): ProfileShowcaseAssetItem = - result = ProfileShowcaseAssetItem() - - discard jsonObj.getProp("order", result.order) - var visibilityInt: int - if (jsonObj.getProp("showcaseVisibility", visibilityInt) and - (visibilityInt >= ord(low(ProfileShowcaseVisibility)) and - 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("decimals", result.decimals) - - result.enabledNetworkBalance = newCurrencyAmount(jsonObj{"enabledNetworkBalance"}.getFloat, result.symbol, result.decimals, false) - -proc toShowcaseVerifiedTokenPreference*(self: ProfileShowcaseAssetItem): ProfileShowcaseVerifiedTokenPreference = - result = ProfileShowcaseVerifiedTokenPreference() - - result.symbol = self.symbol - result.showcaseVisibility = self.showcaseVisibility - result.order = self.order - -proc toShowcaseUnverifiedTokenPreference*(self: ProfileShowcaseAssetItem): ProfileShowcaseUnverifiedTokenPreference = - result = ProfileShowcaseUnverifiedTokenPreference() - - 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 deleted file mode 100644 index 00cb196188..0000000000 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_assets_model.nim +++ /dev/null @@ -1,217 +0,0 @@ -import NimQml, tables, strutils, sequtils, json - -import profile_preferences_asset_item -import app_service/service/profile/dto/profile_showcase_preferences - -type - ModelRole {.pure.} = enum - ShowcaseVisibility = UserRole + 1 - Order - - Address - CommunityId - Symbol - Name - EnabledNetworkBalance - Decimals - -QtObject: - type - ProfileShowcaseAssetsModel* = ref object of QAbstractListModel - items: seq[ProfileShowcaseAssetItem] - - proc delete(self: ProfileShowcaseAssetsModel) = - self.items = @[] - self.QAbstractListModel.delete - - proc setup(self: ProfileShowcaseAssetsModel) = - self.QAbstractListModel.setup - - proc newProfileShowcaseAssetsModel*(): ProfileShowcaseAssetsModel = - new(result, delete) - result.setup - - proc countChanged(self: ProfileShowcaseAssetsModel) {.signal.} - proc getCount(self: ProfileShowcaseAssetsModel): int {.slot.} = - self.items.len - QtProperty[int] count: - read = getCount - notify = countChanged - - proc hiddenCountChanged(self: ProfileShowcaseAssetsModel) {.signal.} - proc getHiddenCount(self: ProfileShowcaseAssetsModel): int {.slot.} = - result = 0 - for i, item in self.items: - if item.showcaseVisibility == ProfileShowcaseVisibility.ToNoOne: - result += 1 - QtProperty[int] hiddenCount: - read = getHiddenCount - notify = hiddenCountChanged - - proc recalcOrder(self: ProfileShowcaseAssetsModel) = - for order, item in self.items: - item.order = order - - proc items*(self: ProfileShowcaseAssetsModel): seq[ProfileShowcaseAssetItem] = - self.items - - method rowCount(self: ProfileShowcaseAssetsModel, index: QModelIndex = nil): int = - return self.items.len - - method roleNames(self: ProfileShowcaseAssetsModel): Table[int, string] = - { - 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", - ModelRole.Decimals.int: "decimals", - }.toTable - - method data(self: ProfileShowcaseAssetsModel, index: QModelIndex, role: int): QVariant = - if (not index.isValid): - return - - if (index.row < 0 or index.row >= self.items.len): - return - - let item = self.items[index.row] - let enumRole = role.ModelRole - - case enumRole: - of ModelRole.ShowcaseVisibility: - 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: - result = newQVariant(item.name) - of ModelRole.EnabledNetworkBalance: - result = newQVariant(item.enabledNetworkBalance) - of ModelRole.Decimals: - result = newQVariant(item.decimals) - - proc findIndexForAsset(self: ProfileShowcaseAssetsModel, symbol: string): int = - for i in 0 ..< self.items.len: - if (self.items[i].symbol == symbol): - return i - return -1 - - proc hasItemInShowcase*(self: ProfileShowcaseAssetsModel, symbol: string): bool {.slot.} = - let ind = self.findIndexForAsset(symbol) - if ind == -1: - return false - return self.items[ind].showcaseVisibility != ProfileShowcaseVisibility.ToNoOne - - proc baseModelFilterConditionsMayHaveChanged*(self: ProfileShowcaseAssetsModel) {.signal.} - - proc appendItem*(self: ProfileShowcaseAssetsModel, item: ProfileShowcaseAssetItem) = - let parentModelIndex = newQModelIndex() - defer: parentModelIndex.delete - self.beginInsertRows(parentModelIndex, self.items.len, self.items.len) - self.items.add(item) - self.endInsertRows() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItemImpl(self: ProfileShowcaseAssetsModel, item: ProfileShowcaseAssetItem) = - let ind = self.findIndexForAsset(item.symbol) - if ind == -1: - self.appendItem(item) - else: - self.items[ind] = item - - let index = self.createIndex(ind, 0, nil) - defer: index.delete - self.dataChanged(index, index) - self.hiddenCountChanged() - - proc upsertItemJson(self: ProfileShowcaseAssetsModel, itemJson: string) {.slot.} = - self.upsertItemImpl(itemJson.parseJson.toProfileShowcaseAssetItem()) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItem*(self: ProfileShowcaseAssetsModel, item: ProfileShowcaseAssetItem) = - self.upsertItemImpl(item) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItems*(self: ProfileShowcaseAssetsModel, items: seq[ProfileShowcaseAssetItem]) = - for item in items: - self.upsertItemImpl(item) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc reset*(self: ProfileShowcaseAssetsModel, items: seq[ProfileShowcaseAssetItem]) = - self.beginResetModel() - self.items = items - self.endResetModel() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc clear*(self: ProfileShowcaseAssetsModel) {.slot.} = - self.reset(@[]) - - proc remove*(self: ProfileShowcaseAssetsModel, index: int) {.slot.} = - if index < 0 or index >= self.items.len: - return - - let parentModelIndex = newQModelIndex() - defer: parentModelIndex.delete - self.beginRemoveRows(parentModelIndex, index, index) - self.items.delete(index) - self.endRemoveRows() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc removeEntry*(self: ProfileShowcaseAssetsModel, symbol: string) {.slot.} = - let ind = self.findIndexForAsset(symbol) - if ind != -1: - self.remove(ind) - - proc move*(self: ProfileShowcaseAssetsModel, fromRow: int, toRow: int, dummyCount: int = 1) {.slot.} = - if fromRow < 0 or fromRow >= self.items.len: - return - - let sourceIndex = newQModelIndex() - defer: sourceIndex.delete - let destIndex = newQModelIndex() - defer: destIndex.delete - - var destRow = toRow - if toRow > fromRow: - inc(destRow) - - self.beginMoveRows(sourceIndex, fromRow, fromRow, destIndex, destRow) - let item = self.items[fromRow] - self.items.delete(fromRow) - self.items.insert(@[item], toRow) - self.recalcOrder() - self.endMoveRows() - - proc setVisibilityByIndex*(self: ProfileShowcaseAssetsModel, ind: int, visibility: int) {.slot.} = - if (visibility >= ord(low(ProfileShowcaseVisibility)) and - visibility <= ord(high(ProfileShowcaseVisibility)) and - ind >= 0 and ind < self.items.len): - self.items[ind].showcaseVisibility = ProfileShowcaseVisibility(visibility) - let index = self.createIndex(ind, 0, nil) - defer: index.delete - self.dataChanged(index, index, @[ModelRole.ShowcaseVisibility.int]) - self.baseModelFilterConditionsMayHaveChanged() - self.hiddenCountChanged() - - proc setVisibility*(self: ProfileShowcaseAssetsModel, symbol: string, visibility: int) {.slot.} = - let index = self.findIndexForAsset(symbol) - if index != -1: - self.setVisibilityByIndex(index, visibility) diff --git a/src/app/modules/main/profile_section/profile/models/profile_preferences_base_item.nim b/src/app/modules/main/profile_section/profile/models/profile_preferences_base_item.nim deleted file mode 100644 index e89d234bff..0000000000 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_base_item.nim +++ /dev/null @@ -1,12 +0,0 @@ -import app_service/service/profile/dto/profile_showcase_preferences - -type - ProfileShowcaseBaseItem* = object of RootObj - showcaseVisibility*: ProfileShowcaseVisibility - order*: int - -proc showcaseVisibility*(self: ProfileShowcaseBaseItem): ProfileShowcaseVisibility {.inline.} = - self.showcaseVisibility - -proc order*(self: ProfileShowcaseBaseItem): int {.inline.} = - self.order 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 deleted file mode 100644 index 806c189466..0000000000 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_collectible_item.nim +++ /dev/null @@ -1,67 +0,0 @@ -import json, strutils, stew/shims/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 - 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() - - discard jsonObj.getProp("order", result.order) - var visibilityInt: int - if (jsonObj.getProp("showcaseVisibility", visibilityInt) and - (visibilityInt >= ord(low(ProfileShowcaseVisibility)) and - visibilityInt <= ord(high(ProfileShowcaseVisibility)))): - result.showcaseVisibility = ProfileShowcaseVisibility(visibilityInt) - - 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) - discard jsonObj.getProp("backgroundColor", result.backgroundColor) - -proc toShowcasePreferenceItem*(self: ProfileShowcaseCollectibleItem): ProfileShowcaseCollectiblePreference = - result = ProfileShowcaseCollectiblePreference() - - result.chainId = self.chainId - result.tokenId = self.tokenId - result.contractAddress = self.contractAddress - result.showcaseVisibility = self.showcaseVisibility - result.order = self.order - -# 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 deleted file mode 100644 index 0f519f2a16..0000000000 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_collectibles_model.nim +++ /dev/null @@ -1,234 +0,0 @@ -import NimQml, tables, strutils, sequtils, json - -import profile_preferences_collectible_item -import app_service/service/profile/dto/profile_showcase_preferences - -type - ModelRole {.pure.} = enum - Uid = UserRole + 1, - ChainId - ContractAddress - TokenId - Name - ImageUrl - BackgroundColor - CollectionName - IsLoading - CommunityId - - ShowcaseVisibility - Order - -QtObject: - type - ProfileShowcaseCollectiblesModel* = ref object of QAbstractListModel - items: seq[ProfileShowcaseCollectibleItem] - - proc delete(self: ProfileShowcaseCollectiblesModel) = - self.items = @[] - self.QAbstractListModel.delete - - proc setup(self: ProfileShowcaseCollectiblesModel) = - self.QAbstractListModel.setup - - proc newProfileShowcaseCollectiblesModel*(): ProfileShowcaseCollectiblesModel = - new(result, delete) - result.setup - - proc countChanged(self: ProfileShowcaseCollectiblesModel) {.signal.} - proc getCount(self: ProfileShowcaseCollectiblesModel): int {.slot.} = - self.items.len - QtProperty[int] count: - read = getCount - notify = countChanged - - proc hiddenCountChanged(self: ProfileShowcaseCollectiblesModel) {.signal.} - proc getHiddenCount(self: ProfileShowcaseCollectiblesModel): int {.slot.} = - result = 0 - for i, item in self.items: - if item.showcaseVisibility == ProfileShowcaseVisibility.ToNoOne: - result += 1 - QtProperty[int] hiddenCount: - read = getHiddenCount - notify = hiddenCountChanged - - proc recalcOrder(self: ProfileShowcaseCollectiblesModel) = - for order, item in self.items: - item.order = order - - proc items*(self: ProfileShowcaseCollectiblesModel): seq[ProfileShowcaseCollectibleItem] = - self.items - - method rowCount(self: ProfileShowcaseCollectiblesModel, index: QModelIndex = nil): int = - return self.items.len - - method roleNames(self: ProfileShowcaseCollectiblesModel): Table[int, string] = - { - ModelRole.Uid.int:"uid", - ModelRole.ChainId.int: "chainId", - ModelRole.ContractAddress.int: "contractAddress", - ModelRole.TokenId.int: "tokenId", - ModelRole.Name.int: "name", - 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 = - if (not index.isValid): - return - - if (index.row < 0 or index.row >= self.items.len): - return - - let item = self.items[index.row] - let enumRole = role.ModelRole - - case enumRole: - of ModelRole.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.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].getID() == uid): - return i - return -1 - - proc hasItemInShowcase*(self: ProfileShowcaseCollectiblesModel, uid: string): bool {.slot.} = - let ind = self.findIndexForCollectible(uid) - if ind == -1: - return false - return self.items[ind].showcaseVisibility != ProfileShowcaseVisibility.ToNoOne - - proc baseModelFilterConditionsMayHaveChanged*(self: ProfileShowcaseCollectiblesModel) {.signal.} - - proc appendItem*(self: ProfileShowcaseCollectiblesModel, item: ProfileShowcaseCollectibleItem) = - let parentModelIndex = newQModelIndex() - defer: parentModelIndex.delete - self.beginInsertRows(parentModelIndex, self.items.len, self.items.len) - self.items.add(item) - self.endInsertRows() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItemImpl(self: ProfileShowcaseCollectiblesModel, item: ProfileShowcaseCollectibleItem) = - let ind = self.findIndexForCollectible(item.getID()) - if ind == -1: - self.appendItem(item) - else: - self.items[ind] = item - - let index = self.createIndex(ind, 0, nil) - defer: index.delete - self.dataChanged(index, index) - self.hiddenCountChanged() - - proc upsertItemJson(self: ProfileShowcaseCollectiblesModel, itemJson: string) {.slot.} = - self.upsertItemImpl(itemJson.parseJson.toProfileShowcaseCollectibleItem()) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItem*(self: ProfileShowcaseCollectiblesModel, item: ProfileShowcaseCollectibleItem) = - self.upsertItemImpl(item) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItems*(self: ProfileShowcaseCollectiblesModel, items: seq[ProfileShowcaseCollectibleItem]) = - for item in items: - self.upsertItemImpl(item) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc reset*(self: ProfileShowcaseCollectiblesModel, items: seq[ProfileShowcaseCollectibleItem]) = - self.beginResetModel() - self.items = items - self.endResetModel() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc clear*(self: ProfileShowcaseCollectiblesModel) {.slot.} = - self.reset(@[]) - - proc remove*(self: ProfileShowcaseCollectiblesModel, index: int) {.slot.} = - if index < 0 or index >= self.items.len: - return - - let parentModelIndex = newQModelIndex() - defer: parentModelIndex.delete - self.beginRemoveRows(parentModelIndex, index, index) - self.items.delete(index) - self.endRemoveRows() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc removeEntry*(self: ProfileShowcaseCollectiblesModel, uid: string) {.slot.} = - let ind = self.findIndexForCollectible(uid) - if ind != -1: - self.remove(ind) - - proc move*(self: ProfileShowcaseCollectiblesModel, fromRow: int, toRow: int, dummyCount: int = 1) {.slot.} = - if fromRow < 0 or fromRow >= self.items.len: - return - - let sourceIndex = newQModelIndex() - defer: sourceIndex.delete - let destIndex = newQModelIndex() - defer: destIndex.delete - - var destRow = toRow - if toRow > fromRow: - inc(destRow) - - self.beginMoveRows(sourceIndex, fromRow, fromRow, destIndex, destRow) - let item = self.items[fromRow] - self.items.delete(fromRow) - self.items.insert(@[item], toRow) - self.recalcOrder() - self.endMoveRows() - - proc setVisibilityByIndex*(self: ProfileShowcaseCollectiblesModel, ind: int, visibility: int) {.slot.} = - if (visibility >= ord(low(ProfileShowcaseVisibility)) and - visibility <= ord(high(ProfileShowcaseVisibility)) and - ind >= 0 and ind < self.items.len): - self.items[ind].showcaseVisibility = ProfileShowcaseVisibility(visibility) - let index = self.createIndex(ind, 0, nil) - defer: index.delete - self.dataChanged(index, index, @[ModelRole.ShowcaseVisibility.int]) - self.baseModelFilterConditionsMayHaveChanged() - self.hiddenCountChanged() - - proc setVisibility*(self: ProfileShowcaseCollectiblesModel, uid: string, visibility: int) {.slot.} = - let index = self.findIndexForCollectible(uid) - if index != -1: - self.setVisibilityByIndex(index, visibility) diff --git a/src/app/modules/main/profile_section/profile/models/profile_preferences_communities_model.nim b/src/app/modules/main/profile_section/profile/models/profile_preferences_communities_model.nim deleted file mode 100644 index 0457547500..0000000000 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_communities_model.nim +++ /dev/null @@ -1,224 +0,0 @@ -import NimQml, tables, strutils, sequtils, json - -import profile_preferences_community_item -import app_service/service/profile/dto/profile_showcase_preferences - -type - ModelRole {.pure.} = enum - ShowcaseVisibility - Order - - Id - Name - MemberRole - Image - Color - Description - MembersCount - Loading - -QtObject: - type - ProfileShowcaseCommunitiesModel* = ref object of QAbstractListModel - items: seq[ProfileShowcaseCommunityItem] - - proc delete(self: ProfileShowcaseCommunitiesModel) = - self.items = @[] - self.QAbstractListModel.delete - - proc setup(self: ProfileShowcaseCommunitiesModel) = - self.QAbstractListModel.setup - - proc newProfileShowcaseCommunitiesModel*(): ProfileShowcaseCommunitiesModel = - new(result, delete) - result.setup - - proc countChanged(self: ProfileShowcaseCommunitiesModel) {.signal.} - proc getCount(self: ProfileShowcaseCommunitiesModel): int {.slot.} = - self.items.len - QtProperty[int] count: - read = getCount - notify = countChanged - - proc hiddenCountChanged(self: ProfileShowcaseCommunitiesModel) {.signal.} - proc getHiddenCount(self: ProfileShowcaseCommunitiesModel): int {.slot.} = - result = 0 - for i, item in self.items: - if item.showcaseVisibility == ProfileShowcaseVisibility.ToNoOne: - result += 1 - QtProperty[int] hiddenCount: - read = getHiddenCount - notify = hiddenCountChanged - - proc recalcOrder(self: ProfileShowcaseCommunitiesModel) = - for order, item in self.items: - item.order = order - - proc items*(self: ProfileShowcaseCommunitiesModel): seq[ProfileShowcaseCommunityItem] = - self.items - - method rowCount(self: ProfileShowcaseCommunitiesModel, index: QModelIndex = nil): int = - return self.items.len - - method roleNames(self: ProfileShowcaseCommunitiesModel): Table[int, string] = - { - ModelRole.Id.int: "id", - ModelRole.ShowcaseVisibility.int: "showcaseVisibility", - ModelRole.Order.int: "order", - ModelRole.Name.int: "name", - ModelRole.MemberRole.int: "memberRole", - ModelRole.Image.int: "image", - ModelRole.Color.int: "color", - ModelRole.Description.int: "description", - ModelRole.MembersCount.int: "membersCount", - ModelRole.Loading.int: "loading", - }.toTable - - method data(self: ProfileShowcaseCommunitiesModel, index: QModelIndex, role: int): QVariant = - if (not index.isValid): - return - - if (index.row < 0 or index.row >= self.items.len): - return - - let item = self.items[index.row] - let enumRole = role.ModelRole - - case enumRole: - of ModelRole.ShowcaseVisibility: - result = newQVariant(item.showcaseVisibility.int) - of ModelRole.Order: - result = newQVariant(item.order) - of ModelRole.Id: - result = newQVariant(item.id) - of ModelRole.Name: - result = newQVariant(item.name) - of ModelRole.MemberRole: - result = newQVariant(item.memberRole.int) - of ModelRole.Image: - result = newQVariant(item.image) - of ModelRole.Color: - result = newQVariant(item.color) - of ModelRole.Description: - result = newQVariant(item.description) - of ModelRole.MembersCount: - result = newQVariant(item.membersCount) - of ModelRole.Loading: - result = newQVariant(item.loading) - - proc findIndexForCommunity(self: ProfileShowcaseCommunitiesModel, id: string): int = - for i in 0 ..< self.items.len: - if (self.items[i].id == id): - return i - return -1 - - proc hasItemInShowcase*(self: ProfileShowcaseCommunitiesModel, id: string): bool {.slot.} = - let ind = self.findIndexForCommunity(id) - if ind == -1: - return false - return self.items[ind].showcaseVisibility != ProfileShowcaseVisibility.ToNoOne - - proc baseModelFilterConditionsMayHaveChanged*(self: ProfileShowcaseCommunitiesModel) {.signal.} - - proc appendItem*(self: ProfileShowcaseCommunitiesModel, item: ProfileShowcaseCommunityItem) = - let parentModelIndex = newQModelIndex() - defer: parentModelIndex.delete - self.beginInsertRows(parentModelIndex, self.items.len, self.items.len) - self.items.add(item) - self.endInsertRows() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItemImpl(self: ProfileShowcaseCommunitiesModel, item: ProfileShowcaseCommunityItem) = - let ind = self.findIndexForCommunity(item.id) - if ind == -1: - self.appendItem(item) - else: - self.items[ind] = item - - let index = self.createIndex(ind, 0, nil) - defer: index.delete - self.dataChanged(index, index) - self.hiddenCountChanged() - - proc upsertItemJson(self: ProfileShowcaseCommunitiesModel, itemJson: string) {.slot.} = - self.upsertItemImpl(itemJson.parseJson.toProfileShowcaseCommunityItem()) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItem*(self: ProfileShowcaseCommunitiesModel, item: ProfileShowcaseCommunityItem) = - self.upsertItemImpl(item) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc upsertItems*(self: ProfileShowcaseCommunitiesModel, items: seq[ProfileShowcaseCommunityItem]) = - for item in items: - self.upsertItemImpl(item) - self.recalcOrder() - self.baseModelFilterConditionsMayHaveChanged() - - proc reset*(self: ProfileShowcaseCommunitiesModel, items: seq[ProfileShowcaseCommunityItem]) = - self.beginResetModel() - self.items = items - self.endResetModel() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc clear*(self: ProfileShowcaseCommunitiesModel) {.slot.} = - self.reset(@[]) - - proc remove*(self: ProfileShowcaseCommunitiesModel, index: int) {.slot.} = - if index < 0 or index >= self.items.len: - return - - let parentModelIndex = newQModelIndex() - defer: parentModelIndex.delete - self.beginRemoveRows(parentModelIndex, index, index) - self.items.delete(index) - self.endRemoveRows() - self.countChanged() - self.hiddenCountChanged() - self.baseModelFilterConditionsMayHaveChanged() - - proc removeEntry*(self: ProfileShowcaseCommunitiesModel, id: string) {.slot.} = - let ind = self.findIndexForCommunity(id) - if ind != -1: - self.remove(ind) - - proc move*(self: ProfileShowcaseCommunitiesModel, fromRow: int, toRow: int, dummyCount: int = 1) {.slot.} = - if fromRow < 0 or fromRow >= self.items.len: - return - - let sourceIndex = newQModelIndex() - defer: sourceIndex.delete - let destIndex = newQModelIndex() - defer: destIndex.delete - - var destRow = toRow - if toRow > fromRow: - inc(destRow) - - self.beginMoveRows(sourceIndex, fromRow, fromRow, destIndex, destRow) - let item = self.items[fromRow] - self.items.delete(fromRow) - self.items.insert(@[item], toRow) - self.recalcOrder() - self.endMoveRows() - - proc setVisibilityByIndex*(self: ProfileShowcaseCommunitiesModel, ind: int, visibility: int) {.slot.} = - if (visibility >= ord(low(ProfileShowcaseVisibility)) and - visibility <= ord(high(ProfileShowcaseVisibility)) and - ind >= 0 and ind < self.items.len): - self.items[ind].showcaseVisibility = ProfileShowcaseVisibility(visibility) - let index = self.createIndex(ind, 0, nil) - defer: index.delete - self.dataChanged(index, index, @[ModelRole.ShowcaseVisibility.int]) - self.baseModelFilterConditionsMayHaveChanged() - self.hiddenCountChanged() - - proc setVisibility*(self: ProfileShowcaseCommunitiesModel, id: string, visibility: int) {.slot.} = - let index = self.findIndexForCommunity(id) - if index != -1: - self.setVisibilityByIndex(index, visibility) diff --git a/src/app/modules/main/profile_section/profile/models/profile_preferences_community_item.nim b/src/app/modules/main/profile_section/profile/models/profile_preferences_community_item.nim deleted file mode 100644 index 78c85a6f1b..0000000000 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_community_item.nim +++ /dev/null @@ -1,88 +0,0 @@ -import json, strutils, stint, json_serialization, tables - -import profile_preferences_base_item - -import app_service/service/community/dto/community -import app_service/service/profile/dto/profile_showcase_preferences - -include app_service/common/json_utils -include app_service/common/utils - -type - ProfileShowcaseCommunityItem* = ref object of ProfileShowcaseBaseItem - id*: string - name*: string - memberRole*: MemberRole - image*: string - color*: string - description*: string - membersCount*: int - loading*: bool - -proc initProfileShowcaseCommunityItem*(community: CommunityDto, visibility: ProfileShowcaseVisibility, order: int): ProfileShowcaseCommunityItem = - result = ProfileShowcaseCommunityItem() - - result.showcaseVisibility = visibility - result.order = order - - result.id = community.id - result.name = community.name - result.memberRole = community.memberRole - result.image = community.images.thumbnail - result.color = community.color - result.description = community.description - result.membersCount = len(community.members) - result.loading = false - -proc initProfileShowcaseCommunityLoadingItem*(communityId: string, visibility: ProfileShowcaseVisibility, order: int): ProfileShowcaseCommunityItem = - result = ProfileShowcaseCommunityItem() - - result.showcaseVisibility = visibility - result.order = order - result.id = communityId - result.loading = true - -proc toProfileShowcaseCommunityItem*(jsonObj: JsonNode): ProfileShowcaseCommunityItem = - result = ProfileShowcaseCommunityItem() - - discard jsonObj.getProp("order", result.order) - var visibilityInt: int - if (jsonObj.getProp("showcaseVisibility", visibilityInt) and - (visibilityInt >= ord(low(ProfileShowcaseVisibility)) and - visibilityInt <= ord(high(ProfileShowcaseVisibility)))): - result.showcaseVisibility = ProfileShowcaseVisibility(visibilityInt) - - discard jsonObj.getProp("id", result.id) - discard jsonObj.getProp("name", result.name) - discard jsonObj.getProp("memberRole", result.memberRole) - discard jsonObj.getProp("image", result.image) - discard jsonObj.getProp("color", result.color) - result.loading = false - -proc toShowcasePreferenceItem*(self: ProfileShowcaseCommunityItem): ProfileShowcaseCommunityPreference = - result = ProfileShowcaseCommunityPreference() - - result.communityId = self.id - result.showcaseVisibility = self.showcaseVisibility - result.order = self.order - -proc patchFromCommunity*(self: ProfileShowcaseCommunityItem, community: CommunityDto) = - self.name = community.name - self.memberRole = community.memberRole - self.image = community.images.thumbnail - self.color = community.color - self.description = community.description - self.membersCount = len(community.members) - self.loading = false - -proc name*(self: ProfileShowcaseCommunityItem): string {.inline.} = - self.name - -proc memberRole*(self: ProfileShowcaseCommunityItem): MemberRole {.inline.} = - self.memberRole - -proc image*(self: ProfileShowcaseCommunityItem): string {.inline.} = - self.image - -proc color*(self: ProfileShowcaseCommunityItem): string {.inline.} = - self.color diff --git a/src/app/modules/main/profile_section/profile/module.nim b/src/app/modules/main/profile_section/profile/module.nim index 5cfa66f4eb..8f6c12cd36 100644 --- a/src/app/modules/main/profile_section/profile/module.nim +++ b/src/app/modules/main/profile_section/profile/module.nim @@ -1,4 +1,4 @@ -import NimQml, chronicles, sequtils, sugar, json, strutils +import NimQml, chronicles, sequtils, sugar, strutils import ./io_interface, ./view, ./controller import ../io_interface as delegate_interface @@ -9,28 +9,17 @@ 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/service/token/service as token_service 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 - -# TODO: remove usage of old models -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 models/showcase_preferences_generic_model import models/showcase_preferences_social_links_model import models/profile_save_data -import backend/collectibles as backend_collectibles - export io_interface logScope: @@ -40,11 +29,9 @@ type Module* = ref object of io_interface.AccessInterface delegate: delegate_interface.AccessInterface controller: controller.Controller - collectiblesController: collectiblesc.Controller view: View viewVariant: QVariant moduleLoaded: bool - presentedPublicKey: string proc newModule*( delegate: delegate_interface.AccessInterface, @@ -53,26 +40,18 @@ proc newModule*( settingsService: settings_service.Service, communityService: community_service.Service, walletAccountService: wallet_account_service.Service, - networkService: network_service.Service, tokenService: token_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, networkService, tokenService) - result.collectiblesController = collectiblesc.newController( - requestId = int32(backend_collectibles.CollectiblesRequestID.ProfileShowcase), - loadType = collectiblesc.LoadType.AutoLoadSingleUpdate, - networkService = networkService, - events = events - ) + result.controller = controller.newController(result, events, profileService, settingsService, communityService, walletAccountService, tokenService) 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() @@ -84,9 +63,6 @@ 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) @@ -153,11 +129,6 @@ method saveProfileIdentity*(self: Module, identity: IdentitySaveData) = self.view.emitProfileIdentitySaveFailedSignal() method saveProfileShowcasePreferences*(self: Module, showcase: ShowcaseSaveData) = - # TODO: remove this check within old api - if self.presentedPublicKey != singletonInstance.userProfile.getPubKey(): - error "Attempt to save preferences with wrong public key" - return - var showcasePreferences = ProfileShowcasePreferencesDto() for _, showcaseCommunity in showcase.communities: @@ -219,89 +190,12 @@ method saveProfileShowcasePreferences*(self: Module, showcase: ShowcaseSaveData) order: showcaseSocialLink.showcasePosition )) - self.controller.storeProfileShowcasePreferences(showcasePreferences, revealedAddresses) + self.controller.saveProfileShowcasePreferences(showcasePreferences, revealedAddresses) method requestProfileShowcasePreferences(self: Module) = - let myPublicKey = singletonInstance.userProfile.getPubKey() - if self.presentedPublicKey != myPublicKey: - self.view.clearModels() - self.presentedPublicKey = myPublicKey - self.controller.requestProfileShowcasePreferences() -method requestProfileShowcase*(self: Module, publicKey: string) = - if publicKey == singletonInstance.userProfile.getPubKey(): - self.requestProfileShowcasePreferences() - return - - if self.presentedPublicKey != publicKey: - self.view.clearModels() - self.presentedPublicKey = publicKey - - self.controller.requestProfileShowcaseForContact(publicKey) - -method fetchProfileShowcaseAccountsByAddress*(self: Module, address: string) = - self.controller.fetchProfileShowcaseAccountsByAddress(address) - -method onProfileShowcaseAccountsByAddressFetched*(self: Module, accounts: seq[ProfileShowcaseAccount]) = - let jsonObj = % accounts - self.view.emitProfileShowcaseAccountsByAddressFetchedSignal($jsonObj) - -method updateProfileShowcase(self: Module, profileShowcase: ProfileShowcaseDto) = - if self.presentedPublicKey != profileShowcase.contactId: - return - - # Communities for a contact - var profileCommunityItems: seq[ProfileShowcaseCommunityItem] = @[] - 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(communityProfile.communityId, shard = nil) - profileCommunityItems.add(initProfileShowcaseCommunityLoadingItem( - communityProfile.communityId, ProfileShowcaseVisibility.ToEveryone, communityProfile.order)) - else: - profileCommunityItems.add(initProfileShowcaseCommunityItem( - community, ProfileShowcaseVisibility.ToEveryone, communityProfile.order)) - self.view.updateProfileShowcaseCommunities(profileCommunityItems) - - # 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)) - 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.getTokenBySymbolList(): - if tokenProfile.symbol == token.symbol: - profileAssetItems.add(initProfileShowcaseVerifiedToken(token, ProfileShowcaseVisibility.ToEveryone, tokenProfile.order)) - - # TODO: Unverified tokens for a contact - self.view.updateProfileShowcaseAssets(profileAssetItems) - -method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowcasePreferencesDto) = - if self.presentedPublicKey != singletonInstance.userProfile.getPubKey(): - return - +method loadProfileShowcasePreferences(self: Module, preferences: ProfileShowcasePreferencesDto) = var communityItems: seq[ShowcasePreferencesGenericItem] = @[] for community in preferences.communities: communityItems.add(ShowcasePreferencesGenericItem( @@ -309,7 +203,7 @@ method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowca showcaseVisibility: community.showcaseVisibility, showcasePosition: community.order )) - self.view.updateProfileShowcasePreferencesCommunities(communityItems) + self.view.loadProfileShowcasePreferencesCommunities(communityItems) var accountItems: seq[ShowcasePreferencesGenericItem] = @[] for account in preferences.accounts: @@ -318,7 +212,7 @@ method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowca showcaseVisibility: account.showcaseVisibility, showcasePosition: account.order )) - self.view.updateProfileShowcasePreferencesAccounts(accountItems) + self.view.loadProfileShowcasePreferencesAccounts(accountItems) var collectibleItems: seq[ShowcasePreferencesGenericItem] = @[] for collectible in preferences.collectibles: @@ -327,7 +221,7 @@ method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowca showcaseVisibility: collectible.showcaseVisibility, showcasePosition: collectible.order )) - self.view.updateProfileShowcasePreferencesCollectibles(collectibleItems) + self.view.loadProfileShowcasePreferencesCollectibles(collectibleItems) var assetItems: seq[ShowcasePreferencesGenericItem] = @[] for token in preferences.verifiedTokens: @@ -342,7 +236,7 @@ method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowca showcaseVisibility: token.showcaseVisibility, showcasePosition: token.order )) - self.view.updateProfileShowcasePreferencesAssets(assetItems) + self.view.loadProfileShowcasePreferencesAssets(assetItems) var socialLinkItems: seq[ShowcasePreferencesSocialLinkItem] = @[] for socialLink in preferences.socialLinks: @@ -351,61 +245,4 @@ method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowca text: socialLink.text, showcasePosition: socialLink.order )) - self.view.updateProfileShowcasePreferencesSocialLinks(socialLinkItems) - - # TODO: remove the code for old models - var profileCommunityItems: seq[ProfileShowcaseCommunityItem] = @[] - 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 = communityProfile.communityId - else: - profileCommunityItems.add(initProfileShowcaseCommunityItem( - community, communityProfile.showcaseVisibility, communityProfile.order)) - self.view.updateProfileShowcaseCommunities(profileCommunityItems) - - # 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 preference in preferences.accounts: - let account = self.controller.getAccountByAddress(preference.address) - if account == nil: - error "Can't find an account with address ", address=preference.address - continue - - profileAccountItems.add(initProfileShowcaseAccountItem( - account.address, account.name, account.emoji, account.colorId, - preference.showcaseVisibility, preference.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) - - var profileAssetItems: seq[ProfileShowcaseAssetItem] = @[] - for tokenProfile in preferences.verifiedTokens: - for token in self.controller.getTokenBySymbolList(): - if tokenProfile.symbol == token.symbol: - profileAssetItems.add(initProfileShowcaseVerifiedToken(token, tokenProfile.showcaseVisibility, tokenProfile.order)) - self.view.updateProfileShowcaseAssets(profileAssetItems) - -method onCommunitiesUpdated*(self: Module, communities: seq[CommunityDto]) = - var profileCommunityItems = self.view.getProfileShowcaseCommunities() - - for community in communities: - for item in profileCommunityItems: - if item.id == community.id: - item.patchFromCommunity(community) - - self.view.updateProfileShowcaseCommunities(profileCommunityItems) + self.view.loadProfileShowcasePreferencesSocialLinks(socialLinkItems) diff --git a/src/app/modules/main/profile_section/profile/view.nim b/src/app/modules/main/profile_section/profile/view.nim index dadf237f88..788ec2cd02 100644 --- a/src/app/modules/main/profile_section/profile/view.nim +++ b/src/app/modules/main/profile_section/profile/view.nim @@ -1,19 +1,9 @@ -import NimQml, json, sequtils, sugar, std/algorithm +import NimQml, json, sequtils import io_interface import app/modules/shared_models/social_links_model import app/modules/shared_models/social_link_item -# TODO remove old models -import models/profile_preferences_communities_model -import models/profile_preferences_community_item -import models/profile_preferences_accounts_model -import models/profile_preferences_account_item -import models/profile_preferences_collectibles_model -import models/profile_preferences_collectible_item -import models/profile_preferences_assets_model -import models/profile_preferences_asset_item - import models/profile_save_data import models/showcase_preferences_generic_model import models/showcase_preferences_social_links_model @@ -27,14 +17,6 @@ QtObject: socialLinksModelVariant: QVariant temporarySocialLinksModel: SocialLinksModel # used for editing purposes temporarySocialLinksModelVariant: QVariant - profileShowcaseCommunitiesModel: ProfileShowcaseCommunitiesModel - profileShowcaseCommunitiesModelVariant: QVariant - profileShowcaseAccountsModel: ProfileShowcaseAccountsModel - profileShowcaseAccountsModelVariant: QVariant - profileShowcaseCollectiblesModel: ProfileShowcaseCollectiblesModel - profileShowcaseCollectiblesModelVariant: QVariant - profileShowcaseAssetsModel: ProfileShowcaseAssetsModel - profileShowcaseAssetsModelVariant: QVariant showcasePreferencesCommunitiesModel: ShowcasePreferencesGenericModel showcasePreferencesCommunitiesModelVariant: QVariant @@ -48,20 +30,11 @@ QtObject: showcasePreferencesSocialLinksModelVariant: QVariant proc delete*(self: View) = - self.QObject.delete # TODO: remove old models self.socialLinksModel.delete self.socialLinksModelVariant.delete self.temporarySocialLinksModel.delete self.temporarySocialLinksModelVariant.delete - self.profileShowcaseCommunitiesModel.delete - self.profileShowcaseCommunitiesModelVariant.delete - self.profileShowcaseAccountsModel.delete - self.profileShowcaseAccountsModelVariant.delete - self.profileShowcaseCollectiblesModel.delete - self.profileShowcaseCollectiblesModelVariant.delete - self.profileShowcaseAssetsModel.delete - self.profileShowcaseAssetsModelVariant.delete self.showcasePreferencesCommunitiesModel.delete self.showcasePreferencesCommunitiesModelVariant.delete @@ -73,6 +46,7 @@ QtObject: self.showcasePreferencesAssetsModelVariant.delete self.showcasePreferencesSocialLinksModel.delete self.showcasePreferencesSocialLinksModelVariant.delete + self.QObject.delete proc newView*(delegate: io_interface.AccessInterface): View = new(result, delete) @@ -83,14 +57,6 @@ QtObject: result.socialLinksModelVariant = newQVariant(result.socialLinksModel) result.temporarySocialLinksModel = newSocialLinksModel() result.temporarySocialLinksModelVariant = newQVariant(result.temporarySocialLinksModel) - result.profileShowcaseCommunitiesModel = newProfileShowcaseCommunitiesModel() - result.profileShowcaseCommunitiesModelVariant = newQVariant(result.profileShowcaseCommunitiesModel) - result.profileShowcaseAccountsModel = newProfileShowcaseAccountsModel() - result.profileShowcaseAccountsModelVariant = newQVariant(result.profileShowcaseAccountsModel) - result.profileShowcaseCollectiblesModel = newProfileShowcaseCollectiblesModel() - result.profileShowcaseCollectiblesModelVariant = newQVariant(result.profileShowcaseCollectiblesModel) - result.profileShowcaseAssetsModel = newProfileShowcaseAssetsModel() - result.profileShowcaseAssetsModelVariant = newQVariant(result.profileShowcaseAssetsModel) result.showcasePreferencesCommunitiesModel = newShowcasePreferencesGenericModel() result.showcasePreferencesCommunitiesModelVariant = newQVariant(result.showcasePreferencesCommunitiesModel) @@ -213,72 +179,30 @@ QtObject: proc emitProfileShowcasePreferencesSaveFailedSignal*(self: View) = self.profileShowcasePreferencesSaveFailed() - # TODO: remove old models - proc getCollectiblesModel(self: View): QVariant {.slot.} = - return self.delegate.getCollectiblesModel() - - QtProperty[QVariant] collectiblesModel: - read = getCollectiblesModel - - proc getProfileShowcaseCommunitiesModel(self: View): QVariant {.slot.} = - return self.profileShowcaseCommunitiesModelVariant - - QtProperty[QVariant] profileShowcaseCommunitiesModel: - read = getProfileShowcaseCommunitiesModel - - proc getProfileShowcaseAccountsModel(self: View): QVariant {.slot.} = - return self.profileShowcaseAccountsModelVariant - - QtProperty[QVariant] profileShowcaseAccountsModel: - read = getProfileShowcaseAccountsModel - - proc getProfileShowcaseCollectiblesModel(self: View): QVariant {.slot.} = - return self.profileShowcaseCollectiblesModelVariant - - QtProperty[QVariant] profileShowcaseCollectiblesModel: - read = getProfileShowcaseCollectiblesModel - - proc getProfileShowcaseAssetsModel(self: View): QVariant {.slot.} = - return self.profileShowcaseAssetsModelVariant - - QtProperty[QVariant] profileShowcaseAssetsModel: - read = getProfileShowcaseAssetsModel - - proc getProfileShowcasePreferencesCommunitiesModel(self: View): QVariant {.slot.} = + proc getShowcasePreferencesCommunitiesModel(self: View): QVariant {.slot.} = return self.showcasePreferencesCommunitiesModelVariant - QtProperty[QVariant] showcasePreferencesCommunitiesModel: - read = getProfileShowcasePreferencesCommunitiesModel + read = getShowcasePreferencesCommunitiesModel - proc getProfileShowcasePreferencesAccountsModel(self: View): QVariant {.slot.} = + proc getShowcasePreferencesAccountsModel(self: View): QVariant {.slot.} = return self.showcasePreferencesAccountsModelVariant - QtProperty[QVariant] showcasePreferencesAccountsModel: - read = getProfileShowcasePreferencesAccountsModel + read = getShowcasePreferencesAccountsModel - proc getProfileShowcasePreferencesCollectiblesModel(self: View): QVariant {.slot.} = + proc getShowcasePreferencesCollectiblesModel(self: View): QVariant {.slot.} = return self.showcasePreferencesCollectiblesModelVariant - QtProperty[QVariant] showcasePreferencesCollectiblesModel: - read = getProfileShowcasePreferencesCollectiblesModel + read = getShowcasePreferencesCollectiblesModel - proc getProfileShowcasePreferencesAssetsModel(self: View): QVariant {.slot.} = + proc getShowcasePreferencesAssetsModel(self: View): QVariant {.slot.} = return self.showcasePreferencesAssetsModelVariant - QtProperty[QVariant] showcasePreferencesAssetsModel: - read = getProfileShowcasePreferencesAssetsModel + read = getShowcasePreferencesAssetsModel - proc getProfileShowcasePreferencesSocialLinksModel(self: View): QVariant {.slot.} = + proc getShowcasePreferencesSocialLinksModel(self: View): QVariant {.slot.} = return self.showcasePreferencesSocialLinksModelVariant - QtProperty[QVariant] showcasePreferencesSocialLinksModel: - read = getProfileShowcasePreferencesSocialLinksModel - - proc clearModels*(self: View) {.slot.} = - self.profileShowcaseCommunitiesModel.clear() - self.profileShowcaseAccountsModel.clear() - self.profileShowcaseCollectiblesModel.clear() - self.profileShowcaseAssetsModel.clear() + read = getShowcasePreferencesSocialLinksModel proc saveProfileIdentity(self: View, profileData: string) {.slot.} = let profileDataObj = profileData.parseJson @@ -296,49 +220,23 @@ QtObject: proc getProfileShowcaseEntriesLimit*(self: View): int {.slot.} = self.delegate.getProfileShowcaseEntriesLimit() - proc requestProfileShowcase(self: View, publicKey: string) {.slot.} = - self.delegate.requestProfileShowcase(publicKey) - proc requestProfileShowcasePreferences(self: View) {.slot.} = self.delegate.requestProfileShowcasePreferences() proc setIsFirstShowcaseInteraction(self: View) {.slot.} = self.delegate.setIsFirstShowcaseInteraction() - proc getProfileShowcaseCommunities*(self: View): seq[ProfileShowcaseCommunityItem] = - return self.profileShowcaseCommunitiesModel.items() - - proc updateProfileShowcasePreferencesCommunities*(self: View, items: seq[ShowcasePreferencesGenericItem]) = + proc loadProfileShowcasePreferencesCommunities*(self: View, items: seq[ShowcasePreferencesGenericItem]) = self.showcasePreferencesCommunitiesModel.setItems(items) - proc updateProfileShowcasePreferencesAccounts*(self: View, items: seq[ShowcasePreferencesGenericItem]) = + proc loadProfileShowcasePreferencesAccounts*(self: View, items: seq[ShowcasePreferencesGenericItem]) = self.showcasePreferencesAccountsModel.setItems(items) - proc updateProfileShowcasePreferencesCollectibles*(self: View, items: seq[ShowcasePreferencesGenericItem]) = + proc loadProfileShowcasePreferencesCollectibles*(self: View, items: seq[ShowcasePreferencesGenericItem]) = self.showcasePreferencesCollectiblesModel.setItems(items) - proc updateProfileShowcasePreferencesAssets*(self: View, items: seq[ShowcasePreferencesGenericItem]) = + proc loadProfileShowcasePreferencesAssets*(self: View, items: seq[ShowcasePreferencesGenericItem]) = self.showcasePreferencesAssetsModel.setItems(items) - proc updateProfileShowcasePreferencesSocialLinks*(self: View, items: seq[ShowcasePreferencesSocialLinkItem]) = + proc loadProfileShowcasePreferencesSocialLinks*(self: View, items: seq[ShowcasePreferencesSocialLinkItem]) = self.showcasePreferencesSocialLinksModel.setItems(items) - - # TODO: remove setters for old models - proc updateProfileShowcaseCommunities*(self: View, communities: seq[ProfileShowcaseCommunityItem]) = - self.profileShowcaseCommunitiesModel.reset(communities.sorted((a, b) => cmp(a.order, b.order), SortOrder.Ascending)) - - proc updateProfileShowcaseAccounts*(self: View, accounts: seq[ProfileShowcaseAccountItem]) = - self.profileShowcaseAccountsModel.reset(accounts.sorted((a, b) => cmp(a.order, b.order), SortOrder.Ascending)) - - 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]) = - self.profileShowcaseAssetsModel.reset(assets.sorted((a, b) => cmp(a.order, b.order), SortOrder.Ascending)) - - proc fetchProfileShowcaseAccountsByAddress*(self: View, address: string) {.slot.} = - self.delegate.fetchProfileShowcaseAccountsByAddress(address) - - proc profileShowcaseAccountsByAddressFetched*(self: View, accounts: string) {.signal.} - proc emitProfileShowcaseAccountsByAddressFetchedSignal*(self: View, accounts: string) = - self.profileShowcaseAccountsByAddressFetched(accounts) diff --git a/src/app_service/service/contacts/async_tasks.nim b/src/app_service/service/contacts/async_tasks.nim index 96cd225d2f..37c0de84c6 100644 --- a/src/app_service/service/contacts/async_tasks.nim +++ b/src/app_service/service/contacts/async_tasks.nim @@ -68,10 +68,51 @@ const asyncRequestContactInfoTask: Task = proc(argEncoded: string) {.gcsafe, nim arg.finish(%* { "publicKey": arg.pubkey, "response": response, - "error": nil, + "error": "", }) except Exception as e: arg.finish(%* { "publicKey": arg.pubkey, "error": e.msg, }) + +type + AsyncGetProfileShowcaseForContactTaskArg = ref object of QObjectTaskArg + pubkey: string + validate: bool + +const asyncGetProfileShowcaseForContactTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncGetProfileShowcaseForContactTaskArg](argEncoded) + try: + let response = status_go.getProfileShowcaseForContact(arg.pubkey, arg.validate) + arg.finish(%* { + "publicKey": arg.pubkey, + "validated": arg.validate, + "response": response, + "error": "", + }) + except Exception as e: + arg.finish(%* { + "publicKey": arg.pubkey, + "validated": arg.validate, + "error": e.msg, + }) + +type + FetchProfileShowcaseAccountsTaskArg = ref object of QObjectTaskArg + address: string + +const fetchProfileShowcaseAccountsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[FetchProfileShowcaseAccountsTaskArg](argEncoded) + var response = %* { + "response": "", + "error": "", + } + try: + let rpcResponse = status_accounts.getProfileShowcaseAccountsByAddress(arg.address) + if not rpcResponse.error.isNil: + raise newException(CatchableError, rpcResponse.error.message) + response["response"] = rpcResponse.result + except Exception as e: + response["error"] = %* e.msg + arg.finish(response) \ No newline at end of file diff --git a/src/app_service/service/profile/dto/profile_showcase.nim b/src/app_service/service/contacts/dto/profile_showcase.nim similarity index 80% rename from src/app_service/service/profile/dto/profile_showcase.nim rename to src/app_service/service/contacts/dto/profile_showcase.nim index 63fc53f769..6c235725f5 100644 --- a/src/app_service/service/profile/dto/profile_showcase.nim +++ b/src/app_service/service/contacts/dto/profile_showcase.nim @@ -1,10 +1,16 @@ -import json, json_serialization +import json, json_serialization, stew/shims/strformat include ../../../common/json_utils +type ProfileShowcaseMembershipStatus* {.pure.}= enum + Unproven = 0, + ProvenMember = 1, + NotAMember = 2, + type ProfileShowcaseCommunity* = ref object of RootObj communityId*: string order*: int + membershipStatus*: ProfileShowcaseMembershipStatus type ProfileShowcaseAccount* = ref object of RootObj contactId*: string @@ -43,10 +49,19 @@ type ProfileShowcaseDto* = ref object of RootObj unverifiedTokens*: seq[ProfileShowcaseUnverifiedToken] socialLinks*: seq[ProfileShowcaseSocialLink] +proc toProfileShowcaseMembershipStatus*(jsonObj: JsonNode): ProfileShowcaseMembershipStatus = + var membershipStatusInt: int + if (jsonObj.getProp("membershipStatus", membershipStatusInt) and + (membershipStatusInt >= ord(low(ProfileShowcaseMembershipStatus)) and + membershipStatusInt <= ord(high(ProfileShowcaseMembershipStatus)))): + return ProfileShowcaseMembershipStatus(membershipStatusInt) + return ProfileShowcaseMembershipStatus.Unproven + proc toProfileShowcaseCommunity*(jsonObj: JsonNode): ProfileShowcaseCommunity = result = ProfileShowcaseCommunity() discard jsonObj.getProp("communityId", result.communityId) discard jsonObj.getProp("order", result.order) + result.membershipStatus = jsonObj.toProfileShowcaseMembershipStatus() proc toProfileShowcaseAccount*(jsonObj: JsonNode): ProfileShowcaseAccount = result = ProfileShowcaseAccount() @@ -113,3 +128,10 @@ proc `%`*(x: ProfileShowcaseAccount): JsonNode = result["colorId"] = % x.colorId result["emoji"] = % x.emoji result["order"] = % x.order + +# TODO: refactor to utils function on code cleanup stage +proc toCombinedCollectibleId*(self: ProfileShowcaseCollectible): string = + return fmt"{self.chainId}+{self.contractAddress}+{self.tokenId}" + +proc toCombinedTokenId*(self: ProfileShowcaseUnverifiedToken): string = + return fmt"{self.chainId}+{self.contractAddress}" \ No newline at end of file diff --git a/src/app_service/service/contacts/service.nim b/src/app_service/service/contacts/service.nim index c1d6187f18..9f5518f02b 100644 --- a/src/app_service/service/contacts/service.nim +++ b/src/app_service/service/contacts/service.nim @@ -17,6 +17,8 @@ import ../visual_identity/service as procs_from_visual_identity_service import ./dto/contacts as contacts_dto import ./dto/status_update as status_update_dto import ./dto/contact_details +import ./dto/profile_showcase + import ../../../backend/contacts as status_contacts import ../../../backend/accounts as status_accounts @@ -60,6 +62,13 @@ type chatId*: string messages*: JsonNode + ProfileShowcaseForContactArgs* = ref object of Args + profileShowcase*: ProfileShowcaseDto + validated*: bool + + ProfileShowcaseContactIdArgs* = ref object of Args + contactId*: string + # Signals which may be emitted by this service: const SIGNAL_ENS_RESOLVED* = "ensResolved" const SIGNAL_CONTACT_ADDED* = "contactAdded" @@ -84,6 +93,10 @@ const SIGNAL_CONTACT_VERIFICATION_UPDATED* = "contactVerificationRequestUpdated" const SIGNAL_CONTACT_INFO_REQUEST_FINISHED* = "contactInfoRequestFinished" const SIGNAL_APPEND_CHAT_MESSAGES* = "appendChatMessages" +const SIGNAL_CONTACT_PROFILE_SHOWCASE_UPDATED* = "contactProfileShowcaseUpdated" +const SIGNAL_CONTACT_PROFILE_SHOWCASE_LOADED* = "contactProfileShowcaseLoaded" +const SIGNAL_CONTACT_SHOWCASE_ACCOUNTS_BY_ADDRESS_FETCHED* = "profileShowcaseAccountsByAddressFetched" + type ContactsGroup* {.pure.} = enum AllKnownContacts @@ -223,7 +236,12 @@ QtObject: else: self.events.emit(SIGNAL_CONTACT_VERIFICATION_ADDED, data) - + self.events.on(SignalType.Message.event) do(e: Args): + let receivedData = MessageSignal(e) + if receivedData.updatedProfileShowcaseContactIDs.len > 0: + for contactId in receivedData.updatedProfileShowcaseContactIDs: + self.events.emit(SIGNAL_CONTACT_PROFILE_SHOWCASE_UPDATED, + ProfileShowcaseContactIdArgs(contactId: contactId)) self.events.on(SignalType.StatusUpdatesTimedout.event) do(e:Args): var receivedData = StatusUpdatesTimedoutSignal(e) if(receivedData.statusUpdates.len > 0): @@ -881,3 +899,58 @@ QtObject: return response.result.getStr except Exception as e: error "Error getting user url with ens name", msg = e.msg, pubkey + + proc requestProfileShowcaseForContact*(self: Service, contactId: string, validate: bool) = + let arg = AsyncGetProfileShowcaseForContactTaskArg( + pubkey: contactId, + validate: validate, + tptr: cast[ByteAddress](asyncGetProfileShowcaseForContactTask), + vptr: cast[ByteAddress](self.vptr), + slot: "asyncProfileShowcaseForContactLoaded", + ) + self.threadpool.start(arg) + + proc asyncProfileShowcaseForContactLoaded*(self: Service, rpcResponse: string) {.slot.} = + try: + let rpcResponseObj = rpcResponse.parseJson + if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "": + error "Error requesting profile showcase for a contact", msg = rpcResponseObj{"error"} + return + + let profileShowcase = rpcResponseObj["response"]["result"].toProfileShowcaseDto() + let validated = rpcResponseObj["validated"].getBool + + self.events.emit(SIGNAL_CONTACT_PROFILE_SHOWCASE_LOADED, + ProfileShowcaseForContactArgs( + profileShowcase: profileShowcase, + validated: validated + )) + except Exception as e: + error "Error requesting profile showcase for a contact", msg = e.msg + + proc fetchProfileShowcaseAccountsByAddress*(self: Service, address: string) = + let arg = FetchProfileShowcaseAccountsTaskArg( + address: address, + tptr: cast[ByteAddress](fetchProfileShowcaseAccountsTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onProfileShowcaseAccountsByAddressFetched", + ) + self.threadpool.start(arg) + + proc onProfileShowcaseAccountsByAddressFetched*(self: Service, rpcResponse: string) {.slot.} = + var data = ProfileShowcaseForContactArgs( + profileShowcase: ProfileShowcaseDto( + accounts: @[], + ), + ) + try: + let rpcResponseObj = rpcResponse.parseJson + if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "": + raise newException(CatchableError, rpcResponseObj{"error"}.getStr) + if rpcResponseObj{"response"}.kind != JArray: + raise newException(CatchableError, "invalid response") + + data.profileShowcase.accounts = map(rpcResponseObj{"response"}.getElems(), proc(x: JsonNode): ProfileShowcaseAccount = toProfileShowcaseAccount(x)) + except Exception as e: + error "onProfileShowcaseAccountsByAddressFetched", msg = e.msg + self.events.emit(SIGNAL_CONTACT_SHOWCASE_ACCOUNTS_BY_ADDRESS_FETCHED, data) \ No newline at end of file diff --git a/src/app_service/service/profile/async_tasks.nim b/src/app_service/service/profile/async_tasks.nim index 9b0902d64b..22795f2cf8 100644 --- a/src/app_service/service/profile/async_tasks.nim +++ b/src/app_service/service/profile/async_tasks.nim @@ -11,51 +11,13 @@ const asyncGetProfileShowcasePreferencesTask: Task = proc(argEncoded: string) {. let response = status_accounts.getProfileShowcasePreferences() arg.finish(%* { "response": response, - "error": nil, + "error": "", }) except Exception as e: arg.finish(%* { "error": e.msg, }) -type - AsyncGetProfileShowcaseForContactTaskArg = ref object of QObjectTaskArg - pubkey: string - -const asyncGetProfileShowcaseForContactTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = - let arg = decode[AsyncGetProfileShowcaseForContactTaskArg](argEncoded) - try: - let response = status_accounts.getProfileShowcaseForContact(arg.pubkey) - arg.finish(%* { - "publicKey": arg.pubkey, - "response": response, - "error": nil, - }) - except Exception as e: - arg.finish(%* { - "publicKey": arg.pubkey, - "error": e.msg, - }) - -type - FetchProfileShowcaseAccountsTaskArg = ref object of QObjectTaskArg - address: string - -const fetchProfileShowcaseAccountsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = - let arg = decode[FetchProfileShowcaseAccountsTaskArg](argEncoded) - var response = %* { - "response": "", - "error": "", - } - try: - let rpcResponse = status_accounts.getProfileShowcaseAccountsByAddress(arg.address) - if not rpcResponse.error.isNil: - raise newException(CatchableError, rpcResponse.error.message) - response["response"] = rpcResponse.result - except Exception as e: - response["error"] = %* e.msg - arg.finish(response) - type SaveProfileShowcasePreferencesTaskArg = ref object of QObjectTaskArg preferences: ProfileShowcasePreferencesDto @@ -66,7 +28,7 @@ const saveProfileShowcasePreferencesTask: Task = proc(argEncoded: string) {.gcsa let response = status_accounts.setProfileShowcasePreferences(arg.preferences.toJsonNode()) arg.finish(%* { "response": response, - "error": nil, + "error": "", }) except Exception as e: arg.finish(%* { diff --git a/src/app_service/service/profile/service.nim b/src/app_service/service/profile/service.nim index 09fec1155a..c38c143e90 100644 --- a/src/app_service/service/profile/service.nim +++ b/src/app_service/service/profile/service.nim @@ -10,7 +10,6 @@ import ../../../app/core/tasks/[qt, threadpool] import ../../../backend/accounts as status_accounts import ../accounts/dto/accounts -import dto/profile_showcase import dto/profile_showcase_preferences include async_tasks @@ -22,17 +21,10 @@ type ProfileShowcasePreferencesArgs* = ref object of Args preferences*: ProfileShowcasePreferencesDto - ProfileShowcaseForContactArgs* = ref object of Args - profileShowcase*: ProfileShowcaseDto - # Signals which may be emitted by this service: -const SIGNAL_PROFILE_SHOWCASE_PREFERENCES_UPDATED* = "profileShowcasePreferencesUpdated" +const SIGNAL_PROFILE_SHOWCASE_PREFERENCES_LOADED* = "profileShowcasePreferencesLoaded" const SIGNAL_PROFILE_SHOWCASE_PREFERENCES_SAVE_SUCCEEDED* = "profileShowcasePreferencesSaveSucceeded" const SIGNAL_PROFILE_SHOWCASE_PREFERENCES_SAVE_FAILED* = "profileShowcasePreferencesSaveFailed" -const SIGNAL_PROFILE_SHOWCASE_ACCOUNTS_BY_ADDRESS_FETCHED* = "profileShowcaseAccountsByAddressFetched" - -# TODO: move to contacts service -const SIGNAL_PROFILE_SHOWCASE_FOR_CONTACT_UPDATED* = "profileShowcaseForContactUpdated" QtObject: type Service* = ref object of QObject @@ -55,13 +47,6 @@ QtObject: let args = SettingsTextValueArgs(e) singletonInstance.userProfile.setDisplayName(args.value) - self.events.on(SignalType.Message.event) do(e: Args): - let receivedData = MessageSignal(e) - if receivedData.updatedProfileShowcases.len > 0: - for profileShowcase in receivedData.updatedProfileShowcases: - self.events.emit(SIGNAL_PROFILE_SHOWCASE_FOR_CONTACT_UPDATED, - ProfileShowcaseForContactArgs(profileShowcase: profileShowcase)) - proc storeIdentityImage*(self: Service, address: string, image: string, aX: int, aY: int, bX: int, bY: int): seq[Image] = try: let response = status_accounts.storeIdentityImage(address, image, aX, aY, bX, bY) @@ -114,56 +99,6 @@ QtObject: error "error: ", procName="setDisplayName", errName = e.name, errDesription = e.msg return false - proc requestProfileShowcaseForContact*(self: Service, contactId: string) = - let arg = AsyncGetProfileShowcaseForContactTaskArg( - pubkey: contactId, - tptr: cast[ByteAddress](asyncGetProfileShowcaseForContactTask), - vptr: cast[ByteAddress](self.vptr), - slot: "asyncProfileShowcaseForContactLoaded", - ) - self.threadpool.start(arg) - - proc asyncProfileShowcaseForContactLoaded*(self: Service, rpcResponse: string) {.slot.} = - try: - let rpcResponseObj = rpcResponse.parseJson - if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "": - error "Error requesting profile showcase for a contact", msg = rpcResponseObj{"error"} - return - - let profileShowcase = rpcResponseObj["response"]["result"].toProfileShowcaseDto() - - self.events.emit(SIGNAL_PROFILE_SHOWCASE_FOR_CONTACT_UPDATED, - ProfileShowcaseForContactArgs(profileShowcase: profileShowcase)) - except Exception as e: - error "Error requesting profile showcase for a contact", msg = e.msg - - proc fetchProfileShowcaseAccountsByAddress*(self: Service, address: string) = - let arg = FetchProfileShowcaseAccountsTaskArg( - address: address, - tptr: cast[ByteAddress](fetchProfileShowcaseAccountsTask), - vptr: cast[ByteAddress](self.vptr), - slot: "onProfileShowcaseAccountsByAddressFetched", - ) - self.threadpool.start(arg) - - proc onProfileShowcaseAccountsByAddressFetched*(self: Service, rpcResponse: string) {.slot.} = - var data = ProfileShowcaseForContactArgs( - profileShowcase: ProfileShowcaseDto( - accounts: @[], - ), - ) - try: - let rpcResponseObj = rpcResponse.parseJson - if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "": - raise newException(CatchableError, rpcResponseObj{"error"}.getStr) - if rpcResponseObj{"response"}.kind != JArray: - raise newException(CatchableError, "invalid response") - - data.profileShowcase.accounts = map(rpcResponseObj{"response"}.getElems(), proc(x: JsonNode): ProfileShowcaseAccount = toProfileShowcaseAccount(x)) - except Exception as e: - error "onProfileShowcaseAccountsByAddressFetched", msg = e.msg - self.events.emit(SIGNAL_PROFILE_SHOWCASE_ACCOUNTS_BY_ADDRESS_FETCHED, data) - proc requestProfileShowcasePreferences*(self: Service) = let arg = QObjectTaskArg( tptr: cast[ByteAddress](asyncGetProfileShowcasePreferencesTask), @@ -181,7 +116,7 @@ QtObject: let preferences = rpcResponseObj["response"]["result"].toProfileShowcasePreferencesDto() - self.events.emit(SIGNAL_PROFILE_SHOWCASE_PREFERENCES_UPDATED, + self.events.emit(SIGNAL_PROFILE_SHOWCASE_PREFERENCES_LOADED, ProfileShowcasePreferencesArgs(preferences: preferences)) except Exception as e: error "Error requesting profile showcase preferences", msg = e.msg diff --git a/src/backend/accounts.nim b/src/backend/accounts.nim index d2b3b0e7fc..aaafebaa18 100644 --- a/src/backend/accounts.nim +++ b/src/backend/accounts.nim @@ -474,10 +474,6 @@ proc verifyKeystoreFileForAccount*(address, password: string): RpcResponse[JsonN let payload = %* [address, password] return core.callPrivateRPC("accounts_verifyKeystoreFileForAccount", payload) -proc getProfileShowcaseForContact*(contactId: string): RpcResponse[JsonNode] = - let payload = %* [contactId] - result = callPrivateRPC("getProfileShowcaseForContact".prefix, payload) - proc getProfileShowcaseAccountsByAddress*(address: string): RpcResponse[JsonNode] = let payload = %* [address] result = callPrivateRPC("getProfileShowcaseAccountsByAddress".prefix, payload) diff --git a/src/backend/contacts.nim b/src/backend/contacts.nim index 95daffe8f6..507eadc731 100644 --- a/src/backend/contacts.nim +++ b/src/backend/contacts.nim @@ -143,4 +143,8 @@ proc shareUserUrlWithChatKey*(pubkey: string): RpcResponse[JsonNode] = result = callPrivateRPC("shareUserURLWithChatKey".prefix, %*[pubkey]) proc shareUserUrlWithENS*(pubkey: string): RpcResponse[JsonNode] = - result = callPrivateRPC("shareUserURLWithENS".prefix, %*[pubkey]) \ No newline at end of file + result = callPrivateRPC("shareUserURLWithENS".prefix, %*[pubkey]) + +proc getProfileShowcaseForContact*(contactId: string, validate: bool): RpcResponse[JsonNode] = + let payload = %* [contactId, validate] + result = callPrivateRPC("getProfileShowcaseForContact".prefix, payload) \ No newline at end of file diff --git a/storybook/pages/ProfileDialogViewPage.qml b/storybook/pages/ProfileDialogViewPage.qml index fa5151d978..86d689609c 100644 --- a/storybook/pages/ProfileDialogViewPage.qml +++ b/storybook/pages/ProfileDialogViewPage.qml @@ -288,6 +288,14 @@ SplitView { onCloseRequested: logs.logEvent("closeRequested()") + sendToAccountEnabled: true + + showcaseCommunitiesModel: CommunitiesModel {} + showcaseAccountsModel: WalletAccountsModel {} + showcaseCollectiblesModel: ManageCollectiblesModel {} + showcaseSocialLinksModel: assetsStore.groupedAccountAssetsModel + // TODO: showcaseAssetsModel + profileStore: QtObject { readonly property string pubkey: "0xdeadbeef" readonly property string ensName: name.text @@ -298,14 +306,6 @@ SplitView { function copyToClipboard(text) { logs.logEvent("profileStore::copyToClipboard", ["text"], arguments) } - function requestProfileShowcase(publicKey) { - logs.logEvent("profileStore::requestProfileShowcase", ["publicKey"], arguments) - } - - readonly property var profileShowcaseCommunitiesModel: CommunitiesModel {} - readonly property var profileShowcaseAccountsModel: WalletAccountsModel {} - readonly property var profileShowcaseCollectiblesModel: ManageCollectiblesModel {} - readonly property var profileShowcaseAssetsModel: assetsStore.groupedAccountAssetsModel } contactsStore: QtObject { @@ -364,32 +364,10 @@ SplitView { logs.logEvent("contactsStore::changeContactNickname", ["publicKey", "newNickname", "displayName", "isEdit"], arguments) localNickname.text = newNickname } - } - walletStore: QtObject { - function setFilterAddress(address) { - logs.logEvent("walletStore::setFilterAddress", ["address"], arguments) + function requestProfileShowcase(publicKey) { + logs.logEvent("contactsStore::requestProfileShowcase", ["publicKey"], arguments) } - - function getSavedAddress(address) { - return { - name: "My Status Saved Account", - address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000", - ens: false, - colorId: Constants.walletAccountColors.primary, - chainShortNames: "", - isTest: false - } - } - - function createOrUpdateSavedAddress(name, address, ens, colorId, chainShortNames) { - logs.logEvent("walletStore::createOrUpdateSavedAddress", ["name", "address", "ens", "colorId", "chainShortNames"], - arguments) - } - } - - networkConnectionStore: QtObject { - readonly property bool sendBuyBridgeEnabled: true } } } diff --git a/storybook/pages/ProfileShowcaseDirtyStatePage.qml b/storybook/pages/ProfileShowcaseDirtyStatePage.qml index c8cb77522c..56c8c13d50 100644 --- a/storybook/pages/ProfileShowcaseDirtyStatePage.qml +++ b/storybook/pages/ProfileShowcaseDirtyStatePage.qml @@ -17,27 +17,12 @@ Item { ListModel { id: communitiesModel - ListElement { showcaseKey: "1"; name: "Crypto Kitties" } + ListElement { showcaseKey: "1"; name: "Crypto Kitties"; showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts; showcasePosition: 0 } ListElement { showcaseKey: "2"; name: "Status" } - ListElement { showcaseKey: "3"; name: "Fun Stuff" } + ListElement { showcaseKey: "3"; name: "Fun Stuff"; showcaseVisibility: Constants.ShowcaseVisibility.Contacts; showcasePosition: 9} ListElement { showcaseKey: "4"; name: "Other Stuff" } } - ListModel { - id: communitiesShowcaseModel - - ListElement { - showcaseKey: "1" - showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts - showcasePosition: 0 - } - ListElement { - showcaseKey: "3" - showcaseVisibility: Constants.ShowcaseVisibility.Contacts - showcasePosition: 9 - } - } - ListModel { id: comboBoxModel @@ -59,7 +44,6 @@ Item { id: dirtyState sourceModel: communitiesModel - showcaseModel: communitiesShowcaseModel } MovableModel { @@ -77,72 +61,36 @@ Item { Layout.fillHeight: true Layout.margins: 10 - rows: 3 - columns: 3 + rows: 2 + columns: 2 spacing: 10 flow: Grid.TopToBottom - Label { - text: "Backend models" - font.pixelSize: 22 - padding: 10 - } - GenericListView { - width: grid.width / 3 - grid.spacing + width: grid.width / 2 - grid.spacing height: 300 model: communitiesModel - label: "COMMUNITIES MODEL" + label: "COMMUNITIES MODEL - Backend model" } GenericListView { - width: grid.width / 3 - grid.spacing - height: 300 - - model: communitiesShowcaseModel - label: "SHOWCASE MODEL" - roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] - } - - Label { - text: "Internal models" - font.pixelSize: 22 - padding: 10 - } - - GenericListView { - width: grid.width / 3 - grid.spacing - height: 300 - - model: dirtyState.joined_ - label: "JOINED MODEL" - } - - GenericListView { - width: grid.width / 3 - grid.spacing + width: grid.width / 2 - grid.spacing height: 300 model: dirtyState.writable_ - label: "WRITABLE MODEL" + label: "WRITABLE MODEL - Internal Model" roles: ["showcaseKey", "showcaseVisibility", "showcasePosition", "name"] } - - Label { - text: "Display models" - font.pixelSize: 22 - padding: 10 - } - GenericListView { - width: grid.width / 3 - grid.spacing + width: grid.width / 2 - grid.spacing height: 300 model: movableModel - label: "IN SHOWCASE" + label: "IN SHOWCASE - output" movable: true roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] @@ -185,11 +133,11 @@ Item { } GenericListView { - width: grid.width / 3 - grid.spacing + width: grid.width / 2 - grid.spacing height: 300 model: dirtyState.hiddenModel - label: "HIDDEN" + label: "HIDDEN - output" roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] @@ -208,8 +156,13 @@ Item { onClicked: { const toBeSaved = dirtyState.currentState() - communitiesShowcaseModel.clear() - communitiesShowcaseModel.append(toBeSaved) + for (let i = 0; i < communitiesModel.count; i++) { + const item = communitiesModel.get(i) + const found = toBeSaved.find((x) => x.showcaseKey === item.showcaseKey) + + item.showcaseVisibility = !!found ? found.showcaseVisibility : Constants.ShowcaseVisibility.NoOne + item.showcasePosition = !!found ? found.showcasePosition : 0 + } } Layout.alignment: Qt.AlignHCenter diff --git a/storybook/pages/ProfileShowcaseModelsPage.qml b/storybook/pages/ProfileShowcaseModelsPage.qml index bad4c10e76..cad38f4812 100644 --- a/storybook/pages/ProfileShowcaseModelsPage.qml +++ b/storybook/pages/ProfileShowcaseModelsPage.qml @@ -18,162 +18,91 @@ ColumnLayout { ListModel { id: accountsModel - ListElement { address: "1"; name: "Crypto Kitties" } - ListElement { address: "2"; name: "Status" } - ListElement { address: "3"; name: "Fun Stuff" } - ListElement { address: "4"; name: "Other Stuff" } + ListElement { + address: "1" + name: "Crypto Kitties" + showcaseKey: "1" + showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts + showcasePosition: 0 + } + ListElement { + address: "2" + name: "Status" + showcaseKey: "2" + showcaseVisibility: Constants.ShowcaseVisibility.Contacts + } + ListElement { + address: "3"; + name: "Fun Stuff" + showcaseKey: "3" + showcaseVisibility: Constants.ShowcaseVisibility.Contacts + } + ListElement { + address: "4" + name: "Other Stuff" + showcaseKey: "4" + showcaseVisibility: Constants.ShowcaseVisibility.NoOne + } } ListModel { id: socialLinksModel - ListElement { uuid: "1"; text: "Twitter"; url: "https://twitter.com/status" } - ListElement { uuid: "2"; text: "Personal Site"; url: "https://status.im" } - ListElement { uuid: "3"; text: "Github"; url: "https://github.com" } - ListElement { uuid: "4"; text: "Youtube"; url: "https://youtube.com" } - ListElement { uuid: "5"; text: "Discord"; url: "https://discord.com" } - ListElement { uuid: "6"; text: "Telegram"; url: "https://t.me/status" } - ListElement { uuid: "7"; text: "Custom"; url: "https://status.im" } + ListElement { showcaseKey: "1"; showcasePosition: 0; text: "Twitter"; url: "https://twitter.com/status" } + ListElement { showcaseKey: "2"; showcasePosition: 1; text: "Personal Site"; url: "https://status.im" } + ListElement { showcaseKey: "3"; showcasePosition: 2; text: "Github"; url: "https://github.com" } + ListElement { showcaseKey: "4"; showcasePosition: 3; text: "Youtube"; url: "https://youtube.com" } + ListElement { showcaseKey: "5"; showcasePosition: 4; text: "Discord"; url: "https://discord.com" } + ListElement { showcaseKey: "6"; showcasePosition: 5; text: "Telegram"; url: "https://t.me/status" } + ListElement { showcaseKey: "7"; showcasePosition: 6; text: "Custom"; url: "https://status.im" } } ListModel { - id: accountsShowcaseModel - ListElement { - address: "1" - showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts - order: 0 - name: "name" - colorId: "colorId" - emoji: "emoji" - } - ListElement { - address: "2" - showcaseVisibility: Constants.ShowcaseVisibility.Contacts - order: 1 - name: "name" - colorId: "colorId" - emoji: "emoji" - } - ListElement { - address: "3" - showcaseVisibility: Constants.ShowcaseVisibility.Contacts - order: 2 - name: "name" - colorId: "colorId" - emoji: "emoji" - } - } - - ListModel { - id: accounts13 - ListElement { accountAddress: "1" } - ListElement { accountAddress: "3" } - } - - ListModel { - id: accounts3 - ListElement { accountAddress: "3" } - } - - ListModel { - id: accounts123 - ListElement { accountAddress: "1" } - ListElement { accountAddress: "2" } - ListElement { accountAddress: "3" } - } - - ListModel { - id: accounts14 - ListElement { accountAddress: "1" } - ListElement { accountAddress: "4" } - } - - ListModel { - id: collectiblesListModel - - ListElement { item: 1 } - ListElement { item: 2 } - ListElement { item: 3 } - ListElement { item: 4 } - } - - SortFilterProxyModel { id: collectiblesModel - sourceModel: collectiblesListModel - proxyRoles: [ - FastExpressionRole { - name: "ownership" - expression: { - if (index == 0) { - return accounts13 - } else if (index == 1) { - return accounts3 - } else if (index == 2) { - return accounts123 - } else if (index == 3) { - return accounts14 - } - return undefined - } - }, - FastExpressionRole { - name: "uid" - expression: { - return index + 1 - } - }, - FastExpressionRole { - name: "name" - expression: { - return "Collectible " + (index + 1) - } - } - ] - } - ListModel { - id: collectiblesShowcaseModel ListElement { - uid: "1" + uid: 1 + name: "Collectible 1" + showcaseKey: "1" showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts - order: 0 - name: "name" - backgroundColor: "backgroundColor" - chainId: "chainId" - communityId: "communityId" - collectionName: "collectionName" - imageUrl: "imageUrl" - isLoading: "isLoading" - contractAddress: "contractAddress" - tokenId: "tokenId" + showcasePosition: 0 + ownership: [ + ListElement { accountAddress: "1" }, + ListElement { accountAddress: "3" } + ] } ListElement { - uid: "2" + uid: 2 + name: "Collectible 2" + showcaseKey: "2" showcaseVisibility: Constants.ShowcaseVisibility.Contacts - order: 2 - name: "name" - backgroundColor: "backgroundColor" - chainId: "chainId" - communityId: "communityId" - collectionName: "collectionName" - imageUrl: "imageUrl" - isLoading: "isLoading" - contractAddress: "contractAddress" - tokenId: "tokenId" + showcasePosition: 2 + ownership: [ + ListElement { accountAddress: "1" }, + ListElement { accountAddress: "2" }, + ListElement { accountAddress: "3" } + ] } ListElement { - uid: "3" + uid: 3 + name: "Collectible 3" + showcaseKey: "3" showcaseVisibility: Constants.ShowcaseVisibility.Contacts - order: 1 - name: "name" - backgroundColor: "backgroundColor" - chainId: "chainId" - communityId: "communityId" - collectionName: "collectionName" - imageUrl: "imageUrl" - isLoading: "isLoading" - contractAddress: "contractAddress" - tokenId: "tokenId" + showcasePosition: 1 + ownership: [ + ListElement { accountAddress: "3" } + ] + } + ListElement { + uid: 4 + name: "Collectible 4" + showcaseKey: "4" + showcaseVisibility: Constants.ShowcaseVisibility.NoOne + showcasePosition: 3 + ownership: [ + ListElement { accountAddress: "1" }, + ListElement { accountAddress: "4" } + ] } } @@ -181,11 +110,7 @@ ColumnLayout { id: showcaseModels accountsSourceModel: accountsModel - accountsShowcaseModel: accountsShowcaseModel - collectiblesSourceModel: collectiblesModel - collectiblesShowcaseModel: collectiblesShowcaseModel - socialLinksSourceModel: socialLinksModel } @@ -220,25 +145,17 @@ ColumnLayout { Layout.margins: 10 initialItem: collectiblesView - + Component { id: collectiblesView - Flickable { + RowLayout { + id: grid + spacing: 10 + //anchors.fill: parent - contentWidth: grid.width - contentHeight: grid.height - - clip: true - - Grid { - id: grid - - rows: 3 - columns: 4 - - spacing: 10 - - flow: Grid.TopToBottom + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true Label { text: "Backend models" @@ -247,21 +164,17 @@ ColumnLayout { } GenericListView { - width: 300 - height: 300 + Layout.fillWidth: true + Layout.fillHeight: true model: accountsModel label: "ACCOUNTS MODEL" } + } - GenericListView { - width: 300 - height: 300 - - model: accountsShowcaseModel - label: "SHOWCASE MODEL" - roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] - } + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true Label { text: "Display models" @@ -270,8 +183,8 @@ ColumnLayout { } GenericListView { - width: 420 - height: 300 + Layout.fillWidth: true + Layout.fillHeight: true model: showcaseModels.accountsVisibleModel label: "IN SHOWCASE" @@ -288,8 +201,8 @@ ColumnLayout { RoundButton { text: "❌" onClicked: showcaseModels.setAccountVisibility( - model.showcaseKey, - Constants.ShowcaseVisibility.NoOne) + model.showcaseKey, + Constants.ShowcaseVisibility.NoOne) } VisibilityComboBox { @@ -300,7 +213,7 @@ ColumnLayout { return showcaseModels.setAccountVisibility( - topModel.showcaseKey, currentValue) + topModel.showcaseKey, currentValue) } Component.onCompleted: { @@ -312,8 +225,8 @@ ColumnLayout { } GenericListView { - width: 420 - height: 300 + Layout.fillWidth: true + Layout.fillHeight: true model: showcaseModels.accountsHiddenModel @@ -330,30 +243,28 @@ ColumnLayout { Constants.ShowcaseVisibility.IdVerifiedContacts) } } + } + ColumnLayout { + Layout.fillHeight: true + Layout.fillWidth: true Label { text: "Backend models" font.pixelSize: 22 padding: 10 } - GenericListView { - width: 270 - height: 300 + Layout.fillWidth: true + Layout.fillHeight: true model: collectiblesModel label: "COLLECTIBLES MODEL" } + } - GenericListView { - width: 270 - height: 300 - - model: collectiblesShowcaseModel - label: "SHOWCASE MODEL" - roles: ["uid", "showcaseVisibility", "order"] - } - + ColumnLayout { + Layout.fillHeight: true + Layout.fillWidth: true Label { text: "Display models" font.pixelSize: 22 @@ -361,13 +272,13 @@ ColumnLayout { } GenericListView { - width: 610 - height: 300 + Layout.fillHeight: true + Layout.fillWidth: true model: showcaseModels.collectiblesVisibleModel label: "IN SHOWCASE" movable: true - roles: ["showcaseKey", "showcaseVisibility", "showcasePosition"] + roles: ["showcaseKey", "showcaseVisibility", "showcasePosition", "maxVisibility"] onMoveRequested: { showcaseModels.changeCollectiblePosition(from, to); @@ -379,8 +290,8 @@ ColumnLayout { RoundButton { text: "❌" onClicked: showcaseModels.setCollectibleVisibility( - model.showcaseKey, - Constants.ShowcaseVisibility.NoOne) + model.showcaseKey, + Constants.ShowcaseVisibility.NoOne) } VisibilityComboBox { @@ -391,7 +302,7 @@ ColumnLayout { return showcaseModels.setCollectibleVisibility( - topModel.showcaseKey, currentValue) + topModel.showcaseKey, currentValue) } Component.onCompleted: { @@ -403,8 +314,8 @@ ColumnLayout { } GenericListView { - width: 610 - height: 300 + Layout.fillHeight: true + Layout.fillWidth: true model: showcaseModels.collectiblesHiddenModel @@ -425,7 +336,7 @@ ColumnLayout { } } } - + Component { id: webView Flickable { @@ -524,18 +435,28 @@ ColumnLayout { Button { text: "SAVE" - //TODO: enable when showcaseModels backend APIs is integrated - enabled: false onClicked: { const accountsToBeSaved = showcaseModels.accountsCurrentState() const collectiblesToBeSaved = showcaseModels.collectiblesCurrentState() - accountsShowcaseModel.clear() - accountsShowcaseModel.append(accountsToBeSaved) + for (let index = 0; index < accountsModel.count; index++) { + let account = accountsModel.get(index) + const showcaseAccount = accountsToBeSaved.find(item => item.showcaseKey === account.showcaseKey) - collectiblesShowcaseModel.clear() - collectiblesShowcaseModel.append(collectiblesToBeSaved) + account.showcasePosition = !!showcaseAccount ? showcaseAccount.showcasePosition : 0 + account.showcaseVisibility = !!showcaseAccount ? showcaseAccount.showcaseVisibility : Constants.ShowcaseVisibility.NoOne + accountsModel.set(index, account) + } + + for (let index = 0; index < collectiblesModel.count; index++) { + let collectible = collectiblesModel.get(index) + const showcaseCollectible = collectiblesToBeSaved.find(item => item.showcaseKey === collectible.showcaseKey) + + collectible.showcasePosition = !!showcaseCollectible ? showcaseCollectible.showcasePosition : 0 + collectible.showcaseVisibility = !!showcaseCollectible ? showcaseCollectible.showcaseVisibility : Constants.ShowcaseVisibility.NoOne + collectiblesModel.set(index, collectible) + } } Layout.alignment: Qt.AlignHCenter diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml index 48609fb322..77077ff060 100644 --- a/ui/app/AppLayouts/Profile/ProfileLayout.qml +++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml @@ -134,21 +134,22 @@ StatusSectionLayout { active: false asynchronous: true sourceComponent: MyProfileView { + id: myProfileView implicitWidth: parent.width implicitHeight: parent.height - walletAssetsStore: root.walletAssetsStore - currencyStore: root.currencyStore - walletStore: root.store.walletStore profileStore: root.store.profileStore - privacyStore: root.store.privacyStore contactsStore: root.store.contactsStore - networkConnectionStore: root.networkConnectionStore - communitiesModel: root.store.communitiesList + sendToAccountEnabled: root.networkConnectionStore.sendBuyBridgeEnabled sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.profile) contentWidth: d.contentWidth sideBySidePreview: d.sideBySidePreviewAvailable toastClashesWithDirtyBubble: d.toastClashesWithDirtyBubble + + communitiesShowcaseModel: root.store.ownShowcaseCommunitiesModel + accountsShowcaseModel: root.store.ownShowcaseAccountsModel + collectiblesShowcaseModel: root.store.ownShowcaseCollectiblesModel + socialLinksShowcaseModel: root.store.ownShowcaseSocialLinksModel } } @@ -434,13 +435,7 @@ StatusSectionLayout { showRightPanel: d.isProfilePanelActive && d.sideBySidePreviewAvailable rightPanelWidth: d.rightPanelWidth - rightPanel: MyProfilePreview { - profileStore: root.store.profileStore - contactsStore: root.store.contactsStore - networkConnectionStore: root.networkConnectionStore - dirtyValues: d.isProfilePanelActive ? profileContainer.currentItem.dirtyValues : ({}) - dirty: d.isProfilePanelActive ? profileContainer.currentItem.dirty : false - } + rightPanel: d.isProfilePanelActive ? profileContainer.currentItem.sideBySidePreviewComponent : null Connections { target: root.store.keycardStore.keycardModule diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml index 1ace22b483..a98ba130d3 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml @@ -18,16 +18,7 @@ import utils 1.0 QObject { id: root - property alias sourceModel: joined.leftModel - property alias showcaseModel: joined.rightModel - - /** - * True if the showcase model is in single model mode, i.e. the showcase - * model is part of the source model. False if the showcase model is a - * separate model. - */ - property bool singleModelMode: !joined.rightModel - + property alias sourceModel: writable.sourceModel /** * Model holding elements from 'sourceModel' intended to be visible in the * showcase, sorted by 'position' role. Includes roles from both input models. @@ -95,7 +86,6 @@ QObject { // internals, debug purpose only readonly property alias writable_: writable - readonly property alias joined_: joined component HiddenFilter: AnyOf { UndefinedFilter { @@ -108,16 +98,9 @@ QObject { } } - LeftJoinModel { - id: joined - - joinRole: "showcaseKey" - } - VisibilityAndPositionDirtyStateModel { id: writable - sourceModel: root.singleModelMode ? root.sourceModel : joined visibilityHidden: Constants.ShowcaseVisibility.NoOne } diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml index 29a9326d52..7f203d4e32 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModelAdapter.qml @@ -13,9 +13,10 @@ QObject { // Communities input models property alias communitiesSourceModel: communitySFPM.sourceModel + property alias communitiesShowcaseModel: communityJoinedModel.leftModel // adapted models - readonly property alias adaptedCommunitiesSourceModel: communitySFPM + readonly property alias adaptedCommunitiesSourceModel: communityJoinedModel // Accounts input models property alias accountsSourceModel: accountsSFPM.sourceModel @@ -23,11 +24,15 @@ QObject { // adapted models readonly property alias adaptedAccountsSourceModel: accountsSFPM + //helpers + property var isAddressSaved: (address) => false + // Collectibles input models property alias collectiblesSourceModel: collectiblesSFPM.sourceModel + property alias collectiblesShowcaseModel: collectiblesJoinedModel.leftModel // adapted models - readonly property alias adaptedCollectiblesSourceModel: collectiblesSFPM + readonly property alias adaptedCollectiblesSourceModel: collectiblesJoinedModel // Social links input models property alias socialLinksSourceModel: socialLinksSFPM.sourceModel @@ -35,6 +40,12 @@ QObject { // adapted models readonly property alias adaptedSocialLinksSourceModel: socialLinksSFPM + component JoinModel: LeftJoinModel { + joinRole: "showcaseKey" + } + + // Communities proxies + SortFilterProxyModel { id: communitySFPM proxyRoles: [ @@ -42,10 +53,20 @@ QObject { name: "showcaseKey" expression: model.id expectedRoles: ["id"] + }, + FastExpressionRole { + name: "membersCount" + expression: model.members.count + expectedRoles: ["members"] } ] } + JoinModel { + id: communityJoinedModel + rightModel: communitySFPM + } + SortFilterProxyModel { id: accountsSFPM proxyRoles: [ @@ -53,10 +74,17 @@ QObject { name: "showcaseKey" expression: model.address expectedRoles: ["address"] + }, + FastExpressionRole { + name: "saved" + expression: root.isAddressSaved(model.address) + expectedRoles: ["address"] } ] } + // Collectibles proxies + SortFilterProxyModel { id: collectiblesSFPM proxyRoles: [ @@ -68,6 +96,13 @@ QObject { ] } + JoinModel { + id: collectiblesJoinedModel + rightModel: collectiblesSFPM + } + + // Social links proxies + SortFilterProxyModel { id: socialLinksSFPM proxyRoles: [ diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml index 006adcd184..ca50786d29 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml @@ -23,8 +23,7 @@ QObject { // COMMUNITIES // Input models - property alias communitiesSourceModel: modelAdapter.communitiesSourceModel - property alias communitiesShowcaseModel: communities.showcaseModel + property alias communitiesSourceModel: communities.sourceModel property string communitiesSearcherText // Output models @@ -47,8 +46,7 @@ QObject { // ACCOUNTS // Input models - property alias accountsSourceModel: modelAdapter.accountsSourceModel - property alias accountsShowcaseModel: accounts.showcaseModel + property alias accountsSourceModel: accounts.sourceModel property string accountsSearcherText // Output models @@ -78,8 +76,7 @@ QObject { // COLLECTIBLES // Input models - property alias collectiblesSourceModel: modelAdapter.collectiblesSourceModel - property alias collectiblesShowcaseModel: collectibles.showcaseModel + property alias collectiblesSourceModel: collectiblesFilter.sourceModel property string collectiblesSearcherText // Output models @@ -102,7 +99,7 @@ QObject { // SOCIAL LINKS // Input models - property alias socialLinksSourceModel: modelAdapter.socialLinksSourceModel + property alias socialLinksSourceModel: socialLinks.sourceModel // Output models readonly property alias socialLinksVisibleModel: socialLinks.visibleModel @@ -139,10 +136,6 @@ QObject { }) } - ProfileShowcaseModelAdapter { - id: modelAdapter - } - ProfileShowcaseDirtyState { id: communities @@ -150,7 +143,6 @@ QObject { return ProfileUtils.getMemberRoleText(memberRole) } - sourceModel: modelAdapter.adaptedCommunitiesSourceModel searcherFilter: FastExpressionFilter { expression: { root.communitiesSearcherText @@ -164,7 +156,6 @@ QObject { ProfileShowcaseDirtyState { id: accounts - sourceModel: modelAdapter.adaptedAccountsSourceModel searcherFilter: FastExpressionFilter { expression: { root.accountsSearcherText @@ -194,9 +185,6 @@ QObject { ProfileShowcaseDirtyState { id: socialLinks - - sourceModel: modelAdapter.adaptedSocialLinksSourceModel - singleModelMode: true } @@ -204,7 +192,6 @@ QObject { id: collectiblesFilter delayed: true - sourceModel: modelAdapter.adaptedCollectiblesSourceModel proxyRoles: FastExpressionRole { name: "maxVisibility" diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseSettingsModelAdapter.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseSettingsModelAdapter.qml new file mode 100644 index 0000000000..3de2c6da8d --- /dev/null +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseSettingsModelAdapter.qml @@ -0,0 +1,127 @@ +import QtQml 2.15 +import QtQml.Models 2.15 + +import StatusQ 0.1 +import StatusQ.Core.Utils 0.1 + +import SortFilterProxyModel 0.2 + +import utils 1.0 + +QObject { + id: root + + // Communities input models + property alias communitiesSourceModel: communitySFPM.sourceModel + property alias communitiesShowcaseModel: communityJoinedModel.rightModel + + // adapted models + readonly property alias adaptedCommunitiesSourceModel: communityJoinedModel + + // Accounts input models + property alias accountsSourceModel: accountsSFPM.sourceModel + property alias accountsShowcaseModel: accountsJoinedModel.rightModel + + // adapted models + readonly property alias adaptedAccountsSourceModel: accountsJoinedModel + + // Collectibles input models + property alias collectiblesSourceModel: collectiblesSFPM.sourceModel + property alias collectiblesShowcaseModel: collectiblesJoinedModel.rightModel + + // adapted models + readonly property alias adaptedCollectiblesSourceModel: collectiblesJoinedModel + + // Social links input models + property alias socialLinksSourceModel: socialLinksSFPM.sourceModel + + // adapted models + readonly property alias adaptedSocialLinksSourceModel: socialLinksSFPM + + component JoinModel: LeftJoinModel { + joinRole: "showcaseKey" + } + + // + // Communities proxies + // + SortFilterProxyModel { + id: communitySFPM + proxyRoles: [ + FastExpressionRole { + name: "showcaseKey" + expression: model.id + expectedRoles: ["id"] + }, + FastExpressionRole { + name: "membersCount" + expression: model.members.count + expectedRoles: ["members"] + } + ] + } + + JoinModel { + id: communityJoinedModel + leftModel: communitySFPM + } + + // + // Accounts proxies + // + SortFilterProxyModel { + id: accountsSFPM + proxyRoles: [ + FastExpressionRole { + name: "showcaseKey" + expression: model.address + expectedRoles: ["address"] + } + ] + } + + JoinModel { + id: accountsJoinedModel + leftModel: accountsSFPM + } + + // + // Collectibles proxies + // + SortFilterProxyModel { + id: collectiblesSFPM + proxyRoles: [ + FastExpressionRole { + name: "showcaseKey" + expression: model.uid + expectedRoles: ["uid"] + } + ] + } + + JoinModel { + id: collectiblesJoinedModel + leftModel: collectiblesSFPM + } + + // + // Social links proxies + // + SortFilterProxyModel { + id: socialLinksSFPM + proxyRoles: [ + FastExpressionRole { + name: "showcaseKey" + expression: model.url + expectedRoles: ["url"] + }, + FastExpressionRole { + name: "showcaseVisibility" + expression: getShowcaseVisibility() + function getShowcaseVisibility() { + return Constants.ShowcaseVisibility.Everyone + } + } + ] + } +} diff --git a/ui/app/AppLayouts/Profile/helpers/qmldir b/ui/app/AppLayouts/Profile/helpers/qmldir index ddeab1d4f3..7b4ac1e81c 100644 --- a/ui/app/AppLayouts/Profile/helpers/qmldir +++ b/ui/app/AppLayouts/Profile/helpers/qmldir @@ -1,4 +1,5 @@ ProfileShowcaseDirtyState 1.0 ProfileShowcaseDirtyState.qml ProfileShowcaseModelAdapter 1.0 ProfileShowcaseModelAdapter.qml +ProfileShowcaseSettingsModelAdapter 1.0 ProfileShowcaseSettingsModelAdapter.qml ProfileShowcaseModels 1.0 ProfileShowcaseModels.qml VisibilityAndPositionDirtyStateModel 1.0 VisibilityAndPositionDirtyStateModel.qml diff --git a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml index e73e441dcd..a78ea9b1e3 100644 --- a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml @@ -16,6 +16,23 @@ QtObject { property var receivedContactRequestsModel: contactsModule.receivedContactRequestsModel property var sentContactRequestsModel: contactsModule.sentContactRequestsModel + readonly property var showcasePublicKey: contactsModule.showcasePublicKey + + // Showcase models for a contact with showcasePublicKey + readonly property var showcaseContactCommunitiesModel: contactsModule.showcaseContactCommunitiesModel + readonly property var showcaseContactAccountsModel: contactsModule.showcaseContactAccountsModel + readonly property var showcaseContactCollectiblesModel: contactsModule.showcaseContactCollectiblesModel + readonly property var showcaseContactAssetsModel: contactsModule.showcaseContactAssetsModel + readonly property var showcaseContactSocialLinksModel: contactsModule.showcaseContactSocialLinksModel + + // Support models for showcase for a contact with showcasePublicKey + readonly property var showcaseCollectiblesModel: contactsModule.showcaseCollectiblesModel + + // Sets showcasePublicKey and updates showcase models with corresponding data + function requestProfileShowcase(publicKey) { + root.contactsModule.requestProfileShowcase(publicKey) + } + // Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections. // property var receivedButRejectedContactRequestsModel: contactsModule.receivedButRejectedContactRequestsModel // property var sentButRejectedContactRequestsModel: contactsModule.sentButRejectedContactRequestsModel @@ -25,23 +42,23 @@ QtObject { } function generateAlias(pubKey) { - return root.globalUtilsInst.generateAlias(pubKey) + return root.globalUtilsInst.generateAlias(pubKey) } function getFromClipboard() { - return root.globalUtilsInst.getFromClipboard() + return root.globalUtilsInst.getFromClipboard() } function isMyMutualContact(pubKey) { - return root.contactsModule.isMyMutualContact(pubKey) + return root.contactsModule.isMyMutualContact(pubKey) } function isBlockedContact(pubKey) { - return root.contactsModule.isBlockedContact(pubKey) + return root.contactsModule.isBlockedContact(pubKey) } function hasPendingContactRequest(pubKey) { - return root.contactsModule.hasPendingContactRequest(pubKey) + return root.contactsModule.hasPendingContactRequest(pubKey) } function joinPrivateChat(pubKey) { diff --git a/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml index 61fd92ccdd..af6d9d42e7 100644 --- a/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml @@ -2,6 +2,10 @@ import QtQuick 2.13 import utils 1.0 import AppLayouts.Chat.stores 1.0 +import AppLayouts.Communities.stores 1.0 +import AppLayouts.Profile.helpers 1.0 + +import StatusQ.Core.Utils 0.1 import SortFilterProxyModel 0.2 @@ -154,6 +158,51 @@ QtObject { } } + readonly property alias ownShowcaseCommunitiesModel: ownShowcaseModels.adaptedCommunitiesSourceModel + readonly property alias ownShowcaseAccountsModel: ownShowcaseModels.adaptedAccountsSourceModel + readonly property alias ownShowcaseCollectiblesModel: ownShowcaseModels.adaptedCollectiblesSourceModel + readonly property alias ownShowcaseSocialLinksModel: ownShowcaseModels.adaptedSocialLinksSourceModel + + readonly property alias contactShowcaseCommunitiesModel: contactShowcaseModels.adaptedCommunitiesSourceModel + readonly property alias contactShowcaseAccountsModel: contactShowcaseModels.adaptedAccountsSourceModel + readonly property alias contactShowcaseCollectiblesModel: contactShowcaseModels.adaptedCollectiblesSourceModel + readonly property alias contactShowcaseSocialLinksModel: contactShowcaseModels.adaptedSocialLinksSourceModel + + function requestContactShowcase(address) { + root.contactsStore.requestProfileShowcase(address) + } + + function requestOwnShowcase() { + root.profileStore.requestProfileShowcasePreferences() + } + + readonly property QObject d: QObject { + ProfileShowcaseSettingsModelAdapter { + id: ownShowcaseModels + communitiesSourceModel: root.communitiesList + communitiesShowcaseModel: root.profileStore.showcasePreferencesCommunitiesModel + accountsSourceModel: root.walletStore.ownAccounts + accountsShowcaseModel: root.profileStore.showcasePreferencesAccountsModel + collectiblesSourceModel: root.walletStore.collectibles + collectiblesShowcaseModel: root.profileStore.showcasePreferencesCollectiblesModel + socialLinksSourceModel: root.profileStore.showcasePreferencesSocialLinksModel + } + + ProfileShowcaseModelAdapter { + id: contactShowcaseModels + communitiesSourceModel: root.communitiesModuleInst.model + communitiesShowcaseModel: root.contactsStore.showcaseContactCommunitiesModel + accountsSourceModel: root.contactsStore.showcaseContactAccountsModel + collectiblesSourceModel: root.contactsStore.showcaseCollectiblesModel + collectiblesShowcaseModel: root.contactsStore.showcaseContactCollectiblesModel + socialLinksSourceModel: root.contactsStore.showcaseContactSocialLinksModel + + isAddressSaved: (address) => { + return false + } + } + } + function importCommunity(communityKey) { root.communitiesModuleInst.importCommunity(communityKey); } diff --git a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml index 419ff48048..bf1beae4d6 100644 --- a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml @@ -29,20 +29,12 @@ QtObject { readonly property bool isWalletEnabled: Global.appIsReady? mainModule.sectionsModel.getItemEnabledBySectionType(Constants.appSection.wallet) : true - readonly property var collectiblesModel: profileModule.collectiblesModel - readonly property var showcasePreferencesCommunitiesModel: profileModule.showcasePreferencesCommunitiesModel readonly property var showcasePreferencesAccountsModel: profileModule.showcasePreferencesAccountsModel readonly property var showcasePreferencesCollectiblesModel: profileModule.showcasePreferencesCollectiblesModel readonly property var showcasePreferencesAssetsModel: profileModule.showcasePreferencesAssetsModel readonly property var showcasePreferencesSocialLinksModel: profileModule.showcasePreferencesSocialLinksModel - // TODO: remove old models - readonly property var profileShowcaseCommunitiesModel: profileModule.profileShowcaseCommunitiesModel - readonly property var profileShowcaseAccountsModel: profileModule.profileShowcaseAccountsModel - readonly property var profileShowcaseCollectiblesModel: profileModule.profileShowcaseCollectiblesModel - readonly property var profileShowcaseAssetsModel: profileModule.profileShowcaseAssetsModel - readonly property bool isFirstShowcaseInteraction: localAccountSettings.isFirstShowcaseInteraction property var details: Utils.getContactDetailsAsJson(pubkey) @@ -118,10 +110,6 @@ QtObject { root.profileModule.requestProfileShowcasePreferences() } - function requestProfileShowcase(publicKey) { - root.profileModule.requestProfileShowcase(publicKey) - } - function setIsFirstShowcaseInteraction() { root.profileModule.setIsFirstShowcaseInteraction() } diff --git a/ui/app/AppLayouts/Profile/views/MyProfileView.qml b/ui/app/AppLayouts/Profile/views/MyProfileView.qml index 057234f204..ca2c064225 100644 --- a/ui/app/AppLayouts/Profile/views/MyProfileView.qml +++ b/ui/app/AppLayouts/Profile/views/MyProfileView.qml @@ -28,27 +28,24 @@ import AppLayouts.Wallet.stores 1.0 SettingsContentBase { id: root - property WalletStore walletStore property ProfileStore profileStore - property PrivacyStore privacyStore property ContactsStore contactsStore - property NetworkConnectionStore networkConnectionStore - required property WalletAssetsStore walletAssetsStore - required property CurrenciesStore currencyStore - property var communitiesModel + property bool sendToAccountEnabled: false + + property alias communitiesShowcaseModel: showcaseModels.communitiesSourceModel + property alias accountsShowcaseModel: showcaseModels.accountsSourceModel + property alias collectiblesShowcaseModel: showcaseModels.collectiblesSourceModel + property alias socialLinksShowcaseModel: showcaseModels.socialLinksSourceModel property bool sideBySidePreview property bool toastClashesWithDirtyBubble + readonly property alias sideBySidePreviewComponent: myProfilePreviewComponent - property QtObject dirtyValues: QtObject { - property string displayName: descriptionPanel.displayName.text - property string bio: descriptionPanel.bio.text - property url profileLargeImage: profileHeader.previewIcon - property var socialLinks: priv.showcaseModels.socialLinksVisibleModel - property var communitiesModel: priv.showcaseModels.communitiesVisibleModel - property var accountsModel: priv.showcaseModels.accountsVisibleModel - property var collectiblesModel: priv.showcaseModels.collectiblesVisibleModel + readonly property QtObject liveValues: QtObject { + readonly property string displayName: descriptionPanel.displayName.text + readonly property string bio: descriptionPanel.bio.text + readonly property url profileLargeImage: profileHeader.previewIcon } enum TabIndex { @@ -126,7 +123,7 @@ SettingsContentBase { onVisibleChanged: if (visible) profileStore.requestProfileShowcasePreferences() Component.onCompleted: profileStore.requestProfileShowcasePreferences() - readonly property var priv: QtObject { + property QObject priv: QObject { id: priv readonly property bool hasAnyProfileShowcaseChanges: showcaseModels.dirty @@ -137,19 +134,11 @@ SettingsContentBase { profileHeader.icon !== profileStore.profileLargeImage property ProfileShowcaseModels showcaseModels: ProfileShowcaseModels { - communitiesSourceModel: root.communitiesModel - communitiesShowcaseModel: root.profileStore.showcasePreferencesCommunitiesModel + id: showcaseModels + communitiesSearcherText: profileShowcaseCommunitiesPanel.searcherText - - accountsSourceModel: root.walletStore.ownAccounts - accountsShowcaseModel: root.profileStore.showcasePreferencesAccountsModel accountsSearcherText: profileShowcaseAccountsPanel.searcherText - - collectiblesSourceModel: root.profileStore.collectiblesModel - collectiblesShowcaseModel: root.profileStore.showcasePreferencesCollectiblesModel collectiblesSearcherText: profileShowcaseCollectiblesPanel.searcherText - - socialLinksSourceModel: root.profileStore.showcasePreferencesSocialLinksModel } // Used to track which are the expected backend responses (they can be 0, 1 or 2) depending on the dirty changes @@ -363,8 +352,8 @@ SettingsContentBase { // id: profileShowcaseAssetsPanel // baseModel: root.walletAssetsStore.groupedAccountAssetsModel // TODO: instantiate an assets model in profile module - // showcaseModel: root.profileStore.profileShowcaseAssetsModel - // addAccountsButtonVisible: root.profileStore.profileShowcaseAccountsModel.hiddenCount > 0 + // showcaseModel: root.contactsStore.showcaseContactAssetsModel + // addAccountsButtonVisible: root.contactsStore.showcaseContactAccountsModel.hiddenCount > 0 // formatCurrencyAmount: function(amount, symbol) { // return root.currencyStore.formatCurrencyAmount(amount, symbol) // } @@ -401,10 +390,33 @@ SettingsContentBase { publicKey: root.contactsStore.myPublicKey profileStore: root.profileStore contactsStore: root.contactsStore - networkConnectionStore: root.networkConnectionStore + sendToAccountEnabled: root.sendToAccountEnabled onClosed: destroy() - dirtyValues: root.dirtyValues + dirtyValues: root.liveValues dirty: root.dirty + + showcaseCommunitiesModel: priv.showcaseModels.communitiesVisibleModel + showcaseAccountsModel: priv.showcaseModels.accountsVisibleModel + showcaseCollectiblesModel: priv.showcaseModels.collectiblesVisibleModel + showcaseSocialLinksModel: priv.showcaseModels.socialLinksVisibleModel + //showcaseAssetsModel: priv.showcaseModels.assetsVisibleModel + } + } + + Component { + id: myProfilePreviewComponent + MyProfilePreview { + profileStore: root.profileStore + contactsStore: root.contactsStore + sendToAccountEnabled: root.sendToAccountEnabled + dirtyValues: root.liveValues + dirty: root.dirty + + showcaseCommunitiesModel: priv.showcaseModels.communitiesVisibleModel + showcaseAccountsModel: priv.showcaseModels.accountsVisibleModel + showcaseCollectiblesModel: priv.showcaseModels.collectiblesVisibleModel + showcaseSocialLinksModel: priv.showcaseModels.socialLinksVisibleModel + //showcaseAssetsModel: priv.showcaseModels.assetsVisibleModel } } diff --git a/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml b/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml index fdefc8d7a2..df4ecac426 100644 --- a/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml +++ b/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml @@ -8,10 +8,17 @@ import StatusQ.Core.Theme 0.1 Item { property alias profileStore: profilePreview.profileStore property alias contactsStore: profilePreview.contactsStore - property alias networkConnectionStore: profilePreview.networkConnectionStore + property alias sendToAccountEnabled: profilePreview.sendToAccountEnabled property alias dirtyValues: profilePreview.dirtyValues property alias dirty: profilePreview.dirty + property alias showcaseCommunitiesModel: profilePreview.showcaseCommunitiesModel + property alias showcaseAccountsModel: profilePreview.showcaseAccountsModel + property alias showcaseCollectiblesModel: profilePreview.showcaseCollectiblesModel + property alias showcaseSocialLinksModel: profilePreview.showcaseSocialLinksModel + property alias showcaseAssetsModel: profilePreview.showcaseAssetsModel + + implicitHeight: profilePreview.implicitHeight + profilePreview.anchors.topMargin + profilePreview.anchors.bottomMargin diff --git a/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml b/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml index c5fb7ab614..c320248de9 100644 --- a/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml +++ b/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml @@ -173,7 +173,7 @@ StatusModal { mainModule.resolveENS(name, d.uuid) }); - property var profileModuleInst: SharedStores.RootStore.profileSectionModuleInst.profileModule + property var contactsModuleInst: SharedStores.RootStore.profileSectionModuleInst.contactsModule /// Ensures that the \c root.address and \c root.chainShortNames are not reset when the initial text is set property bool initialized: false @@ -215,7 +215,7 @@ StatusModal { d.checkingContactsAddressInProgress = true d.contactsWithSameAddress = 0 - d.profileModuleInst.fetchProfileShowcaseAccountsByAddress(d.address) + d.contactsModuleInst.fetchProfileShowcaseAccountsByAddress(d.address) return } @@ -294,7 +294,7 @@ StatusModal { } Connections { - target: d.profileModuleInst + target: d.contactsModuleInst function onProfileShowcaseAccountsByAddressFetched(accounts: string) { d.cardsModel.clear() d.checkingContactsAddressInProgress = false diff --git a/ui/app/mainui/Popups.qml b/ui/app/mainui/Popups.qml index 8696ab914d..49d5dba18f 100644 --- a/ui/app/mainui/Popups.qml +++ b/ui/app/mainui/Popups.qml @@ -535,10 +535,22 @@ QtObject { id: profilePopupComponent ProfileDialog { id: profilePopup + + property bool isCurrentUser: publicKey === rootStore.profileSectionStore.profileStore.pubkey + profileStore: rootStore.profileSectionStore.profileStore contactsStore: rootStore.profileSectionStore.contactsStore - networkConnectionStore: root.networkConnectionStore + sendToAccountEnabled: root.networkConnectionStore.sendBuyBridgeEnabled + showcaseCommunitiesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCommunitiesModel : rootStore.profileSectionStore.contactShowcaseCommunitiesModel + showcaseAccountsModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseAccountsModel : rootStore.profileSectionStore.contactShowcaseAccountsModel + showcaseCollectiblesModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseCollectiblesModel : rootStore.profileSectionStore.contactShowcaseCollectiblesModel + showcaseSocialLinksModel: isCurrentUser ? rootStore.profileSectionStore.ownShowcaseSocialLinksModel : rootStore.profileSectionStore.contactShowcaseSocialLinksModel + + onOpened: { + isCurrentUser ? rootStore.profileSectionStore.requestOwnShowcase() + : rootStore.profileSectionStore.requestContactShowcase(publicKey) + } onClosed: { if (profilePopup.parentPopup) { profilePopup.parentPopup.close() diff --git a/ui/imports/shared/popups/ProfileDialog.qml b/ui/imports/shared/popups/ProfileDialog.qml index ac1fcb792a..fcf6d0666c 100644 --- a/ui/imports/shared/popups/ProfileDialog.qml +++ b/ui/imports/shared/popups/ProfileDialog.qml @@ -9,14 +9,20 @@ StatusDialog { property var parentPopup - property string publicKey + property alias publicKey: profileView.publicKey - property var profileStore - property var contactsStore - property var networkConnectionStore + property alias profileStore: profileView.profileStore + property alias contactsStore: profileView.contactsStore + property alias sendToAccountEnabled: profileView.sendToAccountEnabled - property var dirtyValues: ({}) - property bool dirty: false + property alias showcaseCommunitiesModel: profileView.showcaseCommunitiesModel + property alias showcaseAccountsModel: profileView.showcaseAccountsModel + property alias showcaseCollectiblesModel: profileView.showcaseCollectiblesModel + property alias showcaseSocialLinksModel: profileView.showcaseSocialLinksModel + property alias showcaseAssetsModel: profileView.showcaseAssetsModel + + property alias dirtyValues: profileView.dirtyValues + property alias dirty: profileView.dirty width: 640 padding: 0 @@ -25,12 +31,8 @@ StatusDialog { footer: null contentItem: ProfileDialogView { - publicKey: root.publicKey - profileStore: root.profileStore - contactsStore: root.contactsStore - networkConnectionStore: root.networkConnectionStore + id: profileView + onCloseRequested: root.close() - dirtyValues: root.dirtyValues - dirty: root.dirty } } diff --git a/ui/imports/shared/views/ProfileDialogView.qml b/ui/imports/shared/views/ProfileDialogView.qml index 590f724220..494402bb19 100644 --- a/ui/imports/shared/views/ProfileDialogView.qml +++ b/ui/imports/shared/views/ProfileDialogView.qml @@ -32,12 +32,18 @@ Pane { property var profileStore property var contactsStore - property var walletStore: WalletNS.RootStore - property var networkConnectionStore + + property alias sendToAccountEnabled: showcaseView.sendToAccountEnabled property var dirtyValues: ({}) property bool dirty: false + property var showcaseCommunitiesModel + property var showcaseAccountsModel + property var showcaseCollectiblesModel + property var showcaseSocialLinksModel + property var showcaseAssetsModel + signal closeRequested() padding: 0 @@ -599,22 +605,24 @@ Pane { // Profile Showcase ProfileShowcaseView { + id: showcaseView + Layout.fillWidth: true Layout.topMargin: -column.spacing Layout.preferredHeight: 300 currentTabIndex: showcaseTabBar.currentIndex - publicKey: root.publicKey mainDisplayName: d.mainDisplayName readOnly: root.readOnly - profileStore: root.profileStore - walletStore: root.walletStore - networkConnectionStore: root.networkConnectionStore - livePreview: root.dirty - livePreviewValues: root.dirtyValues + communitiesModel: root.showcaseCommunitiesModel + accountsModel: root.showcaseAccountsModel + collectiblesModel: root.showcaseCollectiblesModel + // socialLinksModel: root.showcaseSocialLinksModel + // assetsModel: root.showcaseAssetsModel onCloseRequested: root.closeRequested() + onCopyToClipboard: root.profileStore.copyToClipboard(text) } } } diff --git a/ui/imports/shared/views/profile/ProfileShowcaseView.qml b/ui/imports/shared/views/profile/ProfileShowcaseView.qml index 0e8f08f5bf..49df14ade0 100644 --- a/ui/imports/shared/views/profile/ProfileShowcaseView.qml +++ b/ui/imports/shared/views/profile/ProfileShowcaseView.qml @@ -19,20 +19,19 @@ Control { id: root property alias currentTabIndex: stackLayout.currentIndex + + property alias communitiesModel: communitiesProxyModel.sourceModel + property alias accountsModel: accountsProxyModel.sourceModel + property alias collectiblesModel: collectiblesProxyModel.sourceModel + property alias assetsModel: assetsProxyModel.sourceModel + property alias socialLinksModel: socialLinksProxyModel.sourceModel - property string publicKey - property string mainDisplayName - property bool readOnly - property var profileStore - property var walletStore - property var networkConnectionStore - - property bool livePreview: false - property var livePreviewValues: ({}) - + required property string mainDisplayName + required property bool readOnly + required property bool sendToAccountEnabled + signal closeRequested() - - onVisibleChanged: if (visible && !livePreview) profileStore.requestProfileShowcase(publicKey) + signal copyToClipboard(string text) horizontalPadding: readOnly ? 20 : 40 // smaller in settings/preview topPadding: Style.current.bigPadding @@ -41,70 +40,45 @@ Control { id: d readonly property string copyLiteral: qsTr("Copy") + } - readonly property var timer: Timer { - id: timer - } + component PositionSFPM: SortFilterProxyModel { + sorters: [ + RoleSorter { + roleName: "showcasePosition" + } + ] + filters: AnyOf { + inverted: true + UndefinedFilter { + roleName: "showcaseVisibility" + } - readonly property var communitiesModel: root.livePreview ? liveCommunitiesModel - : communitiesStoreModel - readonly property var accountsModel: root.livePreview ? root.livePreviewValues.accountsModel - : accountsStoreModel - readonly property var collectiblesModel: root.livePreview ? root.livePreviewValues.collectiblesModel - : collectiblesStoreModel - // TODO: add dirty values to the livePreviewValues once assets are supported - // readonly property assetsModel: root.livePreview ? root.livePreviewValues.assetsModel - // : root.profileStore.profileShowcaseAssetsModel - readonly property var assetsModel: root.profileStore.profileShowcaseAssetsModel - readonly property var socialLinksModel: root.livePreview ? root.livePreviewValues.socialLinksModel - : root.profileStore.socialLinksModel - SortFilterProxyModel { - id: liveCommunitiesModel - sourceModel: root.livePreviewValues.communitiesModel - proxyRoles: [ - FastExpressionRole { - name: "membersCount" - expression: model.members.count - expectedRoles: ["members"] - } - ] - } - - SortFilterProxyModel { - id: communitiesStoreModel - sourceModel: root.profileStore.profileShowcaseCommunitiesModel - filters: [ - ValueFilter { - roleName: "showcaseVisibility" - value: Constants.ShowcaseVisibility.NoOne - inverted: true - }, - ValueFilter { - roleName: "loading" - value: false - } - ] - } - - SortFilterProxyModel { - id: accountsStoreModel - sourceModel: root.profileStore.profileShowcaseAccountsModel - filters: ValueFilter { + ValueFilter { roleName: "showcaseVisibility" value: Constants.ShowcaseVisibility.NoOne - inverted: true } } + } - SortFilterProxyModel { - id: collectiblesStoreModel - sourceModel: root.profileStore.profileShowcaseCollectiblesModel - filters: ValueFilter { - roleName: "showcaseVisibility" - value: Constants.ShowcaseVisibility.NoOne - inverted: true - } - } + PositionSFPM { + id: communitiesProxyModel + } + + PositionSFPM { + id: accountsProxyModel + } + + PositionSFPM { + id: collectiblesProxyModel + } + + PositionSFPM { + id: assetsProxyModel + } + + PositionSFPM { + id: socialLinksProxyModel } background: StatusDialogBackground { @@ -139,31 +113,33 @@ Control { Layout.fillWidth: true Layout.fillHeight: true id: communitiesView + model: communitiesProxyModel rightMargin: Style.current.halfPadding cellWidth: (width-rightMargin)/2 cellHeight: cellWidth/2 visible: count - model: d.communitiesModel ScrollBar.vertical: StatusScrollBar { } delegate: StatusListItem { // TODO custom delegate width: GridView.view.cellWidth - Style.current.smallPadding height: GridView.view.cellHeight - Style.current.smallPadding - title: model.name + title: model.name ?? "" statusListItemTitle.font.pixelSize: 17 statusListItemTitle.font.bold: true - subTitle: model.description - tertiaryTitle: qsTr("%n member(s)", "", model.membersCount) - asset.name: model.image ?? model.name + subTitle: model.description ?? "" + tertiaryTitle: qsTr("%n member(s)", "", model.membersCount ?? 0) + asset.name: model.image ?? model.name ?? "" asset.isImage: asset.name.startsWith(Constants.dataImagePrefix) asset.isLetterIdenticon: !model.image - asset.color: model.color + asset.color: model.color ?? "" asset.width: 40 asset.height: 40 border.width: 1 border.color: Theme.palette.baseColor2 + loading: !model.id components: [ StatusIcon { - visible: model.memberRole === Constants.memberRole.owner || + visible: !!model.memberRole && + model.memberRole === Constants.memberRole.owner || model.memberRole === Constants.memberRole.admin || model.memberRole === Constants.memberRole.tokenMaster anchors.verticalCenter: parent.verticalCenter @@ -172,7 +148,7 @@ Control { } ] onClicked: { - if (root.readOnly) + if (root.readOnly || loading) return root.closeRequested() Global.switchToCommunity(model.id) @@ -198,24 +174,12 @@ Control { Layout.fillWidth: true Layout.fillHeight: true id: accountsView + model: accountsProxyModel spacing: Style.current.halfPadding visible: count - model: d.accountsModel delegate: StatusListItem { id: accountDelegate - property bool saved: { - let savedAddress = root.walletStore.getSavedAddress(model.address) - if (savedAddress.name !== "") - return true - if (!!root.walletStore.lastCreatedSavedAddress) { - if (root.walletStore.lastCreatedSavedAddress.address.toLowerCase() === model.address.toLowerCase()) { - return !!root.walletStore.lastCreatedSavedAddress.error - } - } - - return false - } border.width: 1 border.color: Theme.palette.baseColor2 width: ListView.view.width @@ -237,8 +201,8 @@ Control { StatusFlatButton { anchors.verticalCenter: parent.verticalCenter size: StatusBaseButton.Size.Small - enabled: !accountDelegate.saved - text: accountDelegate.saved ? qsTr("Address saved") : qsTr("Save Address") + enabled: !model.saved + text: model.saved ? qsTr("Address saved") : qsTr("Save Address") onClicked: { // From here, we should just run add saved address popup Global.openAddEditSavedAddressesPopup({ @@ -252,7 +216,7 @@ Control { type: StatusFlatRoundButton.Type.Secondary icon.name: "send" tooltip.text: qsTr("Send") - enabled: root.networkConnectionStore.sendBuyBridgeEnabled + enabled: root.sendToAccountEnabled onClicked: { Global.openSendModal(model.address) } @@ -264,10 +228,8 @@ Control { tooltip.text: d.copyLiteral onClicked: { tooltip.text = qsTr("Copied") - root.profileStore.copyToClipboard(model.address) - d.timer.setTimeout(function() { - tooltip.text = d.copyLiteral - }, 2000); + root.copyToClipboard(model.address) + Backpressure.setTimeout(this, 2000, () => tooltip.text = d.copyLiteral) } } ] @@ -292,12 +254,11 @@ Control { Layout.fillWidth: true Layout.fillHeight: true id: collectiblesView + model: collectiblesProxyModel rightMargin: Style.current.halfPadding cellWidth: (width-rightMargin)/4 cellHeight: cellWidth visible: count - // TODO Issue #11637: Dedicated controller for user's list of collectibles (no watch-only entries) - model: d.collectiblesModel ScrollBar.vertical: StatusScrollBar { } delegate: StatusRoundedImage { width: GridView.view.cellWidth - Style.current.smallPadding @@ -306,7 +267,8 @@ Control { border.color: Theme.palette.directColor7 color: !!model.backgroundColor ? model.backgroundColor : "transparent" radius: Style.current.radius - showLoadingIndicator: model.isLoading + showLoadingIndicator: true + isLoading: image.isLoading || !model.imageUrl image.fillMode: Image.PreserveAspectCrop image.source: model.imageUrl ?? "" @@ -379,18 +341,11 @@ Control { Layout.fillWidth: true Layout.fillHeight: true id: assetsView + model: assetsProxyModel rightMargin: Style.current.halfPadding cellWidth: (width-rightMargin)/3 cellHeight: cellWidth/2.5 visible: count - model: SortFilterProxyModel { - sourceModel: d.assetsModel - filters: ValueFilter { - roleName: "showcaseVisibility" - value: Constants.ShowcaseVisibility.NoOne - inverted: true - } - } ScrollBar.vertical: StatusScrollBar { } delegate: StatusListItem { readonly property double changePct24hour: model.changePct24hour ?? 0 diff --git a/vendor/status-go b/vendor/status-go index caf3de1190..30e143ca40 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit caf3de119055a4169c1efa83d0a42c11221aa014 +Subproject commit 30e143ca40b68423edff1a54091c339ebc3694dc