Add event message
|
|
@ -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 |
21
Linphone/Assets.xcassets/door.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
1
Linphone/Assets.xcassets/door.imageset/door.svg
vendored
Normal 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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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" : {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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)
|
||||
} else if conversationViewModel.displayedConversation != nil
|
||||
&& conversationViewModel.displayedConversation!.isGroup && !eventLogMessage.message.isOutgoing {
|
||||
VStack {
|
||||
}
|
||||
.padding(.leading, 43)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
.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)
|
||||
VStack(alignment: eventLogMessage.message.isOutgoing ? .trailing : .leading, spacing: 0) {
|
||||
HStack {
|
||||
Image("forward")
|
||||
.resizable()
|
||||
.frame(width: 15, height: 15, alignment: .leading)
|
||||
|
||||
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)
|
||||
}
|
||||
Text("message_forwarded_label")
|
||||
.default_text_style(styleSize: 12)
|
||||
}
|
||||
.padding(.bottom, 2)
|
||||
}
|
||||
|
||||
if !eventLogMessage.message.isOutgoing {
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.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@*/)
|
||||
}
|
||||
}
|
||||
.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)
|
||||
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)
|
||||
)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.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
|
||||
}
|
||||
|
||||
.padding(.vertical, 4)
|
||||
}
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
|
|
|
|||
|
|
@ -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...")
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ struct MessagesSection: Equatable {
|
|||
|
||||
struct EventLogMessage: Equatable {
|
||||
|
||||
let eventLog: EventLog
|
||||
let eventModel: EventModel
|
||||
var message: Message
|
||||
|
||||
static var formatter = {
|
||||
|
|
|
|||
122
Linphone/UI/Main/Conversations/Model/EventModel.swift
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||