refactor(chat): refactor 1-1 chat to new architecture

Fixes #4225
This commit is contained in:
Jonathan Rainville 2021-12-09 11:25:38 -05:00 committed by Sale Djenic
parent f0b39ce4f6
commit a9c968b984
28 changed files with 549 additions and 61 deletions

View File

@ -181,7 +181,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.accountsService = accounts_service.newService(statusFoundation.fleetConfiguration)
result.networkService = network_service.newService()
result.contactsService = contacts_service.newService(statusFoundation.status.events, statusFoundation.threadpool)
result.chatService = chat_service.newService(result.contactsService)
result.chatService = chat_service.newService(statusFoundation.status.events, result.contactsService)
result.communityService = community_service.newService(result.chatService)
result.messageService = message_service.newService(statusFoundation.status.events, statusFoundation.threadpool)
result.tokenService = token_service.newService(statusFoundation.status.events, statusFoundation.threadpool,

View File

@ -2,6 +2,7 @@ import controller_interface
import io_interface
import ../../../../../../app_service/service/community/service as community_service
import ../../../../../../app_service/service/chat/service as chat_service
export controller_interface
@ -11,13 +12,20 @@ type
chatId: string
belongsToCommunity: bool
communityService: community_service.ServiceInterface
chatService: chat_service.ServiceInterface
proc newController*(delegate: io_interface.AccessInterface, chatId: string, belongsToCommunity: bool,
communityService: community_service.ServiceInterface): Controller =
proc newController*(
delegate: io_interface.AccessInterface,
chatId: string,
belongsToCommunity: bool,
chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface
): Controller =
result = Controller()
result.delegate = delegate
result.chatId = chatId
result.belongsToCommunity = belongsToCommunity
result.chatService = chatService
result.communityService = communityService
method delete*(self: Controller) =
@ -30,4 +38,25 @@ method getChatId*(self: Controller): string =
return self.chatId
method belongsToCommunity*(self: Controller): bool =
return self.belongsToCommunity
return self.belongsToCommunity
method sendImages*(self: Controller, imagePathsJson: string): string =
self.chatService.sendImages(self.chatId, imagePathsJson)
method requestAddressForTransaction*(self: Controller, chatId: string, fromAddress: string, amount: string, tokenAddress: string) =
self.chatService.requestAddressForTransaction(chatId, fromAddress, amount, tokenAddress)
method requestTransaction*(self: Controller, chatId: string, fromAddress: string, amount: string, tokenAddress: string) =
self.chatService.requestAddressForTransaction(chatId, fromAddress, amount, tokenAddress)
method declineRequestTransaction*(self: Controller, messageId: string) =
self.chatService.declineRequestTransaction(messageId)
method declineRequestAddressForTransaction*(self: Controller, messageId: string) =
self.chatService.declineRequestAddressForTransaction(messageId)
method acceptRequestAddressForTransaction*(self: Controller, messageId: string, address: string) =
self.chatService.acceptRequestAddressForTransaction(messageId, address)
method acceptRequestTransaction*(self: Controller, transactionHash: string, messageId: string, signature: string) =
self.chatService.acceptRequestTransaction(transactionHash, messageId, signature)

View File

@ -1,4 +1,3 @@
import ../../../../../../app_service/service/community/service_interface as community_service
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -16,4 +15,24 @@ method getChatId*(self: AccessInterface): string {.base.} =
method belongsToCommunity*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method sendImages*(self: AccessInterface, imagePathsJson: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method requestAddressForTransaction*(self: AccessInterface, chatId: string, fromAddress: string, amount: string, tokenAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")
method requestTransaction*(self: AccessInterface, chatId: string, fromAddress: string, amount: string, tokenAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")
method declineRequestTransaction*(self: AccessInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method declineRequestAddressForTransaction*(self: AccessInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method acceptRequestAddressForTransaction*(self: AccessInterface, messageId: string, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method acceptRequestTransaction*(self: AccessInterface, transactionHash: string, messageId: string, signature: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -17,14 +17,19 @@ type
controller: controller.AccessInterface
moduleLoaded: bool
proc newModule*(delegate: delegate_interface.AccessInterface, chatId: string, belongsToCommunity: bool,
chatService: chat_service.ServiceInterface, communityService: community_service.ServiceInterface):
proc newModule*(
delegate: delegate_interface.AccessInterface,
chatId: string,
belongsToCommunity: bool,
chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface
):
Module =
result = Module()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, chatId, belongsToCommunity, communityService)
result.controller = controller.newController(result, chatId, belongsToCommunity, chatService, communityService)
result.moduleLoaded = false
method delete*(self: Module) =
@ -44,4 +49,28 @@ method viewDidLoad*(self: Module) =
self.delegate.inputAreaDidLoad()
method getModuleAsVariant*(self: Module): QVariant =
return self.viewVariant
return self.viewVariant
method getChatId*(self: Module): string =
return self.controller.getChatId()
method sendImages*(self: Module, imagePathsJson: string): string =
self.controller.sendImages(imagePathsJson)
method requestAddressForTransaction*(self: Module, chatId: string, fromAddress: string, amount: string, tokenAddress: string) =
self.controller.requestAddressForTransaction(chatId, fromAddress, amount, tokenAddress)
method requestTransaction*(self: Module, chatId: string, fromAddress: string, amount: string, tokenAddress: string) =
self.controller.requestTransaction(chatId, fromAddress, amount, tokenAddress)
method declineRequestTransaction*(self: Module, messageId: string) =
self.controller.declineRequestTransaction(messageId)
method declineRequestAddressForTransaction*(self: Module, messageId: string) =
self.controller.declineRequestAddressForTransaction(messageId)
method acceptRequestAddressForTransaction*(self: Module, messageId: string, address: string) =
self.controller.acceptRequestAddressForTransaction(messageId, address)
method acceptRequestTransaction*(self: Module, transactionHash: string, messageId: string, signature: string) =
self.controller.acceptRequestTransaction(transactionHash, messageId, signature)

View File

@ -10,4 +10,25 @@ method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
raise newException(ValueError, "No implementation available")
method sendImages*(self: AccessInterface, imagePathsJson: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method requestAddressForTransaction*(self: AccessInterface, chatId: string, fromAddress: string, amount: string, tokenAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")
method requestTransaction*(self: AccessInterface, chatId: string, fromAddress: string, amount: string, tokenAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")
method declineRequestTransaction*(self: AccessInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method declineRequestAddressForTransaction*(self: AccessInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method acceptRequestAddressForTransaction*(self: AccessInterface, messageId: string, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method acceptRequestTransaction*(self: AccessInterface, transactionHash: string, messageId: string, signature: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -19,4 +19,26 @@ QtObject:
result.model = newModel()
proc load*(self: View) =
self.delegate.viewDidLoad()
self.delegate.viewDidLoad()
proc sendImages*(self: View, sendImages: string): string {.slot.} =
self.delegate.sendImages(sendImages)
proc acceptAddressRequest*(self: View, messageId: string , address: string) {.slot.} =
self.delegate.acceptRequestAddressForTransaction(messageId, address)
proc declineAddressRequest*(self: View, messageId: string) {.slot.} =
self.delegate.declineRequestAddressForTransaction(messageId)
proc requestAddress*(self: View, chatId: string, fromAddress: string, amount: string, tokenAddress: string) {.slot.} =
self.delegate.requestAddressForTransaction(chatId, fromAddress, amount, tokenAddress)
proc request*(self: View, chatId: string, fromAddress: string, amount: string, tokenAddress: string) {.slot.} =
self.delegate.requestTransaction(chatId, fromAddress, amount, tokenAddress)
proc declineRequest*(self: View, messageId: string) {.slot.} =
self.delegate.declineRequestTransaction(messageId)
proc acceptRequestTransaction*(self: View, transactionHash: string, messageId: string, signature: string) {.slot.} =
self.delegate.acceptRequestTransaction(transactionHash, messageId, signature)

View File

@ -82,6 +82,20 @@ method setActiveItemSubItem*(self: Controller, itemId: string, subItemId: string
self.delegate.activeItemSubItemSet(self.activeItemId, self.activeSubItemId)
method removeActiveFromThisChat*(self: Controller, itemId: string) =
if self.activeItemId != itemId:
return
let allChats = self.chatService.getAllChats()
self.activeSubItemId = ""
if allChats.len == 0:
self.activeItemId = ""
else:
self.activeItemId = allChats[0].id
self.delegate.activeItemSubItemSet(self.activeItemId, self.activeSubItemId)
method getOneToOneChatNameAndImage*(self: Controller, chatId: string):
tuple[name: string, image: string, isIdenticon: bool] =
return self.chatService.getOneToOneChatNameAndImage(chatId)
@ -89,5 +103,16 @@ method getOneToOneChatNameAndImage*(self: Controller, chatId: string):
method createPublicChat*(self: Controller, chatId: string) =
let response = self.chatService.createPublicChat(chatId)
if(response.success):
self.delegate.addNewPublicChat(response.chatDto, self.events, self.contactService, self.chatService,
self.communityService, self.messageService)
self.delegate.addNewChat(response.chatDto, self.events, self.contactService, self.chatService,
self.communityService, self.messageService)
method createOneToOneChat*(self: Controller, chatId: string, ensName: string) =
let response = self.chatService.createOneToOneChat(chatId, ensName)
if(response.success):
self.delegate.addNewChat(response.chatDto, self.events, self.contactService, self.chatService,
self.communityService, self.messageService)
method leaveChat*(self: Controller, chatId: string) =
let success = self.chatService.leaveChat(chatId)
if success:
self.delegate.removeChat(chatId)

View File

@ -37,10 +37,19 @@ method getChatDetailsForChatTypes*(self: AccessInterface, types: seq[ChatType]):
method setActiveItemSubItem*(self: AccessInterface, itemId: string, subItemId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method removeActiveFromThisChat*(self: AccessInterface, itemId: string) {.base.} =
raise newException(ValueError, "No implementation available")
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")
method createOneToOneChat*(self: AccessInterface, chatId: string, ensName: string) {.base.} =
raise newException(ValueError, "No implementation available")
method leaveChat*(self: AccessInterface, chatId: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -120,6 +120,28 @@ QtObject:
self.countChanged()
proc getItemIdxById*(self: Model, id: string): int =
var idx = 0
for it in self.items:
if(it.id == id):
return idx
idx.inc
return -1
proc removeItemById*(self: Model, id: string) =
let idx = self.getItemIdxById(id)
if idx == -1:
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginRemoveRows(parentModelIndex, idx, idx)
self.items.delete(idx)
self.endRemoveRows()
self.countChanged()
proc prependItem*(self: Model, item: Item) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete

View File

@ -64,6 +64,11 @@ proc addSubmodule(self: Module, chatId: string, belongToCommunity: bool, isUsers
self.chatContentModule[chatId] = chat_content_module.newModule(self, events, self.controller.getMySectionId(), chatId,
belongToCommunity, isUsersListAvailable, contactService, chatService, communityService, messageService)
proc removeSubmodule(self: Module, chatId: string) =
if(not self.chatContentModule.contains(chatId)):
return
self.chatContentModule.del(chatId)
proc buildChatUI(self: Module, events: EventEmitter, contactService: contact_service.Service,
chatService: chat_service.ServiceInterface, communityService: community_service.ServiceInterface,
messageService: message_service.Service) =
@ -232,12 +237,12 @@ method createPublicChat*(self: Module, chatId: string) =
return
if(self.chatContentModule.hasKey(chatId)):
error "error: public chat is already added, ", chatId
error "error: public chat is already added", chatId
return
self.controller.createPublicChat(chatId)
method addNewPublicChat*(self: Module, chatDto: ChatDto, events: EventEmitter, contactService: contact_service.Service,
method addNewChat*(self: Module, chatDto: ChatDto, events: EventEmitter, contactService: contact_service.Service,
chatService: chat_service.ServiceInterface, communityService: community_service.ServiceInterface,
messageService: message_service.Service) =
let hasNotification = chatDto.unviewedMessagesCount > 0 or chatDto.unviewedMentionsCount > 0
@ -248,4 +253,28 @@ method addNewPublicChat*(self: Module, chatDto: ChatDto, events: EventEmitter, c
self.addSubmodule(chatDto.id, false, true, events, contactService, chatService, communityService, messageService)
# make new added chat active one
self.setActiveItemSubItem(item.id, "")
self.setActiveItemSubItem(item.id, "")
method removeChat*(self: Module, chatId: string) =
if(not self.chatContentModule.contains(chatId)):
return
self.view.removeItem(chatId)
self.removeSubmodule(chatId)
# remove active state form the removed chat (if applicable)
self.controller.removeActiveFromThisChat(chatId)
method createOneToOneChat*(self: Module, chatId: string, ensName: string) =
if(self.controller.isCommunity()):
debug "creating an one to one chat is not allowed for community, most likely it's an error in qml"
return
if(self.chatContentModule.hasKey(chatId)):
error "error: one to one chat is already added", chatId
return
self.controller.createOneToOneChat(chatId, ensName)
method leaveChat*(self: Module, chatId: string) =
self.controller.leaveChat(chatId)

View File

@ -1,7 +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,
method addNewChat*(self: AccessInterface, chatDto: ChatDto, events: EventEmitter,
contactService: contact_service.Service, chatService: chat_service.ServiceInterface,
communityService: community_service.ServiceInterface, messageService: message_service.Service) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -13,4 +13,16 @@ 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")
method createOneToOneChat*(self: AccessInterface, chatId: string, ensName: string) {.base.} =
raise newException(ValueError, "No implementation available")
method leaveChat*(self: AccessInterface, chatId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method removeChat*(self: AccessInterface, chatId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method getActiveChatId*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -49,6 +49,9 @@ QtObject:
proc appendItem*(self: View, item: Item) =
self.model.appendItem(item)
proc removeItem*(self: View, id: string) =
self.model.removeItemById(id)
proc prependItem*(self: View, item: Item) =
self.model.prependItem(item)
@ -84,4 +87,10 @@ QtObject:
return chatContentVariant
proc createPublicChat*(self: View, chatId: string) {.slot.} =
self.delegate.createPublicChat(chatId)
self.delegate.createPublicChat(chatId)
proc createOneToOneChat*(self: View, chatId: string, ensName: string) {.slot.} =
self.delegate.createOneToOneChat(chatId, ensName)
proc leaveChat*(self: View, id: string) {.slot.} =
self.delegate.leaveChat(id)

View File

@ -1,9 +1,16 @@
import Tables, json, sequtils, strformat, chronicles
import NimQml, Tables, json, sequtils, strformat, chronicles, os
import service_interface
import eventemitter
import ./dto/chat as chat_dto
import ../message/dto/message as message_dto
import ../contacts/service as contact_service
import status/statusgo_backend_new/chat as status_chat
import status/statusgo_backend_new/chatCommands as status_chat_commands
import ../../../app/utils/image_utils
import ../../../constants
from ../../common/account_constants import ZERO_ADDRESS
# TODO: We need to remove these `status-lib` types from here
import status/types/[message]
@ -16,16 +23,54 @@ logScope:
include ../../common/json_utils
type
# TODO remove New when refactored
ChatUpdateArgsNew* = ref object of Args
chats*: seq[ChatDto]
messages*: seq[MessageDto]
# TODO refactor that part
# pinnedMessages*: seq[MessageDto]
# emojiReactions*: seq[Reaction]
# communities*: seq[Community]
# communityMembershipRequests*: seq[CommunityMembershipRequest]
# activityCenterNotifications*: seq[ActivityCenterNotification]
# statusUpdates*: seq[StatusUpdate]
# deletedMessages*: seq[RemovedMessage]
ChatIdArg* = ref object of Args
chatId*: string
MessageSendingSuccess* = ref object of Args
chat*: ChatDto
message*: MessageDto
MessageArgs* = ref object of Args
id*: string
channel*: string
# Events this service emits
# TODO remove new when refactor is done
const SIGNAL_CHAT_UPDATE* = "chatUpdate_new"
const SIGNAL_CHAT_LEFT* = "channelLeft_new"
const SIGNAL_SENDING_FAILED* = "messageSendingFailed_new"
const SIGNAL_SENDING_SUCCESS* = "messageSendingSuccess_new"
const SIGNAL_MESSAGE_DELETED* = "messageDeleted_new"
type
Service* = ref object of service_interface.ServiceInterface
chats: Table[string, ChatDto] # [chat_id, ChatDto]
contactService: contact_service.Service
events: EventEmitter
method delete*(self: Service) =
discard
proc newService*(contactService: contact_service.Service): Service =
proc newService*(
events: EventEmitter,
contactService: contact_service.Service
): Service =
result = Service()
result.events = events
result.contactService = contactService
result.chats = initTable[string, ChatDto]()
@ -47,6 +92,64 @@ method init*(self: Service) =
method getAllChats*(self: Service): seq[ChatDto] =
return toSeq(self.chats.values)
method hasChannel*(self: Service, chatId: string): bool =
self.chats.hasKey(chatId)
# TODO refactor this to new object types
method parseChatResponse*(self: Service, response: string): (seq[chat_type.Chat], seq[Message]) =
var parsedResponse = parseJson(response)
var chats: seq[Chat] = @[]
var messages: seq[Message] = @[]
if parsedResponse{"result"}{"messages"} != nil:
for jsonMsg in parsedResponse["result"]["messages"]:
messages.add(jsonMsg.toMessage())
if parsedResponse{"result"}{"chats"} != nil:
for jsonChat in parsedResponse["result"]["chats"]:
let chat = chat_type.toChat(jsonChat)
# TODO add the channel back to `chat` when it is refactored
# self.channels[chat.id] = chat
chats.add(chat)
result = (chats, messages)
# TODO refactor this to new object types
method parseChatResponse2*(self: Service, response: RpcResponse[JsonNode]): (seq[ChatDto], seq[MessageDto]) =
var chats: seq[ChatDto] = @[]
var messages: seq[MessageDto] = @[]
if response.result{"messages"} != nil:
for jsonMsg in response.result["messages"]:
messages.add(jsonMsg.toMessageDto)
if response.result{"chats"} != nil:
for jsonChat in response.result["chats"]:
let chat = chat_dto.toChatDto(jsonChat)
# TODO add the channel back to `chat` when it is refactored
self.chats[chat.id] = chat
chats.add(chat)
result = (chats, messages)
method processMessageUpdateAfterSend(self: Service, response: RpcResponse[JsonNode]): (seq[ChatDto], seq[MessageDto]) =
result = self.parseChatResponse2(response)
var (chats, messages) = result
if chats.len == 0 and messages.len == 0:
self.events.emit(SIGNAL_SENDING_FAILED, Args())
return
# This fixes issue#3490
var msg = messages[0]
for m in messages:
if(m.responseTo.len > 0):
msg = m
break
self.events.emit(SIGNAL_SENDING_SUCCESS, MessageSendingSuccess(message: msg, chat: chats[0]))
method processUpdateForTransaction*(self: Service, messageId: string, response: RpcResponse[JsonNode]) =
var (chats, messages) = self.processMessageUpdateAfterSend(response)
self.events.emit(SIGNAL_MESSAGE_DELETED, MessageArgs(id: messageId, channel: chats[0].id))
method emitUpdate(self: Service, response: RpcResponse[JsonNode]) =
var (chats, messages) = self.parseChatResponse2(response)
self.events.emit(SIGNAL_CHAT_UPDATE, ChatUpdateArgsNew(messages: messages, chats: chats))
method getChatsOfChatTypes*(self: Service, types: seq[chat_dto.ChatType]): seq[ChatDto] =
return self.getAllChats().filterIt(it.chatType in types)
@ -61,42 +164,132 @@ method getOneToOneChatNameAndImage*(self: Service, chatId: string):
tuple[name: string, image: string, isIdenticon: bool] =
return self.contactService.getContactNameAndImage(chatId)
method createChatFromResponse*(self: Service, response: RpcResponse[JsonNode]): tuple[chatDto: ChatDto, success: bool] =
var jsonArr: JsonNode
if (not response.result.getProp("chats", jsonArr)):
error "error: response of creating chat doesn't contain created chats"
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 chat"
result.success = false
return
result.chatDto = chats[0]
result.success = true
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
result = self.createChatFromResponse(response)
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
return
# TODO refactor this to new object types
method parseChatResponse*(self: Service, response: string): (seq[Chat], seq[Message]) =
var parsedResponse = parseJson(response)
var chats: seq[Chat] = @[]
var messages: seq[Message] = @[]
if parsedResponse{"result"}{"messages"} != nil:
for jsonMsg in parsedResponse["result"]["messages"]:
messages.add(jsonMsg.toMessage())
if parsedResponse{"result"}{"chats"} != nil:
for jsonChat in parsedResponse["result"]["chats"]:
let chat = jsonChat.toChat
# TODO add the channel back to `chat` when it is refactored
# self.channels[chat.id] = chat
chats.add(chat)
result = (chats, messages)
method createOneToOneChat*(self: Service, chatId: string, ensName: string): tuple[chatDto: ChatDto, success: bool] =
try:
if self.hasChannel(chatId):
# We want to show the chat to the user and for that we activate the chat
discard status_chat.saveChat(
chatId,
chat_dto.ChatType.OneToOne.int,
color=self.chats[chatId].color,
ensName=ensName)
result.success = true
result.chatDto = self.chats[chatId]
return
let response = status_chat.createOneToOneChat(chatId)
result = self.createChatFromResponse(response)
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
return
method leaveChat*(self: Service, chatId: string): bool =
try:
if self.chats.len == 0:
return false
if(not self.chats.contains(chatId)):
error "trying to leave chat for an unexisting chat id", chatId
return false
let chat = self.chats[chatId]
if chat.chatType == chat_dto.ChatType.PrivateGroupChat:
let leaveGroupResponse = status_chat.leaveGroupChat(chatId)
self.emitUpdate(leaveGroupResponse)
discard status_chat.deactivateChat(chatId)
self.chats.del(chatId)
discard status_chat.clearChatHistory(chatId)
self.events.emit(SIGNAL_CHAT_LEFT, ChatIdArg(chatId: chatId))
return true
except Exception as e:
error "Error deleting channel", chatId, msg = e.msg
return false
method sendImages*(self: Service, chatId: string, imagePathsJson: string): string =
result = ""
try:
var images = Json.decode(imagePathsJson, seq[string])
for imagePath in images.mitems:
var image = image_utils.formatImagePath(imagePath)
imagePath = image_resizer(image, 2000, TMPDIR)
discard status_chat.sendImages(chatId, images)
for imagePath in images.items:
removeFile(imagePath)
except Exception as e:
error "Error sending images", msg = e.msg
result = fmt"Error sending images: {e.msg}"
method requestAddressForTransaction*(self: Service, chatId: string, fromAddress: string, amount: string, tokenAddress: string) =
try:
let address = if (tokenAddress == ZERO_ADDRESS): "" else: tokenAddress
let response = status_chat_commands.requestAddressForTransaction(chatId, fromAddress, amount, address)
discard self.processMessageUpdateAfterSend(response)
except Exception as e:
error "Error requesting address for transaction", msg = e.msg
method requestTransaction*(self: Service, chatId: string, fromAddress: string, amount: string, tokenAddress: string) =
try:
let address = if (tokenAddress == ZERO_ADDRESS): "" else: tokenAddress
let response = status_chat_commands.requestTransaction(chatId, fromAddress, amount, address)
discard self.processMessageUpdateAfterSend(response)
except Exception as e:
error "Error requesting transaction", msg = e.msg
method declineRequestTransaction*(self: Service, messageId: string) =
try:
let response = status_chat_commands.declineRequestTransaction(messageId)
self.processUpdateForTransaction(messageId, response)
except Exception as e:
error "Error requesting transaction", msg = e.msg
method declineRequestAddressForTransaction*(self: Service, messageId: string) =
try:
let response = status_chat_commands.declineRequestAddressForTransaction(messageId)
self.processUpdateForTransaction(messageId, response)
except Exception as e:
error "Error requesting transaction", msg = e.msg
method acceptRequestAddressForTransaction*(self: Service, messageId: string, address: string) =
try:
let response = status_chat_commands.acceptRequestAddressForTransaction(messageId, address)
self.processUpdateForTransaction(messageId, response)
except Exception as e:
error "Error requesting transaction", msg = e.msg
method acceptRequestTransaction*(self: Service, transactionHash: string, messageId: string, signature: string) =
try:
let response = status_chat_commands.acceptRequestTransaction(transactionHash, messageId, signature)
discard self.processMessageUpdateAfterSend(response)
except Exception as e:
error "Error requesting transaction", msg = e.msg

View File

@ -1,4 +1,7 @@
import json
import ./dto/chat as chat_dto
import ../message/dto/message as message_dto
import status/statusgo_backend_new/chat as status_chat
# TODO: We need to remove these `status-lib` types from here
import status/types/[message]
@ -16,6 +19,9 @@ method delete*(self: ServiceInterface) {.base.} =
method init*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method hasChannel*(self: ServiceInterface, chatId: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getAllChats*(self: ServiceInterface): seq[ChatDto] {.base.} =
raise newException(ValueError, "No implementation available")
@ -32,5 +38,38 @@ method getOneToOneChatNameAndImage*(self: ServiceInterface, chatId: string):
method createPublicChat*(self: ServiceInterface, chatId: string): tuple[chatDto: ChatDto, success: bool] {.base.} =
raise newException(ValueError, "No implementation available")
method createOneToOneChat*(self: ServiceInterface, chatId: string, ensName: 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")
method parseChatResponse2*(self: ServiceInterface, response: RpcResponse[JsonNode]): (seq[ChatDto], seq[MessageDto]) {.base.} =
raise newException(ValueError, "No implementation available")
method processMessageUpdateAfterSend*(self: ServiceInterface, messageId: string, response: string) {.base.} =
raise newException(ValueError, "No implementation available")
method processUpdateForTransaction*(self: ServiceInterface, response: RpcResponse[JsonNode]): (seq[ChatDto], seq[MessageDto]) {.base.} =
raise newException(ValueError, "No implementation available")
method leaveChat*(self: ServiceInterface, chatId: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method sendImages*(self: ServiceInterface, chatId: string, imagePathsJson: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method requestAddressForTransaction*(self: ServiceInterface, chatId: string, fromAddress: string, amount: string, tokenAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")
method declineRequestTransaction*(self: ServiceInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method declineRequestAddressForTransaction*(self: ServiceInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method acceptRequestAddressForTransaction*(self: ServiceInterface, messageId: string, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method acceptRequestTransaction*(self: ServiceInterface, transactionHash: string, messageId: string, signature: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -178,6 +178,7 @@ StatusAppThreePanelLayout {
MessageContextMenuView {
id: quickActionMessageOptionsMenu
chatSectionModule: root.chatCommunitySectionModule
// Not Refactored
store: root.rootStore
// reactionModel: root.rootStore.emojiReactionsModel

View File

@ -17,6 +17,10 @@ ModalPopup {
id: popup
property var store
// Important:
// We're here in case of ChatSection
// This module is set from `ChatLayout` (each `ChatLayout` has its own chatSectionModule)
property var chatSectionModule
//% "Contact requests"
title: qsTrId("contact-requests")
@ -51,7 +55,7 @@ ModalPopup {
blockContactConfirmationDialog.open()
}
onAcceptClicked: {
popup.store.chatsModelInst.channelView.joinPrivateChat(model.address, "")
chatSectionModule.createOneToOneChat(model.address, "")
popup.store.contactsModuleInst.addContact(model.address)
}
onDeclineClicked: {

View File

@ -19,6 +19,7 @@ import StatusQ.Controls 0.1 as StatusQControls
ModalPopup {
property var rootStore
property var messageStore
property var chatSectionModule
property bool userCanPin: {
switch (popup.rootStore.chatsModelInst.channelView.activeChannel.chatType) {
case Constants.chatTypePublic: return false
@ -210,6 +211,7 @@ ModalPopup {
id: msgContextMenu
pinnedPopup: true
pinnedMessage: true
chatSectionModule: popup.chatSectionModule
store: popup.rootStore
reactionModel: popup.rootStore.emojiReactionsModel
onShouldCloseParentPopup: {

View File

@ -16,10 +16,11 @@ ModalPopup {
//% "New chat"
title: qsTrId("new-chat")
property var store
signal joinPrivateChat(string publicKey, string ensName)
signal profileClicked()
function doJoin(pk, ensName) {
popup.store.chatsModelInst.channelView.joinPrivateChat(pk, Utils.isChatKey(pk) ? "" : ensName);
popup.joinPrivateChat(pk, Utils.isChatKey(pk) ? "" : ensName);
popup.close();
}
@ -39,8 +40,7 @@ ModalPopup {
width: parent.width
addContactEnabled: false
onUserClicked: function (isContact, pubKey, ensName) {
popup.store.chatsModelInst.channelView.joinPrivateChat(pubKey, Utils.isChatKey(pubKey) ? "" : ensName);
popup.close();
popup.doJoin(pubKey, ensName);
}
}

View File

@ -132,6 +132,7 @@ Item {
MessageContextMenuView {
id: contextmenu
chatSectionModule: root.parentModule
store: root.rootStore
reactionModel: root.rootStore.emojiReactionsModel
}
@ -239,6 +240,7 @@ Item {
popupMenu: ChatContextMenuView {
store: root.rootStore
chatSectionModule: parentModule
onOpened: {
chatItem = root.rootStore.chatsModelInst.channelView.activeChannel
}
@ -392,8 +394,10 @@ Item {
packId)
}
onSendMessage: {
if (chatInput.fileUrls.length > 0){
root.rootStore.chatsModelInst.sendImages(JSON.stringify(fileUrls));
if (chatInput.fileUrls.length > 0) {
let inputAreaModule = parentModule.getChatContentModule.getInputAreaModule()
inputAreaModule.sendImages(JSON.stringify(fileUrls));
return
}
let msg = root.rootStore.chatsModelInst.plainText(Emoji.deparse(chatInput.textInput.text))
if (msg.length > 0){
@ -568,6 +572,7 @@ Item {
id: pinnedMessagesPopupComponent
PinnedMessagesPopup {
id: pinnedMessagesPopup
chatSectionModule: root.parentModule
rootStore: root.rootStore
messageStore: root.rootStore.messageStore
onClosed: destroy()

View File

@ -13,6 +13,7 @@ StatusPopupMenu {
id: root
property var chatItem
property var store
property var chatSectionModule
// Not Refactored Yet
property bool communityActive: false // root.store.chatsModelInst.communities.activeCommunity.active
@ -186,7 +187,7 @@ StatusPopupMenu {
if (communityActive) {
root.store.chatsModelInst.communities.deleteCommunityChat(root.store.chatsModelInst.communities.activeCommunity.id, chatId)
} else {
root.store.chatsModelInst.channelView.leaveChat(chatId)
chatSectionModule.leaveChat(chatId)
}
close();
}

View File

@ -258,6 +258,7 @@ Item {
chatListPopupMenu: ChatContextMenuView {
id: chatContextMenuView
store: root.store
chatSectionModule: communitySectionModule
openHandler: function (id) {
root.store.chatsModelInst.channelView.setContextChannel(id)
chatContextMenuView.chatItem = root.store.chatsModelInst.channelView.contextChannel

View File

@ -34,7 +34,7 @@ Item {
Component.onCompleted: {
appMain.openContactsPopup.connect(function(){
Global.openPopup(contactRequestsPopup)
Global.openPopup(contactRequestsPopup, {chatSectionModule})
})
}
@ -262,6 +262,7 @@ Item {
popupMenu: ChatContextMenuView {
id: chatContextMenuView
store: root.store
chatSectionModule: root.chatSectionModule
openHandler: function (id) {
root.store.chatsModelInst.channelView.setContextChannel(id)
chatContextMenuView.chatItem = root.store.chatsModelInst.channelView.contextChannel
@ -309,6 +310,9 @@ Item {
id: privateChatPopupComponent
PrivateChatPopup {
store: root.store
onJoinPrivateChat: {
chatSectionModule.createOneToOneChat(publicKey, ensName)
}
onClosed: {
destroy()
}

View File

@ -198,7 +198,8 @@ QtObject {
}
function joinPrivateChat(address) {
chatsModelInst.channelView.joinPrivateChat(address, "");
let chatCommunitySectionModule = mainModule.getChatSectionModule()
chatCommunitySectionModule.createOneToOneChat(address, "")
}
function unblockContact(address) {

View File

@ -22,6 +22,7 @@ ScrollView {
id: root
property RootStore store: RootStore { }
property var chatSectionModule
Layout.fillWidth: true
Layout.fillHeight: true
@ -219,6 +220,7 @@ ScrollView {
MessageContextMenuView {
id: msgCntxtMenu
store: root.store
chatSectionModule: root.chatSectionModule
reactionModel: EmojiReactions { }
}
}

View File

@ -463,6 +463,9 @@ Item {
TimelineLayout {
messageStore: appMain.rootStore.messageStore
rootStore: appMain.rootStore
Component.onCompleted: {
chatCommunitySectionModule = mainModule.getChatSectionModule()
}
}
}
onLoaded: timelineLayoutContainer.item.onActivated()

View File

@ -19,6 +19,10 @@ StatusPopupMenu {
width: emojiContainer.visible ? emojiContainer.width : 176
property var store
// Important:
// We're here in case of ChatSection
// This module is set from `ChatLayout` (each `ChatLayout` has its own chatSectionModule)
property var chatSectionModule
property string messageId
property int contentType
property bool isProfile: false
@ -256,7 +260,7 @@ StatusPopupMenu {
onTriggered: {
if (root.isProfile) {
Global.changeAppSectionBySectionType(Constants.appSection.chat)
root.store.chatsModelInst.channelView.joinPrivateChat(fromAuthor, "")
chatSectionModule.createOneToOneChat(fromAuthor, "")
} else {
showReplyArea()
}

View File

@ -416,7 +416,9 @@ QtObject {
.arg(isChatKey(pk) ? utilsModel.generateAlias(pk) : ("@" + removeStatusEns(pk)))
result.callback = function () {
if(isChatKey(pk)){
chatsModel.channelView.joinPrivateChat(pk, "");
// TODO refector those to call a store (somehow)
let chatCommunitySectionModule = mainModule.getChatSectionModule()
chatCommunitySectionModule.createOneToOneChat(pk, "")
} else {
chatsModel.channelView.joinWithENS(pk);
}