From 74dfd181c3375015d7ea607cb6461fd56e0174c5 Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Fri, 8 Mar 2024 21:11:48 +0100 Subject: [PATCH] feat: Add new simplified model for profile showcase preferences (#13708) * feat: Add new simplified model for profile showcase preferences Close #13688 * feat: Add new api for saving profile showcase preferences * feat(ProfileShowase): Save action with the new backend - Created JSON file according to new backend structure when saving. - Updated `dirty state` to sync writable and movable models when position is changed to have a better internal models sync. - Reenabled identity fields save. Closes #13799 * feat(ProfileShowcase): Showcase limit values integration with backend Updated showcase limits with values coming from backend. --------- Co-authored-by: Noelia --- .../profile_section/profile/controller.nim | 8 +- .../profile_section/profile/io_interface.nim | 11 ++ .../profile_preferences_account_item.nim | 3 - .../profile_preferences_collectible_item.nim | 1 - .../showcase_preferences_generic_model.nim | 70 +++++++++ ...howcase_preferences_social_links_model.nim | 70 +++++++++ .../profile/models/showcase_save_data.nim | 59 +++++++ .../main/profile_section/profile/module.nim | 147 +++++++++++++++++- .../main/profile_section/profile/view.nim | 102 +++++++++++- .../service/profile/async_tasks.nim | 19 ++- .../service/profile/dto/profile_showcase.nim | 19 ++- .../dto/profile_showcase_preferences.nim | 53 +++++-- src/app_service/service/profile/service.nim | 40 ++++- src/backend/accounts.nim | 8 + .../helpers/ProfileShowcaseDirtyState.qml | 25 +-- .../Profile/helpers/ProfileShowcaseModels.qml | 11 ++ .../Profile/panels/ProfileShowcasePanel.qml | 2 +- .../panels/ProfileSocialLinksPanel.qml | 7 +- .../Profile/stores/ProfileStore.qml | 93 +++++++---- .../Profile/views/MyProfileView.qml | 31 +++- ui/imports/utils/Constants.qml | 1 - ui/imports/utils/ProfileUtils.qml | 1 - vendor/status-go | 2 +- 23 files changed, 687 insertions(+), 96 deletions(-) create mode 100644 src/app/modules/main/profile_section/profile/models/showcase_preferences_generic_model.nim create mode 100644 src/app/modules/main/profile_section/profile/models/showcase_preferences_social_links_model.nim create mode 100644 src/app/modules/main/profile_section/profile/models/showcase_save_data.nim diff --git a/src/app/modules/main/profile_section/profile/controller.nim b/src/app/modules/main/profile_section/profile/controller.nim index d563168109..401324643b 100644 --- a/src/app/modules/main/profile_section/profile/controller.nim +++ b/src/app/modules/main/profile_section/profile/controller.nim @@ -111,7 +111,7 @@ proc setBio*(self: Controller, bio: string): bool = self.settingsService.saveBio(bio) proc storeProfileShowcasePreferences*(self: Controller, preferences: ProfileShowcasePreferencesDto, revealedAddresses: seq[string]) = - self.profileService.setProfileShowcasePreferences(preferences) + self.profileService.saveProfileShowcasePreferences(preferences) self.events.emit(MARK_WALLET_ADDRESSES_AS_SHOWN, WalletAddressesArgs(addresses: revealedAddresses)) proc requestProfileShowcasePreferences*(self: Controller) = @@ -123,6 +123,12 @@ proc requestProfileShowcaseForContact*(self: Controller, contactId: string) = proc fetchProfileShowcaseAccountsByAddress*(self: Controller, address: string) = self.profileService.fetchProfileShowcaseAccountsByAddress(address) +proc getProfileShowcaseSocialLinksLimit*(self: Controller): int = + self.profileService.getProfileShowcaseSocialLinksLimit() + +proc getProfileShowcaseEntriesLimit*(self: Controller): int = + self.profileService.getProfileShowcaseEntriesLimit() + proc requestCommunityInfo*(self: Controller, communityId: string, shard: Shard) = self.communityService.requestCommunityInfo(communityId, shard) 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 cd3c471b09..57e8b0a2bb 100644 --- a/src/app/modules/main/profile_section/profile/io_interface.nim +++ b/src/app/modules/main/profile_section/profile/io_interface.nim @@ -10,6 +10,8 @@ import models/profile_preferences_account_item import models/profile_preferences_collectible_item import models/profile_preferences_asset_item +import models/showcase_save_data + type AccessInterface* {.pure inheritable.} = ref object of RootObj ## Abstract class for any input/interaction with this module. @@ -53,6 +55,15 @@ method saveSocialLinks*(self: AccessInterface) {.base.} = method onSocialLinksUpdated*(self: AccessInterface, socialLinks: SocialLinks, error: string) {.base.} = raise newException(ValueError, "No implementation available") +method saveProfileShowcasePreferences*(self: AccessInterface, showcase: ShowcaseSaveData) {.base.} = + raise newException(ValueError, "No implementation available") + +method getProfileShowcaseSocialLinksLimit*(self: AccessInterface): int {.base.} = + raise newException(ValueError, "No implementation available") + +method getProfileShowcaseEntriesLimit*(self: AccessInterface): int {.base.} = + raise newException(ValueError, "No implementation available") + method storeProfileShowcasePreferences*(self: AccessInterface, communities: seq[ProfileShowcaseCommunityItem], accounts: seq[ProfileShowcaseAccountItem], 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 index a8ea298023..d85a2af686 100644 --- 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 @@ -49,9 +49,6 @@ proc toShowcasePreferenceItem*(self: ProfileShowcaseAccountItem): ProfileShowcas result = ProfileShowcaseAccountPreference() result.address = self.address - result.name = self.name - result.emoji = self.emoji - result.colorId = self.colorId result.showcaseVisibility = self.showcaseVisibility result.order = 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 index 1ab4dc80b1..73d9104288 100644 --- a/src/app/modules/main/profile_section/profile/models/profile_preferences_collectible_item.nim +++ b/src/app/modules/main/profile_section/profile/models/profile_preferences_collectible_item.nim @@ -59,7 +59,6 @@ proc toShowcasePreferenceItem*(self: ProfileShowcaseCollectibleItem): ProfileSho result.chainId = self.chainId result.tokenId = self.tokenId result.contractAddress = self.contractAddress - result.communityId = self.communityId result.showcaseVisibility = self.showcaseVisibility result.order = self.order diff --git a/src/app/modules/main/profile_section/profile/models/showcase_preferences_generic_model.nim b/src/app/modules/main/profile_section/profile/models/showcase_preferences_generic_model.nim new file mode 100644 index 0000000000..86cf7b715f --- /dev/null +++ b/src/app/modules/main/profile_section/profile/models/showcase_preferences_generic_model.nim @@ -0,0 +1,70 @@ +import NimQml, tables, strutils, sequtils, json + +import app_service/service/profile/dto/profile_showcase_preferences + +type + ShowcasePreferencesGenericItem* = object of RootObj + showcaseKey*: string + showcaseVisibility*: ProfileShowcaseVisibility + showcasePosition*: int + +type + ModelRole {.pure.} = enum + ShowcaseKey + ShowcaseVisibility + ShowcasePosition + +QtObject: + type + ShowcasePreferencesGenericModel* = ref object of QAbstractListModel + items: seq[ShowcasePreferencesGenericItem] + + proc delete(self: ShowcasePreferencesGenericModel) = + self.items = @[] + self.QAbstractListModel.delete + + proc setup(self: ShowcasePreferencesGenericModel) = + self.QAbstractListModel.setup + + proc newShowcasePreferencesGenericModel*(): ShowcasePreferencesGenericModel = + new(result, delete) + result.setup + + proc items*(self: ShowcasePreferencesGenericModel): seq[ShowcasePreferencesGenericItem] = + self.items + + method rowCount(self: ShowcasePreferencesGenericModel, index: QModelIndex = nil): int = + return self.items.len + + method roleNames(self: ShowcasePreferencesGenericModel): Table[int, string] = + { + ModelRole.ShowcaseKey.int: "showcaseKey", + ModelRole.ShowcaseVisibility.int: "showcaseVisibility", + ModelRole.ShowcasePosition.int: "showcasePosition", + }.toTable + + method data(self: ShowcasePreferencesGenericModel, 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.ShowcaseVisibility: + result = newQVariant(item.showcaseVisibility.int) + of ModelRole.ShowcasePosition: + result = newQVariant(item.showcasePosition) + + proc setItems*(self: ShowcasePreferencesGenericModel, items: seq[ShowcasePreferencesGenericItem]) = + self.beginResetModel() + self.items = items + self.endResetModel() + + proc clear*(self: ShowcasePreferencesGenericModel) {.slot.} = + self.setItems(@[]) diff --git a/src/app/modules/main/profile_section/profile/models/showcase_preferences_social_links_model.nim b/src/app/modules/main/profile_section/profile/models/showcase_preferences_social_links_model.nim new file mode 100644 index 0000000000..b6ecaa13ff --- /dev/null +++ b/src/app/modules/main/profile_section/profile/models/showcase_preferences_social_links_model.nim @@ -0,0 +1,70 @@ +import NimQml, tables, strutils, sequtils, json + +import app_service/service/profile/dto/profile_showcase_preferences + +type + ShowcasePreferencesSocialLinkItem* = object of RootObj + url*: string + text*: string + showcasePosition*: int + +type + ModelRole {.pure.} = enum + Url + Text + ShowcasePosition + +QtObject: + type + ShowcasePreferencesSocialLinkModel* = ref object of QAbstractListModel + items: seq[ShowcasePreferencesSocialLinkItem] + + proc delete(self: ShowcasePreferencesSocialLinkModel) = + self.items = @[] + self.QAbstractListModel.delete + + proc setup(self: ShowcasePreferencesSocialLinkModel) = + self.QAbstractListModel.setup + + proc newShowcasePreferencesSocialLinkModel*(): ShowcasePreferencesSocialLinkModel = + new(result, delete) + result.setup + + proc items*(self: ShowcasePreferencesSocialLinkModel): seq[ShowcasePreferencesSocialLinkItem] = + self.items + + method rowCount(self: ShowcasePreferencesSocialLinkModel, index: QModelIndex = nil): int = + return self.items.len + + method roleNames(self: ShowcasePreferencesSocialLinkModel): Table[int, string] = + { + ModelRole.Url.int: "url", + ModelRole.Text.int: "text", + ModelRole.ShowcasePosition.int: "showcasePosition", + }.toTable + + method data(self: ShowcasePreferencesSocialLinkModel, 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: ShowcasePreferencesSocialLinkModel, items: seq[ShowcasePreferencesSocialLinkItem]) = + self.beginResetModel() + self.items = items + self.endResetModel() + + proc clear*(self: ShowcasePreferencesSocialLinkModel) {.slot.} = + self.setItems(@[]) diff --git a/src/app/modules/main/profile_section/profile/models/showcase_save_data.nim b/src/app/modules/main/profile_section/profile/models/showcase_save_data.nim new file mode 100644 index 0000000000..85f8da9411 --- /dev/null +++ b/src/app/modules/main/profile_section/profile/models/showcase_save_data.nim @@ -0,0 +1,59 @@ +import json, strutils, sequtils + +include app_service/common/json_utils +include app_service/common/utils + +import app_service/service/profile/dto/profile_showcase_preferences + +type ShowcaseSaveEntry* = ref object of RootObj + showcaseKey*: string + showcaseVisibility*: ProfileShowcaseVisibility + showcasePosition*: int + +type ShowcaseSaveSocialLink* = ref object of RootObj + url*: string + text*: string + showcaseVisibility*: ProfileShowcaseVisibility + showcasePosition*: int + +type ShowcaseSaveData* = ref object of RootObj + communities*: seq[ShowcaseSaveEntry] + accounts*: seq[ShowcaseSaveEntry] + collectibles*: seq[ShowcaseSaveEntry] + assets*: seq[ShowcaseSaveEntry] + socialLinks*: seq[ShowcaseSaveSocialLink] + +proc toShowcaseSaveEntry*(jsonObj: JsonNode): ShowcaseSaveEntry = + result = ShowcaseSaveEntry() + discard jsonObj.getProp("showcaseKey", result.showcaseKey) + result.showcaseVisibility = jsonObj.toProfileShowcaseVisibility() + discard jsonObj.getProp("showcasePosition", result.showcasePosition) + +proc toShowcaseSaveEntries*(jsonObj: JsonNode, entry: string): seq[ShowcaseSaveEntry] = + var entries: seq[ShowcaseSaveEntry] = @[] + if jsonObj{entry} != nil and jsonObj{entry}.kind != JNull: + for jsonMsg in jsonObj{entry}: + entries.add(jsonMsg.toShowcaseSaveEntry()) + return entries + +proc toShowcaseSaveSocialLink*(jsonObj: JsonNode): ShowcaseSaveSocialLink = + result = ShowcaseSaveSocialLink() + discard jsonObj.getProp("url", result.url) + discard jsonObj.getProp("text", result.text) + result.showcaseVisibility = jsonObj.toProfileShowcaseVisibility() + discard jsonObj.getProp("showcasePosition", result.showcasePosition) + +proc toShowcaseSaveSocialLinks*(jsonObj: JsonNode): seq[ShowcaseSaveSocialLink] = + var socialLinks: seq[ShowcaseSaveSocialLink] = @[] + if jsonObj{"socialLinks"} != nil and jsonObj{"socialLinks"}.kind != JNull: + for jsonMsg in jsonObj{"socialLinks"}: + socialLinks.add(jsonMsg.toShowcaseSaveSocialLink()) + return socialLinks + +proc toShowcaseSaveData*(jsonObj: JsonNode): ShowcaseSaveData = + result = ShowcaseSaveData() + result.communities = toShowcaseSaveEntries(jsonObj, "communities") + result.accounts = toShowcaseSaveEntries(jsonObj, "accounts") + result.collectibles = toShowcaseSaveEntries(jsonObj, "collectibles") + result.assets = toShowcaseSaveEntries(jsonObj, "assets") + result.socialLinks = toShowcaseSaveSocialLinks(jsonObj) diff --git a/src/app/modules/main/profile_section/profile/module.nim b/src/app/modules/main/profile_section/profile/module.nim index 276ecda12e..b7adf065f4 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 +import NimQml, chronicles, sequtils, sugar, json, strutils import ./io_interface, ./view, ./controller import ../io_interface as delegate_interface @@ -20,11 +20,16 @@ import app/modules/shared_models/social_link_item import app/modules/shared_modules/collectibles/controller as collectiblesc import app/modules/shared_models/collectibles_entry +# 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/showcase_save_data + import backend/collectibles as backend_collectibles export io_interface @@ -123,6 +128,13 @@ method onSocialLinksUpdated*(self: Module, socialLinks: SocialLinks, error: stri return self.updateSocialLinks(socialLinks) +method getProfileShowcaseSocialLinksLimit*(self: Module): int = + return self.controller.getProfileShowcaseSocialLinksLimit() + +method getProfileShowcaseEntriesLimit*(self: Module): int = + return self.controller.getProfileShowcaseEntriesLimit() + +# TODO: remove old save api method storeProfileShowcasePreferences(self: Module, communities: seq[ProfileShowcaseCommunityItem], accounts: seq[ProfileShowcaseAccountItem], @@ -160,6 +172,75 @@ method storeProfileShowcasePreferences(self: Module, method setIsFirstShowcaseInteraction(self: Module) = singletonInstance.localAccountSettings.setIsFirstShowcaseInteraction(false) +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: + showcasePreferences.communities.add(ProfileShowcaseCommunityPreference( + communityId: showcaseCommunity.showcaseKey, + showcaseVisibility: showcaseCommunity.showcaseVisibility, + order: showcaseCommunity.showcasePosition + )) + + var revealedAddresses: seq[string] + for _, showcaseAccount in showcase.accounts: + showcasePreferences.accounts.add(ProfileShowcaseAccountPreference( + address: showcaseAccount.showcaseKey, + showcaseVisibility: showcaseAccount.showcaseVisibility, + order: showcaseAccount.showcasePosition + )) + + if showcaseAccount.showcaseVisibility != ProfileShowcaseVisibility.ToNoOne: + revealedAddresses.add(showcaseAccount.showcaseKey) + + for _, showcaseCollectible in showcase.collectibles: + let parts = showcaseCollectible.showcaseKey.split('+') + if len(parts) == 3: + showcasePreferences.collectibles.add(ProfileShowcaseCollectiblePreference( + chainId: parseInt(parts[0]), + contractAddress: parts[1], + tokenId: parts[2], + showcaseVisibility: showcaseCollectible.showcaseVisibility, + order: showcaseCollectible.showcasePosition + )) + else: + error "Wrong collectible combined id provided" + + for _, showcaseAsset in showcase.assets: + # TODO: less fragile way to split verified and unverified assets + if len(showcaseAsset.showcaseKey) == 3: + showcasePreferences.verifiedTokens.add(ProfileShowcaseVerifiedTokenPreference( + symbol: showcaseAsset.showcaseKey, + showcaseVisibility: showcaseAsset.showcaseVisibility, + order: showcaseAsset.showcasePosition + )) + else: + let parts = showcaseAsset.showcaseKey.split('+') + if len(parts) == 2: + showcasePreferences.unverifiedTokens.add(ProfileShowcaseUnverifiedTokenPreference( + chainId: parseInt(parts[0]), + contractAddress: parts[1], + showcaseVisibility: showcaseAsset.showcaseVisibility, + order: showcaseAsset.showcasePosition + )) + else: + error "Wrong unverified asset combined id provided" + + for _, showcaseSocialLink in showcase.socialLinks: + showcasePreferences.socialLinks.add(ProfileShowcaseSocialLinkPreference( + text: showcaseSocialLink.text, + url: showcaseSocialLink.url, + showcaseVisibility: showcaseSocialLink.showcaseVisibility, + order: showcaseSocialLink.showcasePosition + )) + + self.controller.storeProfileShowcasePreferences(showcasePreferences, revealedAddresses) + method requestProfileShowcasePreferences(self: Module) = let myPublicKey = singletonInstance.userProfile.getPubKey() if self.presentedPublicKey != myPublicKey: @@ -241,6 +322,58 @@ method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowca if self.presentedPublicKey != singletonInstance.userProfile.getPubKey(): return + var communityItems: seq[ShowcasePreferencesGenericItem] = @[] + for community in preferences.communities: + communityItems.add(ShowcasePreferencesGenericItem( + showcaseKey: community.communityId, + showcaseVisibility: community.showcaseVisibility, + showcasePosition: community.order + )) + self.view.updateProfileShowcasePreferencesCommunities(communityItems) + + var accountItems: seq[ShowcasePreferencesGenericItem] = @[] + for account in preferences.accounts: + accountItems.add(ShowcasePreferencesGenericItem( + showcaseKey: account.address, + showcaseVisibility: account.showcaseVisibility, + showcasePosition: account.order + )) + self.view.updateProfileShowcasePreferencesAccounts(accountItems) + + var collectibleItems: seq[ShowcasePreferencesGenericItem] = @[] + for collectible in preferences.collectibles: + collectibleItems.add(ShowcasePreferencesGenericItem( + showcaseKey: collectible.toCombinedCollectibleId(), + showcaseVisibility: collectible.showcaseVisibility, + showcasePosition: collectible.order + )) + self.view.updateProfileShowcasePreferencesCollectibles(collectibleItems) + + var assetItems: seq[ShowcasePreferencesGenericItem] = @[] + for token in preferences.verifiedTokens: + assetItems.add(ShowcasePreferencesGenericItem( + showcaseKey: token.symbol, + showcaseVisibility: token.showcaseVisibility, + showcasePosition: token.order + )) + for token in preferences.unverifiedTokens: + assetItems.add(ShowcasePreferencesGenericItem( + showcaseKey: token.toCombinedTokenId(), + showcaseVisibility: token.showcaseVisibility, + showcasePosition: token.order + )) + self.view.updateProfileShowcasePreferencesAssets(assetItems) + + var socialLinkItems: seq[ShowcasePreferencesSocialLinkItem] = @[] + for socialLink in preferences.socialLinks: + socialLinkItems.add(ShowcasePreferencesSocialLinkItem( + url: socialLink.url, + 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) @@ -257,10 +390,15 @@ method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowca # Accounts profile preferences var profileAccountItems: seq[ProfileShowcaseAccountItem] = @[] - for account in preferences.accounts: + 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, - account.showcaseVisibility, account.order)) + preference.showcaseVisibility, preference.order)) self.view.updateProfileShowcaseAccounts(profileAccountItems) # Collectibles profile preferences @@ -275,14 +413,11 @@ method updateProfileShowcasePreferences(self: Module, preferences: ProfileShowca collectible, collectibleProfile.showcaseVisibility, collectibleProfile.order)) self.view.updateProfileShowcaseCollectibles(profileCollectibleItems) - # TODO: Verified tokens preferences var profileAssetItems: seq[ProfileShowcaseAssetItem] = @[] for tokenProfile in preferences.verifiedTokens: for token in self.controller.getTokenBySymbolList(): if tokenProfile.symbol == token.symbol: profileAssetItems.add(initProfileShowcaseVerifiedToken(token, tokenProfile.showcaseVisibility, tokenProfile.order)) - - # TODO: Unverified tokens preferences self.view.updateProfileShowcaseAssets(profileAssetItems) method onCommunitiesUpdated*(self: Module, communities: seq[CommunityDto]) = diff --git a/src/app/modules/main/profile_section/profile/view.nim b/src/app/modules/main/profile_section/profile/view.nim index 85f36968cc..06248820c4 100644 --- a/src/app/modules/main/profile_section/profile/view.nim +++ b/src/app/modules/main/profile_section/profile/view.nim @@ -4,6 +4,7 @@ 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 @@ -13,10 +14,15 @@ import models/profile_preferences_collectible_item import models/profile_preferences_assets_model import models/profile_preferences_asset_item +import models/showcase_save_data +import models/showcase_preferences_generic_model +import models/showcase_preferences_social_links_model + QtObject: type View* = ref object of QObject delegate: io_interface.AccessInterface + # TODO: remove old models socialLinksModel: SocialLinksModel socialLinksModelVariant: QVariant temporarySocialLinksModel: SocialLinksModel # used for editing purposes @@ -30,8 +36,20 @@ QtObject: profileShowcaseAssetsModel: ProfileShowcaseAssetsModel profileShowcaseAssetsModelVariant: QVariant + showcasePreferencesCommunitiesModel: ShowcasePreferencesGenericModel + showcasePreferencesCommunitiesModelVariant: QVariant + showcasePreferencesAccountsModel: ShowcasePreferencesGenericModel + showcasePreferencesAccountsModelVariant: QVariant + showcasePreferencesCollectiblesModel: ShowcasePreferencesGenericModel + showcasePreferencesCollectiblesModelVariant: QVariant + showcasePreferencesAssetsModel: ShowcasePreferencesGenericModel + showcasePreferencesAssetsModelVariant: QVariant + showcasePreferencesSocialLinksModel: ShowcasePreferencesSocialLinkModel + showcasePreferencesSocialLinksModelVariant: QVariant + proc delete*(self: View) = self.QObject.delete + # TODO: remove old models self.socialLinksModel.delete self.socialLinksModelVariant.delete self.temporarySocialLinksModel.delete @@ -45,10 +63,22 @@ QtObject: self.profileShowcaseAssetsModel.delete self.profileShowcaseAssetsModelVariant.delete + self.showcasePreferencesCommunitiesModel.delete + self.showcasePreferencesCommunitiesModelVariant.delete + self.showcasePreferencesAccountsModel.delete + self.showcasePreferencesAccountsModelVariant.delete + self.showcasePreferencesCollectiblesModel.delete + self.showcasePreferencesCollectiblesModelVariant.delete + self.showcasePreferencesAssetsModel.delete + self.showcasePreferencesAssetsModelVariant.delete + self.showcasePreferencesSocialLinksModel.delete + self.showcasePreferencesSocialLinksModelVariant.delete + proc newView*(delegate: io_interface.AccessInterface): View = new(result, delete) result.QObject.setup result.delegate = delegate + # TODO: remove old models result.socialLinksModel = newSocialLinksModel() result.socialLinksModelVariant = newQVariant(result.socialLinksModel) result.temporarySocialLinksModel = newSocialLinksModel() @@ -62,6 +92,17 @@ QtObject: result.profileShowcaseAssetsModel = newProfileShowcaseAssetsModel() result.profileShowcaseAssetsModelVariant = newQVariant(result.profileShowcaseAssetsModel) + result.showcasePreferencesCommunitiesModel = newShowcasePreferencesGenericModel() + result.showcasePreferencesCommunitiesModelVariant = newQVariant(result.showcasePreferencesCommunitiesModel) + result.showcasePreferencesAccountsModel = newShowcasePreferencesGenericModel() + result.showcasePreferencesAccountsModelVariant = newQVariant(result.showcasePreferencesAccountsModel) + result.showcasePreferencesCollectiblesModel = newShowcasePreferencesGenericModel() + result.showcasePreferencesCollectiblesModelVariant = newQVariant(result.showcasePreferencesCollectiblesModel) + result.showcasePreferencesAssetsModel = newShowcasePreferencesGenericModel() + result.showcasePreferencesAssetsModelVariant = newQVariant(result.showcasePreferencesAssetsModel) + result.showcasePreferencesSocialLinksModel = newShowcasePreferencesSocialLinkModel() + result.showcasePreferencesSocialLinksModelVariant = newQVariant(result.showcasePreferencesSocialLinksModel) + proc load*(self: View) = self.delegate.viewDidLoad() @@ -174,6 +215,7 @@ QtObject: proc emitBioChangedSignal*(self: View) = self.bioChanged() + # TODO: remove old models proc getCollectiblesModel(self: View): QVariant {.slot.} = return self.delegate.getCollectiblesModel() @@ -204,6 +246,37 @@ QtObject: QtProperty[QVariant] profileShowcaseAssetsModel: read = getProfileShowcaseAssetsModel + proc getProfileShowcasePreferencesCommunitiesModel(self: View): QVariant {.slot.} = + return self.showcasePreferencesCommunitiesModelVariant + + QtProperty[QVariant] showcasePreferencesCommunitiesModel: + read = getProfileShowcasePreferencesCommunitiesModel + + proc getProfileShowcasePreferencesAccountsModel(self: View): QVariant {.slot.} = + return self.showcasePreferencesAccountsModelVariant + + QtProperty[QVariant] showcasePreferencesAccountsModel: + read = getProfileShowcasePreferencesAccountsModel + + proc getProfileShowcasePreferencesCollectiblesModel(self: View): QVariant {.slot.} = + return self.showcasePreferencesCollectiblesModelVariant + + QtProperty[QVariant] showcasePreferencesCollectiblesModel: + read = getProfileShowcasePreferencesCollectiblesModel + + proc getProfileShowcasePreferencesAssetsModel(self: View): QVariant {.slot.} = + return self.showcasePreferencesAssetsModelVariant + + QtProperty[QVariant] showcasePreferencesAssetsModel: + read = getProfileShowcasePreferencesAssetsModel + + proc getProfileShowcasePreferencesSocialLinksModel(self: View): QVariant {.slot.} = + return self.showcasePreferencesSocialLinksModelVariant + + QtProperty[QVariant] showcasePreferencesSocialLinksModel: + read = getProfileShowcasePreferencesSocialLinksModel + + # TODO: remove old save preferences api proc storeProfileShowcasePreferences(self: View) {.slot.} = let communities = self.profileShowcaseCommunitiesModel.items() let accounts = self.profileShowcaseAccountsModel.items() @@ -218,6 +291,17 @@ QtObject: self.profileShowcaseCollectiblesModel.clear() self.profileShowcaseAssetsModel.clear() + proc saveProfileShowcasePreferences(self: View, profileData: string) {.slot.} = + let profileDataObj = profileData.parseJson + let showcase = profileDataObj.toShowcaseSaveData() + self.delegate.saveProfileShowcasePreferences(showcase) + + proc getProfileShowcaseSocialLinksLimit*(self: View): int {.slot.} = + self.delegate.getProfileShowcaseSocialLinksLimit() + + proc getProfileShowcaseEntriesLimit*(self: View): int {.slot.} = + self.delegate.getProfileShowcaseEntriesLimit() + proc requestProfileShowcase(self: View, publicKey: string) {.slot.} = self.delegate.requestProfileShowcase(publicKey) @@ -230,6 +314,22 @@ QtObject: proc getProfileShowcaseCommunities*(self: View): seq[ProfileShowcaseCommunityItem] = return self.profileShowcaseCommunitiesModel.items() + proc updateProfileShowcasePreferencesCommunities*(self: View, items: seq[ShowcasePreferencesGenericItem]) = + self.showcasePreferencesCommunitiesModel.setItems(items) + + proc updateProfileShowcasePreferencesAccounts*(self: View, items: seq[ShowcasePreferencesGenericItem]) = + self.showcasePreferencesAccountsModel.setItems(items) + + proc updateProfileShowcasePreferencesCollectibles*(self: View, items: seq[ShowcasePreferencesGenericItem]) = + self.showcasePreferencesCollectiblesModel.setItems(items) + + proc updateProfileShowcasePreferencesAssets*(self: View, items: seq[ShowcasePreferencesGenericItem]) = + self.showcasePreferencesAssetsModel.setItems(items) + + proc updateProfileShowcasePreferencesSocialLinks*(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)) @@ -247,4 +347,4 @@ QtObject: proc profileShowcaseAccountsByAddressFetched*(self: View, accounts: string) {.signal.} proc emitProfileShowcaseAccountsByAddressFetchedSignal*(self: View, accounts: string) = - self.profileShowcaseAccountsByAddressFetched(accounts) \ No newline at end of file + self.profileShowcaseAccountsByAddressFetched(accounts) diff --git a/src/app_service/service/profile/async_tasks.nim b/src/app_service/service/profile/async_tasks.nim index 8af475a575..9b0902d64b 100644 --- a/src/app_service/service/profile/async_tasks.nim +++ b/src/app_service/service/profile/async_tasks.nim @@ -54,4 +54,21 @@ const fetchProfileShowcaseAccountsTask: Task = proc(argEncoded: string) {.gcsafe response["response"] = rpcResponse.result except Exception as e: response["error"] = %* e.msg - arg.finish(response) \ No newline at end of file + arg.finish(response) + +type + SaveProfileShowcasePreferencesTaskArg = ref object of QObjectTaskArg + preferences: ProfileShowcasePreferencesDto + +const saveProfileShowcasePreferencesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[SaveProfileShowcasePreferencesTaskArg](argEncoded) + try: + let response = status_accounts.setProfileShowcasePreferences(arg.preferences.toJsonNode()) + arg.finish(%* { + "response": response, + "error": nil, + }) + except Exception as e: + arg.finish(%* { + "error": e.msg, + }) diff --git a/src/app_service/service/profile/dto/profile_showcase.nim b/src/app_service/service/profile/dto/profile_showcase.nim index 869ccc93fd..63fc53f769 100644 --- a/src/app_service/service/profile/dto/profile_showcase.nim +++ b/src/app_service/service/profile/dto/profile_showcase.nim @@ -18,8 +18,6 @@ type ProfileShowcaseCollectible* = ref object of RootObj contractAddress*: string chainId*: int tokenId*: string - communityId*: string - accountAddress*: string order*: int type ProfileShowcaseVerifiedToken* = ref object of RootObj @@ -31,6 +29,11 @@ type ProfileShowcaseUnverifiedToken* = ref object of RootObj chainId*: int order*: int +type ProfileShowcaseSocialLink* = ref object of RootObj + text*: string + url*: string + order*: int + type ProfileShowcaseDto* = ref object of RootObj contactId*: string communities*: seq[ProfileShowcaseCommunity] @@ -38,6 +41,7 @@ type ProfileShowcaseDto* = ref object of RootObj collectibles*: seq[ProfileShowcaseCollectible] verifiedTokens*: seq[ProfileShowcaseVerifiedToken] unverifiedTokens*: seq[ProfileShowcaseUnverifiedToken] + socialLinks*: seq[ProfileShowcaseSocialLink] proc toProfileShowcaseCommunity*(jsonObj: JsonNode): ProfileShowcaseCommunity = result = ProfileShowcaseCommunity() @@ -58,8 +62,6 @@ proc toProfileShowcaseCollectible*(jsonObj: JsonNode): ProfileShowcaseCollectibl discard jsonObj.getProp("chainId", result.chainId) discard jsonObj.getProp("tokenId", result.tokenId) discard jsonObj.getProp("contractAddress", result.contractAddress) - discard jsonObj.getProp("communityId", result.communityId) - discard jsonObj.getProp("accountAddress", result.accountAddress) discard jsonObj.getProp("order", result.order) proc toProfileShowcaseVerifiedToken*(jsonObj: JsonNode): ProfileShowcaseVerifiedToken = @@ -73,6 +75,12 @@ proc toProfileShowcaseUnverifiedToken*(jsonObj: JsonNode): ProfileShowcaseUnveri discard jsonObj.getProp("chainId", result.chainId) discard jsonObj.getProp("order", result.order) +proc toProfileShowcaseSocialLink*(jsonObj: JsonNode): ProfileShowcaseSocialLink = + result = ProfileShowcaseSocialLink() + discard jsonObj.getProp("text", result.text) + discard jsonObj.getProp("url", result.url) + discard jsonObj.getProp("order", result.order) + proc toProfileShowcaseDto*(jsonObj: JsonNode): ProfileShowcaseDto = result = ProfileShowcaseDto() @@ -93,6 +101,9 @@ proc toProfileShowcaseDto*(jsonObj: JsonNode): ProfileShowcaseDto = if jsonObj["unverifiedTokens"].kind != JNull: for jsonMsg in jsonObj["unverifiedTokens"]: result.unverifiedTokens.add(jsonMsg.toProfileShowcaseUnverifiedToken()) + if jsonObj["socialLinks"].kind != JNull: + for jsonMsg in jsonObj["socialLinks"]: + result.socialLinks.add(jsonMsg.toProfileShowcaseSocialLink()) proc `%`*(x: ProfileShowcaseAccount): JsonNode = result = newJobject() diff --git a/src/app_service/service/profile/dto/profile_showcase_preferences.nim b/src/app_service/service/profile/dto/profile_showcase_preferences.nim index 3be0181c4f..1ed365c0bc 100644 --- a/src/app_service/service/profile/dto/profile_showcase_preferences.nim +++ b/src/app_service/service/profile/dto/profile_showcase_preferences.nim @@ -1,4 +1,4 @@ -import json, strutils, stint, sequtils, json_serialization +import json, strutils, strformat, stint, sequtils, json_serialization include ../../../common/json_utils include ../../../common/utils @@ -16,9 +16,6 @@ type ProfileShowcaseCommunityPreference* = ref object of RootObj type ProfileShowcaseAccountPreference* = ref object of RootObj address*: string - name*: string - colorId*: string - emoji*: string showcaseVisibility*: ProfileShowcaseVisibility order*: int @@ -26,8 +23,6 @@ type ProfileShowcaseCollectiblePreference* = ref object of RootObj contractAddress*: string chainId*: int tokenId*: string - communityId*: string - accountAddress*: string showcaseVisibility*: ProfileShowcaseVisibility order*: int @@ -42,12 +37,19 @@ type ProfileShowcaseUnverifiedTokenPreference* = ref object of RootObj showcaseVisibility*: ProfileShowcaseVisibility order*: int +type ProfileShowcaseSocialLinkPreference* = ref object of RootObj + url*: string + text*: string + showcaseVisibility*: ProfileShowcaseVisibility + order*: int + type ProfileShowcasePreferencesDto* = ref object of RootObj communities*: seq[ProfileShowcaseCommunityPreference] accounts*: seq[ProfileShowcaseAccountPreference] collectibles*: seq[ProfileShowcaseCollectiblePreference] verifiedTokens*: seq[ProfileShowcaseVerifiedTokenPreference] unverifiedTokens*: seq[ProfileShowcaseUnverifiedTokenPreference] + socialLinks*: seq[ProfileShowcaseSocialLinkPreference] proc toProfileShowcaseVisibility*(jsonObj: JsonNode): ProfileShowcaseVisibility = var visibilityInt: int @@ -73,18 +75,12 @@ proc toJsonNode*(self: ProfileShowcaseCommunityPreference): JsonNode = proc toProfileShowcaseAccountPreference*(jsonObj: JsonNode): ProfileShowcaseAccountPreference = result = ProfileShowcaseAccountPreference() discard jsonObj.getProp("address", result.address) - discard jsonObj.getProp("name", result.name) - discard jsonObj.getProp("colorId", result.colorId) - discard jsonObj.getProp("emoji", result.emoji) discard jsonObj.getProp("order", result.order) result.showcaseVisibility = jsonObj.toProfileShowcaseVisibility() proc toJsonNode*(self: ProfileShowcaseAccountPreference): JsonNode = %* { "address": self.address, - "name": self.name, - "colorId": self.colorId, - "emoji": self.emoji, "showcaseVisibility": self.showcaseVisibility.int, "order": self.order, } @@ -94,8 +90,6 @@ proc toProfileShowcaseCollectiblePreference*(jsonObj: JsonNode): ProfileShowcase discard jsonObj.getProp("chainId", result.chainId) discard jsonObj.getProp("tokenId", result.tokenId) discard jsonObj.getProp("contractAddress", result.contractAddress) - discard jsonObj.getProp("communityId", result.communityId) - discard jsonObj.getProp("accountAddress", result.accountAddress) discard jsonObj.getProp("order", result.order) result.showcaseVisibility = jsonObj.toProfileShowcaseVisibility() @@ -104,12 +98,14 @@ proc toJsonNode*(self: ProfileShowcaseCollectiblePreference): JsonNode = "chainId": self.chainId, "tokenId": self.tokenId, "contractAddress": self.contractAddress, - "communityId": self.communityId, - "accountAddress": self.accountAddress, "showcaseVisibility": self.showcaseVisibility.int, "order": self.order, } +# TODO: refactor to utils function on code cleanup stage +proc toCombinedCollectibleId*(self: ProfileShowcaseCollectiblePreference): string = + return fmt"{self.chainId}+{self.contractAddress}+{self.tokenId}" + proc toProfileShowcaseVerifiedTokenPreference*(jsonObj: JsonNode): ProfileShowcaseVerifiedTokenPreference = result = ProfileShowcaseVerifiedTokenPreference() discard jsonObj.getProp("symbol", result.symbol) @@ -138,6 +134,24 @@ proc toJsonNode*(self: ProfileShowcaseUnverifiedTokenPreference): JsonNode = "order": self.order, } +proc toCombinedTokenId*(self: ProfileShowcaseUnverifiedTokenPreference): string = + return fmt"{self.chainId}+{self.contractAddress}" + +proc toProfileShowcaseSocialLinkPreference*(jsonObj: JsonNode): ProfileShowcaseSocialLinkPreference = + result = ProfileShowcaseSocialLinkPreference() + discard jsonObj.getProp("text", result.text) + discard jsonObj.getProp("url", result.url) + discard jsonObj.getProp("order", result.order) + result.showcaseVisibility = jsonObj.toProfileShowcaseVisibility() + +proc toJsonNode*(self: ProfileShowcaseSocialLinkPreference): JsonNode = + %* { + "text": self.text, + "url": self.url, + "showcaseVisibility": self.showcaseVisibility.int, + "order": self.order, + } + proc toProfileShowcasePreferencesDto*(jsonObj: JsonNode): ProfileShowcasePreferencesDto = result = ProfileShowcasePreferencesDto() @@ -156,6 +170,9 @@ proc toProfileShowcasePreferencesDto*(jsonObj: JsonNode): ProfileShowcasePrefere if jsonObj["unverifiedTokens"].kind != JNull: for jsonMsg in jsonObj["unverifiedTokens"]: result.unverifiedTokens.add(jsonMsg.toProfileShowcaseUnverifiedTokenPreference()) + if jsonObj["socialLinks"].kind != JNull: + for jsonMsg in jsonObj["socialLinks"]: + result.socialLinks.add(jsonMsg.toProfileShowcaseSocialLinkPreference()) proc toJsonNode*(self: ProfileShowcasePreferencesDto): JsonNode = let communities = self.communities.map(entry => entry.toJsonNode()) @@ -163,11 +180,13 @@ proc toJsonNode*(self: ProfileShowcasePreferencesDto): JsonNode = let collectibles = self.collectibles.map(entry => entry.toJsonNode()) let verifiedTokens = self.verifiedTokens.map(entry => entry.toJsonNode()) let unverifiedTokens = self.unverifiedTokens.map(entry => entry.toJsonNode()) + let socialLinks = self.socialLinks.map(entry => entry.toJsonNode()) return %*[{ "communities": communities, "accounts": accounts, "collectibles": collectibles, "verifiedTokens": verifiedTokens, - "unverifiedTokens": unverifiedTokens + "unverifiedTokens": unverifiedTokens, + "socialLinks": socialLinks }] diff --git a/src/app_service/service/profile/service.nim b/src/app_service/service/profile/service.nim index 78a658d633..d0f08ab800 100644 --- a/src/app_service/service/profile/service.nim +++ b/src/app_service/service/profile/service.nim @@ -96,7 +96,7 @@ QtObject: proc setDisplayName*(self: Service, displayName: string) = try: - let response = status_accounts.setDisplayName(displayName) + let response = status_accounts.setDisplayName(displayName) if(not response.error.isNil): error "could not set display name" return @@ -178,10 +178,38 @@ QtObject: except Exception as e: error "Error requesting profile showcase preferences", msg = e.msg - proc setProfileShowcasePreferences*(self: Service, preferences: ProfileShowcasePreferencesDto) = + proc saveProfileShowcasePreferences*(self: Service, preferences: ProfileShowcasePreferencesDto) = + let arg = SaveProfileShowcasePreferencesTaskArg( + preferences: preferences, + tptr: cast[ByteAddress](saveProfileShowcasePreferencesTask), + vptr: cast[ByteAddress](self.vptr), + slot: "asyncProfileShowcasePreferencesSaved", + ) + self.threadpool.start(arg) + + proc asyncProfileShowcasePreferencesSaved*(self: Service, rpcResponse: string) {.slot.} = try: - let response = status_accounts.setProfileShowcasePreferences(preferences.toJsonNode()) - if not response.error.isNil: - error "error saving profile showcase preferences" + let rpcResponseObj = rpcResponse.parseJson + if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "": + error "Error saving profile showcase preferences", msg = rpcResponseObj{"error"} + return except Exception as e: - error "error: ", procName="setProfileShowcasePreferences", errName = e.name, errDesription = e.msg + error "Error saving profile showcase preferences", msg = e.msg + + proc getProfileShowcaseSocialLinksLimit*(self: Service): int = + try: + let response = status_accounts.getProfileShowcaseSocialLinksLimit() + + if response.result.kind != JNull: + return response.result.getInt + except Exception as e: + error "Error getting unseen activity center notifications", msg = e.msg + + proc getProfileShowcaseEntriesLimit*(self: Service): int = + try: + let response = status_accounts.getProfileShowcaseEntriesLimit() + + if response.result.kind != JNull: + return response.result.getInt + except Exception as e: + error "Error getting unseen activity center notifications", msg = e.msg \ No newline at end of file diff --git a/src/backend/accounts.nim b/src/backend/accounts.nim index 1ffc8c2aa3..4c75ab26d0 100644 --- a/src/backend/accounts.nim +++ b/src/backend/accounts.nim @@ -488,6 +488,14 @@ proc getProfileShowcasePreferences*(): RpcResponse[JsonNode] {.raises: [Exceptio proc setProfileShowcasePreferences*(preferences: JsonNode): RpcResponse[JsonNode] {.raises: [Exception].} = result = callPrivateRPC("setProfileShowcasePreferences".prefix, preferences) +proc getProfileShowcaseSocialLinksLimit*(): RpcResponse[JsonNode] {.raises: [Exception].} = + let payload = %* [] + result = callPrivateRPC("getProfileShowcaseSocialLinksLimit".prefix, payload) + +proc getProfileShowcaseEntriesLimit*(): RpcResponse[JsonNode] {.raises: [Exception].} = + let payload = %* [] + result = callPrivateRPC("getProfileShowcaseEntriesLimit".prefix, payload) + proc addressWasShown*(address: string): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* [address] return core.callPrivateRPC("accounts_addressWasShown", payload) \ No newline at end of file diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml index f794f07695..bef8be27e3 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseDirtyState.qml @@ -49,20 +49,9 @@ QObject { } function currentState() { - if (visibleModel.synced) { + if (visible.synced) { return writable.currentState() } - const newOrder = visible.order() - let writableIndexes = [] - - for (var i = 0; i < newOrder.length; i++) { - writableIndexes.push(visibleSFPM.mapFromSource(newOrder[i])) - } - - for (var i = 0; i < newOrder.length; i++) { - writable.set(writableIndexes[i], { "showcasePosition": i}) - } - return writable.currentState() } @@ -72,6 +61,18 @@ QObject { function changePosition(from, to) { visible.move(from, to) + + // Sync writable with movable new positions: + const newOrder = visible.order() + let writableIndexes = [] + + for (var i = 0; i < newOrder.length; i++) { + writableIndexes.push(visibleSFPM.mapToSource(newOrder[i])) + } + + for (var j = 0; j < newOrder.length; j++) { + writable.set(writableIndexes[j], { "showcasePosition": j}) + } } // internals, debug purpose only diff --git a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml index 38f28a3568..52f5d89887 100644 --- a/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml +++ b/ui/app/AppLayouts/Profile/helpers/ProfileShowcaseModels.qml @@ -98,6 +98,17 @@ QObject { collectibles.changePosition(from, to) } + // The complete preferences models json current state: + function buildJSONModelsCurrentState() { + return JSON.stringify({ + "communities": communitiesCurrentState(), + "accounts": accountsCurrentState(), + "collectibles": collectiblesCurrentState() + // TODO: Assets --> Issue #13492 + // TODO: Web --> Issue #13495 + }) + } + ProfileShowcaseModelAdapter { id: modelAdapter } diff --git a/ui/app/AppLayouts/Profile/panels/ProfileShowcasePanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileShowcasePanel.qml index f0f309450a..34562b5c1a 100644 --- a/ui/app/AppLayouts/Profile/panels/ProfileShowcasePanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ProfileShowcasePanel.qml @@ -35,7 +35,7 @@ DoubleFlickableWithFolding { property string emptyHiddenPlaceholderText property string emptySearchPlaceholderText - property int showcaseLimit: ProfileUtils.showcaseLimit + property int showcaseLimit: 100 // Searcher related properties: property string searchPlaceholderText diff --git a/ui/app/AppLayouts/Profile/panels/ProfileSocialLinksPanel.qml b/ui/app/AppLayouts/Profile/panels/ProfileSocialLinksPanel.qml index faa5b75065..6895c36cc2 100644 --- a/ui/app/AppLayouts/Profile/panels/ProfileSocialLinksPanel.qml +++ b/ui/app/AppLayouts/Profile/panels/ProfileSocialLinksPanel.qml @@ -20,6 +20,7 @@ Control { property var profileStore property var socialLinksModel + property int showcaseLimit: 20 background: null @@ -53,7 +54,7 @@ Control { } Item { Layout.fillWidth: true } StatusBaseText { - text: qsTr("%1 / %2").arg(root.profileStore.temporarySocialLinksModel.count).arg(Constants.maxNumOfSocialLinks) + text: qsTr("%1 / %2").arg(root.profileStore.temporarySocialLinksModel.count).arg(root.showcaseLimit) color: Theme.palette.baseColor1 font.pixelSize: Theme.tertiaryTextFontSize } @@ -61,13 +62,13 @@ Control { // empty placeholder when no links; dashed rounded rectangle ShapeRectangle { - readonly property bool maxReached: root.profileStore.temporarySocialLinksModel.count === Constants.maxNumOfSocialLinks + readonly property bool maxReached: root.profileStore.temporarySocialLinksModel.count === root.showcaseLimit Layout.alignment: Qt.AlignHCenter Layout.preferredWidth: parent.width - 4 // the rectangular path is rendered outside Layout.preferredHeight: 48 - text: maxReached ? qsTr("Link limit of %1 reached").arg(Constants.maxNumOfSocialLinks) : "" + text: maxReached ? qsTr("Link limit of %1 reached").arg(root.showcaseLimit) : "" path.strokeColor: maxReached ? "transparent" : Theme.palette.baseColor2 path.fillColor: maxReached ? Theme.palette.baseColor4 : "transparent" font.pixelSize: Theme.tertiaryTextFontSize diff --git a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml index 3222cba9be..ff441e8f66 100644 --- a/ui/app/AppLayouts/Profile/stores/ProfileStore.qml +++ b/ui/app/AppLayouts/Profile/stores/ProfileStore.qml @@ -31,10 +31,18 @@ QtObject { 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 onUserDeclinedBackupBannerChanged: { @@ -45,14 +53,6 @@ QtObject { property var details: Utils.getContactDetailsAsJson(pubkey) - function uploadImage(source, aX, aY, bX, bY) { - return root.profileModule.upload(source, aX, aY, bX, bY) - } - - function removeImage() { - return root.profileModule.remove() - } - function getQrCodeSource(text) { return globalUtils.qrCode(text) } @@ -61,10 +61,64 @@ QtObject { globalUtils.copyToClipboard(value) } - function setDisplayName(displayName) { + // Identity related: + function saveIdentityInfo(displayName, bio, source, aX, aY, bX, bY) { + // TODO: Update according to issue #13767 + _setDisplayName(displayName) + _setBio(bio) + if(source) + _uploadImage(source, aX, aY, bX, bY) + else + _removeImage() + } + + function _setDisplayName(displayName) { root.profileModule.setDisplayName(displayName) } + function _setBio(bio) { + root.profileModule.setBio(bio) + } + + function _uploadImage(source, aX, aY, bX, bY) { + return root.profileModule.upload(source, aX, aY, bX, bY) + } + + function _removeImage() { + return root.profileModule.remove() + } + + // Preferences (Accounts, Communities, Collectibles, Assets and social links): + // TO BE REMOVED: Deprecated --> Issue #13688 + function storeProfileShowcasePreferences() { + root.profileModule.storeProfileShowcasePreferences() + } + + function getProfileShowcaseEntriesLimit() { + return root.profileModule.getProfileShowcaseEntriesLimit() + } + + function getProfileShowcaseSocialLinksLimit() { + return root.profileModule.getProfileShowcaseSocialLinksLimit() + } + + function saveProfileShowcasePreferences(json) { + root.profileModule.saveProfileShowcasePreferences(json) + } + + function requestProfileShowcasePreferences() { + root.profileModule.requestProfileShowcasePreferences() + } + + function requestProfileShowcase(publicKey) { + root.profileModule.requestProfileShowcase(publicKey) + } + + function setIsFirstShowcaseInteraction() { + root.profileModule.setIsFirstShowcaseInteraction() + } + + // Social links related: All to be removed: Deprecated --> Issue #13688 function containsSocialLink(text, url) { return root.profileModule.containsSocialLink(text, url) } @@ -92,24 +146,5 @@ QtObject { function saveSocialLinks(silent = false) { root.profileModule.saveSocialLinks(silent) } - - function setBio(bio) { - root.profileModule.setBio(bio) - } - - function storeProfileShowcasePreferences() { - root.profileModule.storeProfileShowcasePreferences() - } - - function requestProfileShowcasePreferences() { - root.profileModule.requestProfileShowcasePreferences() - } - - function requestProfileShowcase(publicKey) { - root.profileModule.requestProfileShowcase(publicKey) - } - - function setIsFirstShowcaseInteraction() { - root.profileModule.setIsFirstShowcaseInteraction() - } + // End of social links to be removed } diff --git a/ui/app/AppLayouts/Profile/views/MyProfileView.qml b/ui/app/AppLayouts/Profile/views/MyProfileView.qml index 4d78509baf..9027bfd452 100644 --- a/ui/app/AppLayouts/Profile/views/MyProfileView.qml +++ b/ui/app/AppLayouts/Profile/views/MyProfileView.qml @@ -61,11 +61,7 @@ SettingsContentBase { visible: !root.sideBySidePreview } - dirty: (!descriptionPanel.isEnsName && - descriptionPanel.displayName.text !== profileStore.displayName) || - descriptionPanel.bio.text !== profileStore.bio || - profileStore.socialLinksDirty || - profileHeader.icon !== profileStore.profileLargeImage || + dirty: priv.isIdentityTabDirty || priv.hasAnyProfileShowcaseChanges saveChangesButtonEnabled: !!descriptionPanel.displayName.text && descriptionPanel.displayName.valid @@ -126,6 +122,11 @@ SettingsContentBase { id: priv property bool hasAnyProfileShowcaseChanges: showcaseModels.dirty + property bool isIdentityTabDirty: (!descriptionPanel.isEnsName && + descriptionPanel.displayName.text !== profileStore.displayName) || + descriptionPanel.bio.text !== profileStore.bio || + profileStore.socialLinksDirty || + profileHeader.icon !== profileStore.profileLargeImage property ProfileShowcaseModels showcaseModels: ProfileShowcaseModels { communitiesSourceModel: root.communitiesModel @@ -152,10 +153,20 @@ SettingsContentBase { } function save() { + // Accounts, Communities, Assets, Collectibles and social links info if (hasAnyProfileShowcaseChanges) - print ("Profile showcase changes detected: SAVING") - //TODO: implement save as deschibed here - // https://github.com/status-im/status-desktop/pull/13708 + root.profileStore.saveProfileShowcasePreferences(showcaseModels.buildJSONModelsCurrentState()) + + // Identity info + if(isIdentityTabDirty) + root.profileStore.saveIdentityInfo(descriptionPanel.displayName.text, + descriptionPanel.bio.text.trim(), + profileHeader.icon, + profileHeader.cropRect.x.toFixed(), + profileHeader.cropRect.y.toFixed(), + (profileHeader.cropRect.x + profileHeader.cropRect.width).toFixed(), + (profileHeader.cropRect.y + profileHeader.cropRect.height).toFixed()) + reset() } } @@ -216,6 +227,7 @@ SettingsContentBase { id: profileShowcaseCommunitiesPanel inShowcaseModel: priv.showcaseModels.communitiesVisibleModel hiddenModel: priv.showcaseModels.communitiesHiddenModel + showcaseLimit: root.profileStore.getProfileShowcaseEntriesLimit() onChangePositionRequested: function (from, to) { priv.showcaseModels.changeCommunityPosition(from, to) @@ -230,6 +242,7 @@ SettingsContentBase { id: profileShowcaseAccountsPanel inShowcaseModel: priv.showcaseModels.accountsVisibleModel hiddenModel: priv.showcaseModels.accountsHiddenModel + showcaseLimit: root.profileStore.getProfileShowcaseEntriesLimit() currentWallet: root.walletStore.overview.mixedcaseAddress onChangePositionRequested: function (from, to) { @@ -246,6 +259,7 @@ SettingsContentBase { id: profileShowcaseCollectiblesPanel inShowcaseModel: priv.showcaseModels.collectiblesVisibleModel hiddenModel: priv.showcaseModels.collectiblesHiddenModel + showcaseLimit: root.profileStore.getProfileShowcaseEntriesLimit() addAccountsButtonVisible: priv.showcaseModels.accountsHiddenModel.count > 0 onNavigateToAccountsTab: profileTabBar.currentIndex = MyProfileView.TabIndex.Accounts @@ -279,6 +293,7 @@ SettingsContentBase { ProfileSocialLinksPanel { profileStore: root.profileStore socialLinksModel: root.profileStore.temporarySocialLinksModel + showcaseLimit: root.profileStore.getProfileShowcaseSocialLinksLimit() } Component { diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 46da3bb69a..c7f7329f34 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -702,7 +702,6 @@ QtObject { readonly property int telegram: 6 } - readonly property int maxNumOfSocialLinks: 20 readonly property int maxSocialLinkTextLength: 24 readonly property QtObject localPairingEventType: QtObject { diff --git a/ui/imports/utils/ProfileUtils.qml b/ui/imports/utils/ProfileUtils.qml index b299d66adb..4510c7bec6 100644 --- a/ui/imports/utils/ProfileUtils.qml +++ b/ui/imports/utils/ProfileUtils.qml @@ -7,7 +7,6 @@ import StatusQ.Core.Theme 0.1 QtObject { readonly property int defaultDelegateHeight: 76 - readonly property int showcaseLimit: 100 function displayName(nickName, ensName, displayName, aliasName) { diff --git a/vendor/status-go b/vendor/status-go index 580f697f57..6522d52016 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit 580f697f57757daa2ad0671bf8590fb26381342e +Subproject commit 6522d52016eae3d848c228a82d79dde902d69688