Improve performance by only updating the properties that changed in the model instead of reseting (#16436)

* perf(notifications): update item props instead of resetting the item

* perf(sections): update sections by properties instead of reseting
This commit is contained in:
Jonathan Rainville 2024-10-23 09:50:05 -04:00 committed by GitHub
parent 1ab4b15e2b
commit d317df032d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 699 additions and 387 deletions

View File

@ -196,7 +196,7 @@ method onChatMemberUpdated*(self: Module, publicKey: string, memberRole: MemberR
return
let contactDetails = self.controller.getContactDetails(publicKey)
let isMe = publicKey == singletonInstance.userProfile.getPubKey()
self.view.model().updateItem(
discard self.view.model().updateItem(
pubKey = publicKey,
displayName = contactDetails.dto.displayName,
ensName = contactDetails.dto.name,

View File

@ -410,7 +410,7 @@ proc init*(self: Controller) =
self.delegate.updateRequestToJoinState(RequestToJoinState.Requested)
self.events.on(SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED) do(e:Args):
let args = community_service.CommunityIdArgs(e)
let args = community_service.CanceledCommunityRequestArgs(e)
if args.communityId == self.sectionId:
self.delegate.updateRequestToJoinState(RequestToJoinState.None)

View File

@ -1,54 +0,0 @@
import stew/shims/strformat
type
PendingRequestItem* = ref object
id: string
publicKey: string
chatId: string
communityId: string
state: int
our: string
proc initItem*(
id: string,
publicKey: string,
chatId: string,
communityId: string,
state: int,
our: string
): PendingRequestItem =
result = PendingRequestItem()
result.id = id
result.publicKey = publicKey
result.chatId = chatId
result.communityId = communityId
result.state = state
result.our = our
proc id*(self: PendingRequestItem): string =
self.id
proc pubKey*(self: PendingRequestItem): string =
self.publicKey
proc chatId*(self: PendingRequestItem): string =
self.chatId
proc communityId*(self: PendingRequestItem): string =
self.communityId
proc state*(self: PendingRequestItem): int =
self.state
proc our*(self: PendingRequestItem): string =
self.our
proc `$`*(self: PendingRequestItem): string =
result = fmt"""PendingRequestItem(
id: {self.id},
publicKey: {$self.publicKey},
chatId: {$self.chatId},
communityId: {$self.communityId},
state: {$self.state},
our: {$self.our},
]"""

View File

@ -1,120 +0,0 @@
import NimQml, Tables
import pending_request_item
type
ModelRole {.pure.} = enum
Id = UserRole + 1
PubKey
ChatId
CommunityId
State
Our
QtObject:
type PendingRequestModel* = ref object of QAbstractListModel
items*: seq[PendingRequestItem]
proc setup(self: PendingRequestModel) =
self.QAbstractListModel.setup
proc delete(self: PendingRequestModel) =
self.items = @[]
self.QAbstractListModel.delete
proc newPendingRequestModel*(): PendingRequestModel =
new(result, delete)
result.setup
proc countChanged(self: PendingRequestModel) {.signal.}
proc setItems*(self: PendingRequestModel, items: seq[PendingRequestItem]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
proc getCount(self: PendingRequestModel): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: PendingRequestModel, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: PendingRequestModel): Table[int, string] =
{
ModelRole.Id.int:"id",
ModelRole.PubKey.int:"pubKey",
ModelRole.ChatId.int:"chatId",
ModelRole.CommunityId.int:"communityId",
ModelRole.State.int:"state",
ModelRole.Our.int:"our"
}.toTable
method data(self: PendingRequestModel, 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.Id:
result = newQVariant(item.id)
of ModelRole.PubKey:
result = newQVariant(item.pubKey)
of ModelRole.ChatId:
result = newQVariant(item.chatId)
of ModelRole.CommunityId:
result = newQVariant(item.communityId)
of ModelRole.State:
result = newQVariant(item.state)
of ModelRole.Our:
result = newQVariant(item.our)
proc findIndexById(self: PendingRequestModel, id: string): int =
for i in 0 ..< self.items.len:
if(self.items[i].id == id):
return i
return -1
proc addItems*(self: PendingRequestModel, items: seq[PendingRequestItem]) =
if(items.len == 0):
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
let first = self.items.len
let last = first + items.len - 1
self.beginInsertRows(parentModelIndex, first, last)
self.items.add(items)
self.endInsertRows()
self.countChanged()
proc addItem*(self: PendingRequestModel, item: PendingRequestItem) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.endInsertRows()
self.countChanged()
proc containsItemWithId*(self: PendingRequestModel, id: string): bool =
return self.findIndexById(id) != -1
proc removeItemWithId*(self: PendingRequestModel, id: string) =
let ind = self.findIndexById(id)
if(ind == -1):
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginRemoveRows(parentModelIndex, ind, ind)
self.items.delete(ind)
self.endRemoveRows()
self.countChanged()

View File

@ -319,8 +319,7 @@ method navigateToCommunity*(self: Module, communityId: string) =
self.delegate.setActiveSectionById(communityId)
method communityEdited*(self: Module, community: CommunityDto) =
self.view.model().editItem(self.getCommunityItem(community))
self.view.communityChanged(community.id)
self.view.updateItem(self.getCommunityItem(community))
method setCuratedCommunities*(self: Module, curatedCommunities: seq[CommunityDto]) =
for community in curatedCommunities:

View File

@ -315,7 +315,7 @@ QtObject:
self.model.addItem(item)
self.communityAdded(item.id)
proc updateItem(self: View, item: SectionItem) =
proc updateItem*(self: View, item: SectionItem) =
self.model.editItem(item)
self.communityChanged(item.id)

View File

@ -309,6 +309,10 @@ proc init*(self: Controller) =
var args = CommunityRequestArgs(e)
self.delegate.newCommunityMembershipRequestReceived(args.communityRequest)
self.events.on(SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED) do(e:Args):
let args = community_service.CanceledCommunityRequestArgs(e)
self.delegate.communityMembershipRequestCanceled(args.communityId, args.requestId, args.pubKey)
self.events.on(SIGNAL_NEW_REQUEST_TO_JOIN_COMMUNITY_ACCEPTED) do(e: Args):
var args = CommunityRequestArgs(e)
self.delegate.communityMemberRevealedAccountsAdded(args.communityRequest)
@ -496,6 +500,13 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e: Args):
self.delegate.onAppNetworkChanged()
self.events.on(SIGNAL_CONTACT_UPDATED) do(e: Args):
let args = ContactArgs(e)
self.delegate.contactUpdated(args.contactId)
self.events.on(SIGNAL_LOGGEDIN_USER_NAME_CHANGED) do(e: Args):
self.delegate.contactUpdated(singletonInstance.userProfile.getPubKey())
proc isConnected*(self: Controller): bool =
return self.nodeService.isConnected()

View File

@ -219,6 +219,9 @@ method newCommunityMembershipRequestReceived*(self: AccessInterface, membershipR
{.base.} =
raise newException(ValueError, "No implementation available")
method communityMembershipRequestCanceled*(self: AccessInterface, communityId: string, requestId: string, pubKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method meMentionedCountChanged*(self: AccessInterface, allMentions: int) {.base.} =
raise newException(ValueError, "No implementation available")
@ -433,6 +436,9 @@ method startTokenHoldersManagement*(self: AccessInterface, communityId: string,
method stopTokenHoldersManagement*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method contactUpdated*(self: AccessInterface, contactId: string) {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c

View File

@ -1,8 +1,7 @@
import NimQml, tables, json, sugar, sequtils, stew/shims/strformat, marshal, times, chronicles, stint, browsers, strutils
import NimQml, tables, json, sequtils, stew/shims/strformat, marshal, times, chronicles, stint, browsers, strutils
import io_interface, view, controller, chat_search_item, chat_search_model
import ephemeral_notification_item, ephemeral_notification_model
import ./communities/models/[pending_request_item, pending_request_model]
import ../shared_models/[user_item, member_item, member_model, section_item, section_model, section_details]
import ../shared_models/[color_hash_item, color_hash_model]
import ../shared_modules/keycard_popup/module as keycard_shared_module
@ -127,7 +126,7 @@ method calculateProfileSectionHasNotification*[T](self: Module[T]): bool
proc switchToContactOrDisplayUserProfile[T](self: Module[T], publicKey: string)
method activateStatusDeepLink*[T](self: Module[T], statusDeepLink: string)
proc checkIfWeHaveNotifications[T](self: Module[T])
proc createMemberItem[T](self: Module[T], memberId: string, requestId: string, state: MembershipRequestState, role: MemberRole, airdropAddress: string = ""): MemberItem
proc newModule*[T](
delegate: T,
@ -342,7 +341,6 @@ proc createCommunitySectionItem[T](self: Module[T], communityDetails: CommunityD
let hasNotification = unviewedCount > 0 or notificationsCount > 0
let active = self.getActiveSectionId() == communityDetails.id # We must pass on if the current item section is currently active to keep that property as it is
# Add members who were kicked from the community after the ownership change for auto-rejoin after they share addresses
var members = communityDetails.members
for requestForAutoRejoin in communityDetails.waitingForSharedAddressesRequestsToJoin:
@ -408,15 +406,6 @@ proc createCommunitySectionItem[T](self: Module[T], communityDetails: CommunityD
airdropAddress,
)
),
# pendingRequestsToJoin
communityDetails.pendingRequestsToJoin.map(x => pending_request_item.initItem(
x.id,
x.publicKey,
x.chatId,
x.communityId,
x.state,
x.our
)),
communityDetails.settings.historyArchiveSupportEnabled,
communityDetails.adminSettings.pinMessageAllMembersEnabled,
bannedMembers,
@ -1102,7 +1091,7 @@ method communityLeft*[T](self: Module[T], communityId: string) =
method communityEdited*[T](
self: Module[T],
community: CommunityDto) =
if(not self.chatSectionModules.contains(community.id)):
if not self.chatSectionModules.contains(community.id):
return
var communitySectionItem = self.createCommunitySectionItem(community, isEdit = true)
# We need to calculate the unread counts because the community update doesn't come with it
@ -1367,7 +1356,17 @@ method newCommunityMembershipRequestReceived*[T](self: Module[T], membershipRequ
let (contactName, _, _) = self.controller.getContactNameAndImage(membershipRequest.publicKey)
let community = self.controller.getCommunityById(membershipRequest.communityId)
singletonInstance.globalEvents.newCommunityMembershipRequestNotification("New membership request",
fmt "{contactName} asks to join {community.name}", community.id)
fmt "{contactName} asks to join {community.name}", community.id)
self.view.model().addPendingMember(membershipRequest.communityId, self.createMemberItem(
membershipRequest.publicKey,
membershipRequest.id,
MembershipRequestState(membershipRequest.state),
MemberRole.None,
))
method communityMembershipRequestCanceled*[T](self: Module[T], communityId: string, requestId: string, pubKey: string) =
self.view.model().removePendingMember(communityId, pubKey)
method meMentionedCountChanged*[T](self: Module[T], allMentions: int) =
singletonInstance.globalEvents.meMentionedIconBadgeNotification(allMentions)
@ -1725,7 +1724,7 @@ method updateRequestToJoinState*[T](self: Module[T], sectionId: string, requestT
if sectionId in self.chatSectionModules:
self.chatSectionModules[sectionId].updateRequestToJoinState(requestToJoinState)
proc createMemberItem*[T](
proc createMemberItem[T](
self: Module[T],
memberId: string,
requestId: string,
@ -1754,4 +1753,20 @@ proc createMemberItem*[T](
airdropAddress = airdropAddress,
)
method contactUpdated*[T](self: Module[T], contactId: string) =
let contactDetails = self.controller.getContactDetails(contactId)
let isMe = contactId == singletonInstance.userProfile.getPubKey()
self.view.model().updateMemberItemInSections(
pubKey = contactId,
displayName = contactDetails.dto.displayName,
ensName = contactDetails.dto.name,
isEnsVerified = contactDetails.dto.ensVerified,
localNickname = contactDetails.dto.localNickname,
alias = contactDetails.dto.alias,
icon = contactDetails.icon,
isContact = contactDetails.dto.isContact,
isVerified = not isMe and contactDetails.dto.isContactVerified(),
isUntrustworthy = contactDetails.dto.trustStatus == TrustStatus.Untrustworthy,
)
{.pop.}

View File

@ -19,9 +19,15 @@ type
globalMentions: string
otherMessages: string
proc initItem*(id, name, image, color: string, joinedTimestamp: int64, itemType: Type, muteAllMessages = false,
personalMentions = VALUE_NOTIF_SEND_ALERTS, globalMentions = VALUE_NOTIF_SEND_ALERTS,
otherMessages = VALUE_NOTIF_TURN_OFF): Item =
proc initItem*(
id, name, image, color: string,
joinedTimestamp: int64,
itemType: Type,
muteAllMessages = false,
personalMentions = VALUE_NOTIF_SEND_ALERTS,
globalMentions = VALUE_NOTIF_SEND_ALERTS,
otherMessages = VALUE_NOTIF_TURN_OFF,
): Item =
result = Item()
result.id = id
result.name = name
@ -46,9 +52,15 @@ proc `name=`*(self: Item, value: string) =
proc image*(self: Item): string =
return self.image
proc `image=`*(self: Item, value: string) =
self.image = value
proc color*(self: Item): string =
self.color
proc `color=`*(self: Item, value: string) =
self.color = value
proc joinedTimestamp*(self: Item): int64 =
return self.joinedTimestamp

View File

@ -2,6 +2,7 @@ import NimQml, Tables
import item
import ../../../../../app_service/service/settings/dto/settings
import ../../../shared_models/model_utils
type
ModelRole {.pure.} = enum
@ -57,10 +58,10 @@ QtObject:
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
if not index.isValid:
return
if (index.row < 0 or index.row >= self.items.len):
if index.row < 0 or index.row >= self.items.len:
return
let item = self.items[index.row]
@ -108,7 +109,7 @@ QtObject:
self.countChanged()
proc setItems*(self: Model, items: seq[Item]) =
if(items.len == 0):
if items.len == 0:
return
let parentModelIndex = newQModelIndex()
@ -129,7 +130,7 @@ QtObject:
proc removeItemById*(self: Model, id: string) =
let ind = self.findIndexForItemId(id)
if(ind == -1):
if ind == -1:
return
let parentModelIndex = newQModelIndex()
@ -150,24 +151,48 @@ QtObject:
let ind = self.findIndexForItemId(id)
if(ind == -1):
return
var roles: seq[int] = @[]
self.items[ind].muteAllMessages = muteAllMessages
self.items[ind].personalMentions = personalMentions
self.items[ind].globalMentions = globalMentions
self.items[ind].otherMessages = otherMessages
updateRole(muteAllMessages, MuteAllMessages)
updateRole(personalMentions, PersonalMentions)
updateRole(globalMentions, GlobalMentions)
updateRole(otherMessages, OtherMessages)
if roles.len == 0:
return
roles.add(ModelRole.Customized.int)
let index = self.createIndex(ind, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.MuteAllMessages.int, ModelRole.PersonalMentions.int,
ModelRole.GlobalMentions.int, ModelRole.OtherMessages.int, ModelRole.Customized.int])
self.dataChanged(index, index, roles)
proc updateName*(self: Model, id: string, name: string) =
let ind = self.findIndexForItemId(id)
if(ind == -1):
if ind == -1 or self.items[ind].name == name:
return
self.items[ind].name = name
let index = self.createIndex(ind, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.Name.int])
self.dataChanged(index, index, @[ModelRole.Name.int])
proc updateItem*(self: Model, id, name, image, color: string) =
let ind = self.findIndexForItemId(id)
if ind == -1:
return
var roles: seq[int] = @[]
updateRole(name, Name)
updateRole(image, Image)
updateRole(color, Color)
if roles.len == 0:
return
let index = self.createIndex(ind, 0, nil)
defer: index.delete
self.dataChanged(index, index, roles)

View File

@ -129,27 +129,29 @@ method addCommunity*(self: Module, communityDto: CommunityDto) =
self.view.exemptionsModel().addItem(item)
method editCommunity*(self: Module, communityDto: CommunityDto) =
self.view.exemptionsModel().removeItemById(communityDto.id)
let item = self.createItem(communityDto.id, communityDto.name, communityDto.images.thumbnail, communityDto.color,
joinedTimestamp = 0, item.Type.Community)
self.view.exemptionsModel().addItem(item)
self.view.exemptionsModel().updateItem(
communityDto.id,
communityDto.name,
communityDto.images.thumbnail,
communityDto.color,
)
method removeItemWithId*(self: Module, itemId: string) =
if(self.controller.removeNotifSettingExemptions(itemId)):
if self.controller.removeNotifSettingExemptions(itemId):
self.view.exemptionsModel().removeItemById(itemId)
method addChat*(self: Module, chatDto: ChatDto) =
if chatDto.chatType != ChatType.OneToOne and chatDto.chatType != ChatType.PrivateGroupChat:
return
let ind = self.view.exemptionsModel().findIndexForItemId(chatDto.id)
if(ind != -1):
if ind != -1:
return
let item = self.createChatItem(chatDto)
self.view.exemptionsModel().addItem(item)
method addChat*(self: Module, itemId: string) =
let ind = self.view.exemptionsModel().findIndexForItemId(itemId)
if(ind != -1):
if ind != -1:
return
let chatDto = self.controller.getChatDetails(itemId)
if chatDto.chatType != ChatType.OneToOne and chatDto.chatType != ChatType.PrivateGroupChat:

View File

@ -73,7 +73,7 @@ QtObject:
proc editItem*(self: View, item: SectionItem) =
self.model.editItem(item)
if (self.activeSection.getId() == item.id):
if self.activeSection.getId() == item.id:
self.activeSectionSet(item)
proc model*(self: View): SectionModel =
@ -164,7 +164,6 @@ QtObject:
proc activeSectionSet*(self: View, item: SectionItem) =
self.activeSection.setActiveSectionData(item)
self.activeSectionChanged()
proc setNthEnabledSectionActive*(self: View, nth: int) {.slot.} =
let item = self.model.getNthEnabledItem(nth)

View File

@ -1,11 +1,11 @@
import NimQml, Tables, stew/shims/strformat, sequtils, sugar
# TODO: use generics to remove duplication between user_model and member_model
import ../../../app_service/common/types
import ../../../app_service/service/contacts/dto/contacts
import member_item
import contacts_utils
import model_utils
type
ModelRole {.pure.} = enum
@ -74,7 +74,7 @@ QtObject:
read = getCount
notify = countChanged
method rowCount(self: Model, index: QModelIndex = nil): int =
method rowCount*(self: Model, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: Model): Table[int, string] =
@ -174,6 +174,44 @@ QtObject:
self.endInsertRows()
self.countChanged()
proc findIndexForMember(self: Model, pubKey: string): int =
for i in 0 ..< self.items.len:
if(self.items[i].pubKey == pubKey):
return i
return -1
proc getMemberItem*(self: Model, pubKey: string): MemberItem =
let ind = self.findIndexForMember(pubKey)
if ind != -1:
return self.items[ind]
proc removeItemWithIndex(self: Model, index: int) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginRemoveRows(parentModelIndex, index, index)
self.items.delete(index)
self.endRemoveRows()
self.countChanged()
proc removeAllItems(self: Model) =
if self.items.len <= 0:
return
self.beginResetModel()
self.items = @[]
self.endResetModel()
self.countChanged()
# TODO: rename me to removeItemByPubkey
proc removeItemById*(self: Model, pubKey: string) =
let ind = self.findIndexForMember(pubKey)
if ind == -1:
return
self.removeItemWithIndex(ind)
proc addItems*(self: Model, items: seq[MemberItem]) =
if items.len == 0:
return
@ -189,22 +227,6 @@ QtObject:
self.endInsertRows()
self.countChanged()
proc findIndexForMember(self: Model, pubKey: string): int =
for i in 0 ..< self.items.len:
if(self.items[i].pubKey == pubKey):
return i
return -1
proc removeItemWithIndex(self: Model, index: int) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginRemoveRows(parentModelIndex, index, index)
self.items.delete(index)
self.endRemoveRows()
self.countChanged()
proc isContactWithIdAdded*(self: Model, id: string): bool =
return self.findIndexForMember(id) != -1
@ -219,17 +241,9 @@ QtObject:
resolvePreferredDisplayName(self.items[ind].localNickname, self.items[ind].ensName, self.items[ind].displayName, self.items[ind].alias) !=
resolvePreferredDisplayName(localNickname, ensName, displayName, self.items[ind].alias)
if self.items[ind].displayName != displayName:
self.items[ind].displayName = displayName
roles.add(ModelRole.DisplayName.int)
if self.items[ind].ensName != ensName:
self.items[ind].ensName = ensName
roles.add(ModelRole.EnsName.int)
if self.items[ind].localNickname != localNickname:
self.items[ind].localNickname = localNickname
roles.add(ModelRole.LocalNickname.int)
updateRole(displayName, DisplayName)
updateRole(ensName, EnsName)
updateRole(localNickname, LocalNickname)
if roles.len == 0:
return
@ -269,7 +283,8 @@ QtObject:
memberRole: MemberRole,
joined: bool,
isUntrustworthy: bool,
) =
callDataChanged: bool = true,
): seq[int] =
let ind = self.findIndexForMember(pubKey)
if ind == -1:
return
@ -278,51 +293,19 @@ QtObject:
let preferredDisplayNameChanged =
resolvePreferredDisplayName(self.items[ind].localNickname, self.items[ind].ensName, self.items[ind].displayName, self.items[ind].alias) !=
resolvePreferredDisplayName(localNickname, ensName, displayName, alias)
resolvePreferredDisplayName(localNickname, ensName, displayName, self.items[ind].alias)
if self.items[ind].displayName != displayName:
self.items[ind].displayName = displayName
roles.add(ModelRole.DisplayName.int)
if self.items[ind].ensName != ensName:
self.items[ind].ensName = ensName
roles.add(ModelRole.EnsName.int)
if self.items[ind].localNickname != localNickname:
self.items[ind].localNickname = localNickname
roles.add(ModelRole.LocalNickname.int)
if self.items[ind].isEnsVerified != isEnsVerified:
self.items[ind].isEnsVerified = isEnsVerified
roles.add(ModelRole.IsEnsVerified.int)
if self.items[ind].alias != alias:
self.items[ind].alias = alias
roles.add(ModelRole.Alias.int)
if self.items[ind].icon != icon:
self.items[ind].icon = icon
roles.add(ModelRole.Icon.int)
if self.items[ind].isContact != isContact:
self.items[ind].isContact = isContact
roles.add(ModelRole.IsContact.int)
if self.items[ind].isVerified != isVerified:
self.items[ind].isVerified = isVerified
roles.add(ModelRole.IsVerified.int)
if self.items[ind].memberRole != memberRole:
self.items[ind].memberRole = memberRole
roles.add(ModelRole.MemberRole.int)
if self.items[ind].joined != joined:
self.items[ind].joined = joined
roles.add(ModelRole.Joined.int)
if self.items[ind].isUntrustworthy != isUntrustworthy:
self.items[ind].isUntrustworthy = isUntrustworthy
roles.add(ModelRole.IsUntrustworthy.int)
updateRole(displayName, DisplayName)
updateRole(ensName, EnsName)
updateRole(localNickname, LocalNickname)
updateRole(isEnsVerified, IsEnsVerified)
updateRole(alias, Alias)
updateRole(icon, Icon)
updateRole(isContact, IsContact)
updateRole(isVerified, IsVerified)
updateRole(memberRole, MemberRole)
updateRole(joined, Joined)
updateRole(isUntrustworthy, IsUntrustworthy)
if preferredDisplayNameChanged:
roles.add(ModelRole.PreferredDisplayName.int)
@ -330,9 +313,89 @@ QtObject:
if roles.len == 0:
return
let index = self.createIndex(ind, 0, nil)
defer: index.delete
self.dataChanged(index, index, roles)
if callDataChanged:
let index = self.createIndex(ind, 0, nil)
defer: index.delete
self.dataChanged(index, index, roles)
return roles
proc updateItems*(self: Model, items: seq[MemberItem]) =
var startIndex = -1
var endIndex = -1
var allRoles: seq[int] = @[]
for item in items:
let itemIndex = self.findIndexForMember(item.pubKey)
if itemIndex == -1:
continue
let roles = self.updateItem(
item.pubKey,
item.displayName,
item.ensName,
item.isEnsVerified,
item.localNickname,
item.alias,
item.icon,
item.isContact,
item.isVerified,
item.memberRole,
item.joined,
item.isUntrustworthy,
callDataChanged = false,
)
if roles.len > 0:
if startIndex == -1:
startIndex = itemIndex
endIndex = itemIndex
allRoles = concat(allRoles, roles)
if allRoles.len == 0:
return
let startModelIndex = self.createIndex(startIndex, 0, nil)
let endModelIndex = self.createIndex(endIndex, 0, nil)
defer: startModelIndex.delete
defer: endModelIndex.delete
self.dataChanged(startModelIndex, endModelIndex, allRoles)
proc updateToTheseItems*(self: Model, items: seq[MemberItem]) =
if items.len == 0:
self.removeAllItems()
return
# Check for removals
var itemsToRemove: seq[string] = @[]
for oldItem in self.items:
var found = false
for newItem in items:
if oldItem.pubKey == newItem.pubKey:
found = true
break
if not found:
itemsToRemove.add(oldItem.pubKey)
for itemToRemove in itemsToRemove:
self.removeItemById(itemToRemove)
var itemsToAdd: seq[MemberItem] = @[]
var itemsToUpdate: seq[MemberItem] = @[]
for item in items:
let ind = self.findIndexForMember(item.pubKey)
if ind == -1:
# Item does not exist, we add it
itemsToAdd.add(item)
continue
itemsToUpdate.add(item)
if itemsToUpdate.len > 0:
self.updateItems(itemsToUpdate)
if itemsToAdd.len > 0:
self.addItems(itemsToAdd)
proc updateItem*(
self: Model,
@ -351,7 +414,7 @@ QtObject:
if ind == -1:
return
self.updateItem(
discard self.updateItem(
pubKey,
displayName,
ensName,
@ -403,14 +466,6 @@ QtObject:
return self.items[idx].airdropAddress
# TODO: rename me to removeItemByPubkey
proc removeItemById*(self: Model, pubKey: string) =
let ind = self.findIndexForMember(pubKey)
if ind == -1:
return
self.removeItemWithIndex(ind)
# TODO: rename me to getItemsAsPubkeys
proc getItemIds*(self: Model): seq[string] =
return self.items.map(i => i.pubKey)

View File

@ -0,0 +1,20 @@
import std/macros
# Macro that simplifies checking and updating values in a model
# IMPORTANT:
# The model's items need to be in a `seq` called `items`
# A `seq[string]` named `roles` needs to exist
# The index of the item being checked must be named `ind`
macro updateRole*(propertyName: untyped, roleName: untyped): untyped =
quote do:
if self.items[ind].`propertyName` != `propertyName`:
self.items[ind].`propertyName` = `propertyName`
roles.add(ModelRole.`roleName`.int)
# Same thing as updateRole where you have a value to set that is not the same **exact** name as the propertyName
# Eg: updateRoleWithValue(name, Name, item.name)
macro updateRoleWithValue*(propertyName: untyped, roleName: untyped, value: untyped): untyped =
quote do:
if self.items[ind].`propertyName` != `value`:
self.items[ind].`propertyName` = `value`
roles.add(ModelRole.`roleName`.int)

View File

@ -17,25 +17,50 @@ QtObject:
new(result, delete)
result.setup
proc setActiveSectionData*(self: SectionDetails, item: SectionItem) =
self.id = item.id
self.sectionType = item.sectionType
self.joined = item.joined
proc idChanged*(self: SectionDetails) {.signal.}
proc getId*(self: SectionDetails): string {.slot.} =
return self.id
QtProperty[string] id:
read = getId
notify = idChanged
proc sectionTypeChanged*(self: SectionDetails) {.signal.}
proc getSectionType(self: SectionDetails): int {.slot.} =
return self.sectionType.int
QtProperty[int] sectionType:
read = getSectionType
notify = sectionTypeChanged
proc joinedChanged*(self: SectionDetails) {.signal.}
proc getJoined(self: SectionDetails): bool {.slot.} =
return self.joined
QtProperty[bool] joined:
read = getJoined
read = getJoined
notify = joinedChanged
proc setActiveSectionData*(self: SectionDetails, item: SectionItem) =
var idChanged = false
var joinedChanged = false
var sectionTypeChanged = false
if self.id != item.id:
self.id = item.id
idChanged = true
if self.joined != item.joined:
self.joined = item.joined
joinedChanged = true
if self.sectionType != item.sectionType:
self.sectionType = item.sectionType
sectionTypeChanged = true
if idChanged:
self.idChanged()
if joinedChanged:
self.joinedChanged()
if sectionTypeChanged:
self.sectionTypeChanged()

View File

@ -1,6 +1,5 @@
import stew/shims/strformat, stint
import ./member_model, ./member_item
import ../main/communities/models/[pending_request_item, pending_request_model]
import ../main/communities/tokens/models/token_model as community_tokens_model
import ../main/communities/tokens/models/token_item
@ -48,7 +47,6 @@ type
ensOnly: bool
muted: bool
membersModel: member_model.Model
pendingRequestsToJoinModel: PendingRequestModel
historyArchiveSupportEnabled: bool
pinMessageAllMembersEnabled: bool
bannedMembersModel: member_model.Model
@ -89,7 +87,6 @@ proc initItem*(
ensOnly = false,
muted = false,
members: seq[MemberItem] = @[],
pendingRequestsToJoin: seq[PendingRequestItem] = @[],
historyArchiveSupportEnabled = false,
pinMessageAllMembersEnabled = false,
bannedMembers: seq[MemberItem] = @[],
@ -130,8 +127,6 @@ proc initItem*(
result.muted = muted
result.membersModel = newModel()
result.membersModel.setItems(members)
result.pendingRequestsToJoinModel = newPendingRequestModel()
result.pendingRequestsToJoinModel.setItems(pendingRequestsToJoin)
result.historyArchiveSupportEnabled = historyArchiveSupportEnabled
result.pinMessageAllMembersEnabled = pinMessageAllMembersEnabled
result.bannedMembersModel = newModel()
@ -199,6 +194,9 @@ proc sectionType*(self: SectionItem): SectionType {.inline.} =
proc name*(self: SectionItem): string {.inline.} =
self.name
proc `name=`*(self: var SectionItem, value: string) {.inline.} =
self.name = value
proc memberRole*(self: SectionItem): MemberRole {.inline.} =
self.memberRole
@ -208,30 +206,57 @@ proc `memberRole=`*(self: var SectionItem, value: MemberRole) {.inline.} =
proc isControlNode*(self: SectionItem): bool {.inline.} =
self.isControlNode
proc `isControlNode=`*(self: var SectionItem, value: bool) {.inline.} =
self.isControlNode = value
proc description*(self: SectionItem): string {.inline.} =
self.description
proc `description=`*(self: var SectionItem, value: string) {.inline.} =
self.description = value
proc introMessage*(self: SectionItem): string {.inline.} =
self.introMessage
proc `introMessage=`*(self: var SectionItem, value: string) {.inline.} =
self.introMessage = value
proc outroMessage*(self: SectionItem): string {.inline.} =
self.outroMessage
proc `outroMessage=`*(self: var SectionItem, value: string) {.inline.} =
self.outroMessage = value
proc image*(self: SectionItem): string {.inline.} =
self.image
proc `image=`*(self: var SectionItem, value: string) {.inline.} =
self.image = value
proc bannerImageData*(self: SectionItem): string {.inline.} =
self.bannerImageData
proc `bannerImageData=`*(self: var SectionItem, value: string) {.inline.} =
self.bannerImageData = value
proc icon*(self: SectionItem): string {.inline.} =
self.icon
proc `icon=`*(self: var SectionItem, value: string) {.inline.} =
self.icon = value
proc color*(self: SectionItem): string {.inline.} =
self.color
proc `color=`*(self: var SectionItem, value: string) {.inline.} =
self.color = value
proc tags*(self: SectionItem): string {.inline.} =
self.tags
proc `tags=`*(self: var SectionItem, value: string) {.inline.} =
self.tags = value
proc hasNotification*(self: SectionItem): bool {.inline.} =
self.hasNotification
@ -265,27 +290,51 @@ proc `enabled=`*(self: var SectionItem, value: bool) {.inline.} =
proc joined*(self: SectionItem): bool {.inline.} =
self.joined
proc `joined=`*(self: var SectionItem, value: bool) {.inline.} =
self.joined = value
proc canJoin*(self: SectionItem): bool {.inline.} =
self.canJoin
proc `canJoin=`*(self: var SectionItem, value: bool) {.inline.} =
self.canJoin = value
proc spectated*(self: SectionItem): bool {.inline.} =
self.spectated
proc `spectated=`*(self: var SectionItem, value: bool) {.inline.} =
self.spectated = value
proc canRequestAccess*(self: SectionItem): bool {.inline.} =
self.canRequestAccess
proc `canRequestAccess=`*(self: var SectionItem, value: bool) {.inline.} =
self.canRequestAccess = value
proc canManageUsers*(self: SectionItem): bool {.inline.} =
self.canManageUsers
proc `canManageUsers=`*(self: var SectionItem, value: bool) {.inline.} =
self.canManageUsers = value
proc isMember*(self: SectionItem): bool {.inline.} =
self.isMember
proc `isMember=`*(self: var SectionItem, value: bool) {.inline.} =
self.isMember = value
proc access*(self: SectionItem): int {.inline.} =
self.access
proc `access=`*(self: var SectionItem, value: int) {.inline.} =
self.access = value
proc ensOnly*(self: SectionItem): bool {.inline.} =
self.ensOnly
proc `ensOnly=`*(self: var SectionItem, value: bool) {.inline.} =
self.ensOnly = value
proc muted*(self: SectionItem): bool {.inline.} =
self.muted
@ -331,21 +380,30 @@ proc declinedMemberRequests*(self: SectionItem): member_model.Model {.inline.} =
proc isPendingOwnershipRequest*(self: SectionItem): bool {.inline.} =
self.isPendingOwnershipRequest
proc `isPendingOwnershipRequest=`*(self: var SectionItem, value: bool) {.inline.} =
self.isPendingOwnershipRequest = value
proc setIsPendingOwnershipRequest*(self: var SectionItem, isPending: bool) {.inline.} =
self.isPendingOwnershipRequest = isPending
proc pendingRequestsToJoin*(self: SectionItem): PendingRequestModel {.inline.} =
self.pendingRequestsToJoinModel
proc historyArchiveSupportEnabled*(self: SectionItem): bool {.inline.} =
self.historyArchiveSupportEnabled
proc `historyArchiveSupportEnabled=`*(self: var SectionItem, value: bool) {.inline.} =
self.historyArchiveSupportEnabled = value
proc pinMessageAllMembersEnabled*(self: SectionItem): bool {.inline.} =
self.pinMessageAllMembersEnabled
proc `pinMessageAllMembersEnabled=`*(self: var SectionItem, value: bool) {.inline.} =
self.pinMessageAllMembersEnabled = value
proc encrypted*(self: SectionItem): bool {.inline.} =
self.encrypted
proc `encrypted=`*(self: var SectionItem, value: bool) {.inline.} =
self.encrypted = value
proc appendCommunityToken*(self: SectionItem, item: TokenItem) {.inline.} =
self.communityTokensModel.appendItem(item)

View File

@ -2,8 +2,9 @@ import NimQml, Tables, strutils, stew/shims/strformat
import json
import section_item, member_model
import section_item, member_model, member_item
import ../main/communities/tokens/models/[token_item, token_model]
import model_utils
type
ModelRole {.pure.} = enum
@ -34,7 +35,6 @@ type
EnsOnly
Muted
MembersModel
PendingRequestsToJoinModel
HistoryArchiveSupportEnabled
PinMessageAllMembersEnabled
BannedMembersModel
@ -111,7 +111,6 @@ QtObject:
ModelRole.EnsOnly.int:"ensOnly",
ModelRole.Muted.int:"muted",
ModelRole.MembersModel.int:"members",
ModelRole.PendingRequestsToJoinModel.int:"pendingRequestsToJoin",
ModelRole.HistoryArchiveSupportEnabled.int:"historyArchiveSupportEnabled",
ModelRole.PinMessageAllMembersEnabled.int:"pinMessageAllMembersEnabled",
ModelRole.BannedMembersModel.int:"bannedMembers",
@ -191,8 +190,6 @@ QtObject:
result = newQVariant(item.muted)
of ModelRole.MembersModel:
result = newQVariant(item.members)
of ModelRole.PendingRequestsToJoinModel:
result = newQVariant(item.pendingRequestsToJoin)
of ModelRole.HistoryArchiveSupportEnabled:
result = newQVariant(item.historyArchiveSupportEnabled)
of ModelRole.PinMessageAllMembersEnabled:
@ -283,9 +280,11 @@ QtObject:
self.countChanged()
proc setMuted*(self: SectionModel, id: string, muted: bool) =
let index = self.getItemIndex(id)
if (index == -1):
if index == -1:
return
if self.items[index].muted == muted:
return
self.items[index].muted = muted
@ -294,14 +293,119 @@ QtObject:
self.dataChanged(dataIndex, dataIndex, @[ModelRole.Muted.int])
proc editItem*(self: SectionModel, item: SectionItem) =
let index = self.getItemIndex(item.id)
if (index == -1):
let ind = self.getItemIndex(item.id)
if ind == -1:
return
var roles: seq[int] = @[]
updateRoleWithValue(name, Name, item.name)
updateRoleWithValue(memberRole, MemberRole, item.memberRole)
updateRoleWithValue(isControlNode, IsControlNode, item.isControlNode)
updateRoleWithValue(description, Description, item.description)
updateRoleWithValue(introMessage, IntroMessage, item.introMessage)
updateRoleWithValue(outroMessage, OutroMessage, item.outroMessage)
updateRoleWithValue(image, Image, item.image)
updateRoleWithValue(bannerImageData, BannerImageData, item.bannerImageData)
updateRoleWithValue(icon, Icon, item.icon)
updateRoleWithValue(color, Color, item.color)
updateRoleWithValue(tags, Tags, item.tags)
updateRoleWithValue(hasNotification, HasNotification, item.hasNotification)
updateRoleWithValue(notificationsCount, NotificationsCount, item.notificationsCount)
updateRoleWithValue(active, Active, item.active)
updateRoleWithValue(enabled, Enabled, item.enabled)
updateRoleWithValue(joined, Joined, item.joined)
updateRoleWithValue(spectated, Spectated, item.spectated)
updateRoleWithValue(isMember, IsMember, item.isMember)
updateRoleWithValue(isMember, IsMember, item.isMember)
updateRoleWithValue(canManageUsers, CanManageUsers, item.canManageUsers)
updateRoleWithValue(canRequestAccess, CanRequestAccess, item.canRequestAccess)
updateRoleWithValue(access, Access, item.access)
updateRoleWithValue(ensOnly, EnsOnly, item.ensOnly)
updateRoleWithValue(muted, Muted, item.muted)
updateRoleWithValue(historyArchiveSupportEnabled, HistoryArchiveSupportEnabled, item.historyArchiveSupportEnabled)
updateRoleWithValue(pinMessageAllMembersEnabled, PinMessageAllMembersEnabled, item.pinMessageAllMembersEnabled)
updateRoleWithValue(encrypted, Encrypted, item.encrypted)
updateRoleWithValue(pubsubTopic, PubsubTopic, item.pubsubTopic)
updateRoleWithValue(pubsubTopicKey, PubsubTopicKey, item.pubsubTopicKey)
updateRoleWithValue(shardIndex, ShardIndex, item.shardIndex)
updateRoleWithValue(isPendingOwnershipRequest, IsPendingOwnershipRequest, item.isPendingOwnershipRequest)
self.items[ind].members.updateToTheseItems(item.members.getItems())
self.items[ind].bannedMembers.updateToTheseItems(item.bannedMembers.getItems())
self.items[ind].pendingMemberRequests.updateToTheseItems(item.pendingMemberRequests.getItems())
self.items[ind].declinedMemberRequests.updateToTheseItems(item.declinedMemberRequests.getItems())
if roles.len == 0:
return
self.items[index] = item
let dataIndex = self.createIndex(index, 0, nil)
let dataIndex = self.createIndex(ind, 0, nil)
defer: dataIndex.delete
self.dataChanged(dataIndex, dataIndex)
self.dataChanged(dataIndex, dataIndex, roles)
proc updateMemberItemInSections*(
self: SectionModel,
pubKey: string,
displayName: string,
ensName: string,
isEnsVerified: bool,
localNickname: string,
alias: string,
icon: string,
isContact: bool,
isVerified: bool,
isUntrustworthy: bool,
) =
for item in self.items:
# TODO refactor to use only one model https://github.com/status-im/status-desktop/issues/16433
item.members.updateItem(
pubKey,
displayName,
ensName,
isEnsVerified,
localNickname,
alias,
icon,
isContact,
isVerified,
isUntrustworthy,
)
item.bannedMembers.updateItem(
pubKey,
displayName,
ensName,
isEnsVerified,
localNickname,
alias,
icon,
isContact,
isVerified,
isUntrustworthy,
)
item.pendingMemberRequests.updateItem(
pubKey,
displayName,
ensName,
isEnsVerified,
localNickname,
alias,
icon,
isContact,
isVerified,
isUntrustworthy,
)
item.declinedMemberRequests.updateItem(
pubKey,
displayName,
ensName,
isEnsVerified,
localNickname,
alias,
icon,
isContact,
isVerified,
isUntrustworthy,
)
proc getNthEnabledItem*(self: SectionModel, nth: int): SectionItem =
if nth >= 0 and nth < self.items.len:
@ -330,13 +434,13 @@ QtObject:
proc setActiveSection*(self: SectionModel, id: string) =
for i in 0 ..< self.items.len:
if(self.items[i].active):
if self.items[i].active:
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.items[i].active = false
self.dataChanged(index, index, @[ModelRole.Active.int])
if(self.items[i].id == id):
if self.items[i].id == id:
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.items[i].active = true
@ -348,9 +452,11 @@ QtObject:
proc notificationsCountChanged*(self: SectionModel) {.signal.}
proc enableDisableSection(self: SectionModel, sectionType: SectionType, value: bool) =
if(sectionType != SectionType.Community):
if sectionType != SectionType.Community:
for i in 0 ..< self.items.len:
if(self.items[i].sectionType == sectionType):
if self.items[i].sectionType == sectionType:
if self.items[i].enabled == value:
continue
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.items[i].enabled = value
@ -359,9 +465,9 @@ QtObject:
var topInd = -1
var bottomInd = -1
for i in 0 ..< self.items.len:
if(self.items[i].sectionType == sectionType):
if self.items[i].sectionType == sectionType:
self.items[i].enabled = value
if(topInd == -1):
if topInd == -1:
topInd = i
bottomInd = i
@ -393,21 +499,31 @@ QtObject:
proc updateIsPendingOwnershipRequest*(self: SectionModel, id: string, isPending: bool) =
for i in 0 ..< self.items.len:
if(self.items[i].id == id):
if self.items[i].id == id:
let index = self.createIndex(i, 0, nil)
defer: index.delete
if self.items[i].isPendingOwnershipRequest == isPending:
return
self.items[i].setIsPendingOwnershipRequest(isPending)
self.dataChanged(index, index, @[ModelRole.IsPendingOwnershipRequest.int])
return
proc updateNotifications*(self: SectionModel, id: string, hasNotification: bool, notificationsCount: int) =
for i in 0 ..< self.items.len:
if(self.items[i].id == id):
let index = self.createIndex(i, 0, nil)
for ind in 0 ..< self.items.len:
if self.items[ind].id == id:
var roles: seq[int] = @[]
updateRole(hasNotification, HasNotification)
updateRole(notificationsCount, NotificationsCount)
if roles.len == 0:
return
let index = self.createIndex(ind, 0, nil)
defer: index.delete
self.items[i].hasNotification = hasNotification
self.items[i].notificationsCount = notificationsCount
self.dataChanged(index, index, @[ModelRole.HasNotification.int, ModelRole.NotificationsCount.int])
self.dataChanged(index, index, roles)
self.notificationsCountChanged()
return
@ -423,7 +539,6 @@ QtObject:
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.items[i].appendCommunityToken(item)
self.dataChanged(index, index, @[ModelRole.CommunityTokensModel.int])
return
proc getSectionNameById*(self: SectionModel, sectionId: string): string {.slot.} =
@ -476,9 +591,23 @@ QtObject:
for pubkey, airdropAddress in communityMembersAirdropAddress.pairs:
self.items[index].members.setAirdropAddress(pubkey, airdropAddress)
proc setTokenItems*(self: SectionModel, id: string, communityTokensItems: seq[TokenItem]) =
proc setTokenItems*(self: SectionModel, id: string, communityTokensItems: seq[TokenItem]) =
let index = self.getItemIndex(id)
if (index == -1):
return
self.items[index].communityTokens.setItems(communityTokensItems)
proc addPendingMember*(self: SectionModel, communityId: string, memberItem: MemberItem) =
let i = self.getItemIndex(communityId)
if i == -1:
return
self.items[i].pendingMemberRequests.addItem(memberItem)
proc removePendingMember*(self: SectionModel, communityId: string, memberId: string) =
let i = self.getItemIndex(communityId)
if i == -1:
return
self.items[i].pendingMemberRequests.removeItemById(memberId)

View File

@ -3,6 +3,7 @@ import user_item
import ../../../app_service/common/types
import contacts_utils
import model_utils
type
ModelRole {.pure.} = enum
@ -272,17 +273,9 @@ QtObject:
resolvePreferredDisplayName(self.items[ind].localNickname, self.items[ind].ensName, self.items[ind].displayName, self.items[ind].alias) !=
resolvePreferredDisplayName(localNickname, ensName, displayName, self.items[ind].alias)
if self.items[ind].displayName != displayName:
self.items[ind].displayName = displayName
roles.add(ModelRole.DisplayName.int)
if self.items[ind].ensName != ensName:
self.items[ind].ensName = ensName
roles.add(ModelRole.EnsName.int)
if self.items[ind].localNickname != localNickname:
self.items[ind].localNickname = localNickname
roles.add(ModelRole.LocalNickname.int)
updateRole(displayName, DisplayName)
updateRole(ensName, EnsName)
updateRole(localNickname, LocalNickname)
if preferredDisplayNameChanged:
roles.add(ModelRole.PreferredDisplayName.int)
@ -319,7 +312,7 @@ QtObject:
isUntrustworthy: bool = false,
) =
let ind = self.findIndexByPubKey(pubKey)
if(ind == -1):
if ind == -1:
return
var roles: seq[int] = @[]
@ -328,33 +321,12 @@ QtObject:
resolvePreferredDisplayName(self.items[ind].localNickname, self.items[ind].ensName, self.items[ind].displayName, self.items[ind].alias) !=
resolvePreferredDisplayName(localNickname, ensName, displayName, alias)
if self.items[ind].displayName != displayName:
self.items[ind].displayName = displayName
roles.add(ModelRole.DisplayName.int)
if self.items[ind].ensName != ensName:
self.items[ind].ensName = ensName
roles.add(ModelRole.EnsName.int)
if self.items[ind].isEnsVerified != isEnsVerified:
self.items[ind].isEnsVerified = isEnsVerified
roles.add(ModelRole.IsEnsVerified.int)
if self.items[ind].localNickname != localNickname:
self.items[ind].localNickname = localNickname
roles.add(ModelRole.LocalNickname.int)
if self.items[ind].alias != alias:
self.items[ind].alias = alias
roles.add(ModelRole.Alias.int)
if self.items[ind].icon != icon:
self.items[ind].icon = icon
roles.add(ModelRole.Icon.int)
if self.items[ind].isUntrustworthy != isUntrustworthy:
self.items[ind].isUntrustworthy = isUntrustworthy
roles.add(ModelRole.IsUntrustworthy.int)
updateRole(displayName, DisplayName)
updateRole(ensName, EnsName)
updateRole(localNickname, LocalNickname)
updateRole(alias, Alias)
updateRole(icon, Icon)
updateRole(isUntrustworthy, IsUntrustworthy)
if preferredDisplayNameChanged:
roles.add(ModelRole.PreferredDisplayName.int)

View File

@ -1,6 +1,6 @@
{.used.}
import json, sequtils, sugar, tables, strutils, json_serialization
import json, sequtils, sugar, tables, strutils, json_serialization, strformat
import ../../../../backend/communities
include ../../../common/json_utils
@ -64,6 +64,17 @@ type CommunityMembershipRequestDto* = object
our*: string #FIXME: should be bool
revealedAccounts*: seq[RevealedAccount]
proc `$`*(self: CommunityMembershipRequestDto): string =
return fmt"""CommunityMembershipRequestDto(
id:{self.id},
publicKey:{self.publicKey},
chatId:{self.chatId},
communityId:{self.communityId},
state:{self.state},
our:{self.our},
revealedAccounts.count:{self.revealedAccounts.len},
"""
type CommunitySettingsDto* = object
id*: string
historyArchiveSupportEnabled*: bool

View File

@ -55,6 +55,11 @@ type
CommunityRequestArgs* = ref object of Args
communityRequest*: CommunityMembershipRequestDto
CanceledCommunityRequestArgs* = ref object of Args
communityId*: string
requestId*: string
pubKey*: string
CommunityRequestFailedArgs* = ref object of Args
communityId*: string
error*: string
@ -1976,6 +1981,14 @@ QtObject:
# If the state is now declined, add to the declined requests
if newState == RequestToJoinType.Declined:
community.declinedRequestsToJoin.add(community.pendingRequestsToJoin[indexPending])
elif newState == RequestToJoinType.Canceled:
self.events.emit(SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED,
CanceledCommunityRequestArgs(
communityId: communityId,
requestId: requestId,
pubKey: community.pendingRequestsToJoin[indexPending].publicKey,
)
)
# If the state is no longer pending, delete the request
community.pendingRequestsToJoin.delete(indexPending)
@ -2013,9 +2026,15 @@ QtObject:
error "error while cancel membership request ", msg
return
self.events.emit(SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED,
CanceledCommunityRequestArgs(
communityId: communityId,
requestId: myPendingRequest.id,
pubKey: community.pendingRequestsToJoin[i].publicKey,
)
)
community.pendingRequestsToJoin.delete(i)
self.communities[communityId] = community
self.events.emit(SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED, CommunityIdArgs(communityId: communityId))
checkAndEmitACNotificationsFromResponse(self.events, response.result{"activityCenterNotifications"})
return

View File

@ -0,0 +1,128 @@
import unittest
import app/modules/shared_models/[member_model, member_item]
import app_service/common/types
proc createTestMemberItem(pubKey: string): MemberItem =
return initMemberItem(
pubKey = pubKey,
displayName = "",
ensName = "",
isEnsVerified = false,
localNickname = "",
alias = "",
icon = "",
colorId = 0,
isVerified = false,
)
let memberA = createTestMemberItem("0xa")
let memberB = createTestMemberItem("0xb")
let memberC = createTestMemberItem("0xc")
let memberD = createTestMemberItem("0xd")
let memberE = createTestMemberItem("0xe")
suite "empty member model":
let model = newModel()
test "initial size":
require(model.rowCount() == 0)
suite "updating member items":
setup:
let model = newModel()
model.addItems(@[memberA, memberB, memberC])
check(model.rowCount() == 3)
test "update only display name":
let updatedRoles = model.updateItem(
pubkey = "0xa",
displayName = "newName",
ensName = "",
isEnsVerified = false,
localNickname = "",
alias = "",
icon = "",
isContact = false,
isVerified = false,
memberRole = MemberRole.None,
joined = false,
isUntrustworthy = false,
callDataChanged = false,
)
# Two updated roles, because preferredDisplayName gets updated too
check(updatedRoles.len() == 2)
let item = model.getMemberItem("0xa")
check(item.displayName == "newName")
test "update two properties not related to name":
let updatedRoles = model.updateItem(
pubkey = "0xb",
displayName = "",
ensName = "",
isEnsVerified = false,
localNickname = "",
alias = "",
icon = "icon",
isContact = true,
isVerified = false,
memberRole = MemberRole.None,
joined = false,
isUntrustworthy = false,
callDataChanged = false,
)
check(updatedRoles.len() == 2)
let item = model.getMemberItem("0xb")
check(item.icon == "icon")
check(item.isContact == true)
test "update two items at the same time":
let memberACopy = memberA
memberACopy.displayName = "bob"
let memberBCopy = memberB
memberBCopy.displayName = "alice"
model.updateItems(@[memberACopy, memberBCopy])
let itemA = model.getMemberItem("0xa")
check(itemA.displayName == "bob")
model.updateItems(@[memberACopy, memberBCopy])
let itemB = model.getMemberItem("0xb")
check(itemB.displayName == "alice")
test "remove an item using updateToTheseItems":
model.updateToTheseItems(@[memberA, memberB])
check(model.rowCount == 2)
test "add an item using updateToTheseItems":
model.updateToTheseItems(@[memberA, memberB, memberD])
check(model.rowCount == 3)
test "add an item and update another using updateToTheseItems":
let memberACopy = memberA
memberACopy.displayName = "roger"
model.updateToTheseItems(@[memberACopy, memberB, memberD, memberE])
check(model.rowCount == 4)
let itemA = model.getMemberItem("0xa")
check(itemA.displayName == "roger")
test "add an item, remove one and update another using updateToTheseItems":
let memberACopy = memberA
memberACopy.displayName = "brandon"
let memberCCopy = memberC
memberCCopy.displayName = "kurt"
let memberDCopy = memberD
memberDCopy.displayName = "amanda"
let memberECopy = memberE
memberECopy.displayName = "gina"
model.updateToTheseItems(@[memberACopy, memberCCopy, memberDCopy, memberECopy])
check(model.rowCount == 4)
let itemA = model.getMemberItem("0xa")
check(itemA.displayName == "brandon")
let itemC = model.getMemberItem("0xc")
check(itemC.displayName == "kurt")
let itemD = model.getMemberItem("0xd")
check(itemD.displayName == "amanda")
let itemE = model.getMemberItem("0xe")
check(itemE.displayName == "gina")