feat(Chat): display MutualStateUpdate system messages in 1-to-1 chats (#10847)
* feat(Chat): Display MutualStateUpdate system messages in 1-to-1 chats * feat(ActivityCenter): Add AC notification when a user get removed by another contact * fix: crutch fixing segfault on contact removal
This commit is contained in:
parent
96f4b5cc83
commit
010640acd0
|
@ -109,7 +109,9 @@ proc blockContact*(self: Controller, publicKey: string) =
|
|||
self.contactsService.blockContact(publicKey)
|
||||
|
||||
proc removeContact*(self: Controller, publicKey: string) =
|
||||
self.contactsService.removeContact(publicKey)
|
||||
let response = self.contactsService.removeContact(publicKey)
|
||||
# TODO: segfault if using SIGNAL_CHAT_REQUEST_UPDATE_AFTER_SEND
|
||||
discard self.chatService.processMessageUpdateAfterSend(response)
|
||||
|
||||
proc changeContactNickname*(self: Controller, publicKey: string, nickname: string) =
|
||||
self.contactsService.changeContactNickname(publicKey, nickname)
|
||||
|
|
|
@ -9,7 +9,7 @@ type
|
|||
Status = 3
|
||||
Emoji = 4
|
||||
Transaction = 5
|
||||
Group = 6
|
||||
SystemMessageGroup = 6
|
||||
Image = 7
|
||||
Audio = 8
|
||||
Community = 9
|
||||
|
@ -19,6 +19,7 @@ type
|
|||
ContactIdentityVerification = 13
|
||||
# Local only
|
||||
SystemMessagePinnedMessage = 14
|
||||
SystemMessageMutualStateUpdate = 15
|
||||
|
||||
proc toContentType*(value: int): ContentType =
|
||||
try:
|
||||
|
|
|
@ -19,6 +19,7 @@ type ActivityCenterNotificationType* {.pure.}= enum
|
|||
CommunityMembershipRequest = 8,
|
||||
CommunityKicked = 9,
|
||||
ContactVerification = 10
|
||||
ContactRemoved = 11
|
||||
|
||||
type ActivityCenterGroup* {.pure.}= enum
|
||||
All = 0,
|
||||
|
@ -140,7 +141,8 @@ proc activityCenterNotificationTypesByGroup*(group: ActivityCenterGroup) : seq[i
|
|||
ActivityCenterNotificationType.CommunityRequest.int,
|
||||
ActivityCenterNotificationType.CommunityMembershipRequest.int,
|
||||
ActivityCenterNotificationType.CommunityKicked.int,
|
||||
ActivityCenterNotificationType.ContactVerification.int
|
||||
ActivityCenterNotificationType.ContactVerification.int,
|
||||
ActivityCenterNotificationType.ContactRemoved.int
|
||||
]
|
||||
of ActivityCenterGroup.Mentions:
|
||||
return @[ActivityCenterNotificationType.Mention.int]
|
||||
|
@ -157,7 +159,10 @@ proc activityCenterNotificationTypesByGroup*(group: ActivityCenterGroup) : seq[i
|
|||
of ActivityCenterGroup.Admin:
|
||||
return @[ActivityCenterNotificationType.CommunityMembershipRequest.int]
|
||||
of ActivityCenterGroup.ContactRequests:
|
||||
return @[ActivityCenterNotificationType.ContactRequest.int]
|
||||
return @[
|
||||
ActivityCenterNotificationType.ContactRequest.int,
|
||||
ActivityCenterNotificationType.ContactRemoved.int
|
||||
]
|
||||
of ActivityCenterGroup.IdentityVerification:
|
||||
return @[ActivityCenterNotificationType.ContactVerification.int]
|
||||
else:
|
||||
|
|
|
@ -83,6 +83,9 @@ type
|
|||
admin*: bool
|
||||
joined*: bool
|
||||
|
||||
RpcResponseArgs* = ref object of Args
|
||||
response*: RpcResponse[JsonNode]
|
||||
|
||||
|
||||
# Signals which may be emitted by this service:
|
||||
const SIGNAL_CHANNEL_GROUPS_LOADED* = "channelGroupsLoaded"
|
||||
|
@ -104,6 +107,7 @@ const SIGNAL_CHAT_MEMBER_UPDATED* = "chatMemberUpdated"
|
|||
const SIGNAL_CHAT_SWITCH_TO_OR_CREATE_1_1_CHAT* = "switchToOrCreateOneToOneChat"
|
||||
const SIGNAL_CHAT_ADDED_OR_UPDATED* = "chatAddedOrUpdated"
|
||||
const SIGNAL_CHAT_CREATED* = "chatCreated"
|
||||
const SIGNAL_CHAT_REQUEST_UPDATE_AFTER_SEND* = "chatRequestUpdateAfterSend"
|
||||
|
||||
QtObject:
|
||||
type Service* = ref object of QObject
|
||||
|
@ -133,6 +137,7 @@ QtObject:
|
|||
proc updateOrAddChat*(self: Service, chat: ChatDto)
|
||||
proc hydrateChannelGroups*(self: Service, data: JsonNode)
|
||||
proc updateOrAddChannelGroup*(self: Service, channelGroup: ChannelGroupDto, isCommunityChannelGroup: bool = false)
|
||||
proc processMessageUpdateAfterSend*(self: Service, response: RpcResponse[JsonNode]): (seq[ChatDto], seq[MessageDto])
|
||||
|
||||
proc doConnect(self: Service) =
|
||||
self.events.on(SignalType.Message.event) do(e: Args):
|
||||
|
@ -161,7 +166,11 @@ QtObject:
|
|||
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.processMessageUpdateAfterSend(args.response)
|
||||
|
||||
proc getChannelGroups*(self: Service): seq[ChannelGroupDto] =
|
||||
return toSeq(self.channelGroups.values)
|
||||
|
||||
|
|
|
@ -51,6 +51,9 @@ type
|
|||
publicKey*: string
|
||||
ok*: bool
|
||||
|
||||
RpcResponseArgs* = ref object of Args
|
||||
response*: RpcResponse[JsonNode]
|
||||
|
||||
# Signals which may be emitted by this service:
|
||||
const SIGNAL_ENS_RESOLVED* = "ensResolved"
|
||||
const SIGNAL_CONTACT_ADDED* = "contactAdded"
|
||||
|
@ -73,6 +76,7 @@ const SIGNAL_CONTACT_VERIFICATION_ACCEPTED* = "contactVerificationRequestAccepte
|
|||
const SIGNAL_CONTACT_VERIFICATION_ADDED* = "contactVerificationRequestAdded"
|
||||
const SIGNAL_CONTACT_VERIFICATION_UPDATED* = "contactVerificationRequestUpdated"
|
||||
const SIGNAL_CONTACT_INFO_REQUEST_FINISHED* = "contactInfoRequestFinished"
|
||||
const SIGNAL_CHAT_REQUEST_UPDATE_AFTER_SEND* = "chatRequestUpdateAfterSend"
|
||||
|
||||
type
|
||||
ContactsGroup* {.pure.} = enum
|
||||
|
@ -453,8 +457,6 @@ QtObject:
|
|||
if response.result["contacts"] != nil:
|
||||
for contactJson in response.result["contacts"]:
|
||||
self.updateContact(contactJson.toContactsDto())
|
||||
# NOTE: this response may also contain chats and messages
|
||||
self.activityCenterService.parseActivityCenterResponse(response)
|
||||
|
||||
proc sendContactRequest*(self: Service, publicKey: string, message: string) =
|
||||
# Prefetch contact to avoid race condition with AC notification
|
||||
|
@ -467,6 +469,8 @@ QtObject:
|
|||
return
|
||||
|
||||
self.parseContactsResponse(response)
|
||||
self.activityCenterService.parseActivityCenterResponse(response)
|
||||
self.events.emit(SIGNAL_CHAT_REQUEST_UPDATE_AFTER_SEND, RpcResponseArgs(response: response))
|
||||
|
||||
except Exception as e:
|
||||
error "an error occurred while sending contact request", msg = e.msg
|
||||
|
@ -485,6 +489,8 @@ QtObject:
|
|||
return
|
||||
|
||||
self.parseContactsResponse(response)
|
||||
self.activityCenterService.parseActivityCenterResponse(response)
|
||||
self.events.emit(SIGNAL_CHAT_REQUEST_UPDATE_AFTER_SEND, RpcResponseArgs(response: response))
|
||||
|
||||
except Exception as e:
|
||||
error "an error occurred while accepting contact request", msg=e.msg
|
||||
|
@ -503,6 +509,8 @@ QtObject:
|
|||
return
|
||||
|
||||
self.parseContactsResponse(response)
|
||||
self.activityCenterService.parseActivityCenterResponse(response)
|
||||
self.events.emit(SIGNAL_CHAT_REQUEST_UPDATE_AFTER_SEND, RpcResponseArgs(response: response))
|
||||
|
||||
except Exception as e:
|
||||
error "an error occurred while dismissing contact request", msg=e.msg
|
||||
|
@ -542,13 +550,15 @@ QtObject:
|
|||
self.parseContactsResponse(response)
|
||||
self.events.emit(SIGNAL_CONTACT_BLOCKED, ContactArgs(contactId: contact.id))
|
||||
|
||||
proc removeContact*(self: Service, publicKey: string) =
|
||||
proc removeContact*(self: Service, publicKey: string): RpcResponse[JsonNode] =
|
||||
let response = status_contacts.retractContactRequest(publicKey)
|
||||
if not response.error.isNil:
|
||||
error "error removing contact ", msg = response.error.message
|
||||
return
|
||||
|
||||
self.parseContactsResponse(response)
|
||||
self.activityCenterService.parseActivityCenterResponse(response)
|
||||
return response
|
||||
|
||||
proc ensResolved*(self: Service, jsonObj: string) {.slot.} =
|
||||
let jsonObj = jsonObj.parseJson()
|
||||
|
|
|
@ -22,7 +22,8 @@ Control {
|
|||
Transaction = 6,
|
||||
Invitation = 7,
|
||||
DiscordMessage = 8,
|
||||
SystemMessagePinnedMessage = 14
|
||||
SystemMessagePinnedMessage = 14,
|
||||
SystemMessageMutualStateUpdate = 15
|
||||
}
|
||||
|
||||
property list<Item> quickActions
|
||||
|
@ -188,7 +189,10 @@ Control {
|
|||
|
||||
Loader {
|
||||
Layout.fillWidth: true
|
||||
active: isAReply && root.messageDetails.contentType !== StatusMessage.ContentType.SystemMessagePinnedMessage
|
||||
active: isAReply &&
|
||||
root.messageDetails.contentType !== StatusMessage.ContentType.SystemMessagePinnedMessage &&
|
||||
root.messageDetails.contentType !== StatusMessage.ContentType.SystemMessageMutualStateUpdate
|
||||
|
||||
visible: active
|
||||
sourceComponent: StatusMessageReply {
|
||||
objectName: "StatusMessage_replyDetails"
|
||||
|
|
|
@ -111,6 +111,8 @@ Popup {
|
|||
return communityRequestNotificationComponent
|
||||
case ActivityCenterStore.ActivityCenterNotificationType.CommunityKicked:
|
||||
return communityKickedNotificationComponent
|
||||
case ActivityCenterStore.ActivityCenterNotificationType.ContactRemoved:
|
||||
return contactRemovedComponent
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
@ -206,4 +208,16 @@ Popup {
|
|||
onCloseActivityCenter: root.close()
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: contactRemovedComponent
|
||||
|
||||
ActivityNotificationContactRemoved {
|
||||
filteredIndex: parent.filteredIndex
|
||||
notification: parent.notification
|
||||
store: root.store
|
||||
activityCenterStore: root.activityCenterStore
|
||||
onCloseActivityCenter: root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,8 @@ QtObject {
|
|||
CommunityRequest = 7,
|
||||
CommunityMembershipRequest = 8,
|
||||
CommunityKicked = 9,
|
||||
ContactVerification = 10
|
||||
ContactVerification = 10,
|
||||
ContactRemoved = 11
|
||||
}
|
||||
|
||||
enum ActivityCenterReadType {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import shared 1.0
|
||||
import shared.panels 1.0
|
||||
import utils 1.0
|
||||
|
||||
import "../panels"
|
||||
import "../popups"
|
||||
import "../stores"
|
||||
|
||||
ActivityNotificationMessage {
|
||||
id: root
|
||||
|
||||
function checkAndUpdateContactDetails(pubKey) {
|
||||
if (pubKey === root.contactId)
|
||||
root.updateContactDetails()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.store.contactsStore.sentContactRequestsModel
|
||||
|
||||
function onItemChanged(pubKey) {
|
||||
root.checkAndUpdateContactDetails(pubKey)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.store.contactsStore.receivedContactRequestsModel
|
||||
|
||||
function onItemChanged(pubKey) {
|
||||
root.checkAndUpdateContactDetails(pubKey)
|
||||
}
|
||||
}
|
||||
|
||||
messageSubheaderComponent: StatusBaseText {
|
||||
text: qsTr("Removed you as a contact")
|
||||
font.italic: true
|
||||
font.pixelSize: 15
|
||||
color: Theme.palette.baseColor1
|
||||
}
|
||||
|
||||
ctaComponent: StatusFlatButton {
|
||||
enabled: root.contactDetails && !root.contactDetails.added && !root.contactDetails.hasAddedUs
|
||||
size: StatusBaseButton.Size.Small
|
||||
text: qsTr("Send Contact Request")
|
||||
onClicked: Global.openContactRequestPopup(root.contactId, null)
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ import utils 1.0
|
|||
ActivityNotificationBase {
|
||||
id: root
|
||||
|
||||
readonly property bool isOutgoingMessage: notification && notification.message.amISender
|
||||
readonly property bool isOutgoingMessage: notification && notification.message && notification.message.amISender
|
||||
readonly property string contactId: notification ? isOutgoingMessage ? notification.chatId : notification.author : ""
|
||||
readonly property string contactName: contactDetails ? ProfileUtils.displayName(contactDetails.localNickname, contactDetails.name,
|
||||
contactDetails.displayName, contactDetails.alias) : ""
|
||||
|
@ -23,7 +23,7 @@ ActivityNotificationBase {
|
|||
signal messageClicked()
|
||||
|
||||
property StatusMessageDetails messageDetails: StatusMessageDetails {
|
||||
messageText: notification ? notification.message.messageText : ""
|
||||
messageText: notification && notification.message ? notification.message.messageText : ""
|
||||
amISender: false
|
||||
sender.id: contactId
|
||||
sender.displayName: contactName
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ActivityCenterGroupRequest 1.0 ActivityCenterGroupRequest.qml
|
|
@ -111,7 +111,6 @@ Loader {
|
|||
property bool isEmoji: messageContentType === Constants.messageContentType.emojiType
|
||||
property bool isImage: messageContentType === Constants.messageContentType.imageType || (isDiscordMessage && messageImage != "")
|
||||
property bool isAudio: messageContentType === Constants.messageContentType.audioType
|
||||
property bool isStatusMessage: messageContentType === Constants.messageContentType.systemMessagePrivateGroupType
|
||||
property bool isSticker: messageContentType === Constants.messageContentType.stickerType
|
||||
property bool isDiscordMessage: messageContentType === Constants.messageContentType.discordMessageType
|
||||
property bool isText: messageContentType === Constants.messageContentType.messageType || messageContentType === Constants.messageContentType.contactRequestType || isDiscordMessage
|
||||
|
@ -195,8 +194,9 @@ Loader {
|
|||
return channelIdentifierComponent
|
||||
case Constants.messageContentType.fetchMoreMessagesButton:
|
||||
return fetchMoreMessagesButtonComponent
|
||||
case Constants.messageContentType.systemMessagePrivateGroupType:
|
||||
return privateGroupHeaderComponent
|
||||
case Constants.messageContentType.systemMessagePrivateGroupType: // no break
|
||||
case Constants.messageContentType.systemMessageMutualStateUpdate:
|
||||
return systemMessageComponent
|
||||
case Constants.messageContentType.systemMessagePinnedMessage:
|
||||
return systemMessagePinnedMessageComponent
|
||||
case Constants.messageContentType.gapType:
|
||||
|
@ -271,6 +271,8 @@ Loader {
|
|||
return StatusMessage.ContentType.DiscordMessage;
|
||||
case Constants.messageContentType.systemMessagePinnedMessage:
|
||||
return StatusMessage.ContentType.SystemMessagePinnedMessage;
|
||||
case Constants.messageContentType.systemMessageMutualStateUpdate:
|
||||
return StatusMessage.ContentType.SystemMessageMutualStateUpdate;
|
||||
case Constants.messageContentType.fetchMoreMessagesButton:
|
||||
case Constants.messageContentType.chatIdentifier:
|
||||
case Constants.messageContentType.unknownContentType:
|
||||
|
@ -345,11 +347,13 @@ Loader {
|
|||
}
|
||||
}
|
||||
|
||||
// Private group Messages
|
||||
Component {
|
||||
id: privateGroupHeaderComponent
|
||||
id: systemMessageComponent
|
||||
|
||||
StyledText {
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
readonly property string systemMessageText: root.messageText.length > 0 ? root.messageText : root.unparsedText
|
||||
text: {
|
||||
return `<html>`+
|
||||
`<head>`+
|
||||
|
@ -361,14 +365,13 @@ Loader {
|
|||
`</style>`+
|
||||
`</head>`+
|
||||
`<body>`+
|
||||
`${messageText}`+
|
||||
`${systemMessageText}`+
|
||||
`</body>`+
|
||||
`</html>`;
|
||||
}
|
||||
visible: isStatusMessage
|
||||
font.pixelSize: 14
|
||||
color: Style.current.secondaryText
|
||||
width: parent.width - 120
|
||||
width: parent.width - 120
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
textFormat: Text.RichText
|
||||
|
@ -478,6 +481,7 @@ Loader {
|
|||
showHeader: root.shouldRepeatHeader || dateGroupLabel.visible || isAReply ||
|
||||
root.prevMessageContentType === Constants.messageContentType.systemMessagePrivateGroupType ||
|
||||
root.prevMessageContentType === Constants.messageContentType.systemMessagePinnedMessage ||
|
||||
root.prevMessageContentType === Constants.messageContentType.systemMessageMutualStateUpdate ||
|
||||
root.senderId !== root.prevMessageSenderId
|
||||
isActiveMessage: d.isMessageActive
|
||||
topPadding: showHeader ? Style.current.halfPadding : 0
|
||||
|
@ -970,6 +974,4 @@ Loader {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -414,6 +414,7 @@ QtObject {
|
|||
readonly property int contactRequestType: 11
|
||||
readonly property int discordMessageType: 12
|
||||
readonly property int systemMessagePinnedMessage: 14
|
||||
readonly property int systemMessageMutualStateUpdate: 15
|
||||
}
|
||||
|
||||
readonly property QtObject messageModelRoles: QtObject {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 9e0a12cb32bf8921ba7b5c923f743bb7119fab96
|
||||
Subproject commit 8589a525a5531cc4f6e7f6d6e04fe99eecae1658
|
Loading…
Reference in New Issue