Refactor out channel groups (#14202)

Fixes #12595

Gets rid of the concept of channelGroups.
Instead, we use the communities and chats directly, to keep the same concepts as status-go.
This commit is contained in:
Jonathan Rainville 2024-05-13 15:58:55 -04:00 committed by GitHub
parent 2537cdc2f2
commit b6b21c3744
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 495 additions and 629 deletions

View File

@ -44,7 +44,7 @@ proc updateActivityGroupCounters*(self: Controller) =
self.delegate.setActivityGroupCounters(counters)
proc init*(self: Controller) =
self.events.once(chat_service.SIGNAL_CHANNEL_GROUPS_LOADED) do(e:Args):
self.events.once(chat_service.SIGNAL_ACTIVE_CHATS_LOADED) do(e:Args):
# Only fectch activity center notification once channel groups are loaded,
# since we need the chats to associate the notifications to
self.activity_center_service.asyncActivityNotificationLoad()
@ -136,9 +136,6 @@ proc switchTo*(self: Controller, sectionId, chatId, messageId: string) =
proc getChatDetails*(self: Controller, chatId: string): ChatDto =
return self.chatService.getChatById(chatId)
proc getChannelGroups*(self: Controller): seq[ChannelGroupDto] =
return self.chatService.getChannelGroups()
proc getOneToOneChatNameAndImage*(self: Controller, chatId: string):
tuple[name: string, image: string, largeImage: string] =
return self.chatService.getOneToOneChatNameAndImage(chatId)

View File

@ -7,6 +7,7 @@ import ../../shared_models/message_item as msg_item
import ../../shared_models/message_item_qobject as msg_item_qobj
import ../../shared_models/message_transaction_parameters_item
import ../../../global/global_singleton
import ../../../global/app_sections_config as conf
import ../../../core/eventemitter
import ../../../../app_service/service/activity_center/service as activity_center_service
import ../../../../app_service/service/contacts/service as contacts_service
@ -268,32 +269,33 @@ method switchTo*(self: Module, sectionId, chatId, messageId: string) =
self.controller.switchTo(sectionId, chatId, messageId)
method getDetails*(self: Module, sectionId: string, chatId: string): string =
let groups = self.controller.getChannelGroups()
var jsonObject = newJObject()
if sectionId == singletonInstance.userProfile.getPubKey():
jsonObject["sType"] = %* ChatSectionType.Personal
jsonObject["sName"] = %* conf.CHAT_SECTION_NAME
jsonObject["sImage"] = %* ""
jsonObject["sColor"] = %* ""
else:
# Community
let community = self.controller.getCommunityById(sectionId)
for g in groups:
if(g.id != sectionId):
continue
jsonObject["sType"] = %* ChatSectionType.Community
jsonObject["sName"] = %* community.name
jsonObject["sImage"] = %* community.images.thumbnail
jsonObject["sColor"] = %* community.color
jsonObject["sType"] = %* g.channelGroupType
jsonObject["sName"] = %* g.name
jsonObject["sImage"] = %* g.images.thumbnail
jsonObject["sColor"] = %* g.color
let c = self.controller.getChatDetails(chatId)
var chatName = c.name
var chatImage = c.icon
if c.chatType == ChatType.OneToOne:
(chatName, chatImage) = self.controller.getOneToOneChatNameAndImage(c.id)
for c in g.chats:
if(c.id != chatId):
continue
var chatName = c.name
var chatImage = c.icon
if(c.chatType == ChatType.OneToOne):
(chatName, chatImage) = self.controller.getOneToOneChatNameAndImage(c.id)
jsonObject["cName"] = %* chatName
jsonObject["cImage"] = %* chatImage
jsonObject["cColor"] = %* c.color
jsonObject["cEmoji"] = %* c.emoji
return $jsonObject
jsonObject["cName"] = %* chatName
jsonObject["cImage"] = %* chatImage
jsonObject["cColor"] = %* c.color
jsonObject["cEmoji"] = %* c.emoji
return $jsonObject
method getChatDetailsAsJson*(self: Module, chatId: string): string =
let chatDto = self.controller.getChatDetails(chatId)

View File

@ -85,12 +85,15 @@ proc setSearchLocation*(self: Controller, location: string, subLocation: string)
self.searchLocation = location
self.searchSubLocation = subLocation
proc getChannelGroups*(self: Controller): seq[ChannelGroupDto] =
return self.chatService.getChannelGroups()
proc getCommunityById*(self: Controller, communityId: string): CommunityDto =
return self.communityService.getCommunityById(communityId)
proc getJoinedAndSpectatedCommunities*(self: Controller): seq[CommunityDto] =
return self.communityService.getJoinedAndSpectatedCommunities()
proc getChatsForPersonalSection*(self: Controller): seq[ChatDto] =
return self.chatService.getChatsForPersonalSection()
proc getChatDetailsForChatTypes*(self: Controller, types: seq[ChatType]): seq[ChatDto] =
return self.chatService.getChatsOfChatTypes(types)

View File

@ -1,5 +1,5 @@
import NimQml
import json, strutils, chronicles
import json, strutils, chronicles, sequtils
import io_interface
import ../io_interface as delegate_interface
import view, controller
@ -66,18 +66,8 @@ method viewDidLoad*(self: Module) =
method getModuleAsVariant*(self: Module): QVariant =
return self.viewVariant
proc buildLocationMenuForChannelGroup(self: Module, channelGroup: ChannelGroupDto): location_menu_item.Item =
let isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community
var item = location_menu_item.initItem(
channelGroup.id,
if (isCommunity): channelGroup.name else: SEARCH_MENU_LOCATION_CHAT_SECTION_NAME,
channelGroup.images.thumbnail,
icon=if (isCommunity): "" else: "chat",
channelGroup.color)
var subItems: seq[location_menu_sub_item.SubItem]
for chatDto in channelGroup.chats:
proc getChatSubItems(self: Module, chats: seq[ChatDto]): seq[location_menu_sub_item.SubItem] =
for chatDto in chats:
var chatName = chatDto.name
var chatImage = chatDto.icon
var colorHash: ColorHashDto = @[]
@ -95,18 +85,44 @@ proc buildLocationMenuForChannelGroup(self: Module, channelGroup: ChannelGroupDt
chatDto.color,
isOneToOneChat,
colorId,
colorHash)
subItems.add(subItem)
colorHash
)
result.add(subItem)
proc buildLocationMenuForCommunity(self: Module, community: CommunityDto): location_menu_item.Item =
var item = location_menu_item.initItem(
community.id,
community.name,
community.images.thumbnail,
icon="",
community.color
)
var subItems = self.getChatSubItems(community.chats)
item.setSubItems(subItems)
return item
method prepareLocationMenuModel*(self: Module) =
var items: seq[location_menu_item.Item]
let channelGroups = self.controller.getChannelGroups()
for c in channelGroups:
items.add(self.buildLocationMenuForChannelGroup(c))
# Personal Section
let myPubKey = singletonInstance.userProfile.getPubKey()
var personalItem = location_menu_item.initItem(
value = myPubKey,
text = SEARCH_MENU_LOCATION_CHAT_SECTION_NAME,
image = "",
icon = "chat",
)
var subItems = self.getChatSubItems(self.controller.getChatsForPersonalSection())
personalItem.setSubItems(subItems)
items.add(personalItem)
# Community sections
let communities = self.controller.getJoinedAndSpectatedCommunities()
for c in communities:
items.add(self.buildLocationMenuForCommunity(c))
self.view.locationMenuModel().setItems(items)
@ -146,80 +162,85 @@ method searchMessages*(self: Module, searchTerm: string) =
self.controller.searchMessages(searchTerm)
proc getResultItemFromChats(self: Module, sectionId: string, chats: seq[ChatDto], sectionName: string): seq[result_item.Item] =
if (self.controller.searchSubLocation().len == 0 and self.controller.searchLocation().len == 0) or
self.controller.searchLocation() == sectionId:
let searchTerm = self.controller.searchTerm().toLower
for chatDto in chats:
var chatName = chatDto.name
var chatImage = chatDto.icon
var colorHash: ColorHashDto = @[]
var colorId: int = 0
let isOneToOneChat = chatDto.chatType == ChatType.OneToOne
if(isOneToOneChat):
(chatName, chatImage) = self.controller.getOneToOneChatNameAndImage(chatDto.id)
colorHash = self.controller.getColorHash(chatDto.id)
colorId = self.controller.getColorId(chatDto.id)
var rawChatName = chatName
if(chatName.startsWith("@")):
rawChatName = chatName[1 ..^ 1]
if rawChatName.toLower.contains(searchTerm):
let item = result_item.initItem(
chatDto.id,
content="",
time="",
titleId=chatDto.id,
title=chatName,
SEARCH_RESULT_CHANNELS_SECTION_NAME,
chatImage,
chatDto.color,
badgePrimaryText="",
badgeSecondaryText="",
chatImage,
chatDto.color,
false,
isOneToOneChat,
colorId,
colorHash)
self.controller.addResultItemDetails(chatDto.id, sectionId, chatDto.id)
result.add(item)
method onSearchMessagesDone*(self: Module, messages: seq[MessageDto]) =
var items: seq[result_item.Item]
var channels: seq[result_item.Item]
# Add Channel groups
let channelGroups = self.controller.getChannelGroups()
# Add Personal section chats
let myPubKey = singletonInstance.userProfile.getPubKey()
let personalItems = self.getResultItemFromChats(myPubKey, self.controller.getChatsForPersonalSection(), SEARCH_RESULT_CHATS_SECTION_NAME)
var channels = personalItems
# Add Communities
let communities = self.controller.getJoinedAndSpectatedCommunities()
let searchTerm = self.controller.searchTerm().toLower
for channelGroup in channelGroups:
let isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community
if(self.controller.searchLocation().len == 0 and
channelGroup.name.toLower.contains(searchTerm)):
for community in communities:
if self.controller.searchLocation().len == 0 and
community.name.toLower.contains(searchTerm):
let item = result_item.initItem(
channelGroup.id,
community.id,
content="",
time="",
titleId=channelGroup.id,
title=channelGroup.name,
if (isCommunity):
SEARCH_RESULT_COMMUNITIES_SECTION_NAME
else:
SEARCH_RESULT_CHATS_SECTION_NAME,
channelGroup.images.thumbnail,
channelGroup.color,
titleId=community.id,
title=community.name,
SEARCH_RESULT_COMMUNITIES_SECTION_NAME,
community.images.thumbnail,
community.color,
badgePrimaryText="",
badgeSecondaryText="",
channelGroup.images.thumbnail,
channelGroup.color,
community.images.thumbnail,
community.color,
badgeIsLetterIdenticon=false)
self.controller.addResultItemDetails(channelGroup.id, channelGroup.id)
self.controller.addResultItemDetails(community.id, community.id)
items.add(item)
# Add channels
if((self.controller.searchSubLocation().len == 0 and self.controller.searchLocation().len == 0) or
self.controller.searchLocation() == channelGroup.id):
for chatDto in channelGroup.chats:
var chatName = chatDto.name
var chatImage = chatDto.icon
var colorHash: ColorHashDto = @[]
var colorId: int = 0
let isOneToOneChat = chatDto.chatType == ChatType.OneToOne
if(isOneToOneChat):
(chatName, chatImage) = self.controller.getOneToOneChatNameAndImage(chatDto.id)
colorHash = self.controller.getColorHash(chatDto.id)
colorId = self.controller.getColorId(chatDto.id)
var rawChatName = chatName
if(chatName.startsWith("@")):
rawChatName = chatName[1 ..^ 1]
if(rawChatName.toLower.contains(searchTerm)):
let item = result_item.initItem(
chatDto.id,
content="",
time="",
titleId=chatDto.id,
title=chatName,
if isCommunity:
SEARCH_RESULT_CHANNELS_SECTION_NAME
else:
SEARCH_RESULT_CHATS_SECTION_NAME,
chatImage,
chatDto.color,
badgePrimaryText="",
badgeSecondaryText="",
chatImage,
chatDto.color,
false,
isOneToOneChat,
colorId,
colorHash)
self.controller.addResultItemDetails(chatDto.id, channelGroup.id, chatDto.id)
channels.add(item)
let communityChatItems = self.getResultItemFromChats(community.id, community.chats, SEARCH_RESULT_CHANNELS_SECTION_NAME)
if communityChatItems.len > 0:
channels = channels.concat(channels, communityChatItems)
# Add channels in order as requested by the design
items.add(channels)

View File

@ -115,11 +115,18 @@ proc init*(self: Controller) =
proc belongsToCommunity*(self: Controller): bool =
self.belongsToCommunity
proc getMyCommunity*(self: Controller): CommunityDto =
return self.communityService.getCommunityById(self.sectionId)
proc getChat*(self: Controller): ChatDto =
return self.chatService.getChatById(self.chatId)
proc getChatMembers*(self: Controller): seq[ChatMember] =
return self.chatService.getChatById(self.chatId).members
if self.belongsToCommunity:
let myCommunity = self.getMyCommunity()
return myCommunity.getCommunityChat(self.chatId).members
else:
return self.chatService.getChatById(self.chatId).members
proc getContactNameAndImage*(self: Controller, contactId: string):
tuple[name: string, image: string, largeImage: string] =

View File

@ -455,9 +455,30 @@ proc getAllChats*(self: Controller, communityId: string): seq[ChatDto] =
return self.communityService.getAllChats(communityId)
proc getChatsAndBuildUI*(self: Controller) =
let channelGroup = self.chatService.getChannelGroupById(self.sectionId)
var chats: seq[ChatDto]
var community: CommunityDto
if self.isCommunity():
community = self.getMyCommunity()
let normalChats = self.chatService.getChatsForCommunity(community.id)
# TODO remove this once we do this refactor https://github.com/status-im/status-desktop/issues/14219
var fullChats: seq[ChatDto] = @[]
for communityChat in community.chats:
for chat in normalChats:
if chat.id == communityChat.id:
var c = chat
c.updateMissingFields(communityChat)
fullChats.add(c)
break
chats = fullChats
else:
community = CommunityDto()
chats = self.chatService.getChatsForPersonalSection()
# Build chat section with the preloaded community (empty community for personal chat)
self.delegate.onChatsLoaded(
channelGroup,
community,
chats,
self.events,
self.settingsService,
self.nodeConfigurationService,
@ -482,8 +503,8 @@ proc getChatDetailsForChatTypes*(self: Controller, types: seq[ChatType]): seq[Ch
proc getChatDetailsByIds*(self: Controller, chatIds: seq[string]): seq[ChatDto] =
return self.chatService.getChatsByIds(chatIds)
proc chatsWithCategoryHaveUnreadMessages*(self: Controller, communityId: string, categoryId: string): bool =
return self.chatService.chatsWithCategoryHaveUnreadMessages(communityId, categoryId)
proc categoryHasUnreadMessages*(self: Controller, communityId: string, categoryId: string): bool =
return self.communityService.categoryHasUnreadMessages(communityId, categoryId)
proc getCommunityCategoryDetails*(self: Controller, communityId: string, categoryId: string): Category =
return self.communityService.getCategoryById(communityId, categoryId)

View File

@ -26,7 +26,8 @@ method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatsLoaded*(self: AccessInterface,
channelGroup: ChannelGroupDto,
community: CommunityDto,
chats: seq[ChatDto],
events: UniqueUUIDEventEmitter,
settingsService: settings_service.Service,
nodeConfigurationService: node_configuration_service.Service,

View File

@ -57,7 +57,8 @@ type
# Forward declaration
proc buildChatSectionUI(
self: Module,
channelGroup: ChannelGroupDto,
community: CommunityDto,
chats: seq[ChatDto],
events: UniqueUUIDEventEmitter,
settingsService: settings_service.Service,
nodeConfigurationService: node_configuration_service.Service,
@ -75,7 +76,7 @@ proc changeCanPostValues*(self: Module, chatId: string, canPostReactions, viewer
proc addOrUpdateChat(self: Module,
chat: ChatDto,
channelGroup: ChannelGroupDto,
community: CommunityDto,
belongsToCommunity: bool,
events: UniqueUUIDEventEmitter,
settingsService: settings_service.Service,
@ -255,7 +256,7 @@ proc removeSubmodule(self: Module, chatId: string) =
proc addCategoryItem(self: Module, category: Category, memberRole: MemberRole, communityId: string, insertIntoModel: bool = true): chat_item.Item =
let hasUnreadMessages = self.controller.chatsWithCategoryHaveUnreadMessages(communityId, category.id)
let hasUnreadMessages = self.controller.categoryHasUnreadMessages(communityId, category.id)
result = chat_item.initItem(
id = category.id,
category.name,
@ -284,7 +285,8 @@ proc addCategoryItem(self: Module, category: Category, memberRole: MemberRole, c
proc buildChatSectionUI(
self: Module,
channelGroup: ChannelGroupDto,
community: CommunityDto,
chats: seq[ChatDto],
events: UniqueUUIDEventEmitter,
settingsService: settings_service.Service,
nodeConfigurationService: node_configuration_service.Service,
@ -299,11 +301,11 @@ proc buildChatSectionUI(
let sectionLastOpenChat = singletonInstance.localAccountSensitiveSettings.getSectionLastOpenChat(self.controller.getMySectionId())
var items: seq[chat_item.Item] = @[]
for categoryDto in channelGroup.categories:
for categoryDto in community.categories:
# Add items for the categories. We use a special type to identify categories
items.add(self.addCategoryItem(categoryDto, channelGroup.memberRole, channelGroup.id))
items.add(self.addCategoryItem(categoryDto, community.memberRole, community.id))
for chatDto in channelGroup.chats:
for chatDto in chats:
var categoryPosition = -1
# Add an empty chat item that has the category info
@ -315,14 +317,14 @@ proc buildChatSectionUI(
isActive = true
if chatDto.categoryId != "":
for category in channelGroup.categories:
for category in community.categories:
if category.id == chatDto.categoryId:
categoryPosition = category.position
break
items.add(self.addOrUpdateChat(
chatDto,
channelGroup,
community,
belongsToCommunity = chatDto.communityId.len > 0,
events,
settingsService,
@ -392,7 +394,7 @@ proc reevaluateRequiresTokenPermissionToJoin(self: Module) =
break
self.view.setRequiresTokenPermissionToJoin(joinPermissionsChanged)
proc initCommunityTokenPermissionsModel(self: Module, channelGroup: ChannelGroupDto) =
proc initCommunityTokenPermissionsModel(self: Module) =
self.rebuildCommunityTokenPermissionsModel()
proc convertPubKeysToJson(self: Module, pubKeys: string): seq[string] =
@ -419,7 +421,8 @@ method load*(self: Module) =
method onChatsLoaded*(
self: Module,
channelGroup: ChannelGroupDto,
community: CommunityDto,
chats: seq[ChatDto],
events: UniqueUUIDEventEmitter,
settingsService: settings_service.Service,
nodeConfigurationService: node_configuration_service.Service,
@ -431,7 +434,7 @@ method onChatsLoaded*(
sharedUrlsService: shared_urls_service.Service,
) =
self.chatsLoaded = true
self.buildChatSectionUI(channelGroup, events, settingsService, nodeConfigurationService,
self.buildChatSectionUI(community, chats, events, settingsService, nodeConfigurationService,
contactService, chatService, communityService, messageService, mailserversService, sharedUrlsService)
if(not self.controller.isCommunity()):
@ -446,8 +449,8 @@ method onChatsLoaded*(
requestToJoinState = RequestToJoinState.Requested
self.view.setRequestToJoinState(requestToJoinState)
self.initCommunityTokenPermissionsModel(channelGroup)
self.onCommunityCheckAllChannelsPermissionsResponse(channelGroup.channelPermissions)
self.initCommunityTokenPermissionsModel()
self.onCommunityCheckAllChannelsPermissionsResponse(community.channelPermissions)
self.controller.asyncCheckPermissionsToJoin()
let activeChatId = self.controller.getActiveChatId()
@ -589,7 +592,7 @@ proc updateBadgeNotifications(self: Module, chat: ChatDto, hasUnreadMessages: bo
self.chatContentModules[chatId].onNotificationsUpdated(hasUnreadMessages, unviewedMentionsCount)
if chat.categoryId != "":
let hasUnreadMessages = self.controller.chatsWithCategoryHaveUnreadMessages(chat.communityId, chat.categoryId)
let hasUnreadMessages = self.controller.categoryHasUnreadMessages(chat.communityId, chat.categoryId)
self.view.chatsModel().setCategoryHasUnreadMessages(chat.categoryId, hasUnreadMessages)
self.updateParentBadgeNotifications()
@ -629,7 +632,7 @@ method chatsModel*(self: Module): chats_model.Model =
proc addNewChat(
self: Module,
chatDto: ChatDto,
channelGroup: ChannelGroupDto,
community: CommunityDto,
belongsToCommunity: bool,
events: EventEmitter,
settingsService: settings_service.Service,
@ -643,7 +646,7 @@ proc addNewChat(
setChatAsActive: bool = true,
insertIntoModel: bool = true,
): chat_item.Item =
let hasNotification =chatDto.unviewedMessagesCount > 0
let hasNotification = chatDto.unviewedMessagesCount > 0
let notificationsCount = chatDto.unviewedMentionsCount
var chatName = chatDto.name
@ -672,12 +675,11 @@ proc addNewChat(
var memberRole = self.getUserMemberRole(chatDto.members)
if chatDto.chatType != ChatType.PrivateGroupChat:
memberRole = channelGroup.memberRole
memberRole = community.memberRole
if memberRole == MemberRole.None and len(chatDto.communityId) != 0:
memberRole = channelGroup.memberRole
memberRole = community.memberRole
if memberRole == MemberRole.None:
let community = communityService.getCommunityById(chatDto.communityId)
memberRole = community.memberRole
var categoryOpened = true
@ -694,6 +696,16 @@ proc addNewChat(
# preferable. Please fix-me in https://github.com/status-im/status-desktop/issues/14431
self.view.chatsModel().changeCategoryOpened(category.id, category.categoryOpened)
var canPostReactions = true
var hideIfPermissionsNotMet = false
var viewersCanPostReactions = true
if self.controller.isCommunity:
let communityChat = community.getCommunityChat(chatDto.id)
# Some properties are only available on CommunityChat (they are useless for normal chats)
canPostReactions = communityChat.canPostReactions
hideIfPermissionsNotMet = communityChat.hideIfPermissionsNotMet
viewersCanPostReactions = communityChat.viewersCanPostReactions
result = chat_item.initItem(
chatDto.id,
chatName,
@ -726,9 +738,9 @@ proc addNewChat(
self.controller.checkChatHasPermissions(self.controller.getMySectionId(), chatDto.id)
else:
false,
canPostReactions = chatDto.canPostReactions,
viewersCanPostReactions = chatDto.viewersCanPostReactions,
hideIfPermissionsNotMet = chatDto.hideIfPermissionsNotMet,
canPostReactions = canPostReactions,
viewersCanPostReactions = viewersCanPostReactions,
hideIfPermissionsNotMet = hideIfPermissionsNotMet,
viewOnlyPermissionsSatisfied = true, # will be updated in async call
viewAndPostPermissionsSatisfied = true # will be updated in async call
)
@ -1382,7 +1394,7 @@ method setLoadingHistoryMessagesInProgress*(self: Module, isLoading: bool) =
proc addOrUpdateChat(self: Module,
chat: ChatDto,
channelGroup: ChannelGroupDto,
community: CommunityDto,
belongsToCommunity: bool,
events: UniqueUUIDEventEmitter,
settingsService: settings_service.Service,
@ -1398,8 +1410,8 @@ proc addOrUpdateChat(self: Module,
): chat_item.Item =
let sectionId = self.controller.getMySectionId()
if(belongsToCommunity and sectionId != chat.communityId or
not belongsToCommunity and sectionId != singletonInstance.userProfile.getPubKey()):
if belongsToCommunity and sectionId != chat.communityId or
not belongsToCommunity and sectionId != singletonInstance.userProfile.getPubKey():
return
self.updateBadgeNotifications(chat, chat.unviewedMessagesCount > 0, chat.unviewedMentionsCount)
@ -1424,7 +1436,7 @@ proc addOrUpdateChat(self: Module,
result = self.addNewChat(
chat,
channelGroup,
community,
belongsToCommunity,
events.eventsEmitter(),
settingsService,
@ -1456,7 +1468,7 @@ method addOrUpdateChat*(self: Module,
): chat_item.Item =
result = self.addOrUpdateChat(
chat,
ChannelGroupDto(),
CommunityDto(),
belongsToCommunity,
events,
settingsService,

View File

@ -109,10 +109,8 @@ proc delete*(self: Controller) =
discard
proc init*(self: Controller) =
self.events.on(SIGNAL_CHANNEL_GROUPS_LOADED) do(e:Args):
let args = ChannelGroupsArgs(e)
self.delegate.onChannelGroupsLoaded(
args.channelGroups,
self.events.on(SIGNAL_ACTIVE_CHATS_LOADED) do(e:Args):
self.delegate.onChatsLoaded(
self.events,
self.settingsService,
self.nodeConfigurationService,
@ -145,7 +143,7 @@ proc init*(self: Controller) =
self.networksService,
)
self.events.on(SIGNAL_CHANNEL_GROUPS_LOADING_FAILED) do(e:Args):
self.events.on(SIGNAL_CHATS_LOADING_FAILED) do(e:Args):
self.delegate.onChatsLoadingFailed()
self.events.on(SIGNAL_ACTIVE_MAILSERVER_CHANGED) do(e:Args):
@ -489,9 +487,6 @@ proc init*(self: Controller) =
proc isConnected*(self: Controller): bool =
return self.nodeService.isConnected()
proc getChannelGroups*(self: Controller): seq[ChannelGroupDto] =
return self.chatService.getChannelGroups()
proc getActiveSectionId*(self: Controller): string =
result = self.activeSectionId
@ -535,6 +530,9 @@ proc switchTo*(self: Controller, sectionId, chatId, messageId: string) =
let data = ActiveSectionChatArgs(sectionId: sectionId, chatId: chatId, messageId: messageId)
self.events.emit(SIGNAL_MAKE_SECTION_CHAT_ACTIVE, data)
proc getJoinedAndSpectatedCommunities*(self: Controller): seq[CommunityDto] =
return self.communityService.getJoinedAndSpectatedCommunities()
proc getCommunityById*(self: Controller, communityId: string): CommunityDto =
return self.communityService.getCommunityById(communityId)

View File

@ -84,9 +84,8 @@ method chatSectionDidLoad*(self: AccessInterface) {.base.} =
method communitySectionDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onChannelGroupsLoaded*(
method onChatsLoaded*(
self: AccessInterface,
channelGroups: seq[ChannelGroupDto],
events: EventEmitter,
settingsService: settings_service.Service,
nodeConfigurationService: node_configuration_service.Service,

View File

@ -91,7 +91,7 @@ type
view: View
viewVariant: QVariant
controller: Controller
channelGroupModules: OrderedTable[string, chat_section_module.AccessInterface]
chatSectionModules: OrderedTable[string, chat_section_module.AccessInterface]
events: EventEmitter
urlsManager: UrlsManager
keycardService: keycard_service.Service
@ -207,7 +207,7 @@ proc newModule*[T](
result.keychainService = keychainService
# Submodules
result.channelGroupModules = initOrderedTable[string, chat_section_module.AccessInterface]()
result.chatSectionModules = initOrderedTable[string, chat_section_module.AccessInterface]()
result.walletSectionModule = wallet_section_module.newModule(
result, events, tokenService, collectibleService, currencyService,
transactionService, walletAccountService,
@ -246,9 +246,9 @@ method delete*[T](self: Module[T]) =
self.gifsModule.delete
self.activityCenterModule.delete
self.communitiesModule.delete
for cModule in self.channelGroupModules.values:
for cModule in self.chatSectionModules.values:
cModule.delete
self.channelGroupModules.clear
self.chatSectionModules.clear
self.walletSectionModule.delete
self.browserSectionModule.delete
self.appSearchModule.delete
@ -321,27 +321,24 @@ method onCommunityTokensDetailsLoaded[T](self: Module[T], communityId: string,
)
self.view.model().setTokenItems(communityId, communityTokensItems)
proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto): SectionItem =
let isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community
var communityDetails: CommunityDto
proc createCommunitySectionItem[T](self: Module[T], communityDetails: CommunityDto): SectionItem =
var communityTokensItems: seq[TokenItem]
if (isCommunity):
communityDetails = self.controller.getCommunityById(channelGroup.id)
if communityDetails.memberRole == MemberRole.Owner or communityDetails.memberRole == MemberRole.TokenMaster:
self.controller.getCommunityTokensDetailsAsync(channelGroup.id)
# Get community members' revealed accounts
# We will update the model later when we finish loading the accounts
self.controller.asyncGetRevealedAccountsForAllMembers(channelGroup.id)
if communityDetails.memberRole == MemberRole.Owner or communityDetails.memberRole == MemberRole.TokenMaster:
self.controller.getCommunityTokensDetailsAsync(communityDetails.id)
# Get community members' revealed accounts
# We will update the model later when we finish loading the accounts
self.controller.asyncGetRevealedAccountsForAllMembers(communityDetails.id)
let (unviewedCount, notificationsCount) = self.controller.sectionUnreadMessagesAndMentionsCount(communityDetails.id)
let unviewedCount = channelGroup.unviewedMessagesCount
let notificationsCount = channelGroup.unviewedMentionsCount
let hasNotification = unviewedCount > 0 or notificationsCount > 0
let active = self.getActiveSectionId() == channelGroup.id # We must pass on if the current item section is currently active to keep that property as it is
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 = channelGroup.members
var members = communityDetails.members
for requestForAutoRejoin in communityDetails.waitingForSharedAddressesRequestsToJoin:
var chatMember = ChatMember()
chatMember.id = requestForAutoRejoin.publicKey
@ -349,7 +346,6 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
chatMember.role = MemberRole.None
members.add(chatMember)
var bannedMembers = newSeq[MemberItem]()
for memberId, memberState in communityDetails.pendingAndBannedMembers.pairs:
let state = memberState.toMembershipRequestState()
@ -360,32 +356,32 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
discard
result = initItem(
channelGroup.id,
if isCommunity: SectionType.Community else: SectionType.Chat,
if isCommunity: channelGroup.name else: conf.CHAT_SECTION_NAME,
channelGroup.memberRole,
if isCommunity: communityDetails.isControlNode else: false,
channelGroup.description,
channelGroup.introMessage,
channelGroup.outroMessage,
channelGroup.images.thumbnail,
channelGroup.images.banner,
icon = if (isCommunity): "" else: conf.CHAT_SECTION_ICON,
channelGroup.color,
if isCommunity: communityDetails.tags else: "",
communityDetails.id,
sectionType = SectionType.Community,
communityDetails.name,
communityDetails.memberRole,
communityDetails.isControlNode,
communityDetails.description,
communityDetails.introMessage,
communityDetails.outroMessage,
communityDetails.images.thumbnail,
communityDetails.images.banner,
icon = "",
communityDetails.color,
communityDetails.tags,
hasNotification,
notificationsCount,
active,
enabled = true,
if (isCommunity): communityDetails.joined else: true,
if (isCommunity): communityDetails.canJoin else: true,
if (isCommunity): communityDetails.spectated else: false,
channelGroup.canManageUsers,
if (isCommunity): communityDetails.canRequestAccess else: true,
if (isCommunity): communityDetails.isMember else: true,
channelGroup.permissions.access,
channelGroup.permissions.ensOnly,
channelGroup.muted,
communityDetails.joined,
communityDetails.canJoin,
communityDetails.spectated,
communityDetails.canManageUsers,
communityDetails.canRequestAccess,
communityDetails.isMember,
communityDetails.permissions.access,
communityDetails.permissions.ensOnly,
communityDetails.muted,
# members
members.map(proc(member: ChatMember): MemberItem =
let contactDetails = self.controller.getContactDetails(member.id)
@ -400,30 +396,30 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
result = self.createMemberItem(member.id, "", state, member.role)
),
# pendingRequestsToJoin
if (isCommunity): communityDetails.pendingRequestsToJoin.map(x => pending_request_item.initItem(
communityDetails.pendingRequestsToJoin.map(x => pending_request_item.initItem(
x.id,
x.publicKey,
x.chatId,
x.communityId,
x.state,
x.our
)) else: @[],
)),
communityDetails.settings.historyArchiveSupportEnabled,
communityDetails.adminSettings.pinMessageAllMembersEnabled,
bannedMembers,
# pendingMemberRequests
if (isCommunity): communityDetails.pendingRequestsToJoin.map(proc(requestDto: CommunityMembershipRequestDto): MemberItem =
communityDetails.pendingRequestsToJoin.map(proc(requestDto: CommunityMembershipRequestDto): MemberItem =
result = self.createMemberItem(requestDto.publicKey, requestDto.id, MembershipRequestState(requestDto.state), MemberRole.None)
) else: @[],
),
# declinedMemberRequests
if (isCommunity): communityDetails.declinedRequestsToJoin.map(proc(requestDto: CommunityMembershipRequestDto): MemberItem =
communityDetails.declinedRequestsToJoin.map(proc(requestDto: CommunityMembershipRequestDto): MemberItem =
result = self.createMemberItem(requestDto.publicKey, requestDto.id, MembershipRequestState(requestDto.state), MemberRole.None)
) else: @[],
channelGroup.encrypted,
),
communityDetails.encrypted,
communityTokensItems,
channelGroup.pubsubTopic,
channelGroup.pubsubTopicKey,
channelGroup.shard.index,
communityDetails.pubsubTopic,
communityDetails.pubsubTopicKey,
communityDetails.shard.index,
)
proc connectForNotificationsOnly[T](self: Module[T]) =
@ -623,9 +619,8 @@ method load*[T](
else:
self.setActiveSection(activeSection)
method onChannelGroupsLoaded*[T](
method onChatsLoaded*[T](
self: Module[T],
channelGroups: seq[ChannelGroupDto],
events: EventEmitter,
settingsService: settings_service.Service,
nodeConfigurationService: node_configuration_service.Service,
@ -643,17 +638,63 @@ method onChannelGroupsLoaded*[T](
self.chatsLoaded = true
if not self.communityDataLoaded:
return
let myPubKey = singletonInstance.userProfile.getPubKey()
var activeSection: SectionItem
var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection()
if activeSectionId == "" or activeSectionId == conf.SETTINGS_SECTION_ID:
activeSectionId = singletonInstance.userProfile.getPubKey()
activeSectionId = myPubKey
for channelGroup in channelGroups:
self.channelGroupModules[channelGroup.id] = chat_section_module.newModule(
# Create personal chat section
self.chatSectionModules[myPubKey] = chat_section_module.newModule(
self,
events,
sectionId = myPubKey,
isCommunity = false,
settingsService,
nodeConfigurationService,
contactsService,
chatService,
communityService,
messageService,
mailserversService,
walletAccountService,
tokenService,
communityTokensService,
sharedUrlsService,
networkService
)
let (unviewedMessagesCount, unviewedMentionsCount) = self.controller.sectionUnreadMessagesAndMentionsCount(myPubKey)
let personalChatSectionItem = initItem(
myPubKey,
sectionType = SectionType.Chat,
name = conf.CHAT_SECTION_NAME,
icon = conf.CHAT_SECTION_ICON,
hasNotification = unviewedMessagesCount > 0 or unviewedMentionsCount > 0,
notificationsCount = unviewedMentionsCount,
active = self.getActiveSectionId() == myPubKey,
enabled = true,
joined = true,
canJoin = true,
canRequestAccess = true,
isMember = true,
muted = false,
)
self.view.model().addItem(personalChatSectionItem)
if activeSectionId == personalChatSectionItem.id:
activeSection = personalChatSectionItem
self.chatSectionModules[myPubKey].load()
let communities = self.controller.getJoinedAndSpectatedCommunities()
# Create Community sections
for community in communities:
self.chatSectionModules[community.id] = chat_section_module.newModule(
self,
events,
channelGroup.id,
isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community,
community.id,
isCommunity = true,
settingsService,
nodeConfigurationService,
contactsService,
@ -667,12 +708,12 @@ method onChannelGroupsLoaded*[T](
sharedUrlsService,
networkService
)
let channelGroupItem = self.createChannelGroupItem(channelGroup)
self.view.model().addItem(channelGroupItem)
if activeSectionId == channelGroupItem.id:
activeSection = channelGroupItem
let communitySectionItem = self.createCommunitySectionItem(community)
self.view.model().addItem(communitySectionItem)
if activeSectionId == communitySectionItem.id:
activeSection = communitySectionItem
self.channelGroupModules[channelGroup.id].load()
self.chatSectionModules[community.id].load()
# Set active section if it is one of the channel sections
if not activeSection.isEmpty():
@ -705,8 +746,7 @@ method onCommunityDataLoaded*[T](
if not self.chatsLoaded:
return
self.onChannelGroupsLoaded(
self.controller.getChannelGroups(),
self.onChatsLoaded(
events,
settingsService,
nodeConfigurationService,
@ -729,7 +769,7 @@ proc checkIfModuleDidLoad [T](self: Module[T]) =
if self.moduleLoaded:
return
for cModule in self.channelGroupModules.values:
for cModule in self.chatSectionModules.values:
if(not cModule.isLoaded()):
return
@ -839,7 +879,7 @@ method setActiveSectionById*[T](self: Module[T], id: string) =
self.setActiveSection(item)
proc notifySubModulesAboutChange[T](self: Module[T], sectionId: string) =
for cModule in self.channelGroupModules.values:
for cModule in self.chatSectionModules.values:
cModule.onActiveSectionChange(sectionId)
# If there is a need other section may be notified the same way from here...
@ -888,17 +928,17 @@ method setCurrentUserStatus*[T](self: Module[T], status: StatusType) =
self.controller.setCurrentUserStatus(status)
proc getChatSectionModule*[T](self: Module[T]): chat_section_module.AccessInterface =
return self.channelGroupModules[singletonInstance.userProfile.getPubKey()]
return self.chatSectionModules[singletonInstance.userProfile.getPubKey()]
method getChatSectionModuleAsVariant*[T](self: Module[T]): QVariant =
return self.getChatSectionModule().getModuleAsVariant()
method getCommunitySectionModule*[T](self: Module[T], communityId: string): QVariant =
if(not self.channelGroupModules.contains(communityId)):
if(not self.chatSectionModules.contains(communityId)):
echo "main-module, unexisting community key: ", communityId
return
return self.channelGroupModules[communityId].getModuleAsVariant()
return self.chatSectionModules[communityId].getModuleAsVariant()
method rebuildChatSearchModel*[T](self: Module[T]) =
var items: seq[chat_search_item.Item] = @[]
@ -985,13 +1025,13 @@ method communityJoined*[T](
networkService: network_service.Service,
setActive: bool = false,
) =
if self.channelGroupModules.contains(community.id):
if self.chatSectionModules.contains(community.id):
# The community is already spectated
return
var firstCommunityJoined = false
if (self.channelGroupModules.len == 1): # First one is personal chat section
if (self.chatSectionModules.len == 1): # First one is personal chat section
firstCommunityJoined = true
self.channelGroupModules[community.id] = chat_section_module.newModule(
self.chatSectionModules[community.id] = chat_section_module.newModule(
self,
events,
community.id,
@ -1009,10 +1049,9 @@ method communityJoined*[T](
sharedUrlsService,
networkService
)
let channelGroup = community.toChannelGroupDto()
self.channelGroupModules[community.id].load()
self.chatSectionModules[community.id].load()
let communitySectionItem = self.createChannelGroupItem(channelGroup)
let communitySectionItem = self.createCommunitySectionItem(community)
if (firstCommunityJoined):
# If there are no other communities, add the first community after the Chat section in the model so that the order is respected
self.view.model().addItem(communitySectionItem,
@ -1022,11 +1061,12 @@ method communityJoined*[T](
if setActive:
self.setActiveSection(communitySectionItem)
if channelGroup.chats.len > 0:
self.channelGroupModules[community.id].setActiveItem(channelGroup.chats[0].id)
if(community.chats.len > 0):
let chatId = community.chats[0].id
self.chatSectionModules[community.id].setActiveItem(chatId)
method communityLeft*[T](self: Module[T], communityId: string) =
if(not self.channelGroupModules.contains(communityId)):
if(not self.chatSectionModules.contains(communityId)):
echo "main-module, unexisting community key to leave: ", communityId
return
@ -1039,24 +1079,23 @@ method communityLeft*[T](self: Module[T], communityId: string) =
self.setActiveSection(item)
var moduleToDelete: chat_section_module.AccessInterface
discard self.channelGroupModules.pop(communityId, moduleToDelete)
discard self.chatSectionModules.pop(communityId, moduleToDelete)
moduleToDelete.delete
moduleToDelete = nil
method communityEdited*[T](
self: Module[T],
community: CommunityDto) =
if(not self.channelGroupModules.contains(community.id)):
if(not self.chatSectionModules.contains(community.id)):
return
let channelGroup = community.toChannelGroupDto()
var channelGroupItem = self.createChannelGroupItem(channelGroup)
var communitySectionItem = self.createCommunitySectionItem(community)
# We need to calculate the unread counts because the community update doesn't come with it
let (unviewedMessagesCount, unviewedMentionsCount) = self.controller.sectionUnreadMessagesAndMentionsCount(
channelGroupItem.id
communitySectionItem.id
)
channelGroupItem.setHasNotification(unviewedMessagesCount > 0)
channelGroupItem.setNotificationsCount(unviewedMentionsCount)
self.view.editItem(channelGroupItem)
communitySectionItem.setHasNotification(unviewedMessagesCount > 0)
communitySectionItem.setNotificationsCount(unviewedMentionsCount)
self.view.editItem(communitySectionItem)
method onCommunityMuted*[T](
self: Module[T],
@ -1595,8 +1634,8 @@ method activateStatusDeepLink*[T](self: Module[T], statusDeepLink: string) =
return
method onDeactivateChatLoader*[T](self: Module[T], sectionId: string, chatId: string) =
if (sectionId.len > 0 and self.channelGroupModules.contains(sectionId)):
self.channelGroupModules[sectionId].onDeactivateChatLoader(chatId)
if (sectionId.len > 0 and self.chatSectionModules.contains(sectionId)):
self.chatSectionModules[sectionId].onDeactivateChatLoader(chatId)
method windowActivated*[T](self: Module[T]) =
self.controller.slowdownArchivesImport()
@ -1646,12 +1685,12 @@ method checkIfAddressWasCopied*[T](self: Module[T], value: string) =
self.addressWasShown(value)
method openSectionChatAndMessage*[T](self: Module[T], sectionId: string, chatId: string, messageId: string) =
if sectionId in self.channelGroupModules:
self.channelGroupModules[sectionId].openCommunityChatAndScrollToMessage(chatId, messageId)
if sectionId in self.chatSectionModules:
self.chatSectionModules[sectionId].openCommunityChatAndScrollToMessage(chatId, messageId)
method updateRequestToJoinState*[T](self: Module[T], sectionId: string, requestToJoinState: RequestToJoinState) =
if sectionId in self.channelGroupModules:
self.channelGroupModules[sectionId].updateRequestToJoinState(requestToJoinState)
if sectionId in self.chatSectionModules:
self.chatSectionModules[sectionId].updateRequestToJoinState(requestToJoinState)
proc createMemberItem*[T](self: Module[T], memberId: string, requestId: string, state: MembershipRequestState, role: MemberRole): MemberItem =
let contactDetails = self.controller.getContactDetails(memberId)

View File

@ -105,7 +105,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
result.devicesModule = devices_module.newModule(result, events, settingsService, devicesService)
result.syncModule = sync_module.newModule(result, events, settingsService, nodeConfigurationService, mailserversService)
result.wakuModule = waku_module.newModule(result, events, settingsService, nodeConfigurationService)
result.notificationsModule = notifications_module.newModule(result, events, settingsService, chatService, contactsService)
result.notificationsModule = notifications_module.newModule(result, events, settingsService, chatService, contactsService, communityService)
result.ensUsernamesModule = ens_usernames_module.newModule(
result, events, settingsService, ensService, walletAccountService, networkService, tokenService, keycardService
)

View File

@ -17,23 +17,41 @@ type
settingsService: settings_service.Service
chatService: chat_service.Service
contactService: contact_service.Service
communityService: community_service.Service
chatsLoaded: bool
communitiesLoaded: bool
proc newController*(delegate: io_interface.AccessInterface,
events: EventEmitter,
settingsService: settings_service.Service,
chatService: chat_service.Service,
contactService: contact_service.Service): Controller =
events: EventEmitter,
settingsService: settings_service.Service,
chatService: chat_service.Service,
contactService: contact_service.Service,
communityService: community_service.Service,
): Controller =
result = Controller()
result.delegate = delegate
result.events = events
result.settingsService = settingsService
result.chatService = chatService
result.contactService = contactService
result.communityService = communityService
result.chatsLoaded = false
result.communitiesLoaded = false
proc delete*(self: Controller) =
discard
proc init*(self: Controller) =
self.events.on(SIGNAL_ACTIVE_CHATS_LOADED) do(e:Args):
self.chatsLoaded = true
if self.communitiesLoaded:
self.delegate.initModel()
self.events.on(SIGNAL_COMMUNITY_DATA_LOADED) do(e:Args):
self.communitiesLoaded = true
if self.chatsLoaded:
self.delegate.initModel()
self.events.on(SIGNAL_COMMUNITY_JOINED) do(e:Args):
let args = CommunityArgs(e)
if(args.error.len > 0):
@ -95,11 +113,14 @@ proc setNotifSettingExemptions*(self: Controller, id: string, exemptions: Notifi
proc removeNotifSettingExemptions*(self: Controller, id: string): bool =
return self.settingsService.removeNotifSettingExemptions(id)
proc getChannelGroups*(self: Controller): seq[ChannelGroupDto] =
return self.chatService.getChannelGroups()
proc getChatsForPersonalSection*(self: Controller): seq[ChatDto] =
return self.chatService.getChatsForPersonalSection()
proc getChatDetails*(self: Controller, chatId: string): ChatDto =
return self.chatService.getChatById(chatId)
proc getContactDetails*(self: Controller, id: string): ContactDetails =
return self.contactService.getContactDetails(id)
proc getJoinedAndSpectatedCommunities*(self: Controller): seq[CommunityDto] =
return self.communityService.getJoinedAndSpectatedCommunities()

View File

@ -14,6 +14,9 @@ method load*(self: AccessInterface) {.base.} =
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method initModel*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -8,6 +8,7 @@ import ../../../../core/eventemitter
import ../../../../../app_service/service/settings/service as settings_service
import ../../../../../app_service/service/chat/service as chat_service
import ../../../../../app_service/service/contacts/service as contact_service
import ../../../../../app_service/service/community/service as community_service
from ../../../../../app_service/service/community/dto/community import CommunityDto
export io_interface
@ -24,15 +25,18 @@ type
moduleLoaded: bool
proc newModule*(delegate: delegate_interface.AccessInterface,
events: EventEmitter,
settingsService: settings_service.Service,
chatService: chat_service.Service,
contactService: contact_service.Service): Module =
events: EventEmitter,
settingsService: settings_service.Service,
chatService: chat_service.Service,
contactService: contact_service.Service,
communityService: community_service.Service,
): Module =
result = Module()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, events, settingsService, chatService, contactService)
result.controller = controller.newController(result, events, settingsService, chatService, contactService,
communityService)
result.moduleLoaded = false
method delete*(self: Module) =
@ -70,26 +74,34 @@ proc createChatItem(self: Module, chatDto: ChatDto): Item =
return self.createItem(chatDto.id, chatName, chatImage, chatDto.color, chatDto.joined, itemType)
proc initModel(self: Module) =
let channelGroups = self.controller.getChannelGroups()
method initModel(self: Module) =
var items: seq[Item]
for cg in channelGroups:
if cg.channelGroupType == ChannelGroupType.Community:
let item = self.createItem(cg.id, cg.name, cg.images.thumbnail, cg.color, joinedTimestamp = 0, item.Type.Community)
items.add(item)
elif cg.channelGroupType == ChannelGroupType.Personal:
for c in cg.chats:
if c.chatType != ChatType.OneToOne and c.chatType != ChatType.PrivateGroupChat:
continue
let item = self.createChatItem(c)
items.add(item)
# Add personal section
let personalChats = self.controller.getChatsForPersonalSection()
for c in personalChats:
if c.chatType != ChatType.OneToOne and c.chatType != ChatType.PrivateGroupChat:
continue
let item = self.createChatItem(c)
items.add(item)
# Add communities
let communities = self.controller.getJoinedAndSpectatedCommunities()
for community in communities:
let item = self.createItem(
community.id,
community.name,
community.images.thumbnail,
community.color,
joinedTimestamp = 0,
item.Type.Community
)
items.add(item)
# Sort to get most recent first
items.sort(comp, SortOrder.Descending)
self.view.exemptionsModel().setItems(items)
method viewDidLoad*(self: Module) =
self.initModel()
self.moduleLoaded = true
self.delegate.notificationsModuleDidLoad()

View File

@ -1,16 +1,17 @@
#################################################
# Async get chats (channel groups)
# Async get chats
#################################################
type
AsyncGetChannelGroupsTaskArg = ref object of QObjectTaskArg
const asyncGetChannelGroupsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncGetChannelGroupsTaskArg](argEncoded)
type
AsyncGetActiveChatsTaskArg = ref object of QObjectTaskArg
const asyncGetActiveChatsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncGetActiveChatsTaskArg](argEncoded)
try:
let response = status_chat.getChannelGroups()
let response = status_chat.getActiveChats()
let responseJson = %*{
"channelGroups": response.result,
"chats": response.result,
"error": "",
}
arg.finish(responseJson)

View File

@ -16,7 +16,7 @@ type ChatType* {.pure.}= enum
Timeline {.deprecated.} = 5,
CommunityChat = 6
type ChannelGroupType* {.pure.}= enum
type ChatSectionType* {.pure.}= enum
Unknown = "unknown",
Personal = "personal",
Community = "community"
@ -93,35 +93,6 @@ type ChatDto* = object
permissions*: Permission
hideIfPermissionsNotMet*: bool
type ChannelGroupDto* = object
id*: string
channelGroupType*: ChannelGroupType
memberRole*: MemberRole
verified*: bool
name*: string
ensName*: string
description*: string
introMessage*: string
outroMessage*: string
chats*: seq[ChatDto]
categories*: seq[Category]
images*: Images
permissions*: Permission
members*: seq[ChatMember]
canManageUsers*: bool
color*: string
muted*: bool
historyArchiveSupportEnabled*: bool
pinMessageAllMembersEnabled*: bool
bannedMembersIds*: seq[string]
encrypted*: bool
unviewedMessagesCount*: int
unviewedMentionsCount*: int
channelPermissions*: CheckAllChannelsPermissionsResponseDto
pubsubTopic*: string
pubsubTopicKey*: string
shard*: Shard
type ClearedHistoryDto* = object
chatId*: string
clearedAt*: int
@ -324,74 +295,6 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto =
if (result.communityId != "" and not result.id.contains(result.communityId)):
result.id = result.communityId & result.id
proc toChannelGroupDto*(jsonObj: JsonNode): ChannelGroupDto =
result = ChannelGroupDto()
discard jsonObj.getProp("verified", result.verified)
discard jsonObj.getProp("memberRole", result.memberRole)
discard jsonObj.getProp("name", result.name)
discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("introMessage", result.introMessage)
discard jsonObj.getProp("outroMessage", result.outroMessage)
discard jsonObj.getProp("encrypted", result.encrypted)
discard jsonObj.getProp("unviewedMessagesCount", result.unviewedMessagesCount)
discard jsonObj.getProp("unviewedMentionsCount", result.unviewedMentionsCount)
result.channelGroupType = ChannelGroupType.Unknown
var channelGroupTypeString: string
if (jsonObj.getProp("channelGroupType", channelGroupTypeString)):
result.channelGroupType = parseEnum[ChannelGroupType](channelGroupTypeString)
var chatsObj: JsonNode
if(jsonObj.getProp("chats", chatsObj)):
for _, chatObj in chatsObj:
let chat = toChatDto(chatObj)
if (chat.chatType == ChatType.Public):
# Filter out public chats as we don't show them anymore
continue
result.chats.add(chat)
var categoriesObj: JsonNode
if(jsonObj.getProp("categories", categoriesObj)):
for _, categoryObj in categoriesObj:
result.categories.add(toCategory(categoryObj))
var imagesObj: JsonNode
if(jsonObj.getProp("images", imagesObj)):
result.images = toImages(imagesObj)
var permissionObj: JsonNode
if(jsonObj.getProp("permissions", permissionObj)):
result.permissions = toPermission(permissionObj)
var membersObj: JsonNode
if(jsonObj.getProp("members", membersObj) and membersObj.kind == JObject):
for memberId, memberObj in membersObj:
result.members.add(toChannelMember(memberObj, memberId, joined = true))
var bannedMembersIdsObj: JsonNode
if(jsonObj.getProp("banList", bannedMembersIdsObj) and bannedMembersIdsObj.kind == JArray):
for bannedMemberId in bannedMembersIdsObj:
result.bannedMembersIds.add(bannedMemberId.getStr)
discard jsonObj.getProp("canManageUsers", result.canManageUsers)
discard jsonObj.getProp("color", result.color)
discard jsonObj.getProp("muted", result.muted)
var responseDto = CheckAllChannelsPermissionsResponseDto()
responseDto.channels = initTable[string, CheckChannelPermissionsResponseDto]()
result.channelPermissions = responseDto
var checkChannelPermissionResponsesObj: JsonNode
if(jsonObj.getProp("checkChannelPermissionResponses", checkChannelPermissionResponsesObj) and checkChannelPermissionResponsesObj.kind == JObject):
for channelId, permissionResponse in checkChannelPermissionResponsesObj:
result.channelPermissions.channels[channelId] = permissionResponse.toCheckChannelPermissionsResponseDto()
discard jsonObj.getProp("pubsubTopic", result.pubsubTopic)
discard jsonObj.getProp("pubsubTopicKey", result.pubsubTopicKey)
result.shard = jsonObj.getShard()
# To parse Community chats to ChatDto, we need to add the commuity ID and type
proc toChatDto*(jsonObj: JsonNode, communityId: string): ChatDto =
result = jsonObj.toChatDto()
@ -433,3 +336,12 @@ proc updateMissingFields*(chatToUpdate: var ChatDto, oldChat: ChatDto) =
chatToUpdate.viewersCanPostReactions = oldChat.viewersCanPostReactions
chatToUpdate.categoryId = oldChat.categoryId
chatToUpdate.members = oldChat.members
proc isOneToOne*(c: ChatDto): bool =
return c.chatType == ChatType.OneToOne
proc isPrivateGroupChat*(c: ChatDto): bool =
return c.chatType == ChatType.PrivateGroupChat
proc isActivePersonalChat*(c: ChatDto): bool =
return c.active and (c.isOneToOne() or c.isPrivateGroupChat()) and c.communityId == ""

View File

@ -1,4 +1,4 @@
import NimQml, Tables, json, sequtils, stew/shims/strformat, chronicles, os, std/algorithm, strutils, uuids, base64
import NimQml, Tables, json, sequtils, stew/shims/strformat, chronicles, os, strutils, uuids, base64
import std/[times, os]
import ../../../app/core/tasks/[qt, threadpool]
@ -30,12 +30,6 @@ include ../../../app/core/tasks/common
include async_tasks
type
ChannelGroupsArgs* = ref object of Args
channelGroups*: seq[ChannelGroupDto]
ChannelGroupArgs* = ref object of Args
channelGroup*: ChannelGroupDto
ChatUpdateArgs* = ref object of Args
chats*: seq[ChatDto]
@ -102,8 +96,8 @@ type
error*: string
# Signals which may be emitted by this service:
const SIGNAL_CHANNEL_GROUPS_LOADED* = "channelGroupsLoaded"
const SIGNAL_CHANNEL_GROUPS_LOADING_FAILED* = "channelGroupsLoadingFailed"
const SIGNAL_ACTIVE_CHATS_LOADED* = "activeChatsLoaded"
const SIGNAL_CHATS_LOADING_FAILED* = "chatsLoadingFailed"
const SIGNAL_CHAT_UPDATE* = "chatUpdate"
const SIGNAL_CHAT_LEFT* = "channelLeft"
const SIGNAL_SENDING_FAILED* = "messageSendingFailed"
@ -131,7 +125,6 @@ QtObject:
threadpool: ThreadPool
events: EventEmitter
chats: Table[string, ChatDto] # [chat_id, ChatDto]
channelGroups: OrderedTable[string, ChannelGroupDto] # [chatGroup_id, ChannelGroupDto]
contactService: contact_service.Service
proc delete*(self: Service) =
@ -148,12 +141,9 @@ QtObject:
result.threadpool = threadpool
result.contactService = contactService
result.chats = initTable[string, ChatDto]()
result.channelGroups = initOrderedTable[string, ChannelGroupDto]()
# Forward declarations
proc updateOrAddChat*(self: Service, chat: ChatDto)
proc hydrateChannelGroups*(self: Service, data: JsonNode)
proc updateOrAddChannelGroup*(self: Service, channelGroup: ChannelGroupDto, isCommunityChannelGroup: bool = false)
proc processMessengerResponse*(self: Service, response: RpcResponse[JsonNode]): (seq[ChatDto], seq[MessageDto])
proc doConnect(self: Service) =
@ -187,126 +177,63 @@ QtObject:
for clearedHistoryDto in receivedData.clearedHistories:
self.events.emit(SIGNAL_CHAT_HISTORY_CLEARED, ChatArgs(chatId: clearedHistoryDto.chatId))
# Handling community updates
if (receivedData.communities.len > 0):
for community in receivedData.communities:
if community.joined:
self.updateOrAddChannelGroup(community.toChannelGroupDto(), isCommunityChannelGroup = true)
self.events.on(SIGNAL_CHAT_REQUEST_UPDATE_AFTER_SEND) do(e: Args):
var args = RpcResponseArgs(e)
discard self.processMessengerResponse(args.response)
proc getChannelGroups*(self: Service): seq[ChannelGroupDto] =
return toSeq(self.channelGroups.values)
proc loadChannelGroupById*(self: Service, channelGroupId: string) =
try:
let response = status_chat.getChannelGroupById(channelGroupId)
self.hydrateChannelGroups(response.result)
except Exception as e:
error "error loadChannelGroupById: ", errorDescription = e.msg
proc asyncGetChannelGroups*(self: Service) =
let arg = AsyncGetChannelGroupsTaskArg(
tptr: cast[ByteAddress](asyncGetChannelGroupsTask),
proc asyncGetActiveChat*(self: Service) =
let arg = AsyncGetActiveChatsTaskArg(
tptr: cast[ByteAddress](asyncGetActiveChatsTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncGetChannelGroupsResponse",
slot: "onAsyncGetActiveChatsResponse",
)
self.threadpool.start(arg)
proc sortPersonnalChatAsFirst[T, D](x, y: (T, D)): int =
if (x[1].channelGroupType == Personal): return -1
if (y[1].channelGroupType == Personal): return 1
return 0
proc hydrateChannelGroups(self: Service, data: JsonNode) =
var chats: seq[ChatDto] = @[]
for (sectionId, section) in data.pairs:
var channelGroup = section.toChannelGroupDto()
channelGroup.id = sectionId
self.channelGroups[sectionId] = channelGroup
for (chatId, chat) in section["chats"].pairs:
chats.add(chat.toChatDto())
# Make the personal channelGroup the first one
self.channelGroups.sort(sortPersonnalChatAsFirst[string, ChannelGroupDto], SortOrder.Ascending)
for chat in chats:
proc hydrateChats(self: Service, data: JsonNode) =
for chatJson in data:
let chat = chatJson.toChatDto()
if chat.active and chat.chatType != chat_dto.ChatType.Unknown:
if chat.chatType == chat_dto.ChatType.Public:
# Deactivate old public chats
discard status_chat.deactivateChat(chat.id)
else:
self.chats[chat.id] = chat
proc onAsyncGetChannelGroupsResponse*(self: Service, response: string) {.slot.} =
proc onAsyncGetActiveChatsResponse*(self: Service, response: string) {.slot.} =
try:
let rpcResponseObj = response.parseJson
if (rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != ""):
raise newException(CatchableError, rpcResponseObj{"error"}.getStr)
if(rpcResponseObj["channelGroups"].kind == JNull):
raise newException(RpcException, "No channel groups returned")
if rpcResponseObj["chats"].kind != JNull:
self.hydrateChats(rpcResponseObj["chats"])
self.hydrateChannelGroups(rpcResponseObj["channelGroups"])
self.events.emit(SIGNAL_CHANNEL_GROUPS_LOADED, ChannelGroupsArgs(channelGroups: self.getChannelGroups()))
self.events.emit(SIGNAL_ACTIVE_CHATS_LOADED, Args())
except Exception as e:
let errDesription = e.msg
error "error get channel groups: ", errDesription
self.events.emit(SIGNAL_CHANNEL_GROUPS_LOADING_FAILED, Args())
error "error get active chats: ", errDesription
self.events.emit(SIGNAL_CHATS_LOADING_FAILED, Args())
proc init*(self: Service) =
self.doConnect()
self.asyncGetChannelGroups()
self.asyncGetActiveChat()
proc hasChannel*(self: Service, chatId: string): bool =
self.chats.hasKey(chatId)
proc getChatIndex*(self: Service, channelGroupId, chatId: string): int =
var i = 0
if not self.channelGroups.contains(channelGroupId):
warn "unknown channel group", channelGroupId
return -1
for chat in self.channelGroups[channelGroupId].chats:
if (chat.id == chatId):
return i
i.inc()
return -1
proc chatsWithCategoryHaveUnreadMessages*(self: Service, communityId: string, categoryId: string): bool =
if communityId == "" or categoryId == "":
return false
if not self.channelGroups.contains(communityId):
warn "unknown community", communityId
return false
for chat in self.channelGroups[communityId].chats:
if chat.categoryId != categoryId:
continue
if (not chat.muted and chat.unviewedMessagesCount > 0) or chat.unviewedMentionsCount > 0:
return true
return false
proc sectionUnreadMessagesAndMentionsCount*(self: Service, communityId: string):
proc sectionUnreadMessagesAndMentionsCount*(self: Service, sectionId: string):
tuple[unviewedMessagesCount: int, unviewedMentionsCount: int] =
if communityId == "":
return
if not self.channelGroups.contains(communityId):
warn "unknown community", communityId
return
result.unviewedMentionsCount = 0
result.unviewedMessagesCount = 0
for chat in self.channelGroups[communityId].chats:
let myPubKey = singletonInstance.userProfile.getPubKey()
var seactionIdToFind = sectionId
if sectionId == myPubKey:
# If the section is the personal one (ID == pubKey), then we set the seactionIdToFind to ""
# because personal chats have communityId == ""
seactionIdToFind = ""
for _, chat in self.chats:
if chat.communityId != seactionIdToFind:
continue
result.unviewedMentionsCount += chat.unviewedMentionsCount
# We count the unread messages if we are unmuted and it's not a mention, we want to show a badge on mentions
if chat.unviewedMentionsCount == 0 and chat.muted:
@ -328,49 +255,6 @@ QtObject:
self.chats[chat.id].categoryId = categoryId
self.events.emit(SIGNAL_CHAT_ADDED_OR_UPDATED, ChatArgs(communityId: chat.communityId, chatId: chat.id))
var channelGroupId = chat.communityId
if (channelGroupId == ""):
channelGroupId = singletonInstance.userProfile.getPubKey()
if not self.channelGroups.contains(channelGroupId):
warn "unknown community for new channel update", channelGroupId
return
let index = self.getChatIndex(channelGroupId, chat.id)
if (index == -1):
self.channelGroups[channelGroupId].chats.add(self.chats[chat.id])
else:
self.channelGroups[channelGroupId].chats[index] = self.chats[chat.id]
proc updateMissingFieldsInCommunityChat(self: Service, channelGroupId: string, newChat: ChatDto): ChatDto =
if not self.channelGroups.contains(channelGroupId):
warn "unknown channel group", channelGroupId
return
var chat = newChat
for previousChat in self.channelGroups[channelGroupId].chats:
if previousChat.id != newChat.id:
continue
chat.unviewedMessagesCount = previousChat.unviewedMessagesCount
chat.unviewedMentionsCount = previousChat.unviewedMentionsCount
chat.muted = previousChat.muted
chat.highlight = previousChat.highlight
break
return chat
# Community channel groups have less info because they come from community signals
proc updateOrAddChannelGroup*(self: Service, channelGroup: ChannelGroupDto, isCommunityChannelGroup: bool = false) =
var newChannelGroup = channelGroup
if isCommunityChannelGroup and self.channelGroups.contains(channelGroup.id):
# We need to update missing fields in the chats seq before saving
let newChats = channelGroup.chats.mapIt(self.updateMissingFieldsInCommunityChat(channelGroup.id, it))
newChannelGroup.chats = newChats
self.channelGroups[channelGroup.id] = newChannelGroup
for chat in newChannelGroup.chats:
self.updateOrAddChat(chat)
proc updateChannelMembers*(self: Service, channel: ChatDto) =
if not self.chats.hasKey(channel.id):
return
@ -380,12 +264,6 @@ QtObject:
self.updateOrAddChat(chat)
self.events.emit(SIGNAL_CHAT_MEMBERS_CHANGED, ChatMembersChangedArgs(chatId: chat.id, members: chat.members))
proc getChannelGroupById*(self: Service, channelGroupId: string): ChannelGroupDto =
if not self.channelGroups.contains(channelGroupId):
warn "Unknown channel group", channelGroupId
return
return self.channelGroups[channelGroupId]
proc parseChatResponse*(self: Service, response: RpcResponse[JsonNode]): (seq[ChatDto], seq[MessageDto]) =
var chats: seq[ChatDto] = @[]
var messages: seq[MessageDto] = @[]
@ -460,6 +338,12 @@ QtObject:
proc getChatsOfChatTypes*(self: Service, types: seq[chat_dto.ChatType]): seq[ChatDto] =
return self.getAllChats().filterIt(it.chatType in types)
proc getChatsForPersonalSection*(self: Service): seq[ChatDto] =
return self.getAllChats().filterIt(it.isActivePersonalChat())
proc getChatsForCommunity*(self: Service, communityId: string): seq[ChatDto] =
return self.getAllChats().filterIt(it.communityId == communityId)
proc getChatById*(self: Service, chatId: string, showWarning: bool = true): ChatDto =
if(not self.chats.contains(chatId)):
if (showWarning):
@ -527,11 +411,6 @@ QtObject:
discard status_chat.deactivateChat(chatId, preserveHistory = chat.chatType == chat_dto.ChatType.OneToOne)
var channelGroupId = chat.communityId
if (channelGroupId == ""):
channelGroupId = singletonInstance.userProfile.getPubKey()
self.channelGroups[channelGroupId].chats.delete(self.getChatIndex(channelGroupId, chatId))
self.chats.del(chatId)
self.events.emit(SIGNAL_CHAT_LEFT, ChatArgs(chatId: chatId))
except Exception as e:
@ -734,20 +613,11 @@ QtObject:
var parsedImage = imageJson.parseJson
parsedImage["imagePath"] = %singletonInstance.utils.formatImagePath(parsedImage["imagePath"].getStr)
let response = status_chat.editChat(communityID, chatID, name, color, $parsedImage)
if (not response.error.isNil):
let msg = response.error.message & " chatId=" & chatId
error "error while editing group chat details", msg
return
let resultedChat = response.result.toChatDto()
discard self.processMessengerResponse(response)
var chat = self.chats[chatID]
chat.name = name
chat.color = color
chat.icon = resultedChat.icon
self.updateOrAddChat(chat)
self.events.emit(SIGNAL_GROUP_CHAT_DETAILS_UPDATED, ChatUpdateDetailsArgs(id: chatID, newName: name, newColor: color, newImage: resultedChat.icon))
let chat = self.chats[chatID]
self.events.emit(SIGNAL_GROUP_CHAT_DETAILS_UPDATED, ChatUpdateDetailsArgs(id: chatID, newName: name, newColor: color, newImage: chat.icon))
except Exception as e:
error "error while updating group chat: ", msg = e.msg
@ -781,25 +651,6 @@ QtObject:
except Exception as e:
error "error while creating group chat", msg = e.msg
proc getMembers*(self: Service, communityID, chatId: string): seq[ChatMember] =
try:
var realChatId = chatId.replace(communityID, "")
let response = status_chat.getMembers(communityID, realChatId)
if response.result.kind == JNull:
# No members. Could be a public chat
return
let myPubkey = singletonInstance.userProfile.getPubKey()
result = @[]
for (id, memberObj) in response.result.pairs:
var member = toChatMember(memberObj, id)
# Make yourself as the first result
if (id == myPubkey):
result.insert(member)
else:
result.add(member)
except Exception as e:
error "error while getting members", msg = e.msg, communityID, chatId
proc updateUnreadMessage*(self: Service, chatID: string, messagesCount:int, messagesWithMentionsCount:int) =
var chat = self.getChatById(chatID)
if chat.id == "":
@ -842,7 +693,7 @@ QtObject:
let communityId = rpcResponseObj{"communityId"}.getStr()
let chatId = rpcResponseObj{"chatId"}.getStr()
let checkChannelPermissionsResponse = rpcResponseObj["response"]["result"].toCheckChannelPermissionsResponseDto()
self.channelGroups[communityId].channelPermissions.channels[chatId] = checkChannelPermissionsResponse
self.events.emit(SIGNAL_CHECK_CHANNEL_PERMISSIONS_RESPONSE, CheckChannelPermissionsResponseArgs(communityId: communityId, chatId: chatId, checkChannelPermissionsResponse: checkChannelPermissionsResponse))
except Exception as e:
let errMsg = e.msg
@ -870,7 +721,7 @@ QtObject:
raise newException(RpcException, error.message)
let checkAllChannelsPermissionsResponse = rpcResponseObj["response"]["result"].toCheckAllChannelsPermissionsResponseDto()
self.channelGroups[communityId].channelPermissions = checkAllChannelsPermissionsResponse
# TODO save it
self.events.emit(SIGNAL_CHECK_ALL_CHANNELS_PERMISSIONS_RESPONSE, CheckAllChannelsPermissionsResponseArgs(communityId: communityId, checkAllChannelsPermissionsResponse: checkAllChannelsPermissionsResponse))
except Exception as e:
let errMsg = e.msg

View File

@ -548,39 +548,6 @@ proc getBannedMembersIds*(self: CommunityDto): seq[string] =
bannedIds.add(memberId)
return bannedIds
proc toChannelGroupDto*(communityDto: CommunityDto): ChannelGroupDto =
ChannelGroupDto(
id: communityDto.id,
channelGroupType: ChannelGroupType.Community,
name: communityDto.name,
images: communityDto.images,
chats: communityDto.chats,
categories: communityDto.categories,
# Community doesn't have an ensName yet. Add this when it is added in status-go
# ensName: communityDto.ensName,
memberRole: communityDto.memberRole,
verified: communityDto.verified,
description: communityDto.description,
introMessage: communityDto.introMessage,
outroMessage: communityDto.outroMessage,
color: communityDto.color,
# tags: communityDto.tags, NOTE: do we need tags here?
permissions: communityDto.permissions,
members: communityDto.members.map(m => ChatMember(
id: m.id,
joined: true,
role: m.role
)),
canManageUsers: communityDto.canManageUsers,
muted: communityDto.muted,
historyArchiveSupportEnabled: communityDto.settings.historyArchiveSupportEnabled,
bannedMembersIds: communityDto.getBannedMembersIds(),
encrypted: communityDto.encrypted,
shard: communityDto.shard,
pubsubTopic: communityDto.pubsubTopic,
pubsubTopicKey: communityDto.pubsubTopicKey,
)
proc parseCommunitiesSettings*(response: JsonNode): seq[CommunitySettingsDto] =
result = map(response["result"].getElems(),
proc(x: JsonNode): CommunitySettingsDto = x.toCommunitySettingsDto())
@ -628,15 +595,20 @@ proc toMembersRevealedAccounts*(membersRevealedAccountsObj: JsonNode): MembersRe
for (pubkey, revealedAccountsObj) in membersRevealedAccountsObj.pairs:
result[pubkey] = revealedAccountsObj.toRevealedAccounts()
proc getCommunityChats*(self: CommunityDto, chatsIds: seq[string]): seq[ChatDto] =
proc getCommunityChats*(self: CommunityDto, chatIds: seq[string]): seq[ChatDto] =
var chats: seq[ChatDto] = @[]
for chatId in chatsIds:
for chatId in chatIds:
for communityChat in self.chats:
if chatId == communityChat.id:
chats.add(communityChat)
break
return chats
proc getCommunityChat*(self: CommunityDto, chatId: string): ChatDto =
let chats = self.getCommunityChats(@[chatId])
if chats.len > 0:
return chats[0]
proc isOwner*(self: CommunityDto): bool =
return self.memberRole == MemberRole.Owner

View File

@ -306,10 +306,10 @@ QtObject:
result.communityMetrics = initTable[string, CommunityMetricsDto]()
result.communityInfoRequests = initTable[string, Time]()
proc getFilteredJoinedCommunities(self: Service): Table[string, CommunityDto] =
proc getFilteredJoinedAndSpectatedCommunities(self: Service): Table[string, CommunityDto] =
result = initTable[string, CommunityDto]()
for communityId, community in self.communities.pairs:
if community.joined:
if community.joined or community.spectated:
result[communityId] = community
proc getFilteredCuratedCommunities(self: Service): Table[string, CommunityDto] =
@ -650,17 +650,6 @@ QtObject:
chat.emoji != prevChat.emoji or chat.viewersCanPostReactions != prevChat.viewersCanPostReactions or
chat.hideIfPermissionsNotMet != prevChat.hideIfPermissionsNotMet:
var updatedChat = chat
# TODO improve this in https://github.com/status-im/status-desktop/issues/12595
# Currently, status-go only sends canPostReactions on app start (getChannelGroups)
# so here, we need to imply it. If viewersCanPostReactions is true, then everyone can post reactions
# admins can also always post reactions
if chat.viewersCanPostReactions or
(not chat.viewersCanPostReactions and community.memberRole != MemberRole.None):
updatedChat.canPostReactions = true
elif not chat.viewersCanPostReactions and community.memberRole == MemberRole.None:
updatedChat.canPostReactions = false
self.chatService.updateOrAddChat(updatedChat) # we have to update chats stored in the chat service.
let data = CommunityChatArgs(chat: updatedChat)
@ -845,7 +834,7 @@ QtObject:
if self.communities.hasKey(settings.id):
self.communities[settings.id].settings = settings
# Non approver requests to join for all communities
# Non approved requests to join for all communities
let nonAprrovedRequestsToJoinObj = responseObj["nonAprrovedRequestsToJoin"]
if nonAprrovedRequestsToJoinObj{"result"}.kind != JNull:
@ -874,8 +863,8 @@ QtObject:
proc getCommunityTags*(self: Service): string =
return self.communityTags
proc getJoinedCommunities*(self: Service): seq[CommunityDto] =
return toSeq(self.getFilteredJoinedCommunities().values)
proc getJoinedAndSpectatedCommunities*(self: Service): seq[CommunityDto] =
return toSeq(self.getFilteredJoinedAndSpectatedCommunities().values)
proc getAllCommunities*(self: Service): seq[CommunityDto] =
return toSeq(self.communities.values)
@ -1056,13 +1045,9 @@ QtObject:
updatedCommunity.settings = communitySettings
self.communities[communityId] = updatedCommunity
self.chatService.loadChannelGroupById(communityId)
let ownerTokenNotification = self.activityCenterService.getNotificationForTypeAndCommunityId(notification.ActivityCenterNotificationType.OwnerTokenReceived, communityId)
self.events.emit(SIGNAL_COMMUNITIES_UPDATE, CommunitiesArgs(communities: @[updatedCommunity]))
self.events.emit(SIGNAL_COMMUNITY_SPECTATED, CommunityArgs(community: updatedCommunity, fromUserAction: true, isPendingOwnershipRequest: (ownerTokenNotification != nil)))
for k, chat in updatedCommunity.chats:
var fullChatId = chat.id
if not chat.id.startsWith(communityId):
@ -1077,6 +1062,9 @@ QtObject:
# TODO find a way to populate missing infos like the color
self.chatService.updateOrAddChat(chatDto)
self.messageService.asyncLoadInitialMessagesForChat(fullChatId)
self.events.emit(SIGNAL_COMMUNITIES_UPDATE, CommunitiesArgs(communities: @[updatedCommunity]))
self.events.emit(SIGNAL_COMMUNITY_SPECTATED, CommunityArgs(community: updatedCommunity, fromUserAction: true, isPendingOwnershipRequest: (ownerTokenNotification != nil)))
except Exception as e:
error "Error joining the community", msg = e.msg
result = fmt"Error joining the community: {e.msg}"
@ -1225,8 +1213,6 @@ QtObject:
community.settings = communitySettings
# add this to the communities list and communitiesSettings
self.communities[community.id] = community
# add new community channel group and chats to chat service
self.chatService.updateOrAddChannelGroup(community.toChannelGroupDto())
for chat in community.chats:
self.chatService.updateOrAddChat(chat)
@ -2495,3 +2481,18 @@ QtObject:
self.events.emit(SIGNAL_COMMUNITIES_UPDATE, CommunitiesArgs(communities: @[community]))
except Exception as e:
error "error promoting self to control node", msg = e.msg
proc categoryHasUnreadMessages*(self: Service, communityId: string, categoryId: string): bool =
if communityId == "" or categoryId == "":
return false
if not self.communities.contains(communityId):
warn "unknown community", communityId
return false
for chat in self.communities[communityId].chats:
if chat.categoryId != categoryId:
continue
if (not chat.muted and chat.unviewedMessagesCount > 0) or chat.unviewedMentionsCount > 0:
return true
return false

View File

@ -35,13 +35,9 @@ proc saveChat*(
}
])
proc getChannelGroups*(): RpcResponse[JsonNode] =
proc getActiveChats*(): RpcResponse[JsonNode] =
let payload = %* []
result = callPrivateRPC("chat_getChannelGroups", payload)
proc getChannelGroupById*(channelGroupId: string): RpcResponse[JsonNode] =
let payload = %* [channelGroupId]
result = callPrivateRPC("chat_getChannelGroupByID", payload)
result = callPrivateRPC("activeChats".prefix, payload)
proc createOneToOneChat*(chatId: string, ensName: string = ""): RpcResponse[JsonNode] =
let communityId = ""
@ -146,9 +142,6 @@ proc createGroupChatFromInvitation*(groupName: string, chatId: string, adminPK:
let payload = %* [groupName, chatId, adminPK]
result = callPrivateRPC("createGroupChatFromInvitation".prefix, payload)
proc getMembers*(communityId, chatId: string): RpcResponse[JsonNode] =
result = callPrivateRPC("chat_getMembers", %* [communityId, chatId])
proc editChat*(communityID: string, chatID: string, name: string, color: string, imageJson: string): RpcResponse[JsonNode] =
let croppedImage = newCroppedImage(imageJson)
let payload = %* [communityID, chatID, name, color, croppedImage]

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit dcc93dee965a39d9b4ee9dca79f546c497baa77e
Subproject commit 8f50b578d1378c1e43bfa9645910d5e690b8c98b