Add event message

This commit is contained in:
Benoit Martins 2024-09-24 18:20:56 +02:00 committed by QuentinArguillere
parent b715cf1cfd
commit 233ff399ff
14 changed files with 641 additions and 247 deletions

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M232,136.66A104.12,104.12,0,1,1,119.34,24,8,8,0,0,1,120.66,40,88.12,88.12,0,1,0,216,135.34,8,8,0,0,1,232,136.66ZM120,72v56a8,8,0,0,0,8,8h56a8,8,0,0,0,0-16H136V72a8,8,0,0,0-16,0Zm40-24a12,12,0,1,0-12-12A12,12,0,0,0,160,48Zm36,24a12,12,0,1,0-12-12A12,12,0,0,0,196,72Zm24,36a12,12,0,1,0-12-12A12,12,0,0,0,220,108Z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M232,136.66A104.12,104.12,0,1,1,119.34,24,8,8,0,0,1,120.66,40,88.12,88.12,0,1,0,216,135.34,8,8,0,0,1,232,136.66ZM120,72v56a8,8,0,0,0,8,8h56a8,8,0,0,0,0-16H136V72a8,8,0,0,0-16,0Zm40-24a12,12,0,1,0-12-12A12,12,0,0,0,160,48Zm36,24a12,12,0,1,0-12-12A12,12,0,0,0,196,72Zm24,36a12,12,0,1,0-12-12A12,12,0,0,0,220,108Z"></path></svg>

Before

Width:  |  Height:  |  Size: 434 B

After

Width:  |  Height:  |  Size: 434 B

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "door.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M232,216H208V40a16,16,0,0,0-16-16H64A16,16,0,0,0,48,40V216H24a8,8,0,0,0,0,16H232a8,8,0,0,0,0-16ZM64,40H192V216H64Zm104,92a12,12,0,1,1-12-12A12,12,0,0,1,168,132Z"></path></svg>

After

Width:  |  Height:  |  Size: 284 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M227.31,73.37,182.63,28.68a16,16,0,0,0-22.63,0L36.69,152A15.86,15.86,0,0,0,32,163.31V208a16,16,0,0,0,16,16H92.69A15.86,15.86,0,0,0,104,219.31L227.31,96a16,16,0,0,0,0-22.63ZM92.69,208H48V163.31l88-88L180.69,120ZM192,108.68,147.31,64l24-24L216,84.68Z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M227.31,73.37,182.63,28.68a16,16,0,0,0-22.63,0L36.69,152A15.86,15.86,0,0,0,32,163.31V208a16,16,0,0,0,16,16H92.69A15.86,15.86,0,0,0,104,219.31L227.31,96a16,16,0,0,0,0-22.63ZM92.69,208H48V163.31l88-88L180.69,120ZM192,108.68,147.31,64l24-24L216,84.68Z"></path></svg>

Before

Width:  |  Height:  |  Size: 372 B

After

Width:  |  Height:  |  Size: 372 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M228.25,63.07l-4.66-2.69a23.6,23.6,0,0,0,0-8.76l4.66-2.69a8,8,0,0,0-8-13.86l-4.67,2.7A23.92,23.92,0,0,0,208,33.38V28a8,8,0,0,0-16,0v5.38a23.92,23.92,0,0,0-7.58,4.39l-4.67-2.7a8,8,0,1,0-8,13.86l4.66,2.69a23.6,23.6,0,0,0,0,8.76l-4.66,2.69a8,8,0,0,0,4,14.93,7.92,7.92,0,0,0,4-1.07l4.67-2.7A23.92,23.92,0,0,0,192,78.62V84a8,8,0,0,0,16,0V78.62a23.92,23.92,0,0,0,7.58-4.39l4.67,2.7a7.92,7.92,0,0,0,4,1.07,8,8,0,0,0,4-14.93ZM192,56a8,8,0,1,1,8,8A8,8,0,0,1,192,56Zm29.35,48.11a8,8,0,0,0-6.57,9.21A88.85,88.85,0,0,1,216,128a87.62,87.62,0,0,1-22.24,58.41,79.66,79.66,0,0,0-36.06-28.75,48,48,0,1,0-59.4,0,79.66,79.66,0,0,0-36.06,28.75A88,88,0,0,1,128,40a88.76,88.76,0,0,1,14.68,1.22,8,8,0,0,0,2.64-15.78,103.92,103.92,0,1,0,85.24,85.24A8,8,0,0,0,221.35,104.11ZM96,120a32,32,0,1,1,32,32A32,32,0,0,1,96,120ZM74.08,197.5a64,64,0,0,1,107.84,0,87.83,87.83,0,0,1-107.84,0Z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M228.25,63.07l-4.66-2.69a23.6,23.6,0,0,0,0-8.76l4.66-2.69a8,8,0,0,0-8-13.86l-4.67,2.7A23.92,23.92,0,0,0,208,33.38V28a8,8,0,0,0-16,0v5.38a23.92,23.92,0,0,0-7.58,4.39l-4.67-2.7a8,8,0,1,0-8,13.86l4.66,2.69a23.6,23.6,0,0,0,0,8.76l-4.66,2.69a8,8,0,0,0,4,14.93,7.92,7.92,0,0,0,4-1.07l4.67-2.7A23.92,23.92,0,0,0,192,78.62V84a8,8,0,0,0,16,0V78.62a23.92,23.92,0,0,0,7.58-4.39l4.67,2.7a7.92,7.92,0,0,0,4,1.07,8,8,0,0,0,4-14.93ZM192,56a8,8,0,1,1,8,8A8,8,0,0,1,192,56Zm29.35,48.11a8,8,0,0,0-6.57,9.21A88.85,88.85,0,0,1,216,128a87.62,87.62,0,0,1-22.24,58.41,79.66,79.66,0,0,0-36.06-28.75,48,48,0,1,0-59.4,0,79.66,79.66,0,0,0-36.06,28.75A88,88,0,0,1,128,40a88.76,88.76,0,0,1,14.68,1.22,8,8,0,0,0,2.64-15.78,103.92,103.92,0,1,0,85.24,85.24A8,8,0,0,0,221.35,104.11ZM96,120a32,32,0,1,1,32,32A32,32,0,0,1,96,120ZM74.08,197.5a64,64,0,0,1,107.84,0,87.83,87.83,0,0,1-107.84,0Z"></path></svg>

Before

Width:  |  Height:  |  Size: 979 B

After

Width:  |  Height:  |  Size: 979 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24ZM74.08,197.5a64,64,0,0,1,107.84,0,87.83,87.83,0,0,1-107.84,0ZM96,120a32,32,0,1,1,32,32A32,32,0,0,1,96,120Zm97.76,66.41a79.66,79.66,0,0,0-36.06-28.75,48,48,0,1,0-59.4,0,79.66,79.66,0,0,0-36.06,28.75,88,88,0,1,1,131.52,0Z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24ZM74.08,197.5a64,64,0,0,1,107.84,0,87.83,87.83,0,0,1-107.84,0ZM96,120a32,32,0,1,1,32,32A32,32,0,0,1,96,120Zm97.76,66.41a79.66,79.66,0,0,0-36.06-28.75,48,48,0,1,0-59.4,0,79.66,79.66,0,0,0-36.06,28.75,88,88,0,1,1,131.52,0Z"></path></svg>

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 400 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#4e6074" viewBox="0 0 256 256"><path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm-8-80V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"></path></svg>

Before

Width:  |  Height:  |  Size: 318 B

After

Width:  |  Height:  |  Size: 318 B

View file

@ -947,6 +947,210 @@
}
}
},
"conversation_event_admin_set" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ is admin"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ est maintenant administrateur"
}
}
}
},
"conversation_event_admin_unset" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ is no longer admin"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ n'est plus administrateur"
}
}
}
},
"conversation_event_conference_created" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "You have joined the group"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Vous avez rejoint le groupe"
}
}
}
},
"conversation_event_conference_destroyed" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "You have left the group"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Vous avez quitté le groupe"
}
}
}
},
"conversation_event_device_added" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "New device for %@"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Nouvel appareil pour %@"
}
}
}
},
"conversation_event_device_removed" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Device for %@ removed"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Appareil supprimé pour %@"
}
}
}
},
"conversation_event_ephemeral_messages_disabled" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ephemeral messages have been disabled"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Les messages éphémères ont été désactivés"
}
}
}
},
"conversation_event_ephemeral_messages_enabled" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ephemeral messages have been enabled"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Les messages éphémères ont été activés"
}
}
}
},
"conversation_event_ephemeral_messages_lifetime_changed" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Ephemeral lifetime is now %@"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "La durée des messages éphémères est de %@"
}
}
}
},
"conversation_event_participant_added" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ has joined"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ a rejoint le groupe"
}
}
}
},
"conversation_event_participant_removed" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ has left"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ a quitté le groupe"
}
}
}
},
"conversation_event_subject_changed" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "New subject: %@"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Le groupe a été renommé : %@"
}
}
}
},
"conversation_failed_to_create_toast" : {
"extractionState" : "manual",
"localizations" : {

View file

@ -36,244 +36,272 @@ struct ChatBubbleView: View {
var body: some View {
HStack {
VStack {
if !eventLogMessage.message.text.isEmpty || !eventLogMessage.message.attachments.isEmpty {
HStack(alignment: .top, content: {
if eventLogMessage.message.isOutgoing {
Spacer()
}
if conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup
&& !eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage {
VStack {
Avatar(
contactAvatarModel: conversationViewModel.participantConversationModel.first(where: {$0.address == eventLogMessage.message.address}) ??
ContactAvatarModel(friend: nil, name: "??", address: "", withPresence: false),
avatarSize: 35
)
.padding(.top, 30)
if eventLogMessage.eventModel.eventLogType == .ConferenceChatMessage {
VStack {
if !eventLogMessage.message.text.isEmpty || !eventLogMessage.message.attachments.isEmpty {
HStack(alignment: .top, content: {
if eventLogMessage.message.isOutgoing {
Spacer()
}
} else if conversationViewModel.displayedConversation != nil
&& conversationViewModel.displayedConversation!.isGroup && !eventLogMessage.message.isOutgoing {
VStack {
}
.padding(.leading, 43)
}
VStack(alignment: .leading, spacing: 0) {
if conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup
&& !eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage {
Text(conversationViewModel.participantConversationModel.first(where: {$0.address == eventLogMessage.message.address})?.name ?? "")
.default_text_style(styleSize: 12)
.padding(.top, 10)
.padding(.bottom, 2)
}
if eventLogMessage.message.isForward {
HStack {
if eventLogMessage.message.isOutgoing {
Spacer()
}
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading, spacing: 0) {
HStack {
Image("forward")
.resizable()
.frame(width: 15, height: 15, alignment: .leading)
Text("message_forwarded_label")
.default_text_style(styleSize: 12)
}
.padding(.bottom, 2)
}
if !eventLogMessage.message.isOutgoing {
Spacer()
}
VStack {
Avatar(
contactAvatarModel: conversationViewModel.participantConversationModel.first(where: {$0.address == eventLogMessage.message.address}) ??
ContactAvatarModel(friend: nil, name: "??", address: "", withPresence: false),
avatarSize: 35
)
.padding(.top, 30)
}
.frame(maxWidth: .infinity)
}
if eventLogMessage.message.replyMessage != nil {
HStack {
if eventLogMessage.message.isOutgoing {
Spacer()
}
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading, spacing: 0) {
HStack {
Image("reply")
.resizable()
.frame(width: 15, height: 15, alignment: .leading)
Text(conversationViewModel.participantConversationModel.first(
where: {$0.address == eventLogMessage.message.replyMessage!.address})?.name ?? "")
.default_text_style(styleSize: 12)
}
.padding(.bottom, 2)
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading) {
if !eventLogMessage.message.replyMessage!.text.isEmpty {
Text(eventLogMessage.message.replyMessage!.text)
.foregroundStyle(Color.grayMain2c700)
.default_text_style(styleSize: 16)
.lineLimit(/*@START_MENU_TOKEN@*/2/*@END_MENU_TOKEN@*/)
} else if !eventLogMessage.message.replyMessage!.attachmentsNames.isEmpty {
Text(eventLogMessage.message.replyMessage!.attachmentsNames)
.foregroundStyle(Color.grayMain2c700)
.default_text_style(styleSize: 16)
.lineLimit(/*@START_MENU_TOKEN@*/2/*@END_MENU_TOKEN@*/)
}
}
.padding(.all, 15)
.padding(.bottom, 15)
.background(Color.gray200)
.clipShape(RoundedRectangle(cornerRadius: 1))
.roundedCorner(
16,
corners: eventLogMessage.message.isOutgoing ? [.topLeft, .topRight, .bottomLeft] : [.topLeft, .topRight, .bottomRight]
)
}
.onTapGesture {
conversationViewModel.scrollToMessage(message: eventLogMessage.message)
}
if !eventLogMessage.message.isOutgoing {
Spacer()
}
} else if conversationViewModel.displayedConversation != nil
&& conversationViewModel.displayedConversation!.isGroup && !eventLogMessage.message.isOutgoing {
VStack {
}
.frame(maxWidth: .infinity)
.padding(.bottom, -20)
.padding(.leading, 43)
}
ZStack {
HStack {
if eventLogMessage.message.isOutgoing {
Spacer()
VStack(alignment: .leading, spacing: 0) {
if conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup
&& !eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage {
Text(conversationViewModel.participantConversationModel.first(where: {$0.address == eventLogMessage.message.address})?.name ?? "")
.default_text_style(styleSize: 12)
.padding(.top, 10)
.padding(.bottom, 2)
}
if eventLogMessage.message.isForward {
HStack {
if eventLogMessage.message.isOutgoing {
Spacer()
}
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading, spacing: 0) {
HStack {
Image("forward")
.resizable()
.frame(width: 15, height: 15, alignment: .leading)
Text("message_forwarded_label")
.default_text_style(styleSize: 12)
}
.padding(.bottom, 2)
}
if !eventLogMessage.message.isOutgoing {
Spacer()
}
}
.frame(maxWidth: .infinity)
}
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading) {
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading) {
if !eventLogMessage.message.attachments.isEmpty {
messageAttachments()
if eventLogMessage.message.replyMessage != nil {
HStack {
if eventLogMessage.message.isOutgoing {
Spacer()
}
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading, spacing: 0) {
HStack {
Image("reply")
.resizable()
.frame(width: 15, height: 15, alignment: .leading)
Text(conversationViewModel.participantConversationModel.first(
where: {$0.address == eventLogMessage.message.replyMessage!.address})?.name ?? "")
.default_text_style(styleSize: 12)
}
.padding(.bottom, 2)
if !eventLogMessage.message.text.isEmpty {
Text(eventLogMessage.message.text)
.foregroundStyle(Color.grayMain2c700)
.default_text_style(styleSize: 16)
}
HStack(alignment: .center) {
Text(conversationViewModel.getMessageTime(startDate: eventLogMessage.message.dateReceived))
.foregroundStyle(Color.grayMain2c500)
.default_text_style_300(styleSize: 14)
.padding(.top, 1)
if (conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup)
|| eventLogMessage.message.isOutgoing {
if eventLogMessage.message.status == .sending {
ProgressView()
.controlSize(.mini)
.progressViewStyle(CircularProgressViewStyle(tint: .orangeMain500))
.frame(width: 10, height: 10)
.padding(.top, 1)
} else if eventLogMessage.message.status != nil {
Image(conversationViewModel.getImageIMDN(status: eventLogMessage.message.status!))
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.orangeMain500)
.frame(width: 15, height: 15)
.padding(.top, 1)
}
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading) {
if !eventLogMessage.message.replyMessage!.text.isEmpty {
Text(eventLogMessage.message.replyMessage!.text)
.foregroundStyle(Color.grayMain2c700)
.default_text_style(styleSize: 16)
.lineLimit(/*@START_MENU_TOKEN@*/2/*@END_MENU_TOKEN@*/)
} else if !eventLogMessage.message.replyMessage!.attachmentsNames.isEmpty {
Text(eventLogMessage.message.replyMessage!.attachmentsNames)
.foregroundStyle(Color.grayMain2c700)
.default_text_style(styleSize: 16)
.lineLimit(/*@START_MENU_TOKEN@*/2/*@END_MENU_TOKEN@*/)
}
}
.onTapGesture {
conversationViewModel.selectedMessageToDisplayDetails = eventLogMessage
conversationViewModel.prepareBottomSheetForDeliveryStatus()
}
.disabled(conversationViewModel.selectedMessage != nil)
.padding(.top, -4)
.padding(.all, 15)
.padding(.bottom, 15)
.background(Color.gray200)
.clipShape(RoundedRectangle(cornerRadius: 1))
.roundedCorner(
16,
corners: eventLogMessage.message.isOutgoing ? [.topLeft, .topRight, .bottomLeft] : [.topLeft, .topRight, .bottomRight]
)
}
.onTapGesture {
conversationViewModel.scrollToMessage(message: eventLogMessage.message)
}
.padding(.all, 15)
.background(eventLogMessage.message.isOutgoing ? Color.orangeMain100 : Color.grayMain2c100)
.clipShape(RoundedRectangle(cornerRadius: 3))
.roundedCorner(
16,
corners: eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage ? [.topLeft, .topRight, .bottomLeft] :
(!eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage ? [.topRight, .bottomRight, .bottomLeft] : [.allCorners]))
if !eventLogMessage.message.reactions.isEmpty {
HStack {
ForEach(0..<eventLogMessage.message.reactions.count, id: \.self) { index in
if eventLogMessage.message.reactions.firstIndex(of: eventLogMessage.message.reactions[index]) == index {
Text(eventLogMessage.message.reactions[index])
if !eventLogMessage.message.isOutgoing {
Spacer()
}
}
.frame(maxWidth: .infinity)
.padding(.bottom, -20)
}
ZStack {
HStack {
if eventLogMessage.message.isOutgoing {
Spacer()
}
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading) {
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading) {
if !eventLogMessage.message.attachments.isEmpty {
messageAttachments()
}
if !eventLogMessage.message.text.isEmpty {
Text(eventLogMessage.message.text)
.foregroundStyle(Color.grayMain2c700)
.default_text_style(styleSize: 16)
}
HStack(alignment: .center) {
Text(conversationViewModel.getMessageTime(startDate: eventLogMessage.message.dateReceived))
.foregroundStyle(Color.grayMain2c500)
.default_text_style_300(styleSize: 14)
.padding(.top, 1)
if (conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup)
|| eventLogMessage.message.isOutgoing {
if eventLogMessage.message.status == .sending {
ProgressView()
.controlSize(.mini)
.progressViewStyle(CircularProgressViewStyle(tint: .orangeMain500))
.frame(width: 10, height: 10)
.padding(.top, 1)
} else if eventLogMessage.message.status != nil {
Image(conversationViewModel.getImageIMDN(status: eventLogMessage.message.status!))
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.orangeMain500)
.frame(width: 15, height: 15)
.padding(.top, 1)
}
}
}
.onTapGesture {
conversationViewModel.selectedMessageToDisplayDetails = eventLogMessage
conversationViewModel.prepareBottomSheetForDeliveryStatus()
}
.disabled(conversationViewModel.selectedMessage != nil)
.padding(.top, -4)
}
.padding(.all, 15)
.background(eventLogMessage.message.isOutgoing ? Color.orangeMain100 : Color.grayMain2c100)
.clipShape(RoundedRectangle(cornerRadius: 3))
.roundedCorner(
16,
corners: eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage ? [.topLeft, .topRight, .bottomLeft] :
(!eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage ? [.topRight, .bottomRight, .bottomLeft] : [.allCorners]))
if !eventLogMessage.message.reactions.isEmpty {
HStack {
ForEach(0..<eventLogMessage.message.reactions.count, id: \.self) { index in
if eventLogMessage.message.reactions.firstIndex(of: eventLogMessage.message.reactions[index]) == index {
Text(eventLogMessage.message.reactions[index])
.default_text_style(styleSize: 14)
.padding(.horizontal, -2)
}
}
if containsDuplicates(strings: eventLogMessage.message.reactions) {
Text("\(eventLogMessage.message.reactions.count)")
.default_text_style(styleSize: 14)
.padding(.horizontal, -2)
}
}
if containsDuplicates(strings: eventLogMessage.message.reactions) {
Text("\(eventLogMessage.message.reactions.count)")
.default_text_style(styleSize: 14)
.padding(.horizontal, -2)
.onTapGesture {
conversationViewModel.selectedMessageToDisplayDetails = eventLogMessage
conversationViewModel.prepareBottomSheetForReactions()
}
.disabled(conversationViewModel.selectedMessage != nil)
.padding(.vertical, 6)
.padding(.horizontal, 10)
.background(eventLogMessage.message.isOutgoing ? Color.orangeMain100 : Color.grayMain2c100)
.cornerRadius(20)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(.white, lineWidth: 3)
)
.padding(.top, -20)
.padding(eventLogMessage.message.isOutgoing ? .trailing : .leading, 5)
}
.onTapGesture {
conversationViewModel.selectedMessageToDisplayDetails = eventLogMessage
conversationViewModel.prepareBottomSheetForReactions()
}
.disabled(conversationViewModel.selectedMessage != nil)
.padding(.vertical, 6)
.padding(.horizontal, 10)
.background(eventLogMessage.message.isOutgoing ? Color.orangeMain100 : Color.grayMain2c100)
.cornerRadius(20)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(.white, lineWidth: 3)
)
.padding(.top, -20)
.padding(eventLogMessage.message.isOutgoing ? .trailing : .leading, 5)
}
if !eventLogMessage.message.isOutgoing {
Spacer()
}
}
if !eventLogMessage.message.isOutgoing {
Spacer()
}
.frame(maxWidth: .infinity)
}
.frame(maxWidth: .infinity)
}
.frame(maxWidth: .infinity)
if !eventLogMessage.message.isOutgoing {
Spacer()
}
})
.padding(.leading, eventLogMessage.message.isOutgoing ? 40 : 0)
.padding(.trailing, !eventLogMessage.message.isOutgoing ? 40 : 0)
}
}
.onTapGesture {}
.onLongPressGesture(minimumDuration: .infinity, maximumDistance: .infinity, pressing: { (value) in
self.isPressed = value
if value == true {
self.timePassed = 0
self.ticker.start(interval: 0.2)
}
}, perform: {})
.onReceive(ticker.objectWillChange) { (_) in
// Stop timer and reset the start date if the button in not pressed
guard self.isPressed else {
self.ticker.stop()
return
}
self.timePassed = self.ticker.timeIntervalSinceStarted
withAnimation {
conversationViewModel.selectedMessage = eventLogMessage
}
}
} else if !eventLogMessage.eventModel.text.isEmpty {
HStack {
Spacer()
HStack {
if eventLogMessage.eventModel.icon != nil {
eventLogMessage.eventModel.icon!
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c500)
.frame(width: 25, height: 25, alignment: .leading)
}
if !eventLogMessage.message.isOutgoing {
Spacer()
}
})
.padding(.leading, eventLogMessage.message.isOutgoing ? 40 : 0)
.padding(.trailing, !eventLogMessage.message.isOutgoing ? 40 : 0)
}
}
.onTapGesture {}
.onLongPressGesture(minimumDuration: .infinity, maximumDistance: .infinity, pressing: { (value) in
self.isPressed = value
if value == true {
self.timePassed = 0
self.ticker.start(interval: 0.2)
}
Text(eventLogMessage.eventModel.text)
.foregroundStyle(Color.grayMain2c500)
.default_text_style(styleSize: 12)
}
.padding(.horizontal, 10)
.padding(.vertical, 4)
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.grayMain2c200, lineWidth: 1)
)
}, perform: {})
.onReceive(ticker.objectWillChange) { (_) in
// Stop timer and reset the start date if the button in not pressed
guard self.isPressed else {
self.ticker.stop()
return
Spacer()
}
self.timePassed = self.ticker.timeIntervalSinceStarted
withAnimation {
conversationViewModel.selectedMessage = eventLogMessage
}
.padding(.vertical, 4)
}
}
.contentShape(Rectangle())

View file

@ -564,6 +564,11 @@ struct ConversationFragment: View {
.default_text_style(styleSize: 15)
.focused($isMessageTextFocused)
.padding(.vertical, 5)
.onChange(of: conversationViewModel.messageText) { text in
if !text.isEmpty {
conversationViewModel.compose()
}
}
} else {
ZStack(alignment: .leading) {
TextEditor(text: $conversationViewModel.messageText)
@ -572,6 +577,11 @@ struct ConversationFragment: View {
.fixedSize(horizontal: false, vertical: true)
.default_text_style(styleSize: 15)
.focused($isMessageTextFocused)
.onChange(of: conversationViewModel.messageText) { text in
if !text.isEmpty {
conversationViewModel.compose()
}
}
if conversationViewModel.messageText.isEmpty {
Text("Say something...")

View file

@ -525,7 +525,7 @@ struct MessagesSection: Equatable {
struct EventLogMessage: Equatable {
let eventLog: EventLog
let eventModel: EventModel
var message: Message
static var formatter = {

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2010-2023 Belledonne Communications SARL.
*
* This file is part of linphone-iphone
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import SwiftUI
import linphonesw
class EventModel: ObservableObject {
@Published var text: String
@Published var icon: Image?
var eventLog: EventLog
var eventLogType: EventLog.Kind
init(eventLog: EventLog) {
self.eventLog = eventLog
self.eventLogType = eventLog.type
self.text = ""
self.icon = nil
setupEventData()
}
private func setupEventData() {
let address = eventLog.participantAddress ?? eventLog.peerAddress
if address != nil {
ContactsManager.shared.getFriendWithAddressInCoreQueue(address: address) { friendResult in
var name = ""
if let addressFriend = friendResult {
name = addressFriend.name!
} else {
name = address!.displayName != nil ? address!.displayName! : address!.username!
}
let textValue: String
let iconValue: Image?
switch self.eventLog.type {
case .ConferenceCreated:
textValue = NSLocalizedString("conversation_event_conference_created", comment: "")
case .ConferenceTerminated:
textValue = NSLocalizedString("conversation_event_conference_destroyed", comment: "")
case .ConferenceParticipantAdded:
textValue = String(format: NSLocalizedString("conversation_event_participant_added", comment: ""), address != nil ? name : "<?>")
case .ConferenceParticipantRemoved:
textValue = String(format: NSLocalizedString("conversation_event_participant_removed", comment: ""), address != nil ? name : "<?>")
case .ConferenceSubjectChanged:
textValue = String(format: NSLocalizedString("conversation_event_subject_changed", comment: ""), self.eventLog.subject ?? "")
case .ConferenceParticipantSetAdmin:
textValue = String(format: NSLocalizedString("conversation_event_admin_set", comment: ""), address != nil ? name : "<?>")
case .ConferenceParticipantUnsetAdmin:
textValue = String(format: NSLocalizedString("conversation_event_admin_unset", comment: ""), address != nil ? name : "<?>")
case .ConferenceParticipantDeviceAdded:
textValue = String(format: NSLocalizedString("conversation_event_device_added", comment: ""), address != nil ? name : "<?>")
case .ConferenceParticipantDeviceRemoved:
textValue = String(format: NSLocalizedString("conversation_event_device_removed", comment: ""), address != nil ? name : "<?>")
case .ConferenceEphemeralMessageEnabled:
textValue = NSLocalizedString("conversation_event_ephemeral_messages_enabled", comment: "")
case .ConferenceEphemeralMessageDisabled:
textValue = NSLocalizedString("conversation_event_ephemeral_messages_disabled", comment: "")
case .ConferenceEphemeralMessageLifetimeChanged:
textValue = String(format: NSLocalizedString("conversation_event_ephemeral_messages_lifetime_changed", comment: ""),
self.formatEphemeralExpiration(duration: Int64(self.eventLog.ephemeralMessageLifetime)).lowercased())
default:
textValue = String(self.eventLog.type.rawValue)
}
// Icon assignment
switch self.eventLog.type {
case .ConferenceEphemeralMessageEnabled, .ConferenceEphemeralMessageDisabled, .ConferenceEphemeralMessageLifetimeChanged:
iconValue = Image("clock-countdown")
case .ConferenceTerminated:
iconValue = Image("warning-circle")
case .ConferenceSubjectChanged:
iconValue = Image("pencil-simple")
case .ConferenceParticipantAdded, .ConferenceParticipantRemoved, .ConferenceParticipantDeviceAdded, .ConferenceParticipantDeviceRemoved:
iconValue = Image("door")
default:
iconValue = Image("user-circle")
}
DispatchQueue.main.async {
self.text = textValue
self.icon = iconValue
}
}
}
}
private func formatEphemeralExpiration(duration: Int64) -> String {
switch duration {
case 0:
return NSLocalizedString("conversation_ephemeral_messages_duration_disabled", comment: "")
case 60:
return NSLocalizedString("conversation_ephemeral_messages_duration_one_minute", comment: "")
case 3600:
return NSLocalizedString("conversation_ephemeral_messages_duration_one_hour", comment: "")
case 86400:
return NSLocalizedString("conversation_ephemeral_messages_duration_one_day", comment: "")
case 259200:
return NSLocalizedString("conversation_ephemeral_messages_duration_three_days", comment: "")
case 604800:
return NSLocalizedString("conversation_ephemeral_messages_duration_one_week", comment: "")
default:
return "\(duration) s"
}
}
}

View file

@ -280,7 +280,7 @@ class ConversationForwardMessageViewModel: ObservableObject {
func forwardMessage() {
CoreContext.shared.doOnCoreQueue { _ in
if self.displayedConversation != nil && self.selectedMessage != nil {
if let messageToForward = self.selectedMessage!.eventLog.chatMessage {
if let messageToForward = self.selectedMessage!.eventModel.eventLog.chatMessage {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
do {
let forwardedMessage = try self.displayedConversation!.chatRoom.createForwardMessage(message: messageToForward)

View file

@ -125,7 +125,7 @@ class ConversationViewModel: ObservableObject {
}
if !self.conversationMessagesSection.isEmpty && !self.conversationMessagesSection[0].rows.isEmpty {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventLog.chatMessage?.messageId == message.messageId}) {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId}) {
if indexMessage < self.conversationMessagesSection[0].rows.count && self.conversationMessagesSection[0].rows[indexMessage].message.status != statusTmp {
DispatchQueue.main.async {
self.objectWillChange.send()
@ -153,7 +153,7 @@ class ConversationViewModel: ObservableObject {
statusTmp = .sending
}
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventLog.chatMessage?.messageId == message.messageId})
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId})
DispatchQueue.main.async {
if indexMessage != nil {
@ -162,7 +162,7 @@ class ConversationViewModel: ObservableObject {
}
}
}, onNewMessageReaction: { (message: ChatMessage, _: ChatMessageReaction) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventLog.chatMessage?.messageId == message.messageId})
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId})
var reactionsTmp: [String] = []
message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
@ -175,7 +175,7 @@ class ConversationViewModel: ObservableObject {
}
}
}, onReactionRemoved: { (message: ChatMessage, _: Address) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventLog.chatMessage?.messageId == message.messageId})
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.messageId})
var reactionsTmp: [String] = []
message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
@ -453,7 +453,7 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil {
conversationMessage.append(
EventLogMessage(
eventLog: eventLog,
eventModel: EventModel(eventLog: eventLog),
message: Message(
id: !eventLog.chatMessage!.messageId.isEmpty ? eventLog.chatMessage!.messageId : UUID().uuidString,
status: statusTmp,
@ -474,9 +474,9 @@ class ConversationViewModel: ObservableObject {
self.addChatMessageDelegate(message: eventLog.chatMessage!)
} else {
conversationMessage.insert(
conversationMessage.append(
EventLogMessage(
eventLog: eventLog,
eventModel: EventModel(eventLog: eventLog),
message: Message(
id: UUID().uuidString,
status: nil,
@ -489,7 +489,7 @@ class ConversationViewModel: ObservableObject {
ownReaction: "",
reactions: []
)
), at: 0
)
)
}
}
@ -672,7 +672,7 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil {
conversationMessagesTmp.insert(
EventLogMessage(
eventLog: eventLog,
eventModel: EventModel(eventLog: eventLog),
message: Message(
id: !eventLog.chatMessage!.messageId.isEmpty ? eventLog.chatMessage!.messageId : UUID().uuidString,
status: statusTmp,
@ -695,7 +695,7 @@ class ConversationViewModel: ObservableObject {
} else {
conversationMessagesTmp.insert(
EventLogMessage(
eventLog: eventLog,
eventModel: EventModel(eventLog: eventLog),
message: Message(
id: UUID().uuidString,
status: nil,
@ -902,7 +902,7 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil {
let message = EventLogMessage(
eventLog: eventLog,
eventModel: EventModel(eventLog: eventLog),
message: Message(
id: !eventLog.chatMessage!.messageId.isEmpty ? eventLog.chatMessage!.messageId : UUID().uuidString,
appData: eventLog.chatMessage!.appdata ?? "",
@ -943,7 +943,7 @@ class ConversationViewModel: ObservableObject {
}
} else {
let message = EventLogMessage(
eventLog: eventLog,
eventModel: EventModel(eventLog: eventLog),
message: Message(
id: UUID().uuidString,
status: nil,
@ -987,7 +987,7 @@ class ConversationViewModel: ObservableObject {
func scrollToMessage(message: Message) {
coreContext.doOnCoreQueue { _ in
if message.replyMessage != nil {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventLog.chatMessage?.messageId == message.replyMessage!.id}) {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLog.chatMessage?.messageId == message.replyMessage!.id}) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onScrollToIndex"), object: nil, userInfo: ["index": indexMessage, "animated": true])
} else {
if self.conversationMessagesSection[0].rows.last != nil {
@ -1177,7 +1177,7 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil {
conversationMessagesTmp.insert(
EventLogMessage(
eventLog: eventLog,
eventModel: EventModel(eventLog: eventLog),
message: Message(
id: !eventLog.chatMessage!.messageId.isEmpty ? eventLog.chatMessage!.messageId : UUID().uuidString,
status: statusTmp,
@ -1200,7 +1200,7 @@ class ConversationViewModel: ObservableObject {
} else {
conversationMessagesTmp.insert(
EventLogMessage(
eventLog: eventLog,
eventModel: EventModel(eventLog: eventLog),
message: Message(
id: UUID().uuidString,
status: nil,
@ -1243,7 +1243,7 @@ class ConversationViewModel: ObservableObject {
do {
var message: ChatMessage?
if self.messageToReply != nil {
let chatMessageToReply = self.messageToReply!.eventLog.chatMessage
let chatMessageToReply = self.messageToReply!.eventModel.eventLog.chatMessage
if chatMessageToReply != nil {
message = try self.displayedConversation!.chatRoom.createReplyMessage(message: chatMessageToReply!)
}
@ -1482,7 +1482,7 @@ class ConversationViewModel: ObservableObject {
coreContext.doOnCoreQueue { _ in
if self.selectedMessageToDisplayDetails != nil {
Log.info("[ConversationViewModel] Remove reaction to message with ID \(self.selectedMessageToDisplayDetails!.message.id)")
let messageToSendReaction = self.selectedMessageToDisplayDetails!.eventLog.chatMessage
let messageToSendReaction = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage
if messageToSendReaction != nil {
do {
let reaction = try messageToSendReaction!.createReaction(utf8Reaction: "")
@ -1509,7 +1509,7 @@ class ConversationViewModel: ObservableObject {
coreContext.doOnCoreQueue { _ in
if self.selectedMessage != nil {
Log.info("[ConversationViewModel] Sending reaction \(emoji) to message with ID \(self.selectedMessage!.message.id)")
let messageToSendReaction = self.selectedMessage!.eventLog.chatMessage
let messageToSendReaction = self.selectedMessage!.eventModel.eventLog.chatMessage
if messageToSendReaction != nil {
do {
let reaction = try messageToSendReaction!.createReaction(utf8Reaction: messageToSendReaction?.ownReaction?.body == emoji ? "" : emoji)
@ -1533,9 +1533,9 @@ class ConversationViewModel: ObservableObject {
func resend() {
coreContext.doOnCoreQueue { _ in
if self.selectedMessage != nil && self.selectedMessage!.eventLog.chatMessage != nil {
Log.info("[ConversationViewModel] Re-sending message with ID \(self.selectedMessage!.eventLog.chatMessage!)")
self.selectedMessage!.eventLog.chatMessage!.send()
if self.selectedMessage != nil && self.selectedMessage!.eventModel.eventLog.chatMessage != nil {
Log.info("[ConversationViewModel] Re-sending message with ID \(self.selectedMessage!.eventModel.eventLog.chatMessage!)")
self.selectedMessage!.eventModel.eventLog.chatMessage!.send()
}
}
}
@ -1543,9 +1543,9 @@ class ConversationViewModel: ObservableObject {
func prepareBottomSheetForDeliveryStatus() {
self.sheetCategories.removeAll()
coreContext.doOnCoreQueue { _ in
if self.selectedMessageToDisplayDetails != nil && self.selectedMessageToDisplayDetails!.eventLog.chatMessage != nil {
if self.selectedMessageToDisplayDetails != nil && self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage != nil {
let participantsImdnDisplayed = self.selectedMessageToDisplayDetails!.eventLog.chatMessage!.getParticipantsByImdnState(state: .Displayed)
let participantsImdnDisplayed = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.getParticipantsByImdnState(state: .Displayed)
var participantListDisplayed: [InnerSheetCategory] = []
participantsImdnDisplayed.forEach({ participantImdn in
if participantImdn.participant != nil && participantImdn.participant!.address != nil {
@ -1556,7 +1556,7 @@ class ConversationViewModel: ObservableObject {
}
})
let participantsImdnDeliveredToUser = self.selectedMessageToDisplayDetails!.eventLog.chatMessage!.getParticipantsByImdnState(state: .DeliveredToUser)
let participantsImdnDeliveredToUser = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.getParticipantsByImdnState(state: .DeliveredToUser)
var participantListDeliveredToUser: [InnerSheetCategory] = []
participantsImdnDeliveredToUser.forEach({ participantImdn in
if participantImdn.participant != nil && participantImdn.participant!.address != nil {
@ -1567,7 +1567,7 @@ class ConversationViewModel: ObservableObject {
}
})
let participantsImdnDelivered = self.selectedMessageToDisplayDetails!.eventLog.chatMessage!.getParticipantsByImdnState(state: .Delivered)
let participantsImdnDelivered = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.getParticipantsByImdnState(state: .Delivered)
var participantListDelivered: [InnerSheetCategory] = []
participantsImdnDelivered.forEach({ participantImdn in
if participantImdn.participant != nil && participantImdn.participant!.address != nil {
@ -1578,7 +1578,7 @@ class ConversationViewModel: ObservableObject {
}
})
let participantsImdnNotDelivered = self.selectedMessageToDisplayDetails!.eventLog.chatMessage!.getParticipantsByImdnState(state: .NotDelivered)
let participantsImdnNotDelivered = self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.getParticipantsByImdnState(state: .NotDelivered)
var participantListNotDelivered: [InnerSheetCategory] = []
participantsImdnNotDelivered.forEach({ participantImdn in
if participantImdn.participant != nil && participantImdn.participant!.address != nil {
@ -1604,7 +1604,7 @@ class ConversationViewModel: ObservableObject {
func prepareBottomSheetForReactions() {
self.sheetCategories.removeAll()
coreContext.doOnCoreQueue { core in
if self.selectedMessageToDisplayDetails != nil && self.selectedMessageToDisplayDetails!.eventLog.chatMessage != nil {
if self.selectedMessageToDisplayDetails != nil && self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage != nil {
let dispatchGroup = DispatchGroup()
var sheetCategoriesTmp: [SheetCategory] = []
@ -1612,7 +1612,7 @@ class ConversationViewModel: ObservableObject {
var participantList: [[InnerSheetCategory]] = [[]]
var reactionList: [String] = []
self.selectedMessageToDisplayDetails!.eventLog.chatMessage!.reactions.forEach { chatMessageReaction in
self.selectedMessageToDisplayDetails!.eventModel.eventLog.chatMessage!.reactions.forEach { chatMessageReaction in
if chatMessageReaction.fromAddress != nil {
dispatchGroup.enter()
ContactAvatarModel.getAvatarModelFromAddress(address: chatMessageReaction.fromAddress!) { avatarResult in
@ -1701,6 +1701,14 @@ class ConversationViewModel: ObservableObject {
}
}
}
func compose() {
coreContext.doOnCoreQueue { _ in
if self.displayedConversation != nil {
self.displayedConversation!.chatRoom.compose()
}
}
}
}
// swiftlint:enable line_length
// swiftlint:enable type_body_length