Add a bottom sheet to display reactions

This commit is contained in:
Benoit Martins 2024-09-05 17:33:34 +02:00
parent 5ed0fc1f76
commit 89eb159a50
4 changed files with 202 additions and 53 deletions

View file

@ -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" : {
},

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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
}
}
}
}