forked from mirrors/linphone-iphone
Add reaction feature
This commit is contained in:
parent
6742904342
commit
5c82815644
13 changed files with 305 additions and 75 deletions
|
|
@ -1570,6 +1570,9 @@
|
|||
},
|
||||
"Message" : {
|
||||
|
||||
},
|
||||
"Message copied into clipboard" : {
|
||||
|
||||
},
|
||||
"Messages" : {
|
||||
|
||||
|
|
|
|||
|
|
@ -625,7 +625,7 @@ struct CallView: View {
|
|||
)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard"
|
||||
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
|
||||
ToastViewModel.shared.displayToast = true
|
||||
}
|
||||
}, label: {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ struct ContactListBottomSheet: View {
|
|||
dismiss()
|
||||
}
|
||||
|
||||
ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard"
|
||||
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
|
||||
ToastViewModel.shared.displayToast.toggle()
|
||||
|
||||
} label: {
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ struct ContentView: View {
|
|||
self.index = 0
|
||||
historyViewModel.displayedCall = nil
|
||||
conversationViewModel.displayedConversation = nil
|
||||
meetingViewModel.displayedMeeting = nil
|
||||
}, label: {
|
||||
VStack {
|
||||
Image("address-book")
|
||||
|
|
@ -171,6 +172,7 @@ struct ContentView: View {
|
|||
self.index = 1
|
||||
contactViewModel.indexDisplayedFriend = nil
|
||||
conversationViewModel.displayedConversation = nil
|
||||
meetingViewModel.displayedMeeting = nil
|
||||
if historyListViewModel.missedCallsCount > 0 {
|
||||
historyListViewModel.resetMissedCallsCount()
|
||||
}
|
||||
|
|
@ -219,6 +221,7 @@ struct ContentView: View {
|
|||
self.index = 2
|
||||
historyViewModel.displayedCall = nil
|
||||
contactViewModel.indexDisplayedFriend = nil
|
||||
meetingViewModel.displayedMeeting = nil
|
||||
}, label: {
|
||||
VStack {
|
||||
Image("chat-teardrop-text")
|
||||
|
|
@ -275,6 +278,11 @@ struct ContentView: View {
|
|||
}
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Rectangle()
|
||||
.foregroundColor(Color.orangeMain500)
|
||||
.edgesIgnoringSafeArea(.top)
|
||||
.frame(height: 1)
|
||||
|
||||
if searchIsActive == false {
|
||||
HStack {
|
||||
Image("profile-image-example")
|
||||
|
|
@ -392,6 +400,7 @@ struct ContentView: View {
|
|||
.padding(.top, 2.5)
|
||||
.padding(.bottom, 2.5)
|
||||
.background(Color.orangeMain500)
|
||||
.roundedCorner(10, corners: [.bottomRight, .bottomLeft])
|
||||
} else {
|
||||
HStack {
|
||||
Button {
|
||||
|
|
@ -523,6 +532,7 @@ struct ContentView: View {
|
|||
.padding(.horizontal)
|
||||
.padding(.bottom, 5)
|
||||
.background(Color.orangeMain500)
|
||||
.roundedCorner(10, corners: [.bottomRight, .bottomLeft])
|
||||
}
|
||||
|
||||
if self.index == 0 {
|
||||
|
|
@ -592,6 +602,7 @@ struct ContentView: View {
|
|||
self.index = 0
|
||||
historyViewModel.displayedCall = nil
|
||||
conversationViewModel.displayedConversation = nil
|
||||
meetingViewModel.displayedMeeting = nil
|
||||
}, label: {
|
||||
VStack {
|
||||
Image("address-book")
|
||||
|
|
@ -638,6 +649,7 @@ struct ContentView: View {
|
|||
self.index = 1
|
||||
contactViewModel.indexDisplayedFriend = nil
|
||||
conversationViewModel.displayedConversation = nil
|
||||
meetingViewModel.displayedMeeting = nil
|
||||
if historyListViewModel.missedCallsCount > 0 {
|
||||
historyListViewModel.resetMissedCallsCount()
|
||||
}
|
||||
|
|
@ -688,6 +700,7 @@ struct ContentView: View {
|
|||
self.index = 2
|
||||
historyViewModel.displayedCall = nil
|
||||
contactViewModel.indexDisplayedFriend = nil
|
||||
meetingViewModel.displayedMeeting = nil
|
||||
}, label: {
|
||||
VStack {
|
||||
Image("chat-teardrop-text")
|
||||
|
|
|
|||
|
|
@ -70,52 +70,89 @@ struct ChatBubbleView: View {
|
|||
}
|
||||
|
||||
VStack(alignment: message.isOutgoing ? .trailing : .leading) {
|
||||
if !message.attachments.isEmpty {
|
||||
messageAttachments()
|
||||
}
|
||||
|
||||
if !message.text.isEmpty {
|
||||
Text(message.text)
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.default_text_style(styleSize: 16)
|
||||
}
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Text(conversationViewModel.getMessageTime(startDate: message.dateReceived))
|
||||
.foregroundStyle(Color.grayMain2c500)
|
||||
.default_text_style_300(styleSize: 14)
|
||||
.padding(.top, 1)
|
||||
VStack(alignment: message.isOutgoing ? .trailing : .leading) {
|
||||
if !message.attachments.isEmpty {
|
||||
messageAttachments()
|
||||
}
|
||||
|
||||
if (conversationViewModel.displayedConversation != nil && conversationViewModel.displayedConversation!.isGroup) || message.isOutgoing {
|
||||
if message.status == .sending {
|
||||
ProgressView()
|
||||
.progressViewStyle(CircularProgressViewStyle(tint: .orangeMain500))
|
||||
.frame(width: 15, height: 15)
|
||||
.padding(.top, 1)
|
||||
} else if message.status != nil {
|
||||
Image(conversationViewModel.getImageIMDN(status: message.status!))
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 15, height: 15)
|
||||
.padding(.top, 1)
|
||||
if !message.text.isEmpty {
|
||||
Text(message.text)
|
||||
.foregroundStyle(Color.grayMain2c700)
|
||||
.default_text_style(styleSize: 16)
|
||||
}
|
||||
|
||||
HStack(alignment: .center) {
|
||||
Text(conversationViewModel.getMessageTime(startDate: 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 {
|
||||
ProgressView()
|
||||
.progressViewStyle(CircularProgressViewStyle(tint: .orangeMain500))
|
||||
.frame(width: 15, height: 15)
|
||||
.padding(.top, 1)
|
||||
} else if message.status != nil {
|
||||
Image(conversationViewModel.getImageIMDN(status: message.status!))
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orangeMain500)
|
||||
.frame(width: 15, height: 15)
|
||||
.padding(.top, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.top, -4)
|
||||
}
|
||||
.padding(.all, 15)
|
||||
.background(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]))
|
||||
|
||||
if !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])
|
||||
.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)")
|
||||
.default_text_style(styleSize: 14)
|
||||
.padding(.horizontal, -2)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 6)
|
||||
.padding(.horizontal, 10)
|
||||
.background(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(.top, -4)
|
||||
}
|
||||
.padding(.all, 15)
|
||||
.background(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]))
|
||||
|
||||
if !message.isOutgoing {
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
import SwiftUI
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
// swiftlint:disable type_body_length
|
||||
struct ConversationFragment: View {
|
||||
|
|
@ -538,7 +539,7 @@ struct ConversationFragment: View {
|
|||
.blur(radius: conversationViewModel.selectedMessage != nil ? 8 : 0)
|
||||
|
||||
if conversationViewModel.selectedMessage != nil && conversationViewModel.displayedConversation != nil {
|
||||
let iconSize = ((geometry.size.width - (conversationViewModel.displayedConversation!.isGroup ? 43 : 10) - 10) / 6) - 25
|
||||
let iconSize = ((geometry.size.width - (conversationViewModel.displayedConversation!.isGroup ? 43 : 10) - 10) / 6) - 30
|
||||
VStack {
|
||||
Spacer()
|
||||
|
||||
|
|
@ -550,39 +551,54 @@ struct ConversationFragment: View {
|
|||
|
||||
HStack {
|
||||
Button {
|
||||
conversationViewModel.sendReaction(emoji: "👍")
|
||||
} label: {
|
||||
Text("👍")
|
||||
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
|
||||
}
|
||||
.padding(.horizontal, 5)
|
||||
.padding(.horizontal, 8)
|
||||
.background(conversationViewModel.selectedMessage?.ownReaction == "👍" ? Color.gray200 : .white)
|
||||
.cornerRadius(10)
|
||||
|
||||
Button {
|
||||
conversationViewModel.sendReaction(emoji: "❤️")
|
||||
} label: {
|
||||
Text("❤️")
|
||||
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
|
||||
}
|
||||
.padding(.horizontal, 5)
|
||||
.padding(.horizontal, 8)
|
||||
.background(conversationViewModel.selectedMessage?.ownReaction == "❤️" ? Color.gray200 : .white)
|
||||
.cornerRadius(10)
|
||||
|
||||
Button {
|
||||
conversationViewModel.sendReaction(emoji: "😂")
|
||||
} label: {
|
||||
Text("😂")
|
||||
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
|
||||
}
|
||||
.padding(.horizontal, 5)
|
||||
.padding(.horizontal, 8)
|
||||
.background(conversationViewModel.selectedMessage?.ownReaction == "😂" ? Color.gray200 : .white)
|
||||
.cornerRadius(10)
|
||||
|
||||
Button {
|
||||
conversationViewModel.sendReaction(emoji: "😮")
|
||||
} label: {
|
||||
Text("😮")
|
||||
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
|
||||
}
|
||||
.padding(.horizontal, 5)
|
||||
.padding(.horizontal, 8)
|
||||
.background(conversationViewModel.selectedMessage?.ownReaction == "😮" ? Color.gray200 : .white)
|
||||
.cornerRadius(10)
|
||||
|
||||
Button {
|
||||
conversationViewModel.sendReaction(emoji: "😢")
|
||||
} label: {
|
||||
Text("😢")
|
||||
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
|
||||
}
|
||||
.padding(.horizontal, 5)
|
||||
.padding(.horizontal, 8)
|
||||
.background(conversationViewModel.selectedMessage?.ownReaction == "😢" ? Color.gray200 : .white)
|
||||
.cornerRadius(10)
|
||||
|
||||
Button {
|
||||
} label: {
|
||||
|
|
@ -635,22 +651,33 @@ struct ConversationFragment: View {
|
|||
|
||||
Divider()
|
||||
|
||||
Button {
|
||||
} label: {
|
||||
HStack {
|
||||
Text("menu_copy_chat_message")
|
||||
.default_text_style(styleSize: 15)
|
||||
Spacer()
|
||||
Image("copy")
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20, alignment: .leading)
|
||||
if !conversationViewModel.selectedMessage!.text.isEmpty {
|
||||
Button {
|
||||
UIPasteboard.general.setValue(
|
||||
conversationViewModel.selectedMessage!.text,
|
||||
forPasteboardType: UTType.plainText.identifier
|
||||
)
|
||||
|
||||
ToastViewModel.shared.toastMessage = "Success_message_copied_into_clipboard"
|
||||
ToastViewModel.shared.displayToast = true
|
||||
|
||||
conversationViewModel.selectedMessage = nil
|
||||
} label: {
|
||||
HStack {
|
||||
Text("menu_copy_chat_message")
|
||||
.default_text_style(styleSize: 15)
|
||||
Spacer()
|
||||
Image("copy")
|
||||
.resizable()
|
||||
.frame(width: 20, height: 20, alignment: .leading)
|
||||
}
|
||||
.padding(.vertical, 5)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
.padding(.vertical, 5)
|
||||
.padding(.horizontal, 20)
|
||||
|
||||
Divider()
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
Button {
|
||||
} label: {
|
||||
HStack {
|
||||
|
|
@ -698,8 +725,6 @@ struct ConversationFragment: View {
|
|||
.padding(.leading, conversationViewModel.displayedConversation!.isGroup ? 43 : 0)
|
||||
.shadow(color: .black.opacity(0.1), radius: 10)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(.gray.opacity(0.1))
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ public struct Message: Identifiable, Hashable {
|
|||
public var attachments: [Attachment]
|
||||
public var recording: Recording?
|
||||
public var replyMessage: ReplyMessage?
|
||||
public var ownReaction: String
|
||||
public var reactions: [String]
|
||||
|
||||
public init(
|
||||
id: String,
|
||||
|
|
@ -85,7 +87,9 @@ public struct Message: Identifiable, Hashable {
|
|||
text: String = "",
|
||||
attachments: [Attachment] = [],
|
||||
recording: Recording? = nil,
|
||||
replyMessage: ReplyMessage? = nil
|
||||
replyMessage: ReplyMessage? = nil,
|
||||
ownReaction: String = "",
|
||||
reactions: [String] = []
|
||||
) {
|
||||
self.id = id
|
||||
self.status = status
|
||||
|
|
@ -98,6 +102,8 @@ public struct Message: Identifiable, Hashable {
|
|||
self.attachments = attachments
|
||||
self.recording = recording
|
||||
self.replyMessage = replyMessage
|
||||
self.ownReaction = ownReaction
|
||||
self.reactions = reactions
|
||||
}
|
||||
|
||||
public static func makeMessage(
|
||||
|
|
@ -131,7 +137,9 @@ public struct Message: Identifiable, Hashable {
|
|||
text: draft.text,
|
||||
attachments: attachments,
|
||||
recording: draft.recording,
|
||||
replyMessage: draft.replyMessage
|
||||
replyMessage: draft.replyMessage,
|
||||
ownReaction: draft.ownReaction,
|
||||
reactions: draft.reactions
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -144,7 +152,7 @@ extension Message {
|
|||
|
||||
extension Message: Equatable {
|
||||
public static func == (lhs: Message, rhs: Message) -> Bool {
|
||||
lhs.id == rhs.id && lhs.status == rhs.status && lhs.isFirstMessage == rhs.isFirstMessage
|
||||
lhs.id == rhs.id && lhs.status == rhs.status && lhs.isFirstMessage == rhs.isFirstMessage && lhs.ownReaction == rhs.ownReaction && lhs.reactions == rhs.reactions
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -217,6 +225,8 @@ public struct DraftMessage {
|
|||
public let recording: Recording?
|
||||
public let replyMessage: ReplyMessage?
|
||||
public let createdAt: Date
|
||||
public let ownReaction: String
|
||||
public let reactions: [String]
|
||||
|
||||
public init(id: String? = nil,
|
||||
isOutgoing: Bool,
|
||||
|
|
@ -227,7 +237,10 @@ public struct DraftMessage {
|
|||
medias: [Media],
|
||||
recording: Recording?,
|
||||
replyMessage: ReplyMessage?,
|
||||
createdAt: Date) {
|
||||
createdAt: Date,
|
||||
ownReaction: String,
|
||||
reactions: [String]
|
||||
) {
|
||||
self.id = id
|
||||
self.isOutgoing = isOutgoing
|
||||
self.dateReceived = dateReceived
|
||||
|
|
@ -238,6 +251,8 @@ public struct DraftMessage {
|
|||
self.recording = recording
|
||||
self.replyMessage = replyMessage
|
||||
self.createdAt = createdAt
|
||||
self.ownReaction = ownReaction
|
||||
self.reactions = reactions
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class ConversationViewModel: ObservableObject {
|
|||
@Published var messageText: String = ""
|
||||
|
||||
private var chatRoomSuscriptions = Set<AnyCancellable?>()
|
||||
private var chatMessageSuscriptions = Set<AnyCancellable?>()
|
||||
|
||||
@Published var conversationMessagesSection: [MessagesSection] = []
|
||||
@Published var participantConversationModel: [ContactAvatarModel] = []
|
||||
|
|
@ -60,8 +61,73 @@ class ConversationViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func addChatMessageDelegate(message: ChatMessage) {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.displayedConversation != nil {
|
||||
/*
|
||||
self.chatMessageSuscriptions.insert(message.publisher?.onMsgStateChanged?.postOnCoreQueue {(cbValue: (message: ChatMessage, state: ChatMessage.State)) in
|
||||
var statusTmp: Message.Status? = .sending
|
||||
switch cbValue.message.state {
|
||||
case .InProgress:
|
||||
statusTmp = .sending
|
||||
case .Delivered:
|
||||
statusTmp = .sent
|
||||
case .DeliveredToUser:
|
||||
statusTmp = .received
|
||||
case .Displayed:
|
||||
statusTmp = .read
|
||||
default:
|
||||
statusTmp = nil
|
||||
}
|
||||
|
||||
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.id == message.messageId})
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if indexMessage != nil {
|
||||
self.objectWillChange.send()
|
||||
self.conversationMessagesSection[0].rows[indexMessage!].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})
|
||||
var reactionsTmp: [String] = []
|
||||
cbValue.message.reactions.forEach({ chatMessageReaction in
|
||||
reactionsTmp.append(chatMessageReaction.body)
|
||||
})
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if indexMessage != nil {
|
||||
self.objectWillChange.send()
|
||||
self.conversationMessagesSection[0].rows[indexMessage!].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})
|
||||
var reactionsTmp: [String] = []
|
||||
cbValue.message.reactions.forEach({ chatMessageReaction in
|
||||
reactionsTmp.append(chatMessageReaction.body)
|
||||
})
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if indexMessage != nil {
|
||||
self.objectWillChange.send()
|
||||
self.conversationMessagesSection[0].rows[indexMessage!].reactions = reactionsTmp
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeConversationDelegate() {
|
||||
self.chatRoomSuscriptions.removeAll()
|
||||
self.chatMessageSuscriptions.removeAll()
|
||||
}
|
||||
|
||||
func getHistorySize() {
|
||||
|
|
@ -210,19 +276,28 @@ class ConversationViewModel: ObservableObject {
|
|||
statusTmp = nil
|
||||
}
|
||||
|
||||
var reactionsTmp: [String] = []
|
||||
eventLog.chatMessage?.reactions.forEach({ chatMessageReaction in
|
||||
reactionsTmp.append(chatMessageReaction.body)
|
||||
})
|
||||
|
||||
if eventLog.chatMessage != nil {
|
||||
conversationMessage.append(
|
||||
Message(
|
||||
id: UUID().uuidString,
|
||||
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,
|
||||
attachments: attachmentList
|
||||
attachments: attachmentList,
|
||||
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
|
||||
reactions: reactionsTmp
|
||||
)
|
||||
)
|
||||
|
||||
self.addChatMessageDelegate(message: eventLog.chatMessage!)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -324,19 +399,28 @@ class ConversationViewModel: ObservableObject {
|
|||
statusTmp = nil
|
||||
}
|
||||
|
||||
var reactionsTmp: [String] = []
|
||||
eventLog.chatMessage?.reactions.forEach({ chatMessageReaction in
|
||||
reactionsTmp.append(chatMessageReaction.body)
|
||||
})
|
||||
|
||||
if eventLog.chatMessage != nil {
|
||||
conversationMessagesTmp.insert(
|
||||
Message(
|
||||
id: UUID().uuidString,
|
||||
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,
|
||||
attachments: attachmentList
|
||||
attachments: attachmentList,
|
||||
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
|
||||
reactions: reactionsTmp
|
||||
), at: 0
|
||||
)
|
||||
|
||||
self.addChatMessageDelegate(message: eventLog.chatMessage!)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -451,18 +535,27 @@ class ConversationViewModel: ObservableObject {
|
|||
statusTmp = nil
|
||||
}
|
||||
|
||||
var reactionsTmp: [String] = []
|
||||
eventLog.chatMessage?.reactions.forEach({ chatMessageReaction in
|
||||
reactionsTmp.append(chatMessageReaction.body)
|
||||
})
|
||||
|
||||
if eventLog.chatMessage != nil {
|
||||
let message = Message(
|
||||
id: UUID().uuidString,
|
||||
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,
|
||||
attachments: attachmentList
|
||||
attachments: attachmentList,
|
||||
ownReaction: eventLog.chatMessage?.ownReaction?.body ?? "",
|
||||
reactions: reactionsTmp
|
||||
)
|
||||
|
||||
self.addChatMessageDelegate(message: eventLog.chatMessage!)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if !self.conversationMessagesSection.isEmpty
|
||||
&& !self.conversationMessagesSection[0].rows.isEmpty
|
||||
|
|
@ -729,6 +822,43 @@ 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)
|
||||
if messageToSendReaction != nil {
|
||||
do {
|
||||
let reaction = try messageToSendReaction!.createReaction(utf8Reaction: messageToSendReaction?.ownReaction?.body == emoji ? "" : emoji)
|
||||
reaction.send()
|
||||
|
||||
let indexMessageSelected = self.conversationMessagesSection[0].rows.firstIndex(of: self.selectedMessage!)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if indexMessageSelected != nil {
|
||||
self.conversationMessagesSection[0].rows[indexMessageSelected!].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)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct LinphoneCustomEventLog: Hashable {
|
||||
var id = UUID()
|
||||
|
|
|
|||
|
|
@ -80,13 +80,20 @@ struct ToastView: View {
|
|||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
|
||||
case "Success_copied_into_clipboard":
|
||||
case "Success_address_copied_into_clipboard":
|
||||
Text("SIP address copied into clipboard")
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(Color.greenSuccess500)
|
||||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
|
||||
case "Success_message_copied_into_clipboard":
|
||||
Text("Message copied into clipboard")
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(Color.greenSuccess500)
|
||||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
|
||||
case "Info_call_securised":
|
||||
Text("call_can_be_trusted_toast")
|
||||
.multilineTextAlignment(.center)
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ struct HistoryContactFragment: View {
|
|||
)
|
||||
}
|
||||
|
||||
ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard"
|
||||
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
|
||||
ToastViewModel.shared.displayToast.toggle()
|
||||
|
||||
} label: {
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ struct HistoryListBottomSheet: View {
|
|||
dismiss()
|
||||
}
|
||||
|
||||
ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard"
|
||||
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
|
||||
ToastViewModel.shared.displayToast.toggle()
|
||||
|
||||
} label: {
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ struct MeetingFragment: View {
|
|||
)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard"
|
||||
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
|
||||
ToastViewModel.shared.displayToast = true
|
||||
}
|
||||
}, label: {
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ struct Avatar: View {
|
|||
Image(contactAvatarModel.presenceStatus == .Online ? "presence-online" : "presence-busy")
|
||||
.resizable()
|
||||
.frame(width: avatarSize/4, height: avatarSize/4)
|
||||
.padding(.trailing, avatarSize == 50 ? 1 : 3)
|
||||
.padding(.bottom, avatarSize == 50 ? 1 : 3)
|
||||
.padding(.trailing, avatarSize == 50 || avatarSize == 35 ? 1 : 3)
|
||||
.padding(.bottom, avatarSize == 50 || avatarSize == 35 ? 1 : 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue