refactor(groups): Move groups to new architecture

Closes: #4223
This commit is contained in:
Boris Melnik 2021-12-08 15:31:28 +03:00 committed by Sale Djenic
parent f861be5526
commit 1cd83b4d17
19 changed files with 328 additions and 44 deletions

View File

@ -5,6 +5,8 @@ import io_interface
import ../../../../../../app_service/service/contacts/service as contact_service
import ../../../../../../app_service/service/community/service as community_service
import ../../../../../../app_service/service/message/service as message_service
import ../../../../../../app_service/service/chat/service as chat_service
import ../../../../../core/eventemitter
@ -64,6 +66,16 @@ method init*(self: Controller) =
self.events.on(SIGNAL_LOGGEDIN_USER_IMAGE_CHANGED) do(e: Args):
self.delegate.loggedInUserImageChanged()
self.events.on(SIGNAL_CHAT_MEMBERS_ADDED) do(e: Args):
var args = ChatMembersAddedArgs(e)
if (args.chatId == self.chatId):
self.delegate.onChatMembersAdded(args.ids)
self.events.on(SIGNAL_CHAT_MEMBER_REMOVED) do(e: Args):
var args = ChatMemberRemovedArgs(e)
if (args.chatId == self.chatId):
self.delegate.onChatMemberRemoved(args.id)
method getMembersPublicKeys*(self: Controller): seq[string] =
# in case of 1:1 chat, there is no a members list
if(not self.belongsToCommunity):

View File

@ -151,4 +151,11 @@ QtObject:
var item = self.items[ind]
item.onlineStatus = onlineStatus
self.removeItemWithIndex(ind)
self.addItem(item)
self.addItem(item)
proc removeItemById*(self: Model, id: string) =
let ind = self.findIndexForMessageId(id)
if(ind == -1):
return
self.removeItemWithIndex(ind)

View File

@ -87,4 +87,17 @@ method contactUpdated*(self: Module, publicKey: string) =
method loggedInUserImageChanged*(self: Module) =
self.view.model().setIcon(singletonInstance.userProfile.getPubKey(), singletonInstance.userProfile.getIcon(),
singletonInstance.userProfile.getIsIdenticon())
singletonInstance.userProfile.getIsIdenticon())
method onChatMembersAdded*(self: Module, ids: seq[string]) =
for id in ids:
if(self.view.model().isContactWithIdAdded(id)):
continue
let (name, image, isIdenticon) = self.controller.getContactNameAndImage(id)
let statusUpdateDto = self.controller.getStatusForContact(id)
let status = statusUpdateDto.statusType.int.OnlineStatus
self.view.model().addItem(initItem(id, name, status, image, isidenticon))
method onChatMemberRemoved*(self: Module, id: string) =
self.view.model().removeItemById(id)

View File

@ -14,4 +14,10 @@ method contactUpdated*(self: AccessInterface, publicKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method loggedInUserImageChanged*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatMembersAdded*(self: AccessInterface, ids: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatMemberRemoved*(self: AccessInterface, ids: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -130,6 +130,10 @@ method init*(self: Controller) =
var args = ContactArgs(e)
self.delegate.onContactDetailsUpdated(args.contactId)
self.events.on(SIGNAL_CHAT_RENAMED) do(e: Args):
var args = ChatRenameArgs(e)
self.delegate.onChatRenamed(args.id, args.newName)
method getMySectionId*(self: Controller): string =
return self.sectionId
@ -233,3 +237,30 @@ method rejectContactRequest*(self: Controller, publicKey: string) =
method blockContact*(self: Controller, publicKey: string) =
self.contactService.blockContact(publicKey)
method addGroupMembers*(self: Controller, chatId: string, pubKeys: seq[string]) =
self.chatService.addGroupMembers(chatId, pubKeys)
method removeMemberFromGroupChat*(self: Controller, chatId: string, pubKey: string) =
self.chatService.removeMemberFromGroupChat(chatId, pubKey)
method renameGroupChat*(self: Controller, chatId: string, newName: string) =
self.chatService.renameGroupChat(chatId, newName)
method makeAdmin*(self: Controller, chatId: string, pubKey: string) =
self.chatService.makeAdmin(chatId, pubKey)
method createGroupChat*(self: Controller, groupName: string, pubKeys: seq[string]) =
let response = self.chatService.createGroupChat(groupName, pubKeys)
if(response.success):
self.delegate.addNewChat(response.chatDto, false, self.events, self.settingsService, self.contactService, self.chatService,
self.communityService, self.messageService, self.gifService)
method joinGroup*(self: Controller) =
self.chatService.confirmJoiningGroup(self.getActiveChatId())
method joinGroupChatFromInvitation*(self: Controller, groupName: string, chatId: string, adminPK: string) =
let response = self.chatService.createGroupChatFromInvitation(groupName, chatId, adminPK)
if(response.success):
self.delegate.addNewChat(response.chatDto, false, self.events, self.settingsService, self.contactService, self.chatService,
self.communityService, self.messageService, self.gifService)

View File

@ -94,3 +94,24 @@ method rejectContactRequest*(self: AccessInterface, publicKey: string): void {.b
method blockContact*(self: AccessInterface, publicKey: string): void {.base.} =
raise newException(ValueError, "No implementation available")
method addGroupMembers*(self: AccessInterface, chatId: string, pubKeys: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available")
method removeMemberFromGroupChat*(self: AccessInterface, chatId: string, pubKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method renameGroupChat*(self: AccessInterface, chatId: string, newName: string) {.base.} =
raise newException(ValueError, "No implementation available")
method makeAdmin*(self: AccessInterface, chatId: string, pubKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method createGroupChat*(self: AccessInterface, groupName: string, pubKeys: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available")
method joinGroup*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method joinGroupChatFromInvitation*(self: AccessInterface, groupName: string, chatId: string, adminPK: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -219,6 +219,14 @@ QtObject:
self.dataChanged(index, index, @[ModelRole.Name.int, ModelRole.Icon.int, ModelRole.IsIdenticon.int])
return
proc renameItem*(self: Model, id: string, name: string) =
for i in 0 ..< self.items.len:
if(self.items[i].id == id):
self.items[i].BaseItem.name = name
let index = self.createIndex(i, 0, nil)
self.dataChanged(index, index, @[ModelRole.Name.int])
return
proc updateNotificationsForItemOrSubItemById*(self: Model, id: string, hasUnreadMessages: bool,
notificationsCount: int) =
for i in 0 ..< self.items.len:

View File

@ -1,4 +1,4 @@
import NimQml, Tables, chronicles
import NimQml, Tables, chronicles, json, sequtils
import io_interface
import ../io_interface as delegate_interface
import view, controller, item, sub_item, model, sub_model
@ -216,6 +216,20 @@ proc initContactRequestsModel(self: Module) =
self.view.contactRequestsModel().addItems(contactsWhoAddedMe)
method initListOfMyContacts*(self: Module) =
var myContacts: seq[contacts_item.Item]
let contacts = self.controller.getContacts()
for c in contacts:
if(c.isContact() and not c.isBlocked()):
let item = self.createItemFromPublicKey(c.id)
myContacts.add(item)
self.view.listOfMyContacts().addItems(myContacts)
method clearListOfMyContacts*(self: Module) =
self.view.listOfMyContacts().clear()
method load*(self: Module, events: EventEmitter,
settingsService: settings_service.ServiceInterface,
contactService: contact_service.Service,
@ -462,3 +476,30 @@ method onNewMessagesReceived*(self: Module, chatId: string, unviewedMessagesCoun
self.controller.markAllMessagesRead(chatId)
else:
self.updateNotifications(chatId, unviewedMessagesCount, unviewedMentionsCount)
proc convertPubKeysToJson(self: Module, pubKeys: string): seq[string] =
return map(parseJson(pubKeys).getElems(), proc(x:JsonNode):string = x.getStr)
method addGroupMembers*(self: Module, chatId: string, pubKeys: string) =
self.controller.addGroupMembers(chatId, self.convertPubKeysToJson(pubKeys))
method removeMemberFromGroupChat*(self: Module, chatId: string, pubKey: string) =
self.controller.removeMemberFromGroupChat(chatId, pubKey)
method renameGroupChat*(self: Module, chatId: string, newName: string) =
self.controller.renameGroupChat(chatId, newName)
method makeAdmin*(self: Module, chatId: string, pubKey: string) =
self.controller.makeAdmin(chatId, pubKey)
method createGroupChat*(self: Module, groupName: string, pubKeys: string) =
self.controller.createGroupChat(groupName, self.convertPubKeysToJson(pubKeys))
method joinGroup*(self: Module) =
self.controller.joinGroup()
method joinGroupChatFromInvitation*(self: Module, groupName: string, chatId: string, adminPK: string) =
self.controller.joinGroupChatFromInvitation(groupName, chatId, adminPK)
method onChatRenamed*(self: Module, chatId: string, newName: string) =
self.view.chatsModel().renameItem(chatId, newName)

View File

@ -34,3 +34,6 @@ method onContactDetailsUpdated*(self: AccessInterface, contactId: string) {.base
method onCommunityChannelDeleted*(self: AccessInterface, chatId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatRenamed*(self: AccessInterface, chatId: string, newName: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -55,4 +55,31 @@ method rejectAllContactRequests*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method blockContact*(self: AccessInterface, publicKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
raise newException(ValueError, "No implementation available")
method addGroupMembers*(self: AccessInterface, chatId: string, pubKeys: string) {.base.} =
raise newException(ValueError, "No implementation available")
method removeMemberFromGroupChat*(self: AccessInterface, chatId: string, pubKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method renameGroupChat*(self: AccessInterface, chatId: string, newName: string) {.base.} =
raise newException(ValueError, "No implementation available")
method makeAdmin*(self: AccessInterface, chatId: string, pubKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method createGroupChat*(self: AccessInterface, groupName: string, pubKeys: string) {.base.} =
raise newException(ValueError, "No implementation available")
method joinGroup*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method joinGroupChatFromInvitation*(self: AccessInterface, groupName: string, chatId: string, adminPK: string) {.base.} =
raise newException(ValueError, "No implementation available")
method initListOfMyContacts*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method clearListOfMyContacts*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -15,6 +15,8 @@ QtObject:
tmpChatId: string # shouldn't be used anywhere except in prepareChatContentModuleForChatId/getChatContentModule procs
contactRequestsModel: contacts_model.Model
contactRequestsModelVariant: QVariant
listOfMyContacts: contacts_model.Model
listOfMyContactsVariant: QVariant
proc delete*(self: View) =
self.model.delete
@ -23,6 +25,8 @@ QtObject:
self.activeItemVariant.delete
self.contactRequestsModel.delete
self.contactRequestsModelVariant.delete
self.listOfMyContacts.delete
self.listOfMyContactsVariant.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
@ -34,7 +38,9 @@ QtObject:
result.activeItem = newActiveItem()
result.activeItemVariant = newQVariant(result.activeItem)
result.contactRequestsModel = contacts_model.newModel()
result.contactRequestsModelVariant = newQVariant(result.contactRequestsModel)
result.contactRequestsModelVariant = newQVariant(result.contactRequestsModel)
result.listOfMyContacts = contacts_model.newModel()
result.listOfMyContactsVariant = newQVariant(result.listOfMyContacts)
proc load*(self: View) =
self.delegate.viewDidLoad()
@ -58,6 +64,25 @@ QtObject:
QtProperty[QVariant] contactRequestsModel:
read = getContactRequestsModel
proc listOfMyContactsChanged*(self: View) {.signal.}
proc populateMyContacts*(self: View) {.slot.} =
self.delegate.initListOfMyContacts()
self.listOfMyContactsChanged()
proc clearMyContacts*(self: View) {.slot.} =
self.delegate.clearListOfMyContacts()
self.listOfMyContactsChanged()
proc listOfMyContacts*(self: View): contacts_model.Model =
return self.listOfMyContacts
proc getListOfMyContacts(self: View): QVariant {.slot.} =
return self.listOfMyContactsVariant
QtProperty[QVariant] listOfMyContacts:
read = getListOfMyContacts
notify = listOfMyContactsChanged
proc activeItemChanged*(self:View) {.signal.}
proc getActiveItem(self: View): QVariant {.slot.} =
@ -134,3 +159,24 @@ QtObject:
proc removeChat*(self: View, chatId: string) {.slot} =
self.delegate.removeChat(chatId)
proc addGroupMembers*(self: View, chatId: string, pubKeys: string) {.slot.} =
self.delegate.addGroupMembers(chatId, pubKeys)
proc removeMemberFromGroupChat*(self: View, chatId: string, pubKey: string) {.slot.} =
self.delegate.removeMemberFromGroupChat(chatId, pubKey)
proc renameGroupChat*(self: View, chatId: string, newName: string) {.slot.} =
self.delegate.renameGroupChat(chatId, newName)
proc makeAdmin*(self: View, chatId: string, pubKey: string) {.slot.} =
self.delegate.makeAdmin(chatId, pubKey)
proc createGroupChat*(self: View, groupName: string, pubKeys: string) {.slot.} =
self.delegate.createGroupChat(groupName, pubKeys)
proc joinGroup*(self: View) {.slot.} =
self.delegate.joinGroup()
proc joinGroupChatFromInvitation*(self: View, groupName: string, chatId: string, adminPK: string) {.slot.} =
self.delegate.joinGroupChatFromInvitation(groupName, chatId, adminPK)

View File

@ -148,4 +148,9 @@ QtObject:
proc getPublicKeys*(self: Model): seq[string] =
for i in self.items:
result.add(i.pubKey)
result.add(i.pubKey)
proc clear*(self: Model) =
self.beginResetModel()
self.items = @[]
self.endResetModel()

View File

@ -45,6 +45,19 @@ type
id*: string
channel*: string
ChatRenameArgs* = ref object of Args
id*: string
newName*: string
ChatMembersAddedArgs* = ref object of Args
chatId*: string
ids*: seq[string]
ChatMemberRemovedArgs* = ref object of Args
chatId*: string
id*: string
# Signals which may be emitted by this service:
const SIGNAL_CHAT_UPDATE* = "chatUpdate_new"
const SIGNAL_CHAT_LEFT* = "channelLeft_new"
@ -54,6 +67,9 @@ const SIGNAL_MESSAGE_DELETED* = "messageDeleted"
const SIGNAL_CHAT_MUTED* = "chatMuted"
const SIGNAL_CHAT_UNMUTED* = "chatUnmuted"
const SIGNAL_CHAT_HISTORY_CLEARED* = "chatHistoryCleared"
const SIGNAL_CHAT_RENAMED* = "chatRenamed"
const SIGNAL_CHAT_MEMBERS_ADDED* = "chatMemberAdded"
const SIGNAL_CHAT_MEMBER_REMOVED* = "chatMemberRemoved"
QtObject:
type Service* = ref object of QObject
@ -350,3 +366,59 @@ QtObject:
let errDesription = e.msg
error "error: ", errDesription
return
method addGroupMembers*(self: Service, chatId: string, pubKeys: seq[string]) =
try:
let response = status_chat.addGroupMembers(chatId, pubKeys)
if (response.error.isNil):
self.events.emit(SIGNAL_CHAT_MEMBERS_ADDED, ChatMembersAddedArgs(chatId: chatId, ids: pubKeys))
except Exception as e:
error "error while adding group members: ", msg = e.msg
method removeMemberFromGroupChat*(self: Service, chatId: string, pubKey: string) =
try:
let response = status_chat.removeMembersFromGroupChat(chatId, pubKey)
if (response.error.isNil):
self.events.emit(SIGNAL_CHAT_MEMBER_REMOVED, ChatMemberRemovedArgs(chatId: chatId, id: pubkey))
except Exception as e:
error "error while removing member from group: ", msg = e.msg
method renameGroupChat*(self: Service, chatId: string, newName: string) =
try:
let response = status_chat.renameGroupChat(chatId, newName)
if (response.error.isNil):
self.events.emit(SIGNAL_CHAT_RENAMED, ChatRenameArgs(id: chatId, newName: newName))
except Exception as e:
error "error while renaming group chat: ", msg = e.msg
method makeAdmin*(self: Service, chatId: string, pubKey: string) =
try:
let response = status_chat.makeAdmin(chatId, pubKey)
self.emitUpdate(response)
except Exception as e:
error "error while making user admin: ", msg = e.msg
method confirmJoiningGroup*(self: Service, chatId: string) =
try:
let response = status_chat.confirmJoiningGroup(chatId)
self.emitUpdate(response)
except Exception as e:
error "error while confirmation joining to group: ", msg = e.msg
method createGroupChatFromInvitation*(self: Service, groupName: string, chatId: string, adminPK: string): tuple[chatDto: ChatDto, success: bool] =
try:
let response = status_chat.createGroupChatFromInvitation(groupName, chatId, adminPK)
result = self.createChatFromResponse(response)
except Exception as e:
error "error while creating group from invitation: ", msg = e.msg
method createGroupChat*(self: Service, groupName: string, pubKeys: seq[string]): tuple[chatDto: ChatDto, success: bool] =
try:
let response = status_chat.createGroupChat(groupName, pubKeys)
result = self.createChatFromResponse(response)
except Exception as e:
error "error while creating group chat", msg = e.msg

View File

@ -147,7 +147,7 @@ StatusAppThreePanelLayout {
Component {
id: groupInfoPopupComponent
GroupInfoPopup {
// Not Refactored
chatSectionModule: root.rootStore.chatCommunitySectionModule
store: root.rootStore
pinnedMessagesPopupComponent: root.pinnedMessagesListPopupComponent
}

View File

@ -33,7 +33,7 @@ ScrollView {
if (selectMode) {
return !searchString || model.name.toLowerCase().includes(searchString)
}
return checkbox.checked || model.isUser
return checkbox.checked || model.isContact
}
components: [
StatusCheckBox {

View File

@ -18,6 +18,7 @@ import "../controls"
ModalPopup {
id: popup
property var chatSectionModule
property var store
property var pubKeys: []
property bool selectChatMembers: true
@ -32,26 +33,17 @@ ModalPopup {
memberCount = 1;
pubKeys = [];
popup.store.addToGroupContacts.clear();
chatSectionModule.populateMyContacts()
getContactListObject(popup.store.addToGroupContacts)
popup.store.addToGroupContacts.append({
//% "(You)"
name: userProfile.name + " " + qsTrId("(you)"),
pubKey: userProfile.pubKey,
address: "",
identicon: userProfile.icon,
thumbnailImage: userProfile.icon,
isUser: true
});
// noContactsRect.visible = !popup.store.allContacts.hasAddedContacts();
noContactsRect.visible = !chatSectionModule.listOfMyContacts.rowCount() > 0
contactList.visible = !noContactsRect.visible;
if (!contactList.visible) {
memberCount = 0;
}
}
onClosed: chatSectionModule.clearMyContacts()
function validate() {
if (groupName.text === "") {
//% "You need to enter a channel name"
@ -73,8 +65,8 @@ ModalPopup {
if (pubKeys.length === 0) {
return;
}
// Not Refactored Yet
// popup.store.chatsModelInst.groups.create(Utils.filterXSS(groupName.text), JSON.stringify(pubKeys));
popup.chatSectionModule.createGroupChat(Utils.filterXSS(groupName.text), JSON.stringify(pubKeys));
popup.close();
}
@ -137,7 +129,7 @@ ModalPopup {
ContactListPanel {
id: contactList
anchors.fill: parent
model: popup.store.addToGroupContacts
model: chatSectionModule.listOfMyContacts
searchString: searchBox.text.toLowerCase()
selectMode: selectChatMembers && memberCount < maxMembers
anchors.topMargin: 50

View File

@ -23,6 +23,7 @@ StatusModal {
ActiveChannel,
ContextChannel
}
property var chatSectionModule
property var store
property bool addMembers: false
property int currMemberCount: 1
@ -46,8 +47,7 @@ StatusModal {
function doAddMembers(){
if(pubKeys.length === 0) return;
if (popup.channel) {
// Not Refactored Yet
// chatsModel.groups.addMembers(popup.channel.id, JSON.stringify(pubKeys));
popup.chatSectionModule.addGroupMembers(popup.channel.id, JSON.stringify(pubKeys));
}
popup.close();
}
@ -83,7 +83,7 @@ StatusModal {
onOpened: {
addMembers = false;
if (popup.channel) {
popup.isAdmin = popup.channel.isAdmin(userProfile.pubKey)
popup.isAdmin = popup.chatSectionModule.activeItem.amIChatAdmin
}
btnSelectMembers.enabled = false;
resetSelectedMembers();
@ -246,8 +246,7 @@ StatusModal {
icon.height: 16
//% "Make Admin"
text: qsTrId("make-admin")
// Not Refactored Yet
// onTriggered: popup.store.chatsModelInst.groups.makeAdmin(popup.channel.id, model.publicKey)
onTriggered: popup.chatSectionModule.makeAdmin(popup.channel.id, model.publicKey)
}
StatusMenuItem {
icon.name: "remove-contact"
@ -256,8 +255,7 @@ StatusModal {
type: StatusMenuItem.Type.Danger
//% "Remove From Group"
text: qsTrId("remove-from-group")
// Not Refactored Yet
// onTriggered: popup.store.chatsModelInst.groups.kickMember(popup.channel.id, model.publicKey)
onTriggered: popup.chatSectionModule.removeMemberFromGroupChat(popup.channel.id, model.publicKey)
}
}
}
@ -304,12 +302,11 @@ StatusModal {
RenameGroupPopup {
id: renameGroupPopup
// Not Refactored Yet
// activeChannelName: popup.store.chatsModelInst.channelView.activeChannel.name
// onDoRename: {
// popup.store.chatsModelInst.groups.rename(groupName)
// popup.header.title = groupName
// close()
// }
activeChannelName: popup.chatSectionModule.activeItem.name
onDoRename: {
popup.chatSectionModule.renameGroupChat(popup.chatSectionModule.activeItem.id, groupName)
popup.header.title = groupName
close()
}
}
}

View File

@ -108,11 +108,10 @@ ColumnLayout {
chatInfoButton.onClicked: {
switch (chatContentModule.chatDetails.type) {
case Constants.chatType.privateGroupChat:
// Not Refactored Yet
// openPopup(groupInfoPopupComponent, {
// channelType: GroupInfoPopup.ChannelType.ActiveChannel,
// channel: chatContentRoot.rootStore.chatsModelInst.channelView.activeChannel
// })
Global.openPopup(groupInfoPopupComponent, {
channelType: GroupInfoPopup.ChannelType.ActiveChannel,
channel: chatContentModule.chatDetails
})
break;
case Constants.chatType.oneToOne:
Global.openProfilePopup(chatContentModule.chatDetails.id)
@ -214,7 +213,10 @@ ColumnLayout {
}
onDisplayGroupInfoPopup: {
// Not Refactored Yet
Global.openPopup(groupInfoPopupComponent, {
channelType: GroupInfoPopup.ChannelType.ActiveChannel,
channel: chatContentModule.chatDetails
})
}
onEditCommunityChannel: {

View File

@ -339,6 +339,7 @@ Item {
Component {
id: groupChatPopupComponent
GroupChatPopup {
chatSectionModule: root.chatSectionModule
store: root.store
onClosed: {
destroy()