From 61c2c048bbf89979629f3035e633517214611fa0 Mon Sep 17 00:00:00 2001 From: Benoit Martins Date: Thu, 15 Feb 2024 15:19:46 +0100 Subject: [PATCH] Fix conversations list view when receiving a message or a new chat room --- .../bell.imageset/Contents.json | 21 +++++ .../Assets.xcassets/bell.imageset/bell.svg | 1 + Linphone/LinphoneApp.swift | 3 +- Linphone/Localizable.xcstrings | 9 ++ .../Conversations/ConversationsView.swift | 2 +- .../Fragments/ConversationsFragment.swift | 9 +- .../ConversationsListBottomSheet.swift | 92 +++++++++++++------ .../Fragments/ConversationsListFragment.swift | 28 ++++-- .../ViewModel/ConversationViewModel.swift | 4 - .../ConversationsListViewModel.swift | 27 +++++- 10 files changed, 143 insertions(+), 53 deletions(-) create mode 100644 Linphone/Assets.xcassets/bell.imageset/Contents.json create mode 100644 Linphone/Assets.xcassets/bell.imageset/bell.svg diff --git a/Linphone/Assets.xcassets/bell.imageset/Contents.json b/Linphone/Assets.xcassets/bell.imageset/Contents.json new file mode 100644 index 000000000..b0db29476 --- /dev/null +++ b/Linphone/Assets.xcassets/bell.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "bell.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Linphone/Assets.xcassets/bell.imageset/bell.svg b/Linphone/Assets.xcassets/bell.imageset/bell.svg new file mode 100644 index 000000000..7a51a424b --- /dev/null +++ b/Linphone/Assets.xcassets/bell.imageset/bell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index f3a1fc3fa..92b748694 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -66,7 +66,8 @@ struct LinphoneApp: App { && historyViewModel != nil && historyListViewModel != nil && startCallViewModel != nil - && callViewModel != nil { + && callViewModel != nil + && conversationsListViewModel != nil{ ContentView( contactViewModel: contactViewModel!, editContactViewModel: editContactViewModel!, diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index 561647542..7c0dabc93 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -244,6 +244,9 @@ }, "Contacts" : { + }, + "Content" : { + }, "Continue" : { @@ -498,6 +501,9 @@ }, "Quitter la conversation" : { + }, + "Réactiver les notifications" : { + }, "Record" : { @@ -582,6 +588,9 @@ }, "This contact will be deleted definitively." : { + }, + "Title" : { + }, "TLS" : { diff --git a/Linphone/UI/Main/Conversations/ConversationsView.swift b/Linphone/UI/Main/Conversations/ConversationsView.swift index 35ee68224..2119f0ab6 100644 --- a/Linphone/UI/Main/Conversations/ConversationsView.swift +++ b/Linphone/UI/Main/Conversations/ConversationsView.swift @@ -47,5 +47,5 @@ struct ConversationsView: View { } #Preview { - ConversationsListFragment(conversationsListViewModel: ConversationsListViewModel(), conversationViewModel: ConversationViewModel(), showingSheet: .constant(false)) + ConversationsListFragment(conversationsListViewModel: ConversationsListViewModel(), showingSheet: .constant(false)) } diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationsFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationsFragment.swift index 2f375edd9..c4ab574ef 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationsFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationsFragment.swift @@ -22,7 +22,6 @@ import SwiftUI struct ConversationsFragment: View { @ObservedObject var conversationsListViewModel: ConversationsListViewModel - @ObservedObject var conversationViewModel: ConversationViewModel private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } @@ -31,17 +30,19 @@ struct ConversationsFragment: View { var body: some View { ZStack { if #available(iOS 16.0, *), idiom != .pad { - ConversationsListFragment(conversationsListViewModel: conversationsListViewModel, conversationViewModel: conversationViewModel,showingSheet: $showingSheet) + ConversationsListFragment(conversationsListViewModel: conversationsListViewModel, showingSheet: $showingSheet) .sheet(isPresented: $showingSheet) { ConversationsListBottomSheet( + conversationsListViewModel: conversationsListViewModel, showingSheet: $showingSheet ) .presentationDetents([.fraction(0.4)]) } } else { - ConversationsListFragment(conversationsListViewModel: conversationsListViewModel, conversationViewModel: conversationViewModel,showingSheet: $showingSheet) + ConversationsListFragment(conversationsListViewModel: conversationsListViewModel, showingSheet: $showingSheet) .halfSheet(showSheet: $showingSheet) { ConversationsListBottomSheet( + conversationsListViewModel: conversationsListViewModel, showingSheet: $showingSheet ) } onDismiss: {} @@ -51,5 +52,5 @@ struct ConversationsFragment: View { } #Preview { - ConversationsFragment(conversationsListViewModel: ConversationsListViewModel(), conversationViewModel: ConversationViewModel()) + ConversationsFragment(conversationsListViewModel: ConversationsListViewModel()) } diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationsListBottomSheet.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationsListBottomSheet.swift index 4bd5954c1..c51310d32 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationsListBottomSheet.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationsListBottomSheet.swift @@ -18,6 +18,7 @@ */ import SwiftUI +import linphonesw struct ConversationsListBottomSheet: View { @@ -27,6 +28,8 @@ struct ConversationsListBottomSheet: View { @State private var orientation = UIDevice.current.orientation + @ObservedObject var conversationsListViewModel: ConversationsListViewModel + @Binding var showingSheet: Bool var body: some View { @@ -52,6 +55,12 @@ struct ConversationsListBottomSheet: View { Spacer() Button { + if conversationsListViewModel.selectedConversation != nil { + conversationsListViewModel.objectWillChange.send() + conversationsListViewModel.selectedConversation!.markAsRead() + conversationsListViewModel.updateUnreadMessagesCount() + } + if #available(iOS 16.0, *) { if idiom != .pad { showingSheet.toggle() @@ -86,6 +95,11 @@ struct ConversationsListBottomSheet: View { .frame(maxWidth: .infinity) Button { + if conversationsListViewModel.selectedConversation != nil { + conversationsListViewModel.objectWillChange.send() + conversationsListViewModel.selectedConversation!.muted.toggle() + } + if #available(iOS 16.0, *) { if idiom != .pad { showingSheet.toggle() @@ -99,13 +113,13 @@ struct ConversationsListBottomSheet: View { } } label: { HStack { - Image("bell-slash") + Image(conversationsListViewModel.selectedConversation!.muted ? "bell" : "bell-slash") .renderingMode(.template) .resizable() .foregroundStyle(Color.grayMain2c500) .frame(width: 25, height: 25, alignment: .leading) .padding(.all, 10) - Text("Mettre en sourdine") + Text(conversationsListViewModel.selectedConversation!.muted ? "Réactiver les notifications" : "Mettre en sourdine") .default_text_style(styleSize: 16) Spacer() } @@ -119,42 +133,58 @@ struct ConversationsListBottomSheet: View { } .frame(maxWidth: .infinity) - Button { - if #available(iOS 16.0, *) { - if idiom != .pad { - showingSheet.toggle() + if conversationsListViewModel.selectedConversation != nil + && conversationsListViewModel.selectedConversation!.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) { + Button { + if conversationsListViewModel.selectedConversation!.participants.first != nil { + TelecomManager.shared.doCallWithCore( + addr: conversationsListViewModel.selectedConversation!.participants.first!.address!, isVideo: false + ) + } + + if #available(iOS 16.0, *) { + if idiom != .pad { + showingSheet.toggle() + } else { + showingSheet.toggle() + dismiss() + } } else { showingSheet.toggle() dismiss() } - } else { - showingSheet.toggle() - dismiss() + + } label: { + HStack { + Image("phone") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.grayMain2c500) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + Text("Appel") + .default_text_style(styleSize: 16) + Spacer() + } + .frame(maxHeight: .infinity) } + .padding(.horizontal, 30) + .background(Color.gray100) - } label: { - HStack { - Image("phone") - .renderingMode(.template) - .resizable() - .foregroundStyle(Color.grayMain2c500) - .frame(width: 25, height: 25, alignment: .leading) - .padding(.all, 10) - Text("Appel") - .default_text_style(styleSize: 16) - Spacer() + VStack { + Divider() } - .frame(maxHeight: .infinity) + .frame(maxWidth: .infinity) } - .padding(.horizontal, 30) - .background(Color.gray100) - - VStack { - Divider() - } - .frame(maxWidth: .infinity) Button { + if conversationsListViewModel.selectedConversation != nil { + CoreContext.shared.doOnCoreQueue { core in + core.deleteChatRoom(chatRoom: conversationsListViewModel.selectedConversation!) + //conversationsListViewModel.computeChatRoomsList(filter: "") + } + } + if #available(iOS 16.0, *) { if idiom != .pad { showingSheet.toggle() @@ -190,6 +220,10 @@ struct ConversationsListBottomSheet: View { .frame(maxWidth: .infinity) Button { + if conversationsListViewModel.selectedConversation != nil { + conversationsListViewModel.selectedConversation!.leave() + } + if #available(iOS 16.0, *) { if idiom != .pad { showingSheet.toggle() @@ -227,5 +261,5 @@ struct ConversationsListBottomSheet: View { } #Preview { - ConversationsListBottomSheet(showingSheet: .constant(true)) + ConversationsListBottomSheet(conversationsListViewModel: ConversationsListViewModel(), showingSheet: .constant(true)) } diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationsListFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationsListFragment.swift index 8ffa2a1f0..5958ac9a0 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationsListFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationsListFragment.swift @@ -25,7 +25,6 @@ struct ConversationsListFragment: View { @ObservedObject var contactsManager = ContactsManager.shared @ObservedObject var conversationsListViewModel: ConversationsListViewModel - @ObservedObject var conversationViewModel: ConversationViewModel @Binding var showingSheet: Bool @@ -174,6 +173,22 @@ struct ConversationsListFragment: View { Spacer() HStack { + if conversationsListViewModel.conversationsList[index].muted == false + && !(conversationsListViewModel.conversationsList[index].lastMessageInHistory != nil + && conversationsListViewModel.conversationsList[index].lastMessageInHistory!.isOutgoing == true) + && conversationsListViewModel.conversationsList[index].unreadMessagesCount == 0 { + Text("") + .frame(width: 18, height: 18, alignment: .trailing) + } + + if conversationsListViewModel.conversationsList[index].muted { + Image("bell-slash") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.orangeMain500) + .frame(width: 18, height: 18, alignment: .trailing) + } + if conversationsListViewModel.conversationsList[index].lastMessageInHistory != nil && conversationsListViewModel.conversationsList[index].lastMessageInHistory!.isOutgoing == true { let imageName = LinphoneUtils.getChatIconState(chatState: conversationsListViewModel.conversationsList[index].lastMessageInHistory!.state) @@ -199,13 +214,6 @@ struct ConversationsListFragment: View { .background(Color.redDanger500) .cornerRadius(50) } - - if !(conversationsListViewModel.conversationsList[index].lastMessageInHistory != nil - && conversationsListViewModel.conversationsList[index].lastMessageInHistory!.isOutgoing == true) - && conversationsListViewModel.conversationsList[index].unreadMessagesCount == 0 { - Text("") - .frame(width: 18, height: 18, alignment: .trailing) - } } Spacer() @@ -220,7 +228,7 @@ struct ConversationsListFragment: View { .onTapGesture { } .onLongPressGesture(minimumDuration: 0.2) { - conversationViewModel.selectedConversation = conversationsListViewModel.conversationsList[index] + conversationsListViewModel.selectedConversation = conversationsListViewModel.conversationsList[index] showingSheet.toggle() } } @@ -250,5 +258,5 @@ struct ConversationsListFragment: View { } #Preview { - ConversationsListFragment(conversationsListViewModel: ConversationsListViewModel(), conversationViewModel: ConversationViewModel(), showingSheet: .constant(false)) + ConversationsListFragment(conversationsListViewModel: ConversationsListViewModel(), showingSheet: .constant(false)) } diff --git a/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift b/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift index 98707fa02..d71a061b1 100644 --- a/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift +++ b/Linphone/UI/Main/Conversations/ViewModel/ConversationViewModel.swift @@ -22,9 +22,5 @@ import linphonesw class ConversationViewModel: ObservableObject { - @Published var displayedConversation: ChatRoom? - - var selectedConversation: ChatRoom? - init() {} } diff --git a/Linphone/UI/Main/Conversations/ViewModel/ConversationsListViewModel.swift b/Linphone/UI/Main/Conversations/ViewModel/ConversationsListViewModel.swift index 5d4e1633d..5db41c604 100644 --- a/Linphone/UI/Main/Conversations/ViewModel/ConversationsListViewModel.swift +++ b/Linphone/UI/Main/Conversations/ViewModel/ConversationsListViewModel.swift @@ -31,6 +31,10 @@ class ConversationsListViewModel: ObservableObject { @Published var conversationsList: [ChatRoom] = [] @Published var unreadMessages: Int = 0 + @Published var displayedConversation: ChatRoom? + + var selectedConversation: ChatRoom? + init() { computeChatRoomsList(filter: "") addConversationDelegate() @@ -45,6 +49,8 @@ class ConversationsListViewModel: ObservableObject { self.conversationsList = [] chatRooms.forEach { chatRoom in //let disabledBecauseNotSecured = (account?.isInSecureMode() == true && !chatRoom.hasCapability) ? Capabilities.Encrypted.toInt() : 0 + if chatRoom.hasCapability(mask: ChatRoom.Capabilities.OneToOne.rawValue) { + } if filter.isEmpty { //val model = ConversationModel(chatRoom, disabledBecauseNotSecured) @@ -85,11 +91,11 @@ class ConversationsListViewModel: ObservableObject { func addConversationDelegate() { coreContext.doOnCoreQueue { core in - self.mCoreSuscriptions.insert(core.publisher?.onChatRoomStateChanged?.postOnMainQueue { (cbValue: (_: Core, chatRoom: ChatRoom, state: ChatRoom.State)) in + self.mCoreSuscriptions.insert(core.publisher?.onChatRoomStateChanged?.postOnMainQueue { (cbValue: (core: Core, chatRoom: ChatRoom, state: ChatRoom.State)) in //Log.info("[ConversationsListViewModel] Conversation [${LinphoneUtils.getChatRoomId(chatRoom)}] state changed [$state]") switch cbValue.state { case ChatRoom.State.Created: - self.computeChatRoomsList(filter: "") + self.addChatRoom(cbChatRoom: cbValue.chatRoom) case ChatRoom.State.Deleted: self.computeChatRoomsList(filter: "") //ToastViewModel.shared.toastMessage = "toast_conversation_deleted" @@ -100,15 +106,28 @@ class ConversationsListViewModel: ObservableObject { }) self.mCoreSuscriptions.insert(core.publisher?.onMessageSent?.postOnMainQueue { _ in - self.reorderChatRooms() + self.computeChatRoomsList(filter: "") }) self.mCoreSuscriptions.insert(core.publisher?.onMessagesReceived?.postOnMainQueue { _ in - self.reorderChatRooms() + self.computeChatRoomsList(filter: "") }) } } + func addChatRoom(cbChatRoom: ChatRoom) { + Log.info("[ConversationsListViewModel] Re-ordering conversations") + var sortedList: [ChatRoom] = [] + sortedList.append(cbChatRoom) + sortedList.append(contentsOf: self.conversationsList) + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + self.conversationsList = sortedList.sorted { $0.lastUpdateTime > $1.lastUpdateTime } + } + + updateUnreadMessagesCount() + } + func reorderChatRooms() { Log.info("[ConversationsListViewModel] Re-ordering conversations") var sortedList: [ChatRoom] = []