feat(Profile): Profile showcase backend (#12510)

* feat(Profile): simplified approach to reuse existing models with profile

* feat(Profile): adapt nim models for view actions (move and change visibility)

* feat(Profile): save profile showcasse model changes to the db

* feat(Profile): update profile showcase models on changes from status-go

* feat(Profile): Various bug fixes for profile showcase

* fix(Profile): Fixes storing profile order and review fixes

* chore(Profile): Rename and minimise signals for updating base model filters
This commit is contained in:
Mikhail Rogachev 2023-11-01 20:54:22 +04:00 committed by GitHub
parent 38140cdd94
commit c7c5ec340d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1570 additions and 169 deletions

View File

@ -197,7 +197,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
statusFoundation.threadpool, result.chatService, result.activityCenterService, result.messageService)
result.transactionService = transaction_service.newService(statusFoundation.events, statusFoundation.threadpool, result.networkService, result.settingsService, result.tokenService)
result.bookmarkService = bookmark_service.newService(statusFoundation.events)
result.profileService = profile_service.newService(statusFoundation.events, result.settingsService)
result.profileService = profile_service.newService(statusFoundation.events, statusFoundation.threadpool, result.settingsService)
result.stickersService = stickers_service.newService(
statusFoundation.events,
statusFoundation.threadpool,

View File

@ -94,7 +94,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
result.controller = controller.newController(result)
result.moduleLoaded = false
result.profileModule = profile_module.newModule(result, events, profileService, settingsService)
result.profileModule = profile_module.newModule(result, events, profileService, settingsService, communityService, walletAccountService)
result.contactsModule = contacts_module.newModule(result, events, contactsService, chatService)
result.languageModule = language_module.newModule(result, events, languageService)
result.privacyModule = privacy_module.newModule(result, events, settingsService, keychainService, privacyService, generalService)

View File

@ -1,24 +1,39 @@
import json, sugar, sequtils
import io_interface
import app/core/eventemitter
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/common/social_links
import app_service/service/profile/dto/profile_showcase_entry
type
Controller* = ref object of RootObj
delegate: io_interface.AccessInterface
events: EventEmitter
profileService: profile_service.Service
settingsService: settings_service.Service
communityService: community_service.Service
walletAccountService: wallet_account_service.Service
proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter,
profileService: profile_service.Service, settingsService: settings_service.Service): Controller =
proc newController*(
delegate: io_interface.AccessInterface,
events: EventEmitter,
profileService: profile_service.Service,
settingsService: settings_service.Service,
communityService: community_service.Service,
walletAccountService: wallet_account_service.Service): Controller =
result = Controller()
result.delegate = delegate
result.events = events
result.profileService = profileService
result.settingsService = settingsService
result.communityService = communityService
result.walletAccountService = walletAccountService
proc delete*(self: Controller) =
discard
@ -34,6 +49,10 @@ proc init*(self: Controller) =
let args = SocialLinksArgs(e)
self.delegate.onSocialLinksUpdated(args.socialLinks, args.error)
self.events.on(SIGNAL_PROFILE_SHOWCASE_PREFERENCES_LOADED) do(e: Args):
let args = ProfileShowcasePreferences(e)
self.delegate.updateProfileShowcasePreferences(args.communities, args.accounts, args.collectibles, args.assets)
proc storeIdentityImage*(self: Controller, address: string, image: string, aX: int, aY: int, bX: int, bY: int) =
discard self.profileService.storeIdentityImage(address, image, aX, aY, bX, bY)
@ -46,6 +65,15 @@ proc setDisplayName*(self: Controller, displayName: string) =
proc getSocialLinks*(self: Controller): SocialLinks =
return self.settingsService.getSocialLinks()
proc getCommunityById*(self: Controller, id: string): CommunityDto =
return self.communityService.getCommunityById(id)
proc getAccountByAddress*(self: Controller, address: string): WalletAccountDto =
return self.walletAccountService.getAccountByAddress(address)
proc getTokensByAddress*(self: Controller, address: string): seq[WalletTokenDto] =
return self.walletAccountService.getTokensByAddress(address)
proc setSocialLinks*(self: Controller, links: SocialLinks) =
self.settingsService.setSocialLinks(links)
@ -54,3 +82,14 @@ proc getBio*(self: Controller): string =
proc setBio*(self: Controller, bio: string): bool =
self.settingsService.saveBio(bio)
proc storeProfileShowcasePreferences*(self: Controller, communities, accounts, collectibles, assets: seq[ProfileShowcaseEntryDto]) =
self.profileService.setProfileShowcasePreferences(ProfileShowcasePreferences(
communities: communities,
accounts: accounts,
collectibles: collectibles,
assets: assets
))
proc requestProfileShowcasePreferences*(self: Controller) =
self.profileService.requestProfileShowcasePreferences()

View File

@ -1,5 +1,12 @@
import NimQml
import app_service/common/social_links
import app_service/service/profile/dto/profile_showcase_entry
import models/profile_preferences_community_item
import models/profile_preferences_account_item
import models/profile_preferences_collectible_item
import models/profile_preferences_asset_item
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -41,6 +48,19 @@ method saveSocialLinks*(self: AccessInterface) {.base.} =
method onSocialLinksUpdated*(self: AccessInterface, socialLinks: SocialLinks, error: string) {.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 updateProfileShowcasePreferences*(self: AccessInterface, communities, accounts, collectibles, assets: seq[ProfileShowcaseEntryDto]) {.base.} =
raise newException(ValueError, "No implementation available")
# View Delegate Interface
# Delegate for the view must be declared here due to use of QtObject and multi
# inheritance, which is not well supported in Nim.

View File

@ -0,0 +1,68 @@
import json, strutils, stint, json_serialization, tables
import profile_preferences_base_item
import app_service/service/profile/dto/profile_showcase_entry
import app_service/service/wallet_account/dto/account_dto
include app_service/common/json_utils
include app_service/common/utils
type
ProfileShowcaseAccountItem* = ref object of ProfileShowcaseBaseItem
address*: string
name*: string
emoji*: string
walletType*: string
colorId*: string
proc initProfileShowcaseAccountItem*(account: WalletAccountDto, entry: ProfileShowcaseEntryDto): ProfileShowcaseAccountItem =
result = ProfileShowcaseAccountItem()
result.showcaseVisibility = entry.showcaseVisibility
result.order = entry.order
result.address = account.address
result.name = account.name
result.emoji = account.emoji
result.walletType = account.walletType
result.colorId = account.colorId
proc toProfileShowcaseAccountItem*(jsonObj: JsonNode): ProfileShowcaseAccountItem =
result = ProfileShowcaseAccountItem()
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.address)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("emoji", result.emoji)
discard jsonObj.getProp("walletType", result.walletType)
discard jsonObj.getProp("colorId", result.colorId)
proc getEntryDto*(self: ProfileShowcaseAccountItem): ProfileShowcaseEntryDto =
result = ProfileShowcaseEntryDto()
result.id = self.address
result.entryType = ProfileShowcaseEntryType.Account
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

View File

@ -0,0 +1,194 @@
import NimQml, tables, strutils, sequtils, json
import profile_preferences_account_item
import app_service/service/profile/dto/profile_showcase_entry
type
ModelRole {.pure.} = enum
ShowcaseVisibility = UserRole + 1
Order
Address
Name
Emoji
WalletType
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 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.WalletType.int: "walletType",
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.WalletType:
result = newQVariant(item.walletType)
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 baseModelFilterConditionsMayChanged*(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.baseModelFilterConditionsMayChanged()
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, @[
ModelRole.ShowcaseVisibility.int,
ModelRole.Order.int,
ModelRole.Address.int,
ModelRole.Name.int,
ModelRole.WalletType.int,
ModelRole.Emoji.int,
ModelRole.ColorId.int,
])
proc upsertItemJson(self: ProfileShowcaseAccountsModel, itemJson: string) {.slot.} =
self.upsertItemImpl(itemJson.parseJson.toProfileShowcaseAccountItem())
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc upsertItem*(self: ProfileShowcaseAccountsModel, item: ProfileShowcaseAccountItem) =
self.upsertItemImpl(item)
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc upsertItems*(self: ProfileShowcaseAccountsModel, items: seq[ProfileShowcaseAccountItem]) =
for item in items:
self.upsertItemImpl(item)
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc reset*(self: ProfileShowcaseAccountsModel) {.slot.} =
self.beginResetModel()
self.items = @[]
self.endResetModel()
self.countChanged()
self.baseModelFilterConditionsMayChanged()
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.baseModelFilterConditionsMayChanged()
proc removeEntry*(self: ProfileShowcaseAccountsModel, address: string) {.slot.} =
let ind = self.findIndexForAccount(address)
if ind != -1:
self.remove(ind)
proc move*(self: ProfileShowcaseAccountsModel, fromIndex: int, toIndex: int) {.slot.} =
if fromIndex < 0 or fromIndex >= self.items.len:
return
self.beginResetModel()
let item = self.items[fromIndex]
self.items.delete(fromIndex)
self.items.insert(@[item], toIndex)
self.recalcOrder()
self.endResetModel()
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.baseModelFilterConditionsMayChanged()
proc setVisibility*(self: ProfileShowcaseAccountsModel, address: string, visibility: int) {.slot.} =
let index = self.findIndexForAccount(address)
if index != -1:
self.setVisibilityByIndex(index, visibility)

View File

@ -0,0 +1,66 @@
import json, strutils, stint, json_serialization, tables
import profile_preferences_base_item
import app_service/service/wallet_account/dto/account_dto
import app_service/service/profile/dto/profile_showcase_entry
import ../../../../shared_models/currency_amount
include app_service/common/json_utils
include app_service/common/utils
type
ProfileShowcaseAssetItem* = ref object of ProfileShowcaseBaseItem
symbol*: string
name*: string
enabledNetworkBalance*: CurrencyAmount
color*: string
proc initProfileShowcaseAssetItem*(token: WalletTokenDto, entry: ProfileShowcaseEntryDto): ProfileShowcaseAssetItem =
result = ProfileShowcaseAssetItem()
result.showcaseVisibility = entry.showcaseVisibility
result.order = entry.order
result.symbol = token.symbol
result.name = token.name
result.enabledNetworkBalance = newCurrencyAmount(token.getTotalBalanceOfSupportedChains(), token.symbol, token.decimals, false)
result.color = token.color
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("symbol", result.symbol)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("color", result.color)
result.enabledNetworkBalance = jsonObj{"enabledNetworkBalance"}.toCurrencyAmount()
proc getEntryDto*(self: ProfileShowcaseAssetItem): ProfileShowcaseEntryDto =
result = ProfileShowcaseEntryDto()
result.id = self.symbol
result.entryType = ProfileShowcaseEntryType.Asset
result.showcaseVisibility = self.showcaseVisibility
result.order = self.order
proc symbol*(self: ProfileShowcaseAssetItem): string {.inline.} =
self.symbol
proc name*(self: ProfileShowcaseAssetItem): string {.inline.} =
self.name
proc enabledNetworkBalance*(self: ProfileShowcaseAssetItem): CurrencyAmount {.inline.} =
self.enabledNetworkBalance
proc color*(self: ProfileShowcaseAssetItem): string {.inline.} =
self.color

View File

@ -0,0 +1,189 @@
import NimQml, tables, strutils, sequtils, json
import profile_preferences_asset_item
import app_service/service/profile/dto/profile_showcase_entry
type
ModelRole {.pure.} = enum
ShowcaseVisibility = UserRole + 1
Order
Symbol
Name
EnabledNetworkBalance
Color
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 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.Symbol.int: "symbol",
ModelRole.Name.int: "name",
ModelRole.EnabledNetworkBalance.int: "enabledNetworkBalance",
ModelRole.Color.int: "color",
}.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.Symbol:
result = newQVariant(item.symbol)
of ModelRole.Name:
result = newQVariant(item.name)
of ModelRole.EnabledNetworkBalance:
result = newQVariant(item.enabledNetworkBalance)
of ModelRole.Color:
result = newQVariant(item.color)
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 baseModelFilterConditionsMayChanged*(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.baseModelFilterConditionsMayChanged()
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, @[
ModelRole.ShowcaseVisibility.int,
ModelRole.Order.int,
ModelRole.Symbol.int,
ModelRole.Name.int,
ModelRole.EnabledNetworkBalance.int,
ModelRole.Color.int,
])
proc upsertItemJson(self: ProfileShowcaseAssetsModel, itemJson: string) {.slot.} =
self.upsertItemImpl(itemJson.parseJson.toProfileShowcaseAssetItem())
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc upsertItem*(self: ProfileShowcaseAssetsModel, item: ProfileShowcaseAssetItem) =
self.upsertItemImpl(item)
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc upsertItems*(self: ProfileShowcaseAssetsModel, items: seq[ProfileShowcaseAssetItem]) =
for item in items:
self.upsertItemImpl(item)
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc reset*(self: ProfileShowcaseAssetsModel) {.slot.} =
self.beginResetModel()
self.items = @[]
self.endResetModel()
self.countChanged()
self.baseModelFilterConditionsMayChanged()
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.baseModelFilterConditionsMayChanged()
proc removeEntry*(self: ProfileShowcaseAssetsModel, symbol: string) {.slot.} =
let ind = self.findIndexForAsset(symbol)
if ind != -1:
self.remove(ind)
proc move*(self: ProfileShowcaseAssetsModel, fromIndex: int, toIndex: int) {.slot.} =
if fromIndex < 0 or fromIndex >= self.items.len:
return
self.beginResetModel()
let item = self.items[fromIndex]
self.items.delete(fromIndex)
self.items.insert(@[item], toIndex)
self.recalcOrder()
self.endResetModel()
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.baseModelFilterConditionsMayChanged()
proc setVisibility*(self: ProfileShowcaseAssetsModel, symbol: string, visibility: int) {.slot.} =
let index = self.findIndexForAsset(symbol)
if index != -1:
self.setVisibilityByIndex(index, visibility)

View File

@ -0,0 +1,12 @@
import app_service/service/profile/dto/profile_showcase_entry
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

View File

@ -0,0 +1,51 @@
import json, strutils, stint, json_serialization, tables
import profile_preferences_base_item
import app_service/service/profile/dto/profile_showcase_entry
include app_service/common/json_utils
include app_service/common/utils
type
ProfileShowcaseCollectibleItem* = ref object of ProfileShowcaseBaseItem
uid*: string
name*: string
collectionName*: string
imageUrl*: string
backgroundColor*: string
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("uid", result.uid)
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 getEntryDto*(self: ProfileShowcaseCollectibleItem): ProfileShowcaseEntryDto =
result = ProfileShowcaseEntryDto()
result.id = self.uid
result.entryType = ProfileShowcaseEntryType.Collectible
result.showcaseVisibility = self.showcaseVisibility
result.order = self.order
proc name*(self: ProfileShowcaseCollectibleItem): string {.inline.} =
self.name
proc collectionName*(self: ProfileShowcaseCollectibleItem): string {.inline.} =
self.collectionName
proc imageUrl*(self: ProfileShowcaseCollectibleItem): string {.inline.} =
self.imageUrl
proc backgroundColor*(self: ProfileShowcaseCollectibleItem): string {.inline.} =
self.backgroundColor

View File

@ -0,0 +1,194 @@
import NimQml, tables, strutils, sequtils, json
import profile_preferences_collectible_item
import app_service/service/profile/dto/profile_showcase_entry
type
ModelRole {.pure.} = enum
ShowcaseVisibility = UserRole + 1
Order
Uid
Name
CollectionName
ImageUrl
BackgroundColor
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 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.ShowcaseVisibility.int: "showcaseVisibility",
ModelRole.Order.int: "order",
ModelRole.Uid.int: "uid",
ModelRole.Name.int: "name",
ModelRole.CollectionName.int: "collectionName",
ModelRole.ImageUrl.int: "imageUrl",
ModelRole.BackgroundColor.int: "backgroundColor",
}.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.ShowcaseVisibility:
result = newQVariant(item.showcaseVisibility.int)
of ModelRole.Order:
result = newQVariant(item.order)
of ModelRole.Uid:
result = newQVariant(item.uid)
of ModelRole.Name:
result = newQVariant(item.name)
of ModelRole.CollectionName:
result = newQVariant(item.collectionName)
of ModelRole.ImageUrl:
result = newQVariant(item.imageUrl)
of ModelRole.BackgroundColor:
result = newQVariant(item.backgroundColor)
proc findIndexForCollectible(self: ProfileShowcaseCollectiblesModel, uid: string): int =
for i in 0 ..< self.items.len:
if (self.items[i].uid == 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 baseModelFilterConditionsMayChanged*(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.baseModelFilterConditionsMayChanged()
proc upsertItemImpl(self: ProfileShowcaseCollectiblesModel, item: ProfileShowcaseCollectibleItem) =
let ind = self.findIndexForCollectible(item.uid)
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, @[
ModelRole.ShowcaseVisibility.int,
ModelRole.Order.int,
ModelRole.Uid.int,
ModelRole.Name.int,
ModelRole.CollectionName.int,
ModelRole.ImageUrl.int,
ModelRole.BackgroundColor.int,
])
proc upsertItemJson(self: ProfileShowcaseCollectiblesModel, itemJson: string) {.slot.} =
self.upsertItemImpl(itemJson.parseJson.toProfileShowcaseCollectibleItem())
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc upsertItem*(self: ProfileShowcaseCollectiblesModel, item: ProfileShowcaseCollectibleItem) =
self.upsertItemImpl(item)
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc upsertItems*(self: ProfileShowcaseCollectiblesModel, items: seq[ProfileShowcaseCollectibleItem]) =
for item in items:
self.upsertItemImpl(item)
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc reset*(self: ProfileShowcaseCollectiblesModel) {.slot.} =
self.beginResetModel()
self.items = @[]
self.endResetModel()
self.countChanged()
self.baseModelFilterConditionsMayChanged()
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.baseModelFilterConditionsMayChanged()
proc removeEntry*(self: ProfileShowcaseCollectiblesModel, uid: string) {.slot.} =
let ind = self.findIndexForCollectible(uid)
if ind != -1:
self.remove(ind)
proc move*(self: ProfileShowcaseCollectiblesModel, fromIndex: int, toIndex: int) {.slot.} =
if fromIndex < 0 or fromIndex >= self.items.len:
return
self.beginResetModel()
let item = self.items[fromIndex]
self.items.delete(fromIndex)
self.items.insert(@[item], toIndex)
self.recalcOrder()
self.endResetModel()
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.baseModelFilterConditionsMayChanged()
proc setVisibility*(self: ProfileShowcaseCollectiblesModel, uid: string, visibility: int) {.slot.} =
let index = self.findIndexForCollectible(uid)
if index != -1:
self.setVisibilityByIndex(index, visibility)

View File

@ -0,0 +1,193 @@
import NimQml, tables, strutils, sequtils, json
import profile_preferences_community_item
import app_service/service/profile/dto/profile_showcase_entry
type
ModelRole {.pure.} = enum
ShowcaseVisibility
Order
Id
Name
MemberRole
Image
Color
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 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",
}.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)
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 baseModelFilterConditionsMayChanged*(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.baseModelFilterConditionsMayChanged()
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, @[
ModelRole.ShowcaseVisibility.int,
ModelRole.Order.int,
ModelRole.Id.int,
ModelRole.Name.int,
ModelRole.MemberRole.int,
ModelRole.Image.int,
ModelRole.Color.int,
])
proc upsertItemJson(self: ProfileShowcaseCommunitiesModel, itemJson: string) {.slot.} =
self.upsertItemImpl(itemJson.parseJson.toProfileShowcaseCommunityItem())
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc upsertItem*(self: ProfileShowcaseCommunitiesModel, item: ProfileShowcaseCommunityItem) =
self.upsertItemImpl(item)
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc upsertItems*(self: ProfileShowcaseCommunitiesModel, items: seq[ProfileShowcaseCommunityItem]) =
for item in items:
self.upsertItemImpl(item)
self.recalcOrder()
self.baseModelFilterConditionsMayChanged()
proc reset*(self: ProfileShowcaseCommunitiesModel) {.slot.} =
self.beginResetModel()
self.items = @[]
self.endResetModel()
self.countChanged()
self.baseModelFilterConditionsMayChanged()
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.baseModelFilterConditionsMayChanged()
proc removeEntry*(self: ProfileShowcaseCommunitiesModel, id: string) {.slot.} =
let ind = self.findIndexForCommunity(id)
if ind != -1:
self.remove(ind)
proc move*(self: ProfileShowcaseCommunitiesModel, fromIndex: int, toIndex: int) {.slot.} =
if fromIndex < 0 or fromIndex >= self.items.len:
return
self.beginResetModel()
let item = self.items[fromIndex]
self.items.delete(fromIndex)
self.items.insert(@[item], toIndex)
self.recalcOrder()
self.endResetModel()
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.baseModelFilterConditionsMayChanged()
proc setVisibility*(self: ProfileShowcaseCommunitiesModel, id: string, visibility: int) {.slot.} =
let index = self.findIndexForCommunity(id)
if index != -1:
self.setVisibilityByIndex(index, visibility)

View File

@ -0,0 +1,65 @@
import json, strutils, stint, json_serialization, tables
import profile_preferences_base_item
import app_service/service/profile/dto/profile_showcase_entry
import app_service/service/community/dto/community
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
proc initProfileShowcaseCommunityItem*(community: CommunityDto, entry: ProfileShowcaseEntryDto): ProfileShowcaseCommunityItem =
result = ProfileShowcaseCommunityItem()
result.showcaseVisibility = entry.showcaseVisibility
result.order = entry.order
result.id = community.id
result.name = community.name
result.memberRole = community.memberRole
result.image = community.images.thumbnail
result.color = community.color
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)
proc getEntryDto*(self: ProfileShowcaseCommunityItem): ProfileShowcaseEntryDto =
result = ProfileShowcaseEntryDto()
result.id = self.id
result.entryType = ProfileShowcaseEntryType.Community
result.showcaseVisibility = self.showcaseVisibility
result.order = self.order
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

View File

@ -7,11 +7,19 @@ import app/global/global_singleton
import app/core/eventemitter
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/profile/dto/profile_showcase_entry
import app_service/common/social_links
import app/modules/shared_models/social_links_model
import app/modules/shared_models/social_link_item
import models/profile_preferences_community_item
import models/profile_preferences_account_item
import models/profile_preferences_collectible_item
import models/profile_preferences_asset_item
export io_interface
logScope:
@ -25,13 +33,18 @@ type
viewVariant: QVariant
moduleLoaded: bool
proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter,
profileService: profile_service.Service, settingsService: settings_service.Service): Module =
proc newModule*(
delegate: delegate_interface.AccessInterface,
events: EventEmitter,
profileService: profile_service.Service,
settingsService: settings_service.Service,
communityService: community_service.Service,
walletAccountService: wallet_account_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)
result.controller = controller.newController(result, events, profileService, settingsService, communityService, walletAccountService)
result.moduleLoaded = false
method delete*(self: Module) =
@ -87,4 +100,42 @@ method onSocialLinksUpdated*(self: Module, socialLinks: SocialLinks, error: stri
if error.len > 0:
# maybe we want in future popup or somehow display an error to a user
return
self.updateSocialLinks(socialLinks)
self.updateSocialLinks(socialLinks)
method storeProfileShowcasePreferences(self: Module,
communities: seq[ProfileShowcaseCommunityItem],
accounts: seq[ProfileShowcaseAccountItem],
collectibles: seq[ProfileShowcaseCollectibleItem],
assets: seq[ProfileShowcaseAssetItem]) =
let communitiesDto = communities.map(item => item.getEntryDto())
let accountsDto = accounts.map(item => item.getEntryDto())
let collectiblesDto = collectibles.map(item => item.getEntryDto())
let assetsDto = assets.map(item => item.getEntryDto())
self.controller.storeProfileShowcasePreferences(communitiesDto, accountsDto, collectiblesDto, assetsDto)
method requestProfileShowcasePreferences(self: Module) =
self.controller.requestProfileShowcasePreferences()
method updateProfileShowcasePreferences(self: Module, communityEntries, accountEntries, collectibleEntries, assetEntries: seq[ProfileShowcaseEntryDto]) =
var profileCommunityItems: seq[ProfileShowcaseCommunityItem] = @[]
var profileAccountItems: seq[ProfileShowcaseAccountItem] = @[]
var profileCollectibleItems: seq[ProfileShowcaseCollectibleItem] = @[]
var profileAssetItems: seq[ProfileShowcaseAssetItem] = @[]
for communityEntry in communityEntries:
let community = self.controller.getCommunityById(communityEntry.id)
profileCommunityItems.add(initProfileShowcaseCommunityItem(community, communityEntry))
for accountEntry in accountEntries:
let account = self.controller.getAccountByAddress(accountEntry.id)
profileAccountItems.add(initProfileShowcaseAccountItem(account, accountEntry))
for assetEntry in assetEntries:
# TODO: need wallet api to fetch token by symbol
for token in self.controller.getTokensByAddress(account.address):
if assetEntry.id == token.symbol:
profileAssetItems.add(initProfileShowcaseAssetItem(token, assetEntry))
# TODO: collectibles, need wallet api to fetch collectible by uid
self.view.updateProfileShowcasePreferences(profileCommunityItems, profileAccountItems, profileCollectibleItems, profileAssetItems)

View File

@ -1,9 +1,18 @@
import NimQml, json
import NimQml, json, sequtils
import io_interface
import app/modules/shared_models/social_links_model
import app/modules/shared_models/social_link_item
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
QtObject:
type
View* = ref object of QObject
@ -12,6 +21,14 @@ 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
proc delete*(self: View) =
self.QObject.delete
@ -19,6 +36,14 @@ QtObject:
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
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
@ -28,6 +53,14 @@ 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)
proc load*(self: View) =
self.delegate.viewDidLoad()
@ -141,3 +174,47 @@ QtObject:
proc emitBioChangedSignal*(self: View) =
self.bioChanged()
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 storeProfileShowcasePreferences(self: View) {.slot.} =
let communities = self.profileShowcaseCommunitiesModel.items()
let accounts = self.profileShowcaseAccountsModel.items()
let collectibles = self.profileShowcaseCollectiblesModel.items()
let assets = self.profileShowcaseAssetsModel.items()
self.delegate.storeProfileShowcasePreferences(communities, accounts, collectibles, assets)
proc requestProfileShowcasePreferences(self: View) {.slot.} =
self.delegate.requestProfileShowcasePreferences()
proc updateProfileShowcasePreferences*(self: View,
communities: seq[ProfileShowcaseCommunityItem],
accounts: seq[ProfileShowcaseAccountItem],
collectibles: seq[ProfileShowcaseCollectibleItem],
assets: seq[ProfileShowcaseAssetItem]) =
self.profileShowcaseCommunitiesModel.upsertItems(communities)
self.profileShowcaseAccountsModel.upsertItems(accounts)
self.profileShowcaseCollectiblesModel.upsertItems(collectibles)
self.profileShowcaseAssetsModel.upsertItems(assets)

View File

@ -1,5 +1,7 @@
import NimQml, strformat, json
include app_service/common/json_utils
QtObject:
type CurrencyAmount* = ref object of QObject
amount: float64
@ -68,3 +70,12 @@ QtObject:
"displayDecimals": self.displayDecimals,
"stripTrailingZeroes": self.stripTrailingZeroes
}
# Needed by profile showcase
proc toCurrencyAmount*(jsonObj: JsonNode): CurrencyAmount =
new(result, delete)
result.setup
discard jsonObj.getProp("amount", result.amount)
discard jsonObj.getProp("symbol", result.symbol)
discard jsonObj.getProp("displayDecimals", result.displayDecimals)
discard jsonObj.getProp("stripTrailingZeroes", result.stripTrailingZeroes)

View File

@ -0,0 +1,19 @@
import os, parseutils
include ../../common/json_utils
include ../../../app/core/tasks/common
import ../../../backend/accounts as status_accounts
const asyncGetProfileShowcasePreferencesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[QObjectTaskArg](argEncoded)
try:
let response = status_accounts.getProfileShowcasePreferences()
arg.finish(%* {
"response": response,
"error": nil,
})
except Exception as e:
arg.finish(%* {
"error": e.msg,
})

View File

@ -0,0 +1,60 @@
import json, strformat, strutils, stint, json_serialization, tables
include ../../../common/json_utils
include ../../../common/utils
type ProfileShowcaseEntryType* {.pure.}= enum
Community = 0,
Account = 1,
Collectible = 2,
Asset = 3,
type ProfileShowcaseVisibility* {.pure.}= enum
ToNoOne = 0,
ToIDVerifiedContacts = 1,
ToContacts = 2,
ToEveryone = 3,
type ProfileShowcaseEntryDto* = ref object of RootObj
id*: string
entryType*: ProfileShowcaseEntryType
showcaseVisibility*: ProfileShowcaseVisibility
order*: int
proc `$`*(self: ProfileShowcaseEntryDto): string =
result = fmt"""ProfileShowcaseEntryDto(
id: {$self.id},
entryType: {self.entryType.int},
showcaseVisibility: {self.showcaseVisibility.int},
order: {self.order}
)"""
proc toProfileShowcaseEntryDto*(jsonObj: JsonNode): ProfileShowcaseEntryDto =
result = ProfileShowcaseEntryDto()
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("order", result.order)
var entryTypeInt: int
if (jsonObj.getProp("entryType", entryTypeInt) and
(entryTypeInt >= ord(low(ProfileShowcaseEntryType)) and
entryTypeInt <= ord(high(ProfileShowcaseEntryType)))):
result.entryType = ProfileShowcaseEntryType(entryTypeInt)
var visibilityInt: int
if (jsonObj.getProp("showcaseVisibility", visibilityInt) and
(visibilityInt >= ord(low(ProfileShowcaseVisibility)) and
visibilityInt <= ord(high(ProfileShowcaseVisibility)))):
result.showcaseVisibility = ProfileShowcaseVisibility(visibilityInt)
proc parseProfileShowcaseEntries*(jsonMsgs: JsonNode): seq[ProfileShowcaseEntryDto] =
var entries: seq[ProfileShowcaseEntryDto] = @[]
for jsonMsg in jsonMsgs:
entries.add(jsonMsg.toProfileShowcaseEntryDto())
return entries
proc toJsonNode*(self: ProfileShowcaseEntryDto): JsonNode =
%* {
"id": self.id,
"entryType": self.entryType.int,
"showcaseVisibility": self.showcaseVisibility.int,
"order": self.order,
}

View File

@ -1,80 +1,153 @@
import json, chronicles
import NimQml, json, chronicles, tables, sugar, sequtils, json_serialization, std/algorithm
import ../settings/service as settings_service
import ../../../app/global/global_singleton
import ../../../app/core/signals/types
import ../../../app/core/eventemitter
import ../../../app/core/tasks/[qt, threadpool]
import ../../../backend/accounts as status_accounts
import ../accounts/dto/accounts
import dto/profile_showcase_entry
include async_tasks
logScope:
topics = "profile-service"
type
Service* = ref object of RootObj
ProfileShowcasePreferences* = ref object of Args
communities*: seq[ProfileShowcaseEntryDto]
accounts*: seq[ProfileShowcaseEntryDto]
collectibles*: seq[ProfileShowcaseEntryDto]
assets*: seq[ProfileShowcaseEntryDto]
# Signals which may be emitted by this service:
const SIGNAL_PROFILE_SHOWCASE_PREFERENCES_LOADED* = "profileShowcasePreferencesLoaded"
QtObject:
type Service* = ref object of QObject
threadpool: ThreadPool
events: EventEmitter
settingsService: settings_service.Service
proc delete*(self: Service) =
discard
proc delete*(self: Service) =
self.QObject.delete
proc newService*(events: EventEmitter, settingsService: settings_service.Service): Service =
result = Service()
result.events = events
result.settingsService = settingsService
proc newService*(events: EventEmitter, threadpool: ThreadPool, settingsService: settings_service.Service): Service =
new(result, delete)
result.QObject.setup
result.threadpool = threadpool
result.events = events
result.settingsService = settingsService
proc init*(self: Service) =
self.events.on(SIGNAL_DISPLAY_NAME_UPDATED) do(e:Args):
let args = SettingsTextValueArgs(e)
singletonInstance.userProfile.setDisplayName(args.value)
proc init*(self: Service) =
self.events.on(SIGNAL_DISPLAY_NAME_UPDATED) do(e:Args):
let args = SettingsTextValueArgs(e)
singletonInstance.userProfile.setDisplayName(args.value)
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)
if(not response.error.isNil):
error "could not store identity images"
return
if(response.result.kind != JArray):
error "error: ", procName="storeIdentityImage", errDesription = "response is not an array"
return
if(response.result.len == 0):
error "error: array of stored images is empty"
return
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)
if(not response.error.isNil):
error "could not store identity images"
return
if(response.result.kind != JArray):
error "error: ", procName="storeIdentityImage", errDesription = "response is not an array"
return
if(response.result.len == 0):
error "error: array of stored images is empty"
return
for img in response.result:
let imageDto = toImage(img)
result.add(imageDto)
if(imageDto.imgType == "large"):
singletonInstance.userProfile.setLargeImage(imageDto.uri)
elif(imageDto.imgType == "thumbnail"):
singletonInstance.userProfile.setThumbnailImage(imageDto.uri)
for img in response.result:
let imageDto = toImage(img)
result.add(imageDto)
if(imageDto.imgType == "large"):
singletonInstance.userProfile.setLargeImage(imageDto.uri)
elif(imageDto.imgType == "thumbnail"):
singletonInstance.userProfile.setThumbnailImage(imageDto.uri)
except Exception as e:
error "error: ", procName="storeIdentityImage", errName = e.name, errDesription = e.msg
except Exception as e:
error "error: ", procName="storeIdentityImage", errName = e.name, errDesription = e.msg
proc deleteIdentityImage*(self: Service, address: string) =
try:
let response = status_accounts.deleteIdentityImage(address)
if(not response.error.isNil):
error "could not delete identity images"
return
singletonInstance.userProfile.setLargeImage("")
singletonInstance.userProfile.setThumbnailImage("")
proc deleteIdentityImage*(self: Service, address: string) =
try:
let response = status_accounts.deleteIdentityImage(address)
if(not response.error.isNil):
error "could not delete identity images"
return
singletonInstance.userProfile.setLargeImage("")
singletonInstance.userProfile.setThumbnailImage("")
except Exception as e:
error "error: ", procName="deleteIdentityImage", errName = e.name, errDesription = e.msg
except Exception as e:
error "error: ", procName="deleteIdentityImage", errName = e.name, errDesription = e.msg
proc setDisplayName*(self: Service, displayName: string) =
try:
let response = status_accounts.setDisplayName(displayName)
if(not response.error.isNil):
error "could not set display name"
return
if(not self.settingsService.saveDisplayName(displayName)):
error "could save display name to the settings"
return
except Exception as e:
error "error: ", procName="setDisplayName", errName = e.name, errDesription = e.msg
proc setDisplayName*(self: Service, displayName: string) =
try:
let response = status_accounts.setDisplayName(displayName)
if(not response.error.isNil):
error "could not set display name"
return
if(not self.settingsService.saveDisplayName(displayName)):
error "could save display name to the settings"
return
except Exception as e:
error "error: ", procName="setDisplayName", errName = e.name, errDesription = e.msg
proc requestProfileShowcasePreferences*(self: Service) =
let arg = QObjectTaskArg(
tptr: cast[ByteAddress](asyncGetProfileShowcasePreferencesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "asyncProfileShowcaseLoaded",
)
self.threadpool.start(arg)
proc asyncProfileShowcaseLoaded*(self: Service, rpcResponse: string) {.slot.} =
try:
let rpcResponseObj = rpcResponse.parseJson
if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "":
error "Error requesting profile showcase preferences", msg = rpcResponseObj{"error"}
return
let result = rpcResponseObj["response"]["result"]
var communities = result["communities"].parseProfileShowcaseEntries()
var accounts = result["accounts"].parseProfileShowcaseEntries()
var collectibles = result["collectibles"].parseProfileShowcaseEntries()
var assets = result["assets"].parseProfileShowcaseEntries()
# Sort by order before inserting in the model
communities.sort((a, b) => cmp(a.order, b.order))
accounts.sort((a, b) => cmp(a.order, b.order))
collectibles.sort((a, b) => cmp(a.order, b.order))
assets.sort((a, b) => cmp(a.order, b.order))
self.events.emit(SIGNAL_PROFILE_SHOWCASE_PREFERENCES_LOADED,
ProfileShowcasePreferences(
communities: communities,
accounts: accounts,
collectibles: collectibles,
assets: assets
))
except Exception as e:
error "Error requesting profile showcase preferences", msg = e.msg
proc setProfileShowcasePreferences*(self: Service, preferences: ProfileShowcasePreferences) =
try:
let communities = preferences.communities.map(entry => entry.toJsonNode())
let accounts = preferences.accounts.map(entry => entry.toJsonNode())
let collectibles = preferences.collectibles.map(entry => entry.toJsonNode())
let assets = preferences.assets.map(entry => entry.toJsonNode())
var payload = %*[{
"communities": communities,
"accounts": accounts,
"collectibles": collectibles,
"assets": assets,
}]
let response = status_accounts.setProfileShowcasePreferences(payload)
if not response.error.isNil:
error "error saving profile showcase preferences"
except Exception as e:
error "error: ", procName="setProfileShowcasePreferences", errName = e.name, errDesription = e.msg

View File

@ -473,3 +473,9 @@ proc verifyPassword*(password: string): RpcResponse[JsonNode] {.raises: [Excepti
proc verifyKeystoreFileForAccount*(address, password: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [address, password]
return core.callPrivateRPC("accounts_verifyKeystoreFileForAccount", payload)
proc getProfileShowcasePreferences*(): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("getProfileShowcasePreferences".prefix, %*[])
proc setProfileShowcasePreferences*(preferences: JsonNode): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("setProfileShowcasePreferences".prefix, preferences)

View File

@ -9,10 +9,9 @@ ProfileShowcasePanel {
property string currentWallet
settingsKey: "accounts"
keyRole: "address"
roleNames: ["name", "address", "walletType", "emoji", "colorId"]
filterFunc: (modelData) => modelData.walletType !== Constants.keyWalletType && !showcaseModel.hasItem(modelData.address)
roleNames: ["address", "name", "walletType", "emoji", "colorId"].concat(showcaseRoles)
filterFunc: (modelData) => modelData.walletType !== Constants.keyWalletType && !showcaseModel.hasItemInShowcase(modelData.address)
hiddenPlaceholderBanner: qsTr("Accounts here will show on your profile")
showcasePlaceholderBanner: qsTr("Accounts here will be hidden from your profile")
@ -26,8 +25,8 @@ ProfileShowcasePanel {
var tmpObj = Object()
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role])
tmpObj.showcaseVisibility = value
showcaseModel.append(tmpObj)
showcaseVisibility = Constants.ShowcaseVisibility.NoOne // reset
showcaseModel.upsertItemJson(JSON.stringify(tmpObj))
root.showcaseEntryChanged()
}
}
showcaseDraggableDelegateComponent: AccountShowcaseDelegate {
@ -39,11 +38,8 @@ ProfileShowcasePanel {
dragAxis: Drag.YAxis
showcaseVisibility: !!modelData ? modelData.showcaseVisibility : Constants.ShowcaseVisibility.NoOne
onShowcaseVisibilityRequested: {
if (value === Constants.ShowcaseVisibility.NoOne) {
showcaseModel.remove(visualIndex)
} else {
showcaseModel.setProperty(visualIndex, "showcaseVisibility", value)
}
showcaseModel.setVisibility(showcaseObj.address, value)
root.showcaseEntryChanged()
}
}
}

View File

@ -7,10 +7,9 @@ import AppLayouts.Profile.controls 1.0
ProfileShowcasePanel {
id: root
settingsKey: "assets"
keyRole: "symbol"
roleNames: ["symbol", "name", "enabledNetworkBalance"]
filterFunc: (modelData) => !showcaseModel.hasItem(modelData.symbol)
roleNames: ["symbol", "name", "enabledNetworkBalance"].concat(showcaseRoles)
filterFunc: (modelData) => !showcaseModel.hasItemInShowcase(modelData.symbol)
hiddenPlaceholderBanner: qsTr("Assets here will show on your profile")
showcasePlaceholderBanner: qsTr("Assets here will be hidden from your profile")
@ -23,8 +22,8 @@ ProfileShowcasePanel {
var tmpObj = Object()
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role])
tmpObj.showcaseVisibility = value
showcaseModel.append(tmpObj)
showcaseVisibility = Constants.ShowcaseVisibility.NoOne // reset
showcaseModel.upsertItemJson(JSON.stringify(tmpObj))
root.showcaseEntryChanged()
}
}
showcaseDraggableDelegateComponent: AssetShowcaseDelegate {
@ -35,11 +34,8 @@ ProfileShowcasePanel {
dragAxis: Drag.YAxis
showcaseVisibility: !!modelData ? modelData.showcaseVisibility : Constants.ShowcaseVisibility.NoOne
onShowcaseVisibilityRequested: {
if (value === Constants.ShowcaseVisibility.NoOne) {
showcaseModel.remove(visualIndex)
} else {
showcaseModel.setProperty(visualIndex, "showcaseVisibility", value)
}
showcaseModel.setVisibility(showcaseObj.symbol, value)
root.showcaseEntryChanged()
}
}
}

View File

@ -7,10 +7,9 @@ import AppLayouts.Profile.controls 1.0
ProfileShowcasePanel {
id: root
settingsKey: "collectibles"
keyRole: "uid"
roleNames: ["uid", "name", "collectionName", "backgroundColor", "imageUrl"]
filterFunc: (modelData) => !showcaseModel.hasItem(modelData.uid)
roleNames: ["uid", "name", "collectionName", "backgroundColor", "imageUrl"].concat(showcaseRoles)
filterFunc: (modelData) => !showcaseModel.hasItemInShowcase(modelData.uid)
hiddenPlaceholderBanner: qsTr("Collectibles here will show on your profile")
showcasePlaceholderBanner: qsTr("Collectibles here will be hidden from your profile")
@ -23,8 +22,8 @@ ProfileShowcasePanel {
var tmpObj = Object()
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role])
tmpObj.showcaseVisibility = value
showcaseModel.append(tmpObj)
showcaseVisibility = Constants.ShowcaseVisibility.NoOne // reset
showcaseModel.upsertItemJson(JSON.stringify(tmpObj))
root.showcaseEntryChanged()
}
}
showcaseDraggableDelegateComponent: CollectibleShowcaseDelegate {
@ -35,11 +34,8 @@ ProfileShowcasePanel {
dragAxis: Drag.YAxis
showcaseVisibility: !!modelData ? modelData.showcaseVisibility : Constants.ShowcaseVisibility.NoOne
onShowcaseVisibilityRequested: {
if (value === Constants.ShowcaseVisibility.NoOne) {
showcaseModel.remove(visualIndex)
} else {
showcaseModel.setProperty(visualIndex, "showcaseVisibility", value)
}
showcaseModel.setVisibility(showcaseObj.uid, value)
root.showcaseEntryChanged()
}
}
}

View File

@ -7,10 +7,9 @@ import AppLayouts.Profile.controls 1.0
ProfileShowcasePanel {
id: root
settingsKey: "communities"
keyRole: "id"
roleNames: ["id", "name", "memberRole", "image", "color"]
filterFunc: (modelData) => modelData.joined && !showcaseModel.hasItem(modelData.id)
roleNames: ["id", "name", "memberRole", "image", "color"].concat(showcaseRoles)
filterFunc: (modelData) => modelData.joined && !showcaseModel.hasItemInShowcase(modelData.id)
hiddenPlaceholderBanner: qsTr("Communities here will show on your profile")
showcasePlaceholderBanner: qsTr("Communities here will be hidden from your profile")
@ -23,8 +22,8 @@ ProfileShowcasePanel {
var tmpObj = Object()
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role])
tmpObj.showcaseVisibility = value
showcaseModel.append(tmpObj)
showcaseVisibility = Constants.ShowcaseVisibility.NoOne // reset
showcaseModel.upsertItemJson(JSON.stringify(tmpObj))
root.showcaseEntryChanged()
}
}
showcaseDraggableDelegateComponent: CommunityShowcaseDelegate {
@ -35,11 +34,8 @@ ProfileShowcasePanel {
dragAxis: Drag.YAxis
showcaseVisibility: !!modelData ? modelData.showcaseVisibility : Constants.ShowcaseVisibility.NoOne
onShowcaseVisibilityRequested: {
if (value === Constants.ShowcaseVisibility.NoOne) {
showcaseModel.remove(visualIndex)
} else {
showcaseModel.setProperty(visualIndex, "showcaseVisibility", value)
}
showcaseModel.setVisibility(showcaseObj.id, value)
root.showcaseEntryChanged()
}
}
}

View File

@ -2,8 +2,6 @@ import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import Qt.labs.settings 1.0
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
@ -20,12 +18,11 @@ Control {
id: root
property var baseModel
property var showcaseModel
readonly property alias settings: settings
readonly property alias showcaseModel: showcaseModel
readonly property var showcaseRoles: ["showcaseVisibility", "order"]
// to override
property string settingsKey
property string keyRole
property var roleNames: []
property var filterFunc: (modelData) => true
@ -34,6 +31,27 @@ Control {
property Component draggableDelegateComponent
property Component showcaseDraggableDelegateComponent
signal showcaseEntryChanged()
function reset() {
showcaseModel.reset()
updateBaseModelFilters()
}
function updateBaseModelFilters() {
// Reset base model to update filter conditions
hiddenItemsListView.model = null
hiddenItemsListView.model = baseModel
}
readonly property Connections showcaseUpdateConnections: Connections {
target: showcaseModel
function onBaseModelFilterConditionsMayChanged() {
root.updateBaseModelFilters()
}
}
background: null
component VisibilityDropArea: AbstractButton {
@ -65,7 +83,8 @@ Control {
var tmpObj = Object()
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role])
tmpObj.showcaseVisibility = visibilityDropAreaLocal.showcaseVisibility
showcaseModel.append(tmpObj)
showcaseModel.upsertItemJson(JSON.stringify(tmpObj))
root.showcaseEntryChanged()
}
}
}
@ -93,54 +112,6 @@ Control {
}
}
Component.onCompleted: showcaseModel.load()
Component.onDestruction: showcaseModel.save()
// NB temporary model until the backend knows the extra roles: "showcaseVisibility" and "order"
ListModel {
id: showcaseModel
function hasItem(itemId) {
for (let i = 0; i < count; i++) {
let item = get(i)
if (!!item && item[root.keyRole] === itemId)
return true
}
return false
}
function save() {
var result = []
for (let i = 0; i < count; i++) {
let item = get(i)
result.push(item)
}
settings.setValue(root.settingsKey, JSON.stringify(result))
}
function load() {
const data = settings.value(root.settingsKey)
try {
const arr = JSON.parse(data)
for (const i in arr)
showcaseModel.append(arr[i])
} catch (e) {
console.warn(e)
}
}
}
Settings {
id: settings
category: "Showcase"
function reset() {
showcaseModel.clear()
settings.setValue(root.settingsKey, "")
settings.sync()
}
}
QtObject {
id: d
@ -184,16 +155,19 @@ Control {
}
width: ListView.view.width
height: showcaseDraggableDelegateLoader.item ? showcaseDraggableDelegateLoader.item.height : 0
height: visible && showcaseDraggableDelegateLoader.item ? showcaseDraggableDelegateLoader.item.height : 0
keys: ["x-status-draggable-showcase-item"]
visible: model.showcaseVisibility !== Constants.ShowcaseVisibility.NoOne
onEntered: function(drag) {
const from = drag.source.visualIndex
const to = showcaseDraggableDelegateLoader.item.visualIndex
if (to === from)
return
showcaseModel.move(from, to, 1)
root.showcaseEntryChanged()
showcaseModel.move(from, to)
drag.accept()
}
@ -298,7 +272,9 @@ Control {
}
onDropped: function(drop) {
showcaseModel.remove(drop.source.visualIndex)
showcaseModel.setVisibilityByIndex(drop.source.visualIndex, Constants.ShowcaseVisibility.NoOne)
root.showcaseEntryChanged()
}
Rectangle {
@ -346,7 +322,9 @@ Control {
}
onDropped: function(drop) {
showcaseModel.remove(drop.source.visualIndex)
showcaseModel.setVisibilityByIndex(drop.source.visualIndex, Constants.ShowcaseVisibility.NoOne)
root.showcaseEntryChanged()
root.updateModelsAfterChange()
}
}
}

View File

@ -1,4 +1,6 @@
import QtQuick 2.13
import QtQuick 2.15
import QtQml 2.15
import utils 1.0
QtObject {
@ -27,6 +29,11 @@ QtObject {
readonly property bool isWalletEnabled: Global.appIsReady? mainModule.sectionsModel.getItemEnabledBySectionType(Constants.appSection.wallet) : true
readonly property var profileShowcaseCommunitiesModel: profileModule.profileShowcaseCommunitiesModel
readonly property var profileShowcaseAccountsModel: profileModule.profileShowcaseAccountsModel
readonly property var profileShowcaseCollectiblesModel: profileModule.profileShowcaseCollectiblesModel
readonly property var profileShowcaseAssetsModel: profileModule.profileShowcaseAssetsModel
onUserDeclinedBackupBannerChanged: {
if (userDeclinedBackupBanner !== localAccountSensitiveSettings.userDeclinedBackupBanner) {
localAccountSensitiveSettings.userDeclinedBackupBanner = userDeclinedBackupBanner
@ -86,4 +93,12 @@ QtObject {
function setBio(bio) {
root.profileModule.setBio(bio)
}
function storeProfileShowcasePreferences() {
root.profileModule.storeProfileShowcasePreferences()
}
function requestProfileShowcasePreferences() {
root.profileModule.requestProfileShowcasePreferences()
}
}

View File

@ -28,6 +28,8 @@ ColumnLayout {
property WalletStore walletStore
property var communitiesModel
property bool hasAnyProfileShowcaseChanges: false
property QtObject dirtyValues: QtObject {
property string displayName: descriptionPanel.displayName.text
property string bio: descriptionPanel.bio.text
@ -37,10 +39,11 @@ ColumnLayout {
readonly property bool dirty: (!descriptionPanel.isEnsName &&
descriptionPanel.displayName.text !== profileStore.displayName) ||
descriptionPanel.bio.text !== profileStore.bio ||
profileStore.socialLinksDirty ||
biometricsSwitch.checked !== biometricsSwitch.currentStoredValue ||
profileHeader.icon !== profileStore.profileLargeImage
descriptionPanel.bio.text !== profileStore.bio ||
profileStore.socialLinksDirty ||
biometricsSwitch.checked !== biometricsSwitch.currentStoredValue ||
profileHeader.icon !== profileStore.profileLargeImage ||
hasAnyProfileShowcaseChanges
readonly property bool valid: !!descriptionPanel.displayName.text && descriptionPanel.displayName.valid
@ -50,9 +53,19 @@ ColumnLayout {
profileStore.resetSocialLinks()
biometricsSwitch.checked = Qt.binding(() => { return biometricsSwitch.currentStoredValue })
profileHeader.icon = Qt.binding(() => { return profileStore.profileLargeImage })
profileShowcaseCommunitiesPanel.reset()
profileShowcaseAccountsPanel.reset()
profileShowcaseCollectiblesPanel.reset()
profileShowcaseAssetsPanel.reset()
root.profileStore.requestProfileShowcasePreferences()
hasAnyProfileShowcaseChanges = false
}
function save() {
if (hasAnyProfileShowcaseChanges)
profileStore.storeProfileShowcasePreferences()
if (!descriptionPanel.isEnsName)
profileStore.setDisplayName(descriptionPanel.displayName.text)
profileStore.setBio(descriptionPanel.bio.text.trim())
@ -75,7 +88,10 @@ ColumnLayout {
reset()
}
Connections {
onVisibleChanged: if (visible) profileStore.requestProfileShowcasePreferences()
Component.onCompleted: profileStore.requestProfileShowcasePreferences()
readonly property Connections privacyStoreConnections: Connections {
target: Qt.platform.os === Constants.mac ? root.privacyStore.privacyModule : null
function onStoreToKeychainError(errorDescription: string) {
@ -161,7 +177,7 @@ ColumnLayout {
}
StatusBaseText {
text: qsTr("Showcase (demo only)")
text: qsTr("Showcase")
color: Theme.palette.baseColor1
}
@ -182,6 +198,7 @@ ColumnLayout {
StatusTabButton {
width: implicitWidth
text: qsTr("Collectibles")
enabled: false // TODO: implement collectibles nim part
}
StatusTabButton {
@ -196,28 +213,40 @@ ColumnLayout {
currentIndex: showcaseTabBar.currentIndex
ProfileShowcaseCommunitiesPanel {
id: profileShowcaseCommunitiesPanel
Layout.minimumHeight: implicitHeight
Layout.maximumHeight: implicitHeight
baseModel: root.communitiesModel
showcaseModel: root.profileStore.profileShowcaseCommunitiesModel
onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true
}
ProfileShowcaseAccountsPanel {
id: profileShowcaseAccountsPanel
Layout.minimumHeight: implicitHeight
Layout.maximumHeight: implicitHeight
baseModel: root.walletStore.accounts
showcaseModel: root.profileStore.profileShowcaseAccountsModel
currentWallet: root.walletStore.overview.mixedcaseAddress
onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true
}
ProfileShowcaseCollectiblesPanel {
id: profileShowcaseCollectiblesPanel
Layout.minimumHeight: implicitHeight
Layout.maximumHeight: implicitHeight
baseModel: root.walletStore.collectibles
showcaseModel: root.profileStore.profileShowcaseCollectiblesModel
onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true
}
ProfileShowcaseAssetsPanel {
id: profileShowcaseAssetsPanel
Layout.minimumHeight: implicitHeight
Layout.maximumHeight: implicitHeight
baseModel: root.walletStore.assets
showcaseModel: root.profileStore.profileShowcaseAssetsModel
onShowcaseEntryChanged: hasAnyProfileShowcaseChanges = true
}
}
}

View File

@ -1028,7 +1028,14 @@ QtObject {
NoOne = 0,
IdVerifiedContacts = 1,
Contacts = 2,
Everyone = 4
Everyone = 3
}
enum ShowcaseEntryType {
Community = 0,
Account = 1,
Collectible = 2,
Asset = 3
}
// refers to ContractTransactionStatus and DeployState in Nim