forked from mirrors/linphone-iphone
Add a bottom sheet to display reactions
This commit is contained in:
parent
5ed0fc1f76
commit
89eb159a50
4 changed files with 202 additions and 53 deletions
|
|
@ -1742,6 +1742,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"message_reaction_click_to_remove_label" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Click to remove"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Cliquez pour supprimer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"message_reactions_info_all_title" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Reactions"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Réactions"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Messages" : {
|
||||
|
||||
},
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ struct ChatBubbleView: View {
|
|||
conversationViewModel.selectedMessageToDisplayDetails = eventLogMessage
|
||||
conversationViewModel.prepareBottomSheetForDeliveryStatus()
|
||||
}
|
||||
.disabled(conversationViewModel.selectedMessage != nil)
|
||||
.padding(.top, -4)
|
||||
}
|
||||
.padding(.all, 15)
|
||||
|
|
@ -211,18 +212,17 @@ struct ChatBubbleView: View {
|
|||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(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 {
|
||||
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)
|
||||
|
|
@ -285,6 +285,11 @@ struct ChatBubbleView: View {
|
|||
}
|
||||
}
|
||||
|
||||
func containsDuplicates(strings: [String]) -> Bool {
|
||||
let uniqueStrings = Set(strings)
|
||||
return uniqueStrings.count != strings.count
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func messageAttachments() -> some View {
|
||||
if eventLogMessage.message.attachments.count == 1 {
|
||||
|
|
|
|||
|
|
@ -73,10 +73,10 @@ struct ConversationFragment: View {
|
|||
.onDisappear {
|
||||
conversationViewModel.removeConversationDelegate()
|
||||
}
|
||||
.sheet(isPresented: $conversationViewModel.isShowSelectedMessageToDisplayDetailsBottomSheet, onDismiss: {
|
||||
conversationViewModel.isShowSelectedMessageToDisplayDetailsBottomSheet = false
|
||||
.sheet(isPresented: $conversationViewModel.isShowSelectedMessageToDisplayDetails, onDismiss: {
|
||||
conversationViewModel.isShowSelectedMessageToDisplayDetails = false
|
||||
}, content: {
|
||||
imdnSheet()
|
||||
imdnOrReactionsSheet()
|
||||
.presentationDetents([.medium])
|
||||
.presentationDragIndicator(.visible)
|
||||
})
|
||||
|
|
@ -115,10 +115,10 @@ struct ConversationFragment: View {
|
|||
.onDisappear {
|
||||
conversationViewModel.removeConversationDelegate()
|
||||
}
|
||||
.halfSheet(showSheet: $conversationViewModel.isShowSelectedMessageToDisplayDetailsBottomSheet) {
|
||||
imdnSheet()
|
||||
.halfSheet(showSheet: $conversationViewModel.isShowSelectedMessageToDisplayDetails) {
|
||||
imdnOrReactionsSheet()
|
||||
} onDismiss: {
|
||||
conversationViewModel.isShowSelectedMessageToDisplayDetailsBottomSheet = false
|
||||
conversationViewModel.isShowSelectedMessageToDisplayDetails = false
|
||||
}
|
||||
.sheet(isPresented: $isShowPhotoLibrary, onDismiss: {
|
||||
isShowPhotoLibrary = false
|
||||
|
|
@ -864,42 +864,67 @@ struct ConversationFragment: View {
|
|||
//swiftlint:enable function_body_length
|
||||
|
||||
@ViewBuilder
|
||||
func imdnSheet() -> some View {
|
||||
VStack {
|
||||
Picker("Categories", selection: $selectedCategoryIndex) {
|
||||
ForEach(0..<conversationViewModel.sheetCategories.count, id: \.self) { index in
|
||||
Text(conversationViewModel.sheetCategories[index].name)
|
||||
}
|
||||
func imdnOrReactionsSheet() -> some View {
|
||||
VStack {
|
||||
Picker("Categories", selection: $selectedCategoryIndex) {
|
||||
ForEach(0..<conversationViewModel.sheetCategories.count, id: \.self) { index in
|
||||
Text(conversationViewModel.sheetCategories[index].name)
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
.padding()
|
||||
|
||||
List {
|
||||
ForEach(conversationViewModel.sheetCategories[selectedCategoryIndex].innerCategory, id: \.id) { participant in
|
||||
HStack {
|
||||
Avatar(contactAvatarModel: participant.contact, avatarSize: 50)
|
||||
|
||||
Text(participant.contact.name)
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(participant.detail)
|
||||
.default_text_style(styleSize: 16)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.font(.system(size: 40))
|
||||
.buttonStyle(.borderless)
|
||||
.listRowSeparator(.hidden)
|
||||
.background(.white)
|
||||
}
|
||||
}
|
||||
.listStyle(.plain)
|
||||
}
|
||||
.padding(.top)
|
||||
.background(.white)
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
.padding()
|
||||
|
||||
ScrollView {
|
||||
LazyVStack {
|
||||
if selectedCategoryIndex < conversationViewModel.sheetCategories.count && !conversationViewModel.sheetCategories[selectedCategoryIndex].innerCategory.isEmpty {
|
||||
ForEach(conversationViewModel.sheetCategories[selectedCategoryIndex].innerCategory, id: \.id) { participant in
|
||||
Button(
|
||||
action: {
|
||||
if participant.isMe {
|
||||
conversationViewModel.removeReaction()
|
||||
}
|
||||
},
|
||||
label: {
|
||||
Avatar(contactAvatarModel: participant.contact, avatarSize: 50)
|
||||
|
||||
VStack {
|
||||
|
||||
Text(participant.contact.name)
|
||||
.default_text_style(styleSize: 16)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
|
||||
if participant.isMe {
|
||||
Text("message_reaction_click_to_remove_label")
|
||||
.foregroundStyle(Color.grayMain2c400)
|
||||
.default_text_style_300(styleSize: 14)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Text(participant.detail)
|
||||
.default_text_style(styleSize: 16)
|
||||
.lineLimit(1)
|
||||
}
|
||||
)
|
||||
.disabled(!participant.isMe)
|
||||
.padding(.horizontal)
|
||||
.buttonStyle(.borderless)
|
||||
.background(.white)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(.plain)
|
||||
}
|
||||
.onAppear {
|
||||
selectedCategoryIndex = 0
|
||||
}
|
||||
.padding(.top)
|
||||
.background(.white)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class ConversationViewModel: ObservableObject {
|
|||
|
||||
var oldMessageReceived = false
|
||||
|
||||
@Published var isShowSelectedMessageToDisplayDetailsBottomSheet: Bool = false
|
||||
@Published var isShowSelectedMessageToDisplayDetails: Bool = false
|
||||
@Published var selectedMessageToDisplayDetails: EventLogMessage?
|
||||
@Published var selectedMessage: EventLogMessage?
|
||||
@Published var messageToReply: EventLogMessage?
|
||||
|
|
@ -63,6 +63,7 @@ class ConversationViewModel: ObservableObject {
|
|||
let id = UUID()
|
||||
let contact: ContactAvatarModel
|
||||
let detail: String
|
||||
var isMe: Bool = false
|
||||
}
|
||||
|
||||
@Published var sheetCategories: [SheetCategory] = []
|
||||
|
|
@ -1387,6 +1388,33 @@ class ConversationViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func removeReaction() {
|
||||
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
|
||||
if messageToSendReaction != nil {
|
||||
do {
|
||||
let reaction = try messageToSendReaction!.createReaction(utf8Reaction: "")
|
||||
reaction.send()
|
||||
|
||||
let indexMessageSelected = self.conversationMessagesSection[0].rows.firstIndex(of: self.selectedMessageToDisplayDetails!)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if indexMessageSelected != nil {
|
||||
self.conversationMessagesSection[0].rows[indexMessageSelected!].message.ownReaction = ""
|
||||
}
|
||||
self.selectedMessageToDisplayDetails = nil
|
||||
self.isShowSelectedMessageToDisplayDetails = false
|
||||
}
|
||||
} catch {
|
||||
Log.info("[ConversationViewModel] Error: Can't remove reaction to message with ID \(self.selectedMessageToDisplayDetails!.message.id)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sendReaction(emoji: String) {
|
||||
coreContext.doOnCoreQueue { _ in
|
||||
if self.selectedMessage != nil {
|
||||
|
|
@ -1472,12 +1500,69 @@ class ConversationViewModel: ObservableObject {
|
|||
})
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.sheetCategories.append(SheetCategory(name: "message_delivery_info_read_title" + "\(participantListDisplayed.count)", innerCategory: participantListDisplayed))
|
||||
self.sheetCategories.append(SheetCategory(name: "message_delivery_info_received_title" + "\(participantListDeliveredToUser.count)", innerCategory: participantListDeliveredToUser))
|
||||
self.sheetCategories.append(SheetCategory(name: "message_delivery_info_sent_title" + "\(participantListDelivered.count)", innerCategory: participantListDelivered))
|
||||
self.sheetCategories.append(SheetCategory(name: "message_delivery_info_error_title" + "\(participantListNotDelivered.count)", innerCategory: participantListNotDelivered))
|
||||
self.sheetCategories.append(SheetCategory(name: NSLocalizedString("message_delivery_info_read_title", comment: "") + " \(participantListDisplayed.count)", innerCategory: participantListDisplayed))
|
||||
self.sheetCategories.append(SheetCategory(name: NSLocalizedString("message_delivery_info_received_title", comment: "") + " \(participantListDeliveredToUser.count)", innerCategory: participantListDeliveredToUser))
|
||||
self.sheetCategories.append(SheetCategory(name: NSLocalizedString("message_delivery_info_sent_title", comment: "") + " \(participantListDelivered.count)", innerCategory: participantListDelivered))
|
||||
self.sheetCategories.append(SheetCategory(name: NSLocalizedString("message_delivery_info_error_title", comment: "") + " \(participantListNotDelivered.count)", innerCategory: participantListNotDelivered))
|
||||
|
||||
self.isShowSelectedMessageToDisplayDetailsBottomSheet = true
|
||||
self.isShowSelectedMessageToDisplayDetails = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func prepareBottomSheetForReactions() {
|
||||
self.sheetCategories.removeAll()
|
||||
coreContext.doOnCoreQueue { core in
|
||||
if self.selectedMessageToDisplayDetails != nil && self.selectedMessageToDisplayDetails!.eventLog.chatMessage != nil {
|
||||
let dispatchGroup = DispatchGroup()
|
||||
|
||||
var sheetCategoriesTmp: [SheetCategory] = []
|
||||
|
||||
var participantList: [[InnerSheetCategory]] = [[]]
|
||||
var reactionList: [String] = []
|
||||
|
||||
self.selectedMessageToDisplayDetails!.eventLog.chatMessage!.reactions.forEach { chatMessageReaction in
|
||||
if chatMessageReaction.fromAddress != nil {
|
||||
dispatchGroup.enter()
|
||||
ContactAvatarModel.getAvatarModelFromAddress(address: chatMessageReaction.fromAddress!) { avatarResult in
|
||||
if core.defaultAccount != nil && core.defaultAccount!.contactAddress != nil && core.defaultAccount!.contactAddress!.asStringUriOnly().contains(avatarResult.address) {
|
||||
let innerSheetCat = InnerSheetCategory(contact: avatarResult, detail: chatMessageReaction.body, isMe: true)
|
||||
participantList[0].append(innerSheetCat)
|
||||
} else {
|
||||
let innerSheetCat = InnerSheetCategory(contact: avatarResult, detail: chatMessageReaction.body)
|
||||
participantList[0].append(innerSheetCat)
|
||||
}
|
||||
|
||||
if !reactionList.contains(where: {$0 == chatMessageReaction.body}) {
|
||||
reactionList.append(chatMessageReaction.body)
|
||||
}
|
||||
|
||||
dispatchGroup.leave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatchGroup.notify(queue: .main) {
|
||||
reactionList.forEach { reaction in
|
||||
participantList.append([])
|
||||
participantList[0].forEach { innerSheetCategory in
|
||||
if innerSheetCategory.detail == reaction {
|
||||
participantList[participantList.count - 1].append(innerSheetCategory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sheetCategoriesTmp.append(SheetCategory(name: NSLocalizedString("message_reactions_info_all_title", comment: "") + " \(participantList.first!.count)", innerCategory: participantList.first!))
|
||||
|
||||
reactionList.enumerated().forEach { index, reaction in
|
||||
sheetCategoriesTmp.append(SheetCategory(name: reaction + " \(participantList[index + 1].count)", innerCategory: participantList[index + 1]))
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.sheetCategories = sheetCategoriesTmp
|
||||
self.isShowSelectedMessageToDisplayDetails = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue