refactor(chat-section): new chat/community model applied on the qml side

Changes done on the backend side related to the new chat/channel/categories model
are applied here. Necessary changes done on the `statusq` may be seen in PR-486.

Parts of the code which are not refactored yet are commented out.

Displayed chats/categories/channels since now are using refactored backend.
This commit is contained in:
Sale Djenic 2021-12-01 17:47:57 +01:00
parent c8b429388f
commit 80fcb95245
20 changed files with 179 additions and 95 deletions

View File

@ -4,8 +4,8 @@ import ../io_interface as delegate_interface
import view, controller
import ../../../../../global/global_singleton
import ../../../../../../app_service/service/chat/service as chat_service
import ../../../../../../app_service/service/community/service as community_service
import ../../../../../../app_service/service/chat/service_interface as chat_service
import ../../../../../../app_service/service/community/service_interface as community_service
export io_interface
@ -18,7 +18,7 @@ type
moduleLoaded: bool
proc newModule*(delegate: delegate_interface.AccessInterface, chatId: string, belongsToCommunity: bool,
chatService: chat_service.Service, communityService: community_service.Service):
chatService: chat_service.ServiceInterface, communityService: community_service.ServiceInterface):
Module =
result = Module()
result.delegate = delegate

View File

@ -6,8 +6,8 @@ import ../../../../shared_models/message_model
import ../../../../shared_models/message_item
import ../../../../../global/global_singleton
import ../../../../../../app_service/service/chat/service as chat_service
import ../../../../../../app_service/service/community/service as community_service
import ../../../../../../app_service/service/chat/service_interface as chat_service
import ../../../../../../app_service/service/community/service_interface as community_service
import ../../../../../../app_service/service/message/service as message_service
import eventemitter
@ -23,7 +23,7 @@ type
moduleLoaded: bool
proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, chatId: string,
belongsToCommunity: bool, chatService: chat_service.Service, communityService: community_service.Service,
belongsToCommunity: bool, chatService: chat_service.ServiceInterface, communityService: community_service.ServiceInterface,
messageService: message_service.Service):
Module =
result = Module()

View File

@ -33,7 +33,7 @@ type
moduleLoaded: bool
proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, chatId: string, belongsToCommunity: bool,
chatService: chat_service.Service, communityService: community_service.Service,
chatService: chat_service.ServiceInterface, communityService: community_service.ServiceInterface,
messageService: message_service.Service):
Module =
result = Module()

View File

@ -1,7 +1,7 @@
import controller_interface
import io_interface
import ../../../../../../app_service/service/community/service as community_service
import ../../../../../../app_service/service/community/service_interface as community_service
export controller_interface

View File

@ -4,8 +4,8 @@ import ../io_interface as delegate_interface
import view, controller
import ../../../../../global/global_singleton
import ../../../../../../app_service/service/chat/service as chat_service
import ../../../../../../app_service/service/community/service as community_service
import ../../../../../../app_service/service/chat/service_interface as chat_service
import ../../../../../../app_service/service/community/service_interface as community_service
export io_interface
@ -18,7 +18,7 @@ type
moduleLoaded: bool
proc newModule*(delegate: delegate_interface.AccessInterface, chatId: string, belongsToCommunity: bool,
chatService: chat_service.Service, communityService: community_service.Service):
chatService: chat_service.ServiceInterface, communityService: community_service.ServiceInterface):
Module =
result = Module()
result.delegate = delegate

View File

@ -3,31 +3,35 @@ import Tables
import controller_interface
import io_interface
import ../../../../app_service/service/chat/service as chat_service
import ../../../../app_service/service/community/service as community_service
import ../../../../app_service/service/chat/service_interface as chat_service
import ../../../../app_service/service/community/service_interface as community_service
import ../../../../app_service/service/message/service as message_service
import eventemitter
export controller_interface
type
Controller* = ref object of controller_interface.AccessInterface
delegate: io_interface.AccessInterface
sectionId: string
isCommunityModule: bool
isCommunitySection: bool
activeItemId: string
activeSubItemId: string
events: EventEmitter
chatService: chat_service.ServiceInterface
communityService: community_service.ServiceInterface
messageService: message_service.Service
proc newController*(delegate: io_interface.AccessInterface, sectionId: string, isCommunity: bool,
proc newController*(delegate: io_interface.AccessInterface, sectionId: string, isCommunity: bool, events: EventEmitter,
chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface,
messageService: message_service.Service): Controller =
result = Controller()
result.delegate = delegate
result.sectionId = sectionId
result.isCommunityModule = isCommunity
result.isCommunitySection = isCommunity
result.events = events
result.chatService = chatService
result.communityService = communityService
result.messageService = messageService
@ -48,7 +52,7 @@ method getActiveChatId*(self: Controller): string =
return self.activeItemId
method isCommunity*(self: Controller): bool =
return self.isCommunityModule
return self.isCommunitySection
method getCommunityIds*(self: Controller): seq[string] =
return self.communityService.getCommunityIds()
@ -78,4 +82,10 @@ method setActiveItemSubItem*(self: Controller, itemId: string, subItemId: string
method getOneToOneChatNameAndImage*(self: Controller, chatId: string):
tuple[name: string, image: string, isIdenticon: bool] =
return self.chatService.getOneToOneChatNameAndImage(chatId)
return self.chatService.getOneToOneChatNameAndImage(chatId)
method createPublicChat*(self: Controller, chatId: string) =
let response = self.chatService.createPublicChat(chatId)
if(response.success):
self.delegate.addNewPublicChat(response.chatDto, self.events, self.chatService, self.communityService,
self.messageService)

View File

@ -1,5 +1,5 @@
import ../../../../app_service/service/chat/service_interface as chat_service
import ../../../../app_service/service/community/service_interface as community_service
import ../../../../app_service/service/chat/dto/[chat]
import ../../../../app_service/service/community/dto/[community]
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -40,4 +40,7 @@ method setActiveItemSubItem*(self: AccessInterface, itemId: string, subItemId: s
method getOneToOneChatNameAndImage*(self: AccessInterface, chatId: string):
tuple[name: string, image: string, isIdenticon: bool] {.base.} =
raise newException(ValueError, "No implementation available")
method createPublicChat*(self: AccessInterface, chatId: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -5,8 +5,8 @@ import view, controller, item, sub_item, model, sub_model
import chat_content/module as chat_content_module
import ../../../../app_service/service/chat/service as chat_service
import ../../../../app_service/service/community/service as community_service
import ../../../../app_service/service/chat/service_interface as chat_service
import ../../../../app_service/service/community/service_interface as community_service
import ../../../../app_service/service/message/service as message_service
import eventemitter
@ -31,15 +31,15 @@ proc newModule*(
events: EventEmitter,
sectionId: string,
isCommunity: bool,
chatService: chat_service.Service,
communityService: community_service.Service,
chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface,
messageService: message_service.Service
): Module =
result = Module()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, sectionId, isCommunity, chatService, communityService,
result.controller = controller.newController(result, sectionId, isCommunity, events, chatService, communityService,
messageService)
result.moduleLoaded = false
@ -57,13 +57,13 @@ method isCommunity*(self: Module): bool =
return self.controller.isCommunity()
proc addSubmodule(self: Module, chatId: string, belongToCommunity: bool, events: EventEmitter,
chatService: chat_service.Service, communityService: community_service.Service,
chatService: chat_service.ServiceInterface, communityService: community_service.ServiceInterface,
messageService: message_service.Service) =
self.chatContentModule[chatId] = chat_content_module.newModule(self, events, chatId, belongToCommunity, chatService,
communityService, messageService)
proc buildChatUI(self: Module, events: EventEmitter, chatService: chat_service.Service,
communityService: community_service.Service, messageService: message_service.Service) =
proc buildChatUI(self: Module, events: EventEmitter, chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface, messageService: message_service.Service) =
let types = @[ChatType.OneToOne, ChatType.Public, ChatType.PrivateGroupChat]
let chats = self.controller.getChatDetailsForChatTypes(types)
@ -88,8 +88,8 @@ proc buildChatUI(self: Module, events: EventEmitter, chatService: chat_service.S
self.setActiveItemSubItem(selectedItemId, "")
proc buildCommunityUI(self: Module, events: EventEmitter, chatService: chat_service.Service,
communityService: community_service.Service, messageService: message_service.Service) =
proc buildCommunityUI(self: Module, events: EventEmitter, chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface, messageService: message_service.Service) =
var selectedItemId = ""
var selectedSubItemId = ""
let communityIds = self.controller.getCommunityIds()
@ -148,8 +148,8 @@ proc buildCommunityUI(self: Module, events: EventEmitter, chatService: chat_serv
self.setActiveItemSubItem(selectedItemId, selectedSubItemId)
method load*(self: Module, events: EventEmitter, chatService: chat_service.Service,
communityService: community_service.Service, messageService: message_service.Service) =
method load*(self: Module, events: EventEmitter, chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface, messageService: message_service.Service) =
self.controller.init()
self.view.load()
@ -218,3 +218,26 @@ method onActiveSectionChange*(self: Module, sectionId: string) =
return
self.delegate.onActiveChatChange(self.controller.getMySectionId(), self.controller.getActiveChatId())
method createPublicChat*(self: Module, chatId: string) =
if(self.controller.isCommunity()):
debug "creating public chat is not allowed for community, most likely it's an error in qml"
return
if(self.chatContentModule.hasKey(chatId)):
error "error: public chat is already added, ", chatId
return
self.controller.createPublicChat(chatId)
method addNewPublicChat*(self: Module, chatDto: ChatDto, events: EventEmitter, chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface, messageService: message_service.Service) =
let hasNotification = chatDto.unviewedMessagesCount > 0 or chatDto.unviewedMentionsCount > 0
let notificationsCount = chatDto.unviewedMentionsCount
let item = initItem(chatDto.id, chatDto.name, chatDto.identicon, true, chatDto.color, chatDto.description,
chatDto.chatType.int, hasNotification, notificationsCount, chatDto.muted, false, 0)
self.view.appendItem(item)
self.addSubmodule(chatDto.id, false, events, chatService, communityService, messageService)
# make new added chat active one
self.setActiveItemSubItem(item.id, "")

View File

@ -1,7 +1,7 @@
import NimQml
import ../../../../../app_service/service/chat/service as chat_service
import ../../../../../app_service/service/community/service as community_service
import ../../../../../app_service/service/chat/service_interface as chat_service
import ../../../../../app_service/service/community/service_interface as community_service
import ../../../../../app_service/service/message/service as message_service
import eventemitter
@ -9,8 +9,8 @@ import eventemitter
method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface, events: EventEmitter, chatService: chat_service.Service,
communityService: community_service.Service, messageService: message_service.Service) {.base.} =
method load*(self: AccessInterface, events: EventEmitter, chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface, messageService: message_service.Service) {.base.} =
raise newException(ValueError, "No implementation available")
method isLoaded*(self: AccessInterface): bool {.base.} =

View File

@ -1,2 +1,7 @@
method activeItemSubItemSet*(self: AccessInterface, itemId: string, subItemId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method addNewPublicChat*(self: AccessInterface, chatDto: ChatDto, events: EventEmitter,
chatService: chat_service.ServiceInterface, communityService: community_service.ServiceInterface,
messageService: message_service.Service) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -10,4 +10,7 @@ method getChatContentModule*(self: AccessInterface, chatId: string): QVariant {.
raise newException(ValueError, "No implementation available")
method isCommunity*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method createPublicChat*(self: AccessInterface, chatId: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -81,4 +81,7 @@ QtObject:
if(chatContentVariant.isNil):
return newQVariant()
return chatContentVariant
return chatContentVariant
proc createPublicChat*(self: View, chatId: string) {.slot.} =
self.delegate.createPublicChat(chatId)

View File

@ -23,8 +23,8 @@ type ChatDto* = object
chatType*: ChatType
timestamp*: int64 # indicates the last time this chat has received/sent a message
lastClockValue*: int64 # indicates the last clock value to be used when sending messages
deletedAtClockValue*: int64 # indicates the clock value at time of deletion,
# messages with lower clock value of this should be discarded
deletedAtClockValue*: int64 # indicates the clock value at time of deletion, messages with lower clock value of this should be discarded
readMessagesAtClockValue*: int64
unviewedMessagesCount*: int
unviewedMentionsCount*: int
#lastMessage*: Message ???? It's a question why do we need it here within this context ????
@ -51,6 +51,7 @@ proc `$`*(self: ChatDto): string =
timestamp: {self.timestamp},
lastClockValue: {self.lastClockValue},
deletedAtClockValue: {self.deletedAtClockValue},
readMessagesAtClockValue: {self.readMessagesAtClockValue},
unviewedMessagesCount: {self.unviewedMessagesCount},
unviewedMentionsCount: {self.unviewedMentionsCount},
alias: {self.alias},
@ -81,6 +82,7 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto =
discard jsonObj.getProp("timestamp", result.timestamp)
discard jsonObj.getProp("lastClockValue", result.lastClockValue)
discard jsonObj.getProp("deletedAtClockValue", result.deletedAtClockValue)
discard jsonObj.getProp("ReadMessagesAtClockValue", result.readMessagesAtClockValue)
discard jsonObj.getProp("unviewedMessagesCount", result.unviewedMessagesCount)
discard jsonObj.getProp("unviewedMentionsCount", result.unviewedMentionsCount)
discard jsonObj.getProp("alias", result.alias)

View File

@ -3,7 +3,9 @@ import Tables, json, sequtils, strformat, chronicles
import service_interface
import ./dto/chat as chat_dto
import ../contacts/service as contact_service
import status/statusgo_backend_new/chat as status_go
import status/statusgo_backend_new/chat as status_chat
# TODO: We need to remove these `status-lib` types from here
import status/types/[message]
import status/types/chat as chat_type
@ -12,6 +14,8 @@ export service_interface
logScope:
topics = "chat-service"
include ../../common/json_utils
type
Service* = ref object of service_interface.ServiceInterface
chats: Table[string, ChatDto] # [chat_id, ChatDto]
@ -27,7 +31,7 @@ proc newService*(contactService: contact_service.Service): Service =
method init*(self: Service) =
try:
let response = status_go.getChats()
let response = status_chat.getChats()
let chats = map(response.result.getElems(), proc(x: JsonNode): ChatDto = x.toChatDto())
@ -57,8 +61,32 @@ method getOneToOneChatNameAndImage*(self: Service, chatId: string):
tuple[name: string, image: string, isIdenticon: bool] =
return self.contactService.getContactNameAndImage(chatId)
method createPublicChat*(self: Service, chatId: string): tuple[chatDto: ChatDto, success: bool] =
try:
let response = status_chat.createPublicChat(chatId)
var jsonArr: JsonNode
if (not response.result.getProp("chats", jsonArr)):
error "error: response of creating public chat doesn't contain created chats for chat: ", chatId
result.success = false
return
let chats = map(jsonArr.getElems(), proc(x: JsonNode): ChatDto = x.toChatDto())
# created chat is returned as the first elemnt of json array (it's up to `status-go`)
if(chats.len == 0):
error "error: unknown error occured creating public chat ", chatId
result.success = false
return
result.chatDto = chats[0]
result.success = true
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
return
# TODO refactor this to new object types
proc parseChatResponse*(self: Service, response: string): (seq[Chat], seq[Message]) =
method parseChatResponse*(self: Service, response: string): (seq[Chat], seq[Message]) =
var parsedResponse = parseJson(response)
var chats: seq[Chat] = @[]
var messages: seq[Message] = @[]

View File

@ -1,4 +1,6 @@
import ./dto/chat as chat_dto
# TODO: We need to remove these `status-lib` types from here
import status/types/[message]
import status/types/chat as chat_type
@ -27,5 +29,8 @@ method getOneToOneChatNameAndImage*(self: ServiceInterface, chatId: string):
tuple[name: string, image: string, isIdenticon: bool] {.base.} =
raise newException(ValueError, "No implementation available")
method createPublicChat*(self: ServiceInterface, chatId: string): tuple[chatDto: ChatDto, success: bool] {.base.} =
raise newException(ValueError, "No implementation available")
method parseChatResponse*(self: ServiceInterface, response: string): (seq[Chat], seq[Message]) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -67,6 +67,7 @@ StatusAppThreePanelLayout {
centerPanel: ChatColumnView {
id: chatColumn
parentModule: chatCommunitySectionModule
rootStore: root.rootStore
//chatGroupsListViewCount: contactColumnLoader.item.chatGroupsListViewCount

View File

@ -24,6 +24,11 @@ import "../../Wallet"
Item {
id: root
anchors.fill: parent
// Important: we have parent module in this context only cause qml components
// don't follow struct from we have on the backend.
property var parentModule
property var rootStore
property alias pinnedMessagesPopupComponent: pinnedMessagesPopupComponent
// Not Refactored Yet
@ -119,25 +124,27 @@ Item {
reactionModel: root.rootStore.emojiReactionsModel
}
StatusImageModal {
id: imagePopup
onClicked: {
if (button === Qt.LeftButton) {
imagePopup.close()
}
else if(button === Qt.RightButton) {
contextmenu.imageSource = imagePopup.imageSource
contextmenu.hideEmojiPicker = true
contextmenu.isRightClickOnImage = true;
contextmenu.show()
}
}
}
StackLayout {
anchors.fill: parent
// Not Refactored Yet
// currentIndex: root.rootStore.chatsModelInst.channelView.activeChannelIndex > -1
// && chatGroupsListViewCount > 0 ? 0 : 1
currentIndex: parentModule.model.count === 0? 0 : 1
StatusImageModal {
id: imagePopup
onClicked: {
if (button === Qt.LeftButton) {
imagePopup.close()
}
else if(button === Qt.RightButton) {
contextmenu.imageSource = imagePopup.imageSource
contextmenu.hideEmojiPicker = true
contextmenu.isRightClickOnImage = true;
contextmenu.show()
}
}
EmptyChatPanel {
onShareChatKeyClicked: openProfilePopup(userProfile.name, userProfile.pubKey, userProfile.icon);
}
ColumnLayout {
@ -413,10 +420,7 @@ Item {
}
}
}
EmptyChatPanel {
onShareChatKeyClicked: openProfilePopup(userProfile.name, userProfile.pubKey, userProfile.icon);
}
}
Loader {
id: txModalLoader
@ -652,11 +656,4 @@ Item {
toastMessage.open()
}
}
}
}
/*##^##
Designer {
D{i:0;formeditorColor:"#ffffff";height:770;width:800}
}
##^##*/

View File

@ -60,12 +60,13 @@ Item {
if (!foundChannelObj)
{
root.store.chatsModelInst.channelView.joinPublicChat(channelName)
if(root.store.chatsModelInst.communities.activeCommunity.active)
{
root.store.chatsModelInst.channelView.joinPublicChat(channelName)
appMain.changeAppSectionBySectionType(Constants.appSection.chat)
}
// Not Refactored Yet
// root.store.chatsModelInst.channelView.joinPublicChat(channelName)
// if(root.store.chatsModelInst.communities.activeCommunity.active)
// {
// root.store.chatsModelInst.channelView.joinPublicChat(channelName)
// appMain.changeAppSectionBySectionType(Constants.appSection.chat)
// }
return
}
@ -73,11 +74,12 @@ Item {
if(obj.chatType === -1 || obj.chatType === Constants.chatTypePublic)
{
if(root.store.chatsModelInst.communities.activeCommunity.active) {
root.store.chatsModelInst.channelView.joinPublicChat(channelName)
appMain.changeAppSectionBySectionType(Constants.appSection.chat)
}
root.store.chatsModelInst.channelView.setActiveChannel(channelName);
// Not Refactored Yet
// if(root.store.chatsModelInst.communities.activeCommunity.active) {
// root.store.chatsModelInst.channelView.joinPublicChat(channelName)
// appMain.changeAppSectionBySectionType(Constants.appSection.chat)
// }
// root.store.chatsModelInst.channelView.setActiveChannel(channelName);
}
else if(obj.communityId === root.store.chatsModelInst.communities.activeCommunity.id &&
obj.chatType === Constants.chatTypeCommunity &&

View File

@ -275,7 +275,7 @@ Item {
width: parent.width
anchors.top: channelList.bottom
anchors.topMargin: Style.current.padding
onSuggestedMessageClicked: root.store.chatsModelInst.channelView.joinPublicChat(channel)
onSuggestedMessageClicked: chatSectionModule.createPublicChat(channel)
}
}
@ -283,10 +283,10 @@ Item {
id: publicChatPopupComponent
PublicChatPopup {
onJoinPublicChat: {
root.store.chatsModelInst.channelView.joinPublicChat(name);
chatSectionModule.createPublicChat(name)
}
onSuggestedMessageClicked: {
root.store.chatsModelInst.channelView.joinPublicChat(channel);
chatSectionModule.createPublicChat(channel)
}
onClosed: {

View File

@ -475,18 +475,20 @@ QtObject {
return result
}
// Public chat
// This needs to be the last check because it is as VERY loose check
index = link.lastIndexOf("/")
if (index > -1) {
const chatId = link.substring(index + 1)
//% "Join the %1 public channel"
result.title = qsTrId("join-the--1-public-channel").arg(chatId)
result.callback = function () {
chatsModel.channelView.joinPublicChat(chatId);
}
return result
}
// Not Refactored Yet (when we get to this we will most likely remove it, since other approach will be used)
// // Public chat
// // This needs to be the last check because it is as VERY loose check
// index = link.lastIndexOf("/")
// if (index > -1) {
// const chatId = link.substring(index + 1)
// //% "Join the %1 public channel"
// result.title = qsTrId("join-the--1-public-channel").arg(chatId)
// result.callback = function () {
// chatsModel.channelView.joinPublicChat(chatId);
// }
// return result
// }
return result
}