Add eventLog to ui message object for message list

This commit is contained in:
Benoit Martins 2024-08-26 10:52:15 +02:00
parent e792810c3c
commit ace392528b
6 changed files with 311 additions and 254 deletions

View file

@ -7,7 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
4ED1F0A881A9ACB5977A8987 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
4ED1F0A881A9ACB5977A8987 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
660AAF7F2B839272004C0FA6 /* msgNotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
660D8A712B517D260092694D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 660D8A702B517D260092694D /* GoogleService-Info.plist */; };
6613A0AE2BAEB7DF008923A4 /* MeetingFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6613A0AD2BAEB7DF008923A4 /* MeetingFragment.swift */; };
@ -364,7 +364,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4ED1F0A881A9ACB5977A8987 /* BuildFile in Frameworks */,
4ED1F0A881A9ACB5977A8987 /* (null) in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1238,7 +1238,7 @@
INFOPLIST_FILE = msgNotificationService/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = msgNotificationService;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -1277,7 +1277,7 @@
INFOPLIST_FILE = msgNotificationService/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = msgNotificationService;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -1422,7 +1422,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = Linphone/Linphone.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 32;
CURRENT_PROJECT_VERSION = 36;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "\"Linphone/Preview Content\"";
@ -1478,7 +1478,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = Linphone/Linphone.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 32;
CURRENT_PROJECT_VERSION = 36;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"Linphone/Preview Content\"";
DEVELOPMENT_TEAM = Z2V957B3D6;

View file

@ -24,7 +24,7 @@ struct ChatBubbleView: View {
@ObservedObject var conversationViewModel: ConversationViewModel
let message: Message
let eventLogMessage: EventLogMessage
let geometryProxy: GeometryProxy
@ -35,50 +35,50 @@ struct ChatBubbleView: View {
var body: some View {
HStack {
VStack {
if !message.text.isEmpty || !message.attachments.isEmpty {
if !eventLogMessage.message.text.isEmpty || !eventLogMessage.message.attachments.isEmpty {
HStack(alignment: .top, content: {
if message.isOutgoing {
if eventLogMessage.message.isOutgoing {
Spacer()
}
if conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup && !message.isOutgoing && message.isFirstMessage {
if conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup && !eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage {
VStack {
Avatar(
contactAvatarModel: conversationViewModel.participantConversationModel.first(where: {$0.address == message.address}) ??
contactAvatarModel: conversationViewModel.participantConversationModel.first(where: {$0.address == eventLogMessage.message.address}) ??
ContactAvatarModel(friend: nil, name: "??", address: "", withPresence: false),
avatarSize: 35
)
.padding(.top, 30)
}
} else if conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup && !message.isOutgoing {
} 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 && !message.isOutgoing && message.isFirstMessage {
Text(conversationViewModel.participantConversationModel.first(where: {$0.address == message.address})?.name ?? "")
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 message.replyMessage != nil {
if eventLogMessage.message.replyMessage != nil {
HStack {
if message.isOutgoing {
if eventLogMessage.message.isOutgoing {
Spacer()
}
VStack(alignment: message.isOutgoing ? .trailing : .leading) {
VStack(alignment: message.isOutgoing ? .trailing : .leading) {
if !message.replyMessage!.text.isEmpty {
Text(message.replyMessage!.text)
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading) {
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 !message.replyMessage!.attachmentsNames.isEmpty {
Text(message.replyMessage!.attachmentsNames)
} 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@*/)
@ -90,14 +90,14 @@ struct ChatBubbleView: View {
.clipShape(RoundedRectangle(cornerRadius: 1))
.roundedCorner(
16,
corners: message.isOutgoing ? [.topLeft, .topRight, .bottomLeft] : [.topLeft, .topRight, .bottomRight]
corners: eventLogMessage.message.isOutgoing ? [.topLeft, .topRight, .bottomLeft] : [.topLeft, .topRight, .bottomRight]
)
}
.onTapGesture {
conversationViewModel.scrollToMessage(message: message)
conversationViewModel.scrollToMessage(message: eventLogMessage.message)
}
if !message.isOutgoing {
if !eventLogMessage.message.isOutgoing {
Spacer()
}
}
@ -107,37 +107,37 @@ struct ChatBubbleView: View {
ZStack {
HStack {
if message.isOutgoing {
if eventLogMessage.message.isOutgoing {
Spacer()
}
VStack(alignment: message.isOutgoing ? .trailing : .leading) {
VStack(alignment: message.isOutgoing ? .trailing : .leading) {
if !message.attachments.isEmpty {
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading) {
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading) {
if !eventLogMessage.message.attachments.isEmpty {
messageAttachments()
}
if !message.text.isEmpty {
Text(message.text)
if !eventLogMessage.message.text.isEmpty {
Text(eventLogMessage.message.text)
.foregroundStyle(Color.grayMain2c700)
.default_text_style(styleSize: 16)
}
HStack(alignment: .center) {
Text(conversationViewModel.getMessageTime(startDate: message.dateReceived))
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) || message.isOutgoing {
if message.status == .sending {
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 message.status != nil {
Image(conversationViewModel.getImageIMDN(status: message.status!))
} else if eventLogMessage.message.status != nil {
Image(conversationViewModel.getImageIMDN(status: eventLogMessage.message.status!))
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.orangeMain500)
@ -149,49 +149,49 @@ struct ChatBubbleView: View {
.padding(.top, -4)
}
.padding(.all, 15)
.background(message.isOutgoing ? Color.orangeMain100 : Color.grayMain2c100)
.background(eventLogMessage.message.isOutgoing ? Color.orangeMain100 : Color.grayMain2c100)
.clipShape(RoundedRectangle(cornerRadius: 3))
.roundedCorner(
16,
corners: message.isOutgoing && message.isFirstMessage ? [.topLeft, .topRight, .bottomLeft] :
(!message.isOutgoing && message.isFirstMessage ? [.topRight, .bottomRight, .bottomLeft] : [.allCorners]))
corners: eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage ? [.topLeft, .topRight, .bottomLeft] :
(!eventLogMessage.message.isOutgoing && eventLogMessage.message.isFirstMessage ? [.topRight, .bottomRight, .bottomLeft] : [.allCorners]))
if !message.reactions.isEmpty {
if !eventLogMessage.message.reactions.isEmpty {
HStack {
ForEach(0..<message.reactions.count, id: \.self) { index in
if message.reactions.firstIndex(of: message.reactions[index]) == index {
Text(message.reactions[index])
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 (
(message.reactions.contains("👍") ? 1 : 0) +
(message.reactions.contains("❤️") ? 1 : 0) +
(message.reactions.contains("😂") ? 1 : 0) +
(message.reactions.contains("😮") ? 1 : 0) +
(message.reactions.contains("😢") ? 1 : 0)
) != message.reactions.count {
Text("\(message.reactions.count)")
(eventLogMessage.message.reactions.contains("👍") ? 1 : 0) +
(eventLogMessage.message.reactions.contains("❤️") ? 1 : 0) +
(eventLogMessage.message.reactions.contains("😂") ? 1 : 0) +
(eventLogMessage.message.reactions.contains("😮") ? 1 : 0) +
(eventLogMessage.message.reactions.contains("😢") ? 1 : 0)
) != eventLogMessage.message.reactions.count {
Text("\(eventLogMessage.message.reactions.count)")
.default_text_style(styleSize: 14)
.padding(.horizontal, -2)
}
}
.padding(.vertical, 6)
.padding(.horizontal, 10)
.background(message.isOutgoing ? Color.orangeMain100 : Color.grayMain2c100)
.background(eventLogMessage.message.isOutgoing ? Color.orangeMain100 : Color.grayMain2c100)
.cornerRadius(20)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(.white, lineWidth: 3)
)
.padding(.top, -20)
.padding(message.isOutgoing ? .trailing : .leading, 5)
.padding(eventLogMessage.message.isOutgoing ? .trailing : .leading, 5)
}
}
if !message.isOutgoing {
if !eventLogMessage.message.isOutgoing {
Spacer()
}
}
@ -200,12 +200,12 @@ struct ChatBubbleView: View {
.frame(maxWidth: .infinity)
}
if !message.isOutgoing {
if !eventLogMessage.message.isOutgoing {
Spacer()
}
})
.padding(.leading, message.isOutgoing ? 40 : 0)
.padding(.trailing, !message.isOutgoing ? 40 : 0)
.padding(.leading, eventLogMessage.message.isOutgoing ? 40 : 0)
.padding(.trailing, !eventLogMessage.message.isOutgoing ? 40 : 0)
}
}
.onTapGesture {}
@ -226,7 +226,7 @@ struct ChatBubbleView: View {
self.timePassed = self.ticker.timeIntervalSinceStarted
withAnimation {
conversationViewModel.selectedMessage = message
conversationViewModel.selectedMessage = eventLogMessage
}
}
@ -242,9 +242,9 @@ struct ChatBubbleView: View {
@ViewBuilder
func messageAttachments() -> some View {
if message.attachments.count == 1 {
if message.attachments.first!.type == .image || message.attachments.first!.type == .gif || message.attachments.first!.type == .video {
let result = imageDimensions(url: message.attachments.first!.thumbnail.absoluteString)
if eventLogMessage.message.attachments.count == 1 {
if eventLogMessage.message.attachments.first!.type == .image || eventLogMessage.message.attachments.first!.type == .gif || eventLogMessage.message.attachments.first!.type == .video {
let result = imageDimensions(url: eventLogMessage.message.attachments.first!.thumbnail.absoluteString)
ZStack {
Rectangle()
.fill(Color(.white))
@ -268,9 +268,9 @@ struct ChatBubbleView: View {
)
}
if message.attachments.first!.type == .image || message.attachments.first!.type == .video {
if eventLogMessage.message.attachments.first!.type == .image || eventLogMessage.message.attachments.first!.type == .video {
if #available(iOS 16.0, *) {
AsyncImage(url: message.attachments.first!.thumbnail) { phase in
AsyncImage(url: eventLogMessage.message.attachments.first!.thumbnail) { phase in
switch phase {
case .empty:
ProgressView()
@ -281,7 +281,7 @@ struct ChatBubbleView: View {
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
if message.attachments.first!.type == .video {
if eventLogMessage.message.attachments.first!.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
@ -298,7 +298,7 @@ struct ChatBubbleView: View {
.layoutPriority(-1)
.clipShape(RoundedRectangle(cornerRadius: 4))
} else {
AsyncImage(url: message.attachments.first!.thumbnail) { phase in
AsyncImage(url: eventLogMessage.message.attachments.first!.thumbnail) { phase in
switch phase {
case .empty:
ProgressView()
@ -309,7 +309,7 @@ struct ChatBubbleView: View {
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
if message.attachments.first!.type == .video {
if eventLogMessage.message.attachments.first!.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
@ -327,13 +327,13 @@ struct ChatBubbleView: View {
.clipShape(RoundedRectangle(cornerRadius: 4))
.id(UUID())
}
} else if message.attachments.first!.type == .gif {
} else if eventLogMessage.message.attachments.first!.type == .gif {
if #available(iOS 16.0, *) {
GifImageView(message.attachments.first!.thumbnail)
GifImageView(eventLogMessage.message.attachments.first!.thumbnail)
.layoutPriority(-1)
.clipShape(RoundedRectangle(cornerRadius: 4))
} else {
GifImageView(message.attachments.first!.thumbnail)
GifImageView(eventLogMessage.message.attachments.first!.thumbnail)
.id(UUID())
.layoutPriority(-1)
.clipShape(RoundedRectangle(cornerRadius: 4))
@ -343,12 +343,12 @@ struct ChatBubbleView: View {
.clipShape(RoundedRectangle(cornerRadius: 4))
.clipped()
}
} else if message.attachments.count > 1 {
} else if eventLogMessage.message.attachments.count > 1 {
let isGroup = conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup
LazyVGrid(columns: [
GridItem(.adaptive(minimum: 120), spacing: 1)
], spacing: 3) {
ForEach(message.attachments) { attachment in
ForEach(eventLogMessage.message.attachments) { attachment in
ZStack {
Rectangle()
.fill(Color(.white))
@ -402,9 +402,9 @@ struct ChatBubbleView: View {
}
}
.frame(
width: geometryProxy.size.width > 0 && CGFloat(122 * message.attachments.count) > geometryProxy.size.width - 110 - (isGroup ? 40 : 0)
width: geometryProxy.size.width > 0 && CGFloat(122 * eventLogMessage.message.attachments.count) > geometryProxy.size.width - 110 - (isGroup ? 40 : 0)
? 122 * floor(CGFloat(geometryProxy.size.width - 110 - (isGroup ? 40 : 0)) / 122)
: CGFloat(122 * message.attachments.count)
: CGFloat(122 * eventLogMessage.message.attachments.count)
)
}
}

View file

@ -235,8 +235,8 @@ struct ConversationFragment: View {
if conversationViewModel.conversationMessagesSection.first != nil {
let counter = conversationViewModel.conversationMessagesSection.first!.rows.count
ForEach(0..<counter, id: \.self) { index in
ChatBubbleView(conversationViewModel: conversationViewModel, message: conversationViewModel.conversationMessagesSection.first!.rows[index], geometryProxy: geometry)
.id(conversationViewModel.conversationMessagesSection.first!.rows[index].id)
ChatBubbleView(conversationViewModel: conversationViewModel, eventLogMessage: conversationViewModel.conversationMessagesSection.first!.rows[index], geometryProxy: geometry)
.id(conversationViewModel.conversationMessagesSection.first!.rows[index].message.id)
.listRowInsets(EdgeInsets(top: 2, leading: 10, bottom: 2, trailing: 10))
.listRowSeparator(.hidden)
.scaleEffect(x: 1, y: -1, anchor: .center)
@ -250,6 +250,8 @@ struct ConversationFragment: View {
if index == 0 {
displayFloatingButton = false
conversationViewModel.markAsRead()
conversationsListViewModel.computeChatRoomsList(filter: "")
}
}
.onDisappear {
@ -262,12 +264,16 @@ struct ConversationFragment: View {
}
.scaleEffect(x: 1, y: -1, anchor: .center)
.listStyle(.plain)
.onAppear {
conversationViewModel.markAsRead()
conversationsListViewModel.computeChatRoomsList(filter: "")
}
if displayFloatingButton {
Button {
if conversationViewModel.conversationMessagesSection.first != nil && conversationViewModel.conversationMessagesSection.first!.rows.first != nil {
withAnimation {
proxy.scrollTo(conversationViewModel.conversationMessagesSection.first!.rows.first!.id)
proxy.scrollTo(conversationViewModel.conversationMessagesSection.first!.rows.first!.message.id)
}
}
} label: {
@ -327,19 +333,19 @@ struct ConversationFragment: View {
VStack {
(
Text("conversation_reply_to_message_title")
+ Text("**\(conversationViewModel.participantConversationModel.first(where: {$0.address == conversationViewModel.messageToReply!.address})?.name ?? "")**"))
+ Text("**\(conversationViewModel.participantConversationModel.first(where: {$0.address == conversationViewModel.messageToReply!.message.address})?.name ?? "")**"))
.default_text_style_300(styleSize: 15)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.bottom, 1)
.lineLimit(1)
if conversationViewModel.messageToReply!.text.isEmpty {
Text(conversationViewModel.messageToReply!.attachmentsNames)
if conversationViewModel.messageToReply!.message.text.isEmpty {
Text(conversationViewModel.messageToReply!.message.attachmentsNames)
.default_text_style_300(styleSize: 15)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
} else {
Text("\(conversationViewModel.messageToReply!.text)")
Text("\(conversationViewModel.messageToReply!.message.text)")
.default_text_style_300(styleSize: 15)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
@ -586,7 +592,7 @@ struct ConversationFragment: View {
VStack {
HStack {
if conversationViewModel.selectedMessage!.isOutgoing {
if conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
@ -598,7 +604,7 @@ struct ConversationFragment: View {
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.ownReaction == "👍" ? Color.gray200 : .white)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "👍" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
@ -608,7 +614,7 @@ struct ConversationFragment: View {
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.ownReaction == "❤️" ? Color.gray200 : .white)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "❤️" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
@ -618,7 +624,7 @@ struct ConversationFragment: View {
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.ownReaction == "😂" ? Color.gray200 : .white)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "😂" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
@ -628,7 +634,7 @@ struct ConversationFragment: View {
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.ownReaction == "😮" ? Color.gray200 : .white)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "😮" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
@ -638,7 +644,7 @@ struct ConversationFragment: View {
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.ownReaction == "😢" ? Color.gray200 : .white)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "😢" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
@ -656,7 +662,7 @@ struct ConversationFragment: View {
.background(.white)
.cornerRadius(20)
if !conversationViewModel.selectedMessage!.isOutgoing {
if !conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
}
@ -665,19 +671,19 @@ struct ConversationFragment: View {
.padding(.leading, conversationViewModel.displayedConversation!.isGroup ? 43 : 0)
.shadow(color: .black.opacity(0.1), radius: 10)
ChatBubbleView(conversationViewModel: conversationViewModel, message: conversationViewModel.selectedMessage!, geometryProxy: geometry)
ChatBubbleView(conversationViewModel: conversationViewModel, eventLogMessage: conversationViewModel.selectedMessage!, geometryProxy: geometry)
.padding(.horizontal, 10)
.padding(.vertical, 1)
.shadow(color: .black.opacity(0.1), radius: 10)
HStack {
if conversationViewModel.selectedMessage!.isOutgoing {
if conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
VStack {
Button {
let indexMessage = conversationViewModel.conversationMessagesSection[0].rows.firstIndex(where: {$0.id == conversationViewModel.selectedMessage!.id})
let indexMessage = conversationViewModel.conversationMessagesSection[0].rows.firstIndex(where: {$0.message.id == conversationViewModel.selectedMessage!.message.id})
conversationViewModel.selectedMessage = nil
conversationViewModel.replyToMessage(index: indexMessage ?? 0)
} label: {
@ -695,10 +701,10 @@ struct ConversationFragment: View {
Divider()
if !conversationViewModel.selectedMessage!.text.isEmpty {
if !conversationViewModel.selectedMessage!.message.text.isEmpty {
Button {
UIPasteboard.general.setValue(
conversationViewModel.selectedMessage!.text,
conversationViewModel.selectedMessage!.message.text,
forPasteboardType: UTType.plainText.identifier
)
@ -760,7 +766,7 @@ struct ConversationFragment: View {
.background(.white)
.cornerRadius(20)
if !conversationViewModel.selectedMessage!.isOutgoing {
if !conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
}

View file

@ -19,6 +19,7 @@
// swiftlint:disable large_tuple
import SwiftUI
import linphonesw
public extension Notification.Name {
static let onScrollToBottom = Notification.Name("onScrollToBottom")
@ -64,7 +65,7 @@ struct UIList: UIViewRepresentable {
&& conversationViewModel.displayedConversation != nil
&& context.coordinator.sections.first!.chatRoomID == conversationViewModel.displayedConversation!.id
&& context.coordinator.sections.first!.rows.count == conversationViewModel.conversationMessagesSection.first!.rows.count {
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .bottom, animated: true)
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
} else {
NotificationCenter.default.removeObserver(self, name: .onScrollToBottom, object: nil)
}
@ -209,24 +210,26 @@ struct UIList: UIViewRepresentable {
var oldRows = appliedDeletes[oldIndex].rows
var newRows = appliedDeletesSwapsAndEdits[newIndex].rows
let oldRowIDs = Set(oldRows.map { $0.id })
let newRowIDs = Set(newRows.map { $0.id })
let oldRowIDs = Set(oldRows.map { $0.message.id })
let newRowIDs = Set(newRows.map { $0.message.id })
let rowIDsToDelete = oldRowIDs.subtracting(newRowIDs)
let rowIDsToInsert = newRowIDs.subtracting(oldRowIDs)
for rowId in rowIDsToDelete {
if let index = oldRows.firstIndex(where: { $0.id == rowId }) {
if let index = oldRows.firstIndex(where: { $0.message.id == rowId }) {
oldRows.remove(at: index)
deleteOperations.append(.delete(oldIndex, index))
}
}
for rowId in rowIDsToInsert {
if let index = newRows.firstIndex(where: { $0.id == rowId }) {
if let index = newRows.firstIndex(where: { $0.message.id == rowId }) {
insertOperations.append(.insert(newIndex, index))
}
}
for rowId in rowIDsToInsert {
if let index = newRows.firstIndex(where: { $0.id == rowId }) {
if let index = newRows.firstIndex(where: { $0.message.id == rowId }) {
newRows.remove(at: index)
}
}
@ -234,8 +237,8 @@ struct UIList: UIViewRepresentable {
for row in 0..<oldRows.count {
let oldRow = oldRows[row]
let newRow = newRows[row]
if oldRow.id != newRow.id {
if let index = newRows.firstIndex(where: { $0.id == oldRow.id }) {
if oldRow.message.id != newRow.message.id {
if let index = newRows.firstIndex(where: { $0.message.id == oldRow.message.id }) {
if !swapsContain(swaps: swapOperations, section: oldIndex, index: row) ||
!swapsContain(swaps: swapOperations, section: oldIndex, index: index) {
swapOperations.append(.swap(oldIndex, row, index))
@ -338,7 +341,7 @@ struct UIList: UIViewRepresentable {
let row = sections[indexPath.section].rows[indexPath.row]
if #available(iOS 16.0, *) {
tableViewCell.contentConfiguration = UIHostingConfiguration {
ChatBubbleView(conversationViewModel: conversationViewModel, message: row, geometryProxy: geometryProxy)
ChatBubbleView(conversationViewModel: conversationViewModel, eventLogMessage: row, geometryProxy: geometryProxy)
.padding(.vertical, 2)
.padding(.horizontal, 10)
.onTapGesture { }
@ -354,7 +357,7 @@ struct UIList: UIViewRepresentable {
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let row = sections[indexPath.section].rows[indexPath.row]
paginationState.handle(row)
paginationState.handle(row.message)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
@ -367,7 +370,10 @@ struct UIList: UIViewRepresentable {
if !isScrolledToTop && scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.height - 200 {
self.conversationViewModel.getOldMessages()
}
isScrolledToTop = scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.height - 200
DispatchQueue.main.async {
self.isScrolledToTop = scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.frame.height - 200
}
}
func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
@ -390,7 +396,7 @@ struct MessagesSection: Equatable {
let date: Date
let chatRoomID: String
var rows: [Message]
var rows: [EventLogMessage]
static var formatter = {
let formatter = DateFormatter()
@ -398,7 +404,7 @@ struct MessagesSection: Equatable {
return formatter
}()
init(date: Date, chatRoomID: String, rows: [Message]) {
init(date: Date, chatRoomID: String, rows: [EventLogMessage]) {
self.date = date
self.chatRoomID = chatRoomID
self.rows = rows
@ -414,6 +420,28 @@ struct MessagesSection: Equatable {
}
struct EventLogMessage: Equatable {
let eventLog: EventLog
var message: Message
static var formatter = {
let formatter = DateFormatter()
formatter.dateFormat = "EEEE, MMMM d"
return formatter
}()
init(eventLog: EventLog, message: Message) {
self.eventLog = eventLog
self.message = message
}
static func == (lhs: EventLogMessage, rhs: EventLogMessage) -> Bool {
lhs.message == rhs.message
}
}
final class PaginationState: ObservableObject {
var onEvent: ChatPaginationClosure?
var offset: Int

View file

@ -62,6 +62,7 @@ public struct Message: Identifiable, Hashable {
}
public var id: String
public var appData: String
public var status: Status?
public var createdAt: Date
public var isOutgoing: Bool
@ -79,6 +80,7 @@ public struct Message: Identifiable, Hashable {
public init(
id: String,
appData: String = "",
status: Status? = nil,
createdAt: Date = Date(),
isOutgoing: Bool,
@ -94,6 +96,7 @@ public struct Message: Identifiable, Hashable {
reactions: [String] = []
) {
self.id = id
self.appData = appData
self.status = status
self.createdAt = createdAt
self.isOutgoing = isOutgoing

View file

@ -45,8 +45,8 @@ class ConversationViewModel: ObservableObject {
var oldMessageReceived = false
@Published var selectedMessage: Message?
@Published var messageToReply: Message?
@Published var selectedMessage: EventLogMessage?
@Published var messageToReply: EventLogMessage?
init() {}
@ -79,22 +79,24 @@ class ConversationViewModel: ObservableObject {
statusTmp = .received
case .Displayed:
statusTmp = .read
case .NotDelivered:
statusTmp = .error
default:
statusTmp = .sending
}
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.id == message.messageId})
var indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventLog.chatMessage?.messageId == message.messageId})
DispatchQueue.main.async {
if indexMessage != nil {
self.objectWillChange.send()
self.conversationMessagesSection[0].rows[indexMessage!].status = statusTmp
self.conversationMessagesSection[0].rows[indexMessage!].message.status = statusTmp
}
}
})
self.chatMessageSuscriptions.insert(message.publisher?.onNewMessageReaction?.postOnCoreQueue {(cbValue: (message: ChatMessage, reaction: ChatMessageReaction)) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.id == message.messageId})
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventLog.chatMessage?.messageId == message.messageId})
var reactionsTmp: [String] = []
cbValue.message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
@ -103,13 +105,13 @@ class ConversationViewModel: ObservableObject {
DispatchQueue.main.async {
if indexMessage != nil {
self.objectWillChange.send()
self.conversationMessagesSection[0].rows[indexMessage!].reactions = reactionsTmp
self.conversationMessagesSection[0].rows[indexMessage!].message.reactions = reactionsTmp
}
}
})
self.chatMessageSuscriptions.insert(message.publisher?.onReactionRemoved?.postOnCoreQueue {(cbValue: (message: ChatMessage, address: Address)) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.id == message.messageId})
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventLog.chatMessage?.messageId == message.messageId})
var reactionsTmp: [String] = []
cbValue.message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
@ -118,7 +120,7 @@ class ConversationViewModel: ObservableObject {
DispatchQueue.main.async {
if indexMessage != nil {
self.objectWillChange.send()
self.conversationMessagesSection[0].rows[indexMessage!].reactions = reactionsTmp
self.conversationMessagesSection[0].rows[indexMessage!].message.reactions = reactionsTmp
}
}
})
@ -156,13 +158,15 @@ class ConversationViewModel: ObservableObject {
func markAsRead() {
coreContext.doOnCoreQueue { _ in
let unreadMessagesCount = self.displayedConversation!.chatRoom.unreadMessagesCount
if unreadMessagesCount > 0 {
self.displayedConversation!.chatRoom.markAsRead()
if self.displayedConversation != nil {
let unreadMessagesCount = self.displayedConversation!.chatRoom.unreadMessagesCount
DispatchQueue.main.async {
self.displayedConversationUnreadMessagesCount = 0
if unreadMessagesCount > 0 {
self.displayedConversation!.chatRoom.markAsRead()
DispatchQueue.main.async {
self.displayedConversationUnreadMessagesCount = 0
}
}
}
}
@ -206,7 +210,7 @@ class ConversationViewModel: ObservableObject {
if self.displayedConversation != nil {
let historyEvents = self.displayedConversation!.chatRoom.getHistoryRangeEvents(begin: 0, end: 30)
var conversationMessage: [Message] = []
var conversationMessage: [EventLogMessage] = []
historyEvents.enumerated().forEach { index, eventLog in
var attachmentNameList: String = ""
@ -342,36 +346,42 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil {
conversationMessage.append(
Message(
id: eventLog.chatMessage?.messageId ?? UUID().uuidString,
status: statusTmp,
isOutgoing: eventLog.chatMessage?.isOutgoing ?? false,
dateReceived: eventLog.chatMessage?.time ?? 0,
address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp,
text: contentText,
attachmentsNames: attachmentNameList,
attachments: attachmentList,
replyMessage: replyMessageTmp,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
EventLogMessage(
eventLog: eventLog,
message: Message(
id: !eventLog.chatMessage!.messageId.isEmpty ? eventLog.chatMessage!.messageId : UUID().uuidString,
status: statusTmp,
isOutgoing: eventLog.chatMessage?.isOutgoing ?? false,
dateReceived: eventLog.chatMessage?.time ?? 0,
address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp,
text: contentText,
attachmentsNames: attachmentNameList,
attachments: attachmentList,
replyMessage: replyMessageTmp,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
)
)
)
self.addChatMessageDelegate(message: eventLog.chatMessage!)
} else {
conversationMessage.insert(
Message(
id: UUID().uuidString,
status: nil,
isOutgoing: false,
dateReceived: 0,
address: "",
isFirstMessage: false,
text: "",
attachments: [],
ownReaction: "",
reactions: []
EventLogMessage(
eventLog: eventLog,
message: Message(
id: UUID().uuidString,
status: nil,
isOutgoing: false,
dateReceived: 0,
address: "",
isFirstMessage: false,
text: "",
attachments: [],
ownReaction: "",
reactions: []
)
), at: 0
)
}
@ -391,7 +401,7 @@ class ConversationViewModel: ObservableObject {
if self.displayedConversation != nil && self.displayedConversationHistorySize > self.conversationMessagesSection[0].rows.count && !self.oldMessageReceived {
self.oldMessageReceived = true
let historyEvents = self.displayedConversation!.chatRoom.getHistoryRangeEvents(begin: self.conversationMessagesSection[0].rows.count, end: self.conversationMessagesSection[0].rows.count + 30)
var conversationMessagesTmp: [Message] = []
var conversationMessagesTmp: [EventLogMessage] = []
historyEvents.enumerated().reversed().forEach { index, eventLog in
var attachmentNameList: String = ""
@ -479,6 +489,8 @@ class ConversationViewModel: ObservableObject {
statusTmp = .received
case .Displayed:
statusTmp = .read
case .NotDelivered:
statusTmp = .error
default:
statusTmp = .sending
}
@ -525,36 +537,42 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil {
conversationMessagesTmp.insert(
Message(
id: eventLog.chatMessage?.messageId ?? UUID().uuidString,
status: statusTmp,
isOutgoing: eventLog.chatMessage?.isOutgoing ?? false,
dateReceived: eventLog.chatMessage?.time ?? 0,
address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp,
text: contentText,
attachmentsNames: attachmentNameList,
attachments: attachmentList,
replyMessage: replyMessageTmp,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
EventLogMessage(
eventLog: eventLog,
message: Message(
id: !eventLog.chatMessage!.messageId.isEmpty ? eventLog.chatMessage!.messageId : UUID().uuidString,
status: statusTmp,
isOutgoing: eventLog.chatMessage?.isOutgoing ?? false,
dateReceived: eventLog.chatMessage?.time ?? 0,
address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp,
text: contentText,
attachmentsNames: attachmentNameList,
attachments: attachmentList,
replyMessage: replyMessageTmp,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
)
), at: 0
)
self.addChatMessageDelegate(message: eventLog.chatMessage!)
} else {
conversationMessagesTmp.insert(
Message(
id: UUID().uuidString,
status: nil,
isOutgoing: false,
dateReceived: 0,
address: "",
isFirstMessage: false,
text: "",
attachments: [],
ownReaction: "",
reactions: []
EventLogMessage(
eventLog: eventLog,
message: Message(
id: UUID().uuidString,
status: nil,
isOutgoing: false,
dateReceived: 0,
address: "",
isFirstMessage: false,
text: "",
attachments: [],
ownReaction: "",
reactions: []
)
), at: 0
)
}
@ -562,8 +580,8 @@ class ConversationViewModel: ObservableObject {
if !conversationMessagesTmp.isEmpty {
DispatchQueue.main.async {
if self.conversationMessagesSection[0].rows.last?.address == conversationMessagesTmp.last?.address {
self.conversationMessagesSection[0].rows[self.conversationMessagesSection[0].rows.count - 1].isFirstMessage = false
if self.conversationMessagesSection[0].rows.last?.message.address == conversationMessagesTmp.last?.message.address {
self.conversationMessagesSection[0].rows[self.conversationMessagesSection[0].rows.count - 1].message.isFirstMessage = false
}
self.conversationMessagesSection[0].rows.append(contentsOf: conversationMessagesTmp.reversed())
self.oldMessageReceived = false
@ -650,7 +668,7 @@ class ConversationViewModel: ObservableObject {
: (
self.conversationMessagesSection.isEmpty || self.conversationMessagesSection[0].rows.isEmpty
? true
: self.conversationMessagesSection[0].rows[0].address != addressCleaned?.asStringUriOnly()
: self.conversationMessagesSection[0].rows[0].message.address != addressCleaned?.asStringUriOnly()
)
let isFirstMessageOutgoingTmp = index <= eventLogs.count - 2
@ -658,7 +676,7 @@ class ConversationViewModel: ObservableObject {
: (
self.conversationMessagesSection.isEmpty || self.conversationMessagesSection[0].rows.isEmpty
? true
: !self.conversationMessagesSection[0].rows[0].isOutgoing || self.conversationMessagesSection[0].rows[0].address == addressCleaned?.asStringUriOnly()
: !self.conversationMessagesSection[0].rows[0].message.isOutgoing || self.conversationMessagesSection[0].rows[0].message.address == addressCleaned?.asStringUriOnly()
)
let isFirstMessageTmp = (eventLog.chatMessage?.isOutgoing ?? false) ? isFirstMessageOutgoingTmp : isFirstMessageIncomingTmp
@ -675,6 +693,8 @@ class ConversationViewModel: ObservableObject {
statusTmp = .received
case .Displayed:
statusTmp = .read
case .NotDelivered:
statusTmp = .error
default:
statusTmp = .sending
}
@ -720,19 +740,23 @@ class ConversationViewModel: ObservableObject {
}
if eventLog.chatMessage != nil {
let message = Message(
id: eventLog.chatMessage?.messageId ?? UUID().uuidString,
status: statusTmp,
isOutgoing: eventLog.chatMessage?.isOutgoing ?? false,
dateReceived: eventLog.chatMessage?.time ?? 0,
address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp,
text: contentText,
attachmentsNames: attachmentNameList,
attachments: attachmentList,
replyMessage: replyMessageTmp,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
let message = EventLogMessage(
eventLog: eventLog,
message: Message(
id: !eventLog.chatMessage!.messageId.isEmpty ? eventLog.chatMessage!.messageId : UUID().uuidString,
appData: eventLog.chatMessage!.appdata ?? "",
status: statusTmp,
isOutgoing: eventLog.chatMessage?.isOutgoing ?? false,
dateReceived: eventLog.chatMessage?.time ?? 0,
address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp,
text: contentText,
attachmentsNames: attachmentNameList,
attachments: attachmentList,
replyMessage: replyMessageTmp,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
)
)
self.addChatMessageDelegate(message: eventLog.chatMessage!)
@ -740,9 +764,9 @@ class ConversationViewModel: ObservableObject {
DispatchQueue.main.async {
if !self.conversationMessagesSection.isEmpty
&& !self.conversationMessagesSection[0].rows.isEmpty
&& self.conversationMessagesSection[0].rows[0].isOutgoing
&& (self.conversationMessagesSection[0].rows[0].address == message.address) {
self.conversationMessagesSection[0].rows[0].isFirstMessage = false
&& self.conversationMessagesSection[0].rows[0].message.isOutgoing
&& (self.conversationMessagesSection[0].rows[0].message.address == message.message.address) {
self.conversationMessagesSection[0].rows[0].message.isFirstMessage = false
}
if self.conversationMessagesSection.isEmpty && self.displayedConversation != nil {
@ -751,22 +775,25 @@ class ConversationViewModel: ObservableObject {
self.conversationMessagesSection[0].rows.insert(message, at: 0)
}
if !message.isOutgoing {
if !message.message.isOutgoing {
self.displayedConversationUnreadMessagesCount = unreadMessagesCount
}
}
} else {
let message = Message(
id: UUID().uuidString,
status: nil,
isOutgoing: false,
dateReceived: 0,
address: "",
isFirstMessage: false,
text: "",
attachments: [],
ownReaction: "",
reactions: []
let message = EventLogMessage(
eventLog: eventLog,
message: Message(
id: UUID().uuidString,
status: nil,
isOutgoing: false,
dateReceived: 0,
address: "",
isFirstMessage: false,
text: "",
attachments: [],
ownReaction: "",
reactions: []
)
)
DispatchQueue.main.async {
@ -795,10 +822,11 @@ class ConversationViewModel: ObservableObject {
}
}
// swiftlint:disable cyclomatic_complexity
func scrollToMessage(message: Message) {
coreContext.doOnCoreQueue { _ in
if message.replyMessage != nil {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.id == message.replyMessage!.id}) {
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.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 {
@ -825,7 +853,7 @@ class ConversationViewModel: ObservableObject {
historyEvents.insert(contentsOf: historyEventsAfter, at: 0)
var conversationMessagesTmp: [Message] = []
var conversationMessagesTmp: [EventLogMessage] = []
historyEvents.enumerated().reversed().forEach { index, eventLog in
var attachmentNameList: String = ""
@ -913,6 +941,8 @@ class ConversationViewModel: ObservableObject {
statusTmp = .received
case .Displayed:
statusTmp = .read
case .NotDelivered:
statusTmp = .error
default:
statusTmp = .sending
}
@ -959,36 +989,42 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil {
conversationMessagesTmp.insert(
Message(
id: eventLog.chatMessage?.messageId ?? UUID().uuidString,
status: statusTmp,
isOutgoing: eventLog.chatMessage?.isOutgoing ?? false,
dateReceived: eventLog.chatMessage?.time ?? 0,
address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp,
text: contentText,
attachmentsNames: attachmentNameList,
attachments: attachmentList,
replyMessage: replyMessageTmp,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
EventLogMessage(
eventLog: eventLog,
message: Message(
id: !eventLog.chatMessage!.messageId.isEmpty ? eventLog.chatMessage!.messageId : UUID().uuidString,
status: statusTmp,
isOutgoing: eventLog.chatMessage?.isOutgoing ?? false,
dateReceived: eventLog.chatMessage?.time ?? 0,
address: addressCleaned?.asStringUriOnly() ?? "",
isFirstMessage: isFirstMessageTmp,
text: contentText,
attachmentsNames: attachmentNameList,
attachments: attachmentList,
replyMessage: replyMessageTmp,
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
reactions: reactionsTmp
)
), at: 0
)
self.addChatMessageDelegate(message: eventLog.chatMessage!)
} else {
conversationMessagesTmp.insert(
Message(
id: UUID().uuidString,
status: nil,
isOutgoing: false,
dateReceived: 0,
address: "",
isFirstMessage: false,
text: "",
attachments: [],
ownReaction: "",
reactions: []
EventLogMessage(
eventLog: eventLog,
message: Message(
id: UUID().uuidString,
status: nil,
isOutgoing: false,
dateReceived: 0,
address: "",
isFirstMessage: false,
text: "",
attachments: [],
ownReaction: "",
reactions: []
)
), at: 0
)
}
@ -996,8 +1032,8 @@ class ConversationViewModel: ObservableObject {
if !conversationMessagesTmp.isEmpty {
DispatchQueue.main.async {
if self.conversationMessagesSection[0].rows.last?.address == conversationMessagesTmp.last?.address {
self.conversationMessagesSection[0].rows[self.conversationMessagesSection[0].rows.count - 1].isFirstMessage = false
if self.conversationMessagesSection[0].rows.last?.message.address == conversationMessagesTmp.last?.message.address {
self.conversationMessagesSection[0].rows[self.conversationMessagesSection[0].rows.count - 1].message.isFirstMessage = false
}
self.conversationMessagesSection[0].rows.append(contentsOf: conversationMessagesTmp.reversed())
@ -1013,13 +1049,14 @@ class ConversationViewModel: ObservableObject {
}
}
}
// swiftlint:enable cyclomatic_complexity
func sendMessage() {
coreContext.doOnCoreQueue { _ in
do {
var message: ChatMessage?
if self.messageToReply != nil {
let chatMessageToReply = self.displayedConversation!.chatRoom.findMessage(messageId: self.messageToReply!.id)
let chatMessageToReply = self.messageToReply!.eventLog.chatMessage
if chatMessageToReply != nil {
message = try self.displayedConversation!.chatRoom.createReplyMessage(message: chatMessageToReply!)
}
@ -1264,8 +1301,8 @@ class ConversationViewModel: ObservableObject {
func sendReaction(emoji: String) {
coreContext.doOnCoreQueue { _ in
if self.selectedMessage != nil {
Log.info("[ConversationViewModel] Sending reaction \(emoji) to message with ID \(self.selectedMessage!.id)")
let messageToSendReaction = self.displayedConversation!.chatRoom.findMessage(messageId: self.selectedMessage!.id)
Log.info("[ConversationViewModel] Sending reaction \(emoji) to message with ID \(self.selectedMessage!.message.id)")
let messageToSendReaction = self.selectedMessage!.eventLog.chatMessage
if messageToSendReaction != nil {
do {
let reaction = try messageToSendReaction!.createReaction(utf8Reaction: messageToSendReaction?.ownReaction?.body == emoji ? "" : emoji)
@ -1275,12 +1312,12 @@ class ConversationViewModel: ObservableObject {
DispatchQueue.main.async {
if indexMessageSelected != nil {
self.conversationMessagesSection[0].rows[indexMessageSelected!].ownReaction = messageToSendReaction?.ownReaction?.body == emoji ? "" : emoji
self.conversationMessagesSection[0].rows[indexMessageSelected!].message.ownReaction = messageToSendReaction?.ownReaction?.body == emoji ? "" : emoji
}
self.selectedMessage = nil
}
} catch {
Log.info("[ConversationViewModel] Error: Can't send reaction \(emoji) to message with ID \(self.selectedMessage!.id)")
Log.info("[ConversationViewModel] Error: Can't send reaction \(emoji) to message with ID \(self.selectedMessage!.message.id)")
}
}
}
@ -1289,28 +1326,11 @@ class ConversationViewModel: ObservableObject {
func resend() {
coreContext.doOnCoreQueue { _ in
if self.selectedMessage != nil {
Log.info("[ConversationViewModel] Re-sending message with ID \(self.selectedMessage!.id)")
let messageToResend = self.displayedConversation!.chatRoom.findMessage(messageId: self.selectedMessage!.id)
if messageToResend != nil {
messageToResend!.send()
}
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()
}
}
}
}
struct LinphoneCustomEventLog: Hashable {
var id = UUID()
var eventLog: EventLog
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
extension LinphoneCustomEventLog {
static func ==(lhs: LinphoneCustomEventLog, rhs: LinphoneCustomEventLog) -> Bool {
return lhs.id == rhs.id
}
}
// swiftlint:enable type_body_length