From 865f889a3cdb0b4a55a990fb1ed880cde24965e8 Mon Sep 17 00:00:00 2001 From: Benoit Martins Date: Wed, 28 May 2025 17:24:44 +0200 Subject: [PATCH] Refactored ContactsView (Part 2) --- Linphone/Core/CoreContext.swift | 9 +- Linphone/LinphoneApp.swift | 115 ++--- Linphone/UI/Call/CallView.swift | 6 +- Linphone/UI/Main/Contacts/ContactsView.swift | 11 +- .../Contacts/Fragments/ContactFragment.swift | 73 ++-- .../ContactInnerActionsFragment.swift | 32 +- .../Fragments/ContactInnerFragment.swift | 31 +- .../Fragments/ContactListBottomSheet.swift | 16 +- .../Contacts/Fragments/ContactsFragment.swift | 14 +- .../Fragments/ContactsInnerFragment.swift | 12 +- .../Fragments/ContactsListBottomSheet.swift | 26 +- .../Fragments/ContactsListFragment.swift | 24 +- .../Fragments/EditContactFragment.swift | 19 +- .../FavoriteContactsListFragment.swift | 7 +- .../Fragments/SipAddressesPopup.swift | 8 +- .../Contacts/ViewModel/ContactViewModel.swift | 215 ---------- .../ViewModel/ContactsListViewModel.swift | 191 ++++++++- .../ViewModel/EditContactViewModel.swift | 6 +- .../FavoriteContactsListViewModel.swift | 26 -- Linphone/UI/Main/ContentView.swift | 397 +++++++++--------- .../ConversationForwardMessageFragment.swift | 3 +- .../Fragments/ConversationFragment.swift | 4 +- .../Fragments/ConversationInfoFragment.swift | 4 +- .../Fragments/StartConversationFragment.swift | 3 +- .../Fragments/HistoryContactFragment.swift | 6 +- .../History/Fragments/HistoryFragment.swift | 8 +- .../Fragments/HistoryListBottomSheet.swift | 4 +- .../History/Fragments/StartCallFragment.swift | 2 +- Linphone/UI/Main/History/HistoryView.swift | 6 +- LinphoneApp.xcodeproj/project.pbxproj | 16 +- 30 files changed, 584 insertions(+), 710 deletions(-) delete mode 100644 Linphone/UI/Main/Contacts/ViewModel/ContactViewModel.swift delete mode 100644 Linphone/UI/Main/Contacts/ViewModel/FavoriteContactsListViewModel.swift diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift index 20ab6c4ab..5ff3617d4 100644 --- a/Linphone/Core/CoreContext.swift +++ b/Linphone/Core/CoreContext.swift @@ -32,9 +32,10 @@ import SwiftUI import Firebase #endif -final class CoreContext: ObservableObject { - - static let shared = CoreContext() +class CoreContext: ObservableObject { + + static let shared = CoreContext() + var pipViewModel = PIPViewModel() var coreVersion: String = Core.getVersion @@ -426,7 +427,7 @@ final class CoreContext: ObservableObject { func performActionOnCoreQueueWhenCoreIsStarted(action: @escaping (_ core: Core) -> Void ) { if coreIsStarted { - CoreContext.shared.doOnCoreQueue { core in + doOnCoreQueue { core in action(core) } } else { diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index 78c8912b1..85aeb7e5e 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -30,14 +30,17 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele var launchNotificationPeerAddr: String? var launchNotificationLocalAddr: String? - var navigationManager: NavigationManager? + var coreContext: CoreContext? + var navigationManager: NavigationManager? func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let tokenStr = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() Log.info("Received remote push token : \(tokenStr)") - CoreContext.shared.doOnCoreQueue { core in - Log.info("Forwarding remote push token to core") - core.didRegisterForRemotePushWithStringifiedToken(deviceTokenStr: tokenStr + ":remote") + if let coreContext = coreContext { + coreContext.doOnCoreQueue { core in + Log.info("Forwarding remote push token to core") + core.didRegisterForRemotePushWithStringifiedToken(deviceTokenStr: tokenStr + ":remote") + } } } @@ -92,14 +95,16 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele } else { // Only display notification if we're not in the chatroom they come from if displayedChatroomPeerAddr != strPeerAddr { - CoreContext.shared.doOnCoreQueue { core in - let nilParams: ConferenceParams? = nil - if let peerAddr = try? Factory.Instance.createAddress(addr: strPeerAddr!) - , let chatroom = core.searchChatRoom(params: nilParams, localAddr: nil, remoteAddr: peerAddr, participants: nil), chatroom.muted { - Log.info("message comes from a muted chatroom, ignore it") - return + if let coreContext = coreContext { + coreContext.doOnCoreQueue { core in + let nilParams: ConferenceParams? = nil + if let peerAddr = try? Factory.Instance.createAddress(addr: strPeerAddr!) + , let chatroom = core.searchChatRoom(params: nilParams, localAddr: nil, remoteAddr: peerAddr, participants: nil), chatroom.muted { + Log.info("message comes from a muted chatroom, ignore it") + return + } + completionHandler([.banner, .sound]) } - completionHandler([.banner, .sound]) } } } @@ -108,13 +113,15 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele func applicationWillTerminate(_ application: UIApplication) { Log.info("IOS applicationWillTerminate") - CoreContext.shared.doOnCoreQueue(synchronous: true) { core in - Log.info("applicationWillTerminate - Stopping linphone core") - MagicSearchSingleton.shared.destroyMagicSearch() - if core.globalState != GlobalState.Off { - core.stop() - } else { - Log.info("applicationWillTerminate - Core already stopped") + if let coreContext = coreContext { + coreContext.doOnCoreQueue(synchronous: true) { core in + Log.info("applicationWillTerminate - Stopping linphone core") + MagicSearchSingleton.shared.destroyMagicSearch() + if core.globalState != GlobalState.Off { + core.stop() + } else { + Log.info("applicationWillTerminate - Core already stopped") + } } } } @@ -125,27 +132,12 @@ struct LinphoneApp: App { @Environment(\.scenePhase) var scenePhase @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate - @StateObject var navigationManager = NavigationManager() - @ObservedObject private var coreContext = CoreContext.shared + @StateObject private var coreContext = CoreContext.shared + @StateObject private var navigationManager = NavigationManager() - @State var index: Int = 0 - - /* - @State private var editContactViewModel: EditContactViewModel? - @State private var historyViewModel: HistoryViewModel? - @State private var historyListViewModel: HistoryListViewModel? - @State private var startCallViewModel: StartCallViewModel? - @State private var startConversationViewModel: StartConversationViewModel? - @State private var callViewModel: CallViewModel? - @State private var meetingWaitingRoomViewModel: MeetingWaitingRoomViewModel? - @State private var conversationsListViewModel: ConversationsListViewModel? - @State private var conversationViewModel: ConversationViewModel? - @State private var meetingsListViewModel: MeetingsListViewModel? - @State private var meetingViewModel: MeetingViewModel? - @State private var conversationForwardMessageViewModel: ConversationForwardMessageViewModel? - @State private var accountProfileViewModel: AccountProfileViewModel? - */ + @ObservedObject private var telecomManager = TelecomManager.shared + @ObservedObject private var sharedMainViewModel = SharedMainViewModel.shared @State private var pendingURL: URL? @@ -153,14 +145,14 @@ struct LinphoneApp: App { WindowGroup { if coreContext.coreHasStartedOnce { ZStack { - if !SharedMainViewModel.shared.welcomeViewDisplayed { + if !sharedMainViewModel.welcomeViewDisplayed { ZStack { WelcomeView() ToastView() .zIndex(3) } - } else if (coreContext.coreIsStarted && coreContext.accounts.isEmpty) || SharedMainViewModel.shared.displayProfileMode { + } else if (coreContext.coreIsStarted && coreContext.accounts.isEmpty) || sharedMainViewModel.displayProfileMode { ZStack { AssistantView() @@ -168,36 +160,21 @@ struct LinphoneApp: App { .zIndex(3) } } else { - ContentView( - //editContactViewModel: editContactViewModel!, - //historyViewModel: historyViewModel!, - //historyListViewModel: historyListViewModel!, - //startCallViewModel: startCallViewModel!, - //startConversationViewModel: startConversationViewModel!, - //callViewModel: callViewModel!, - //meetingWaitingRoomViewModel: meetingWaitingRoomViewModel!, - //conversationsListViewModel: conversationsListViewModel!, - //conversationViewModel: conversationViewModel!, - //meetingsListViewModel: meetingsListViewModel!, - //meetingViewModel: meetingViewModel!, - //conversationForwardMessageViewModel: conversationForwardMessageViewModel!, - //accountProfileViewModel: accountProfileViewModel!, - index: $index - ) - .environmentObject(navigationManager) - .onAppear { - index = SharedMainViewModel.shared.indexView - // Link the navigation manager to the AppDelegate - delegate.navigationManager = navigationManager - - // Check if the app was launched with a notification payload - if let callId = delegate.launchNotificationCallId, let peerAddr = delegate.launchNotificationPeerAddr, let localAddr = delegate.launchNotificationLocalAddr { - // Notify the app to navigate to the chat room - navigationManager.openChatRoom(callId: callId, peerAddr: peerAddr, localAddr: localAddr) + ContentView() + .environmentObject(navigationManager) + .onAppear { + // Link the navigation manager to the AppDelegate + delegate.coreContext = coreContext + delegate.navigationManager = navigationManager + + // Check if the app was launched with a notification payload + if let callId = delegate.launchNotificationCallId, let peerAddr = delegate.launchNotificationPeerAddr, let localAddr = delegate.launchNotificationLocalAddr { + // Notify the app to navigate to the chat room + navigationManager.openChatRoom(callId: callId, peerAddr: peerAddr, localAddr: localAddr) + } + + //accountProfileViewModel!.setAvatarModel() } - - //accountProfileViewModel!.setAvatarModel() - } } if coreContext.coreIsStarted { @@ -223,7 +200,7 @@ struct LinphoneApp: App { SplashScreen() } }.onChange(of: scenePhase) { newPhase in - if !TelecomManager.shared.callInProgress { + if !telecomManager.callInProgress { if newPhase == .active { Log.info("Entering foreground") coreContext.onEnterForeground() diff --git a/Linphone/UI/Call/CallView.swift b/Linphone/UI/Call/CallView.swift index 0d3ae59c4..c45767251 100644 --- a/Linphone/UI/Call/CallView.swift +++ b/Linphone/UI/Call/CallView.swift @@ -37,7 +37,7 @@ struct CallView: View { @ObservedObject var conversationViewModel: ConversationViewModel @ObservedObject var conversationsListViewModel: ConversationsListViewModel @ObservedObject var conversationForwardMessageViewModel: ConversationForwardMessageViewModel - @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var contactsListViewModel: ContactsListViewModel @ObservedObject var editContactViewModel: EditContactViewModel @ObservedObject var meetingViewModel: MeetingViewModel @ObservedObject var accountProfileViewModel: AccountProfileViewModel @@ -209,7 +209,7 @@ struct CallView: View { conversationViewModel: conversationViewModel, conversationsListViewModel: conversationsListViewModel, conversationForwardMessageViewModel: conversationForwardMessageViewModel, - contactViewModel: contactViewModel, + contactsListViewModel: contactsListViewModel, editContactViewModel: editContactViewModel, meetingViewModel: meetingViewModel, accountProfileViewModel: accountProfileViewModel, @@ -2864,7 +2864,7 @@ struct PressedButtonStyle: ButtonStyle { conversationViewModel: ConversationViewModel(), conversationsListViewModel: ConversationsListViewModel(), conversationForwardMessageViewModel: ConversationForwardMessageViewModel(), - contactViewModel: ContactViewModel(), + contactsListViewModel: ContactsListViewModel(), editContactViewModel: EditContactViewModel(), meetingViewModel: MeetingViewModel(), accountProfileViewModel: AccountProfileViewModel(), diff --git a/Linphone/UI/Main/Contacts/ContactsView.swift b/Linphone/UI/Main/Contacts/ContactsView.swift index f318035b1..22f547de5 100644 --- a/Linphone/UI/Main/Contacts/ContactsView.swift +++ b/Linphone/UI/Main/Contacts/ContactsView.swift @@ -21,7 +21,7 @@ import SwiftUI struct ContactsView: View { - @EnvironmentObject var contactViewModel: ContactViewModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @Binding var isShowEditContactFragment: Bool @Binding var isShowDeletePopup: Bool @@ -30,12 +30,11 @@ struct ContactsView: View { var body: some View { NavigationView { ZStack(alignment: .bottomTrailing) { - ContactsFragment(contactViewModel: contactViewModel, isShowDeletePopup: $isShowDeletePopup, text: $text) + ContactsFragment(isShowDeletePopup: $isShowDeletePopup, text: $text) Button { withAnimation { - contactViewModel.selectedEditFriend = nil - //editContactViewModel.resetValues() + contactsListViewModel.selectedEditFriend = nil isShowEditContactFragment.toggle() } } label: { @@ -49,6 +48,7 @@ struct ContactsView: View { } .padding() + // For testing crashlytics /*Button(action: CoreContext.shared.crashForCrashlytics, label: { Text("CRASH ME") @@ -61,9 +61,6 @@ struct ContactsView: View { #Preview { ContactsView( - //contactViewModel: ContactViewModel(), - //historyViewModel: HistoryViewModel(), - //editContactViewModel: EditContactViewModel(), isShowEditContactFragment: .constant(false), isShowDeletePopup: .constant(false), text: .constant("") diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactFragment.swift index e419c131c..1d69e1c6f 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactFragment.swift @@ -24,37 +24,23 @@ struct ContactFragment: View { private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } - @ObservedObject var contactViewModel: ContactViewModel - @ObservedObject var editContactViewModel: EditContactViewModel - @ObservedObject var conversationViewModel: ConversationViewModel + @EnvironmentObject var contactAvatarModel: ContactAvatarModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @Binding var isShowDeletePopup: Bool @Binding var isShowDismissPopup: Bool @Binding var isShowSipAddressesPopup: Bool @Binding var isShowSipAddressesPopupType: Int + @Binding var isShowEditContactFragmentInContactDetails: Bool @State private var showingSheet = false @State private var showShareSheet = false var body: some View { - let indexDisplayed = SharedMainViewModel.shared.indexDisplayedFriend != nil ? SharedMainViewModel.shared.indexDisplayedFriend! : 0 - if ContactsManager.shared.avatarListModel.count > indexDisplayed { - if #available(iOS 16.0, *), idiom != .pad { - ContactInnerFragment( - contactAvatarModel: ContactsManager.shared.avatarListModel[indexDisplayed], - contactViewModel: contactViewModel, - editContactViewModel: editContactViewModel, - conversationViewModel: conversationViewModel, - cnContact: CNContact(), - isShowDeletePopup: $isShowDeletePopup, - showingSheet: $showingSheet, - showShareSheet: $showShareSheet, - isShowDismissPopup: $isShowDismissPopup, - isShowSipAddressesPopup: $isShowSipAddressesPopup, - isShowSipAddressesPopupType: $isShowSipAddressesPopupType - ) + if #available(iOS 16.0, *), idiom != .pad { + contactInnerContent(contactsListViewModel: contactsListViewModel) .sheet(isPresented: $showingSheet) { - ContactListBottomSheet(contactViewModel: contactViewModel, showingSheet: $showingSheet) + ContactListBottomSheet(contactsListViewModel: contactsListViewModel, showingSheet: $showingSheet) .presentationDetents([.fraction(0.2)]) } .sheet(isPresented: $showShareSheet) { @@ -62,40 +48,39 @@ struct ContactFragment: View { .presentationDetents([.medium]) .edgesIgnoringSafeArea(.bottom) } - } else { - ContactInnerFragment( - contactAvatarModel: ContactsManager.shared.avatarListModel[indexDisplayed], - contactViewModel: contactViewModel, - editContactViewModel: editContactViewModel, - conversationViewModel: conversationViewModel, - cnContact: CNContact(), - isShowDeletePopup: $isShowDeletePopup, - showingSheet: $showingSheet, - showShareSheet: $showShareSheet, - isShowDismissPopup: $isShowDismissPopup, - isShowSipAddressesPopup: $isShowSipAddressesPopup, - isShowSipAddressesPopupType: $isShowSipAddressesPopupType - ) + } else { + contactInnerContent(contactsListViewModel: contactsListViewModel) .halfSheet(showSheet: $showingSheet) { - ContactListBottomSheet(contactViewModel: contactViewModel, showingSheet: $showingSheet) + ContactListBottomSheet(contactsListViewModel: contactsListViewModel, showingSheet: $showingSheet) } onDismiss: {} - .sheet(isPresented: $showShareSheet) { - ShareSheet(friendToShare: ContactsManager.shared.lastSearch[SharedMainViewModel.shared.indexDisplayedFriend!].friend!) - .edgesIgnoringSafeArea(.bottom) - } - } + .sheet(isPresented: $showShareSheet) { + ShareSheet(friendToShare: ContactsManager.shared.lastSearch[SharedMainViewModel.shared.indexDisplayedFriend!].friend!) + .edgesIgnoringSafeArea(.bottom) + } } } + + @ViewBuilder + private func contactInnerContent(contactsListViewModel: ContactsListViewModel) -> some View { + ContactInnerFragment( + cnContact: CNContact(), + isShowDeletePopup: $isShowDeletePopup, + showingSheet: $showingSheet, + showShareSheet: $showShareSheet, + isShowDismissPopup: $isShowDismissPopup, + isShowSipAddressesPopup: $isShowSipAddressesPopup, + isShowSipAddressesPopupType: $isShowSipAddressesPopupType, + isShowEditContactFragmentInContactDetails: $isShowEditContactFragmentInContactDetails + ) + } } #Preview { ContactFragment( - contactViewModel: ContactViewModel(), - editContactViewModel: EditContactViewModel(), - conversationViewModel: ConversationViewModel(), isShowDeletePopup: .constant(false), isShowDismissPopup: .constant(false), isShowSipAddressesPopup: .constant(false), - isShowSipAddressesPopupType: .constant(0) + isShowSipAddressesPopupType: .constant(0), + isShowEditContactFragmentInContactDetails: .constant(false) ) } diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift index 88e3621c4..065ec2a93 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift @@ -26,9 +26,8 @@ struct ContactInnerActionsFragment: View { @ObservedObject var contactsManager = ContactsManager.shared @ObservedObject private var telecomManager = TelecomManager.shared - @ObservedObject var contactViewModel: ContactViewModel - @ObservedObject var editContactViewModel: EditContactViewModel - @ObservedObject var contactAvatarModel: ContactAvatarModel + @EnvironmentObject var contactAvatarModel: ContactAvatarModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @State private var informationIsOpen = true @@ -36,6 +35,7 @@ struct ContactInnerActionsFragment: View { @Binding var showShareSheet: Bool @Binding var isShowDeletePopup: Bool @Binding var isShowDismissPopup: Bool + @Binding var isShowEditContactFragmentInContactDetails: Bool var actionEditButton: () -> Void @@ -102,7 +102,7 @@ struct ContactInnerActionsFragment: View { } } .onLongPressGesture(minimumDuration: 0.2) { - contactViewModel.stringToCopy = contactAvatarModel.addresses[index] + contactsListViewModel.stringToCopy = contactAvatarModel.addresses[index] showingSheet.toggle() } @@ -142,7 +142,7 @@ struct ContactInnerActionsFragment: View { } .background(.white) .onLongPressGesture(minimumDuration: 0.2) { - contactViewModel.stringToCopy = + contactsListViewModel.stringToCopy = contactAvatarModel.friend!.phoneNumbersWithLabel[index].phoneNumber showingSheet.toggle() } @@ -238,9 +238,8 @@ struct ContactInnerActionsFragment: View { } } else { NavigationLink(destination: EditContactFragment( - editContactViewModel: editContactViewModel, - contactViewModel: contactViewModel, - isShowEditContactFragment: .constant(false), + friend: contactAvatarModel.friend!, + isShowEditContactFragment: $isShowEditContactFragmentInContactDetails, isShowDismissPopup: $isShowDismissPopup)) { HStack { Image("pencil-simple") @@ -259,13 +258,12 @@ struct ContactInnerActionsFragment: View { } .padding(.vertical, 15) .padding(.horizontal, 20) - } - .simultaneousGesture( - TapGesture().onEnded { - editContactViewModel.selectedEditFriend = contactAvatarModel.friend! - editContactViewModel.resetValues() - } - ) + } + .simultaneousGesture( + TapGesture().onEnded { + isShowEditContactFragmentInContactDetails = true + } + ) } VStack { @@ -365,13 +363,11 @@ struct ContactInnerActionsFragment: View { #Preview { ContactInnerActionsFragment( - contactViewModel: ContactViewModel(), - editContactViewModel: EditContactViewModel(), - contactAvatarModel: ContactAvatarModel(friend: nil, name: "", address: "", withPresence: false), showingSheet: .constant(false), showShareSheet: .constant(false), isShowDeletePopup: .constant(false), isShowDismissPopup: .constant(false), + isShowEditContactFragmentInContactDetails: .constant(false), actionEditButton: {} ) } diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift index 5756841ac..5e367a452 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift @@ -27,10 +27,8 @@ struct ContactInnerFragment: View { @ObservedObject var contactsManager = ContactsManager.shared @ObservedObject private var telecomManager = TelecomManager.shared - @ObservedObject var contactAvatarModel: ContactAvatarModel - @ObservedObject var contactViewModel: ContactViewModel - @ObservedObject var editContactViewModel: EditContactViewModel - @ObservedObject var conversationViewModel: ConversationViewModel + @EnvironmentObject var contactAvatarModel: ContactAvatarModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @State private var orientation = UIDevice.current.orientation @@ -43,6 +41,7 @@ struct ContactInnerFragment: View { @Binding var isShowDismissPopup: Bool @Binding var isShowSipAddressesPopup: Bool @Binding var isShowSipAddressesPopupType: Int + @Binding var isShowEditContactFragmentInContactDetails: Bool var body: some View { NavigationView { @@ -87,9 +86,8 @@ struct ContactInnerFragment: View { }) } else { NavigationLink(destination: EditContactFragment( - editContactViewModel: editContactViewModel, - contactViewModel: contactViewModel, - isShowEditContactFragment: .constant(false), + friend: contactAvatarModel.friend, + isShowEditContactFragment: $isShowEditContactFragmentInContactDetails, isShowDismissPopup: $isShowDismissPopup)) { Image("pencil-simple") .renderingMode(.template) @@ -101,10 +99,9 @@ struct ContactInnerFragment: View { } .simultaneousGesture( TapGesture().onEnded { - editContactViewModel.selectedEditFriend = contactAvatarModel.friend - editContactViewModel.resetValues() + isShowEditContactFragmentInContactDetails = true } - ) + ) } } .frame(maxWidth: .infinity) @@ -181,7 +178,7 @@ struct ContactInnerFragment: View { if contactAvatarModel.addresses.count <= 1 { do { let address = try Factory.Instance.createAddress(addr: contactAvatarModel.address) - contactViewModel.createOneToOneChatRoomWith(remote: address) + contactsListViewModel.createOneToOneChatRoomWith(remote: address) } catch { Log.error("[ContactInnerFragment] unable to create address for a new outgoing call : \(contactAvatarModel.address) \(error) ") } @@ -248,12 +245,11 @@ struct ContactInnerFragment: View { .background(Color.gray100) ContactInnerActionsFragment( - contactViewModel: contactViewModel, - editContactViewModel: editContactViewModel, - contactAvatarModel: contactAvatarModel, showingSheet: $showingSheet, + showingSheet: $showingSheet, showShareSheet: $showShareSheet, isShowDeletePopup: $isShowDeletePopup, isShowDismissPopup: $isShowDismissPopup, + isShowEditContactFragmentInContactDetails: $isShowEditContactFragmentInContactDetails, actionEditButton: editNativeContact ) } @@ -301,15 +297,12 @@ struct ContactInnerFragment: View { #Preview { ContactInnerFragment( - contactAvatarModel: ContactAvatarModel(friend: nil, name: "", address: "", withPresence: true), - contactViewModel: ContactViewModel(), - editContactViewModel: EditContactViewModel(), - conversationViewModel: ConversationViewModel(), isShowDeletePopup: .constant(false), showingSheet: .constant(false), showShareSheet: .constant(false), isShowDismissPopup: .constant(false), isShowSipAddressesPopup: .constant(false), - isShowSipAddressesPopupType: .constant(0) + isShowSipAddressesPopupType: .constant(0), + isShowEditContactFragmentInContactDetails: .constant(false) ) } diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactListBottomSheet.swift b/Linphone/UI/Main/Contacts/Fragments/ContactListBottomSheet.swift index 10a88ece4..04fc8c833 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactListBottomSheet.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactListBottomSheet.swift @@ -24,7 +24,7 @@ struct ContactListBottomSheet: View { private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } - @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var contactsListViewModel: ContactsListViewModel @State private var orientation = UIDevice.current.orientation @@ -55,9 +55,9 @@ struct ContactListBottomSheet: View { Spacer() Button { UIPasteboard.general.setValue( - contactViewModel.stringToCopy.prefix(4) == "sip:" - ? contactViewModel.stringToCopy.dropFirst(4) - : contactViewModel.stringToCopy, + contactsListViewModel.stringToCopy.prefix(4) == "sip:" + ? contactsListViewModel.stringToCopy.dropFirst(4) + : contactsListViewModel.stringToCopy, forPasteboardType: UTType.plainText.identifier) if #available(iOS 16.0, *) { @@ -78,7 +78,7 @@ struct ContactListBottomSheet: View { .foregroundStyle(Color.grayMain2c500) .frame(width: 25, height: 25, alignment: .leading) .padding(.all, 10) - Text(contactViewModel.stringToCopy.prefix(4) == "sip:" + Text(contactsListViewModel.stringToCopy.prefix(4) == "sip:" ? "menu_copy_sip_address" : "menu_copy_phone_number") .default_text_style(styleSize: 16) Spacer() @@ -93,7 +93,7 @@ struct ContactListBottomSheet: View { } .frame(maxWidth: .infinity) - if contactViewModel.stringToCopy.prefix(4) != "sip:" { + if contactsListViewModel.stringToCopy.prefix(4) != "sip:" { Button { if #available(iOS 16.0, *) { if idiom != .pad { @@ -144,7 +144,7 @@ struct ContactListBottomSheet: View { .foregroundStyle(Color.grayMain2c500) .frame(width: 25, height: 25, alignment: .leading) .padding(.all, 10) - Text(contactViewModel.stringToCopy.prefix(4) == "sip:" + Text(contactsListViewModel.stringToCopy.prefix(4) == "sip:" ? "menu_block_address" : "menu_block_number") .default_text_style(styleSize: 16) Spacer() @@ -164,5 +164,5 @@ struct ContactListBottomSheet: View { } #Preview { - ContactListBottomSheet(contactViewModel: ContactViewModel(), showingSheet: .constant(false)) + ContactListBottomSheet(contactsListViewModel: ContactsListViewModel(), showingSheet: .constant(false)) } diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactsFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsFragment.swift index 7ed99e3bb..a64525b45 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactsFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactsFragment.swift @@ -23,7 +23,7 @@ struct ContactsFragment: View { private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } - @ObservedObject var contactViewModel: ContactViewModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @Binding var isShowDeletePopup: Bool @@ -34,10 +34,9 @@ struct ContactsFragment: View { var body: some View { ZStack { if #available(iOS 16.0, *), idiom != .pad { - ContactsInnerFragment(contactViewModel: contactViewModel, showingSheet: $showingSheet, text: $text) + ContactsInnerFragment(showingSheet: $showingSheet, text: $text) .sheet(isPresented: $showingSheet) { ContactsListBottomSheet( - contactViewModel: contactViewModel, isShowDeletePopup: $isShowDeletePopup, showingSheet: $showingSheet, showShareSheet: $showShareSheet @@ -45,22 +44,21 @@ struct ContactsFragment: View { .presentationDetents([.fraction(0.2)]) } .sheet(isPresented: $showShareSheet) { - ShareSheet(friendToShare: contactViewModel.selectedFriendToShare!) + ShareSheet(friendToShare: contactsListViewModel.selectedFriendToShare!) .presentationDetents([.medium]) .edgesIgnoringSafeArea(.bottom) } } else { - ContactsInnerFragment(contactViewModel: contactViewModel, showingSheet: $showingSheet, text: $text) + ContactsInnerFragment(showingSheet: $showingSheet, text: $text) .halfSheet(showSheet: $showingSheet) { ContactsListBottomSheet( - contactViewModel: contactViewModel, isShowDeletePopup: $isShowDeletePopup, showingSheet: $showingSheet, showShareSheet: $showShareSheet ) } onDismiss: {} .sheet(isPresented: $showShareSheet) { - ShareSheet(friendToShare: contactViewModel.selectedFriendToShare!) + ShareSheet(friendToShare: contactsListViewModel.selectedFriendToShare!) .edgesIgnoringSafeArea(.bottom) } } @@ -69,5 +67,5 @@ struct ContactsFragment: View { } #Preview { - ContactsFragment(contactViewModel: ContactViewModel(), isShowDeletePopup: .constant(false), text: .constant("")) + ContactsFragment(isShowDeletePopup: .constant(false), text: .constant("")) } diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactsInnerFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsInnerFragment.swift index 774d33b1b..20bd5d5f5 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactsInnerFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactsInnerFragment.swift @@ -24,7 +24,7 @@ struct ContactsInnerFragment: View { @ObservedObject var contactsManager = ContactsManager.shared - @ObservedObject var contactViewModel: ContactViewModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @State private var isFavoriteOpen = true @@ -57,10 +57,7 @@ struct ContactsInnerFragment: View { } if isFavoriteOpen { - FavoriteContactsListFragment( - contactViewModel: contactViewModel, - favoriteContactsListViewModel: FavoriteContactsListViewModel(), - showingSheet: $showingSheet) + FavoriteContactsListFragment(showingSheet: $showingSheet) .zIndex(-1) .transition(.move(edge: .top)) } @@ -77,8 +74,7 @@ struct ContactsInnerFragment: View { VStack { List { - ContactsListFragment(contactViewModel: contactViewModel, contactsListViewModel: ContactsListViewModel(), - showingSheet: $showingSheet, startCallFunc: {_ in })} + ContactsListFragment(showingSheet: $showingSheet, startCallFunc: {_ in })} .safeAreaInset(edge: .top, content: { Spacer() .frame(height: 12) @@ -108,5 +104,5 @@ struct ContactsInnerFragment: View { } #Preview { - ContactsInnerFragment(contactViewModel: ContactViewModel(), showingSheet: .constant(false), text: .constant("")) + ContactsInnerFragment(showingSheet: .constant(false), text: .constant("")) } diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift index d1e199961..5f97af6c0 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift @@ -27,7 +27,7 @@ struct ContactsListBottomSheet: View { private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } - @ObservedObject var contactViewModel: ContactViewModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @State private var orientation = UIDevice.current.orientation @@ -57,10 +57,10 @@ struct ContactsListBottomSheet: View { Spacer() Button { - if contactViewModel.selectedFriend != nil { - contactViewModel.selectedFriend!.edit() - contactViewModel.selectedFriend!.starred.toggle() - contactViewModel.selectedFriend!.done() + if contactsListViewModel.selectedFriend != nil { + contactsListViewModel.selectedFriend!.edit() + contactsListViewModel.selectedFriend!.starred.toggle() + contactsListViewModel.selectedFriend!.done() } MagicSearchSingleton.shared.searchForContacts(sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) @@ -78,19 +78,19 @@ struct ContactsListBottomSheet: View { } } label: { HStack { - Image(contactViewModel.selectedFriend != nil && contactViewModel.selectedFriend!.starred == true ? "heart-fill" : "heart") + Image(contactsListViewModel.selectedFriend != nil && contactsListViewModel.selectedFriend!.starred == true ? "heart-fill" : "heart") .renderingMode(.template) .resizable() .foregroundStyle( - contactViewModel.selectedFriend != nil && contactViewModel.selectedFriend!.starred == true + contactsListViewModel.selectedFriend != nil && contactsListViewModel.selectedFriend!.starred == true ? Color.redDanger500 : Color.grayMain2c500 ) .frame(width: 25, height: 25, alignment: .leading) .padding(.all, 10) - Text(contactViewModel.selectedFriend != nil && contactViewModel.selectedFriend!.starred == true - ? "contact_details_add_to_favourites" - : "contact_details_remove_from_favourites") + Text(contactsListViewModel.selectedFriend != nil && contactsListViewModel.selectedFriend!.starred == true + ? "contact_details_remove_from_favourites" + : "contact_details_add_to_favourites") .default_text_style(styleSize: 16) Spacer() } @@ -117,7 +117,7 @@ struct ContactsListBottomSheet: View { dismiss() } - contactViewModel.selectedFriendToShare = contactViewModel.selectedFriend + contactsListViewModel.selectedFriendToShare = contactsListViewModel.selectedFriend DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { showShareSheet.toggle() @@ -146,7 +146,7 @@ struct ContactsListBottomSheet: View { .frame(maxWidth: .infinity) Button { - if contactViewModel.selectedFriend != nil { + if contactsListViewModel.selectedFriend != nil { isShowDeletePopup.toggle() } @@ -186,7 +186,7 @@ struct ContactsListBottomSheet: View { orientation = newOrientation } .onDisappear { - contactViewModel.selectedFriend = nil + contactsListViewModel.selectedFriend = nil } } } diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift index 7afd8ea35..0c085488c 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift @@ -24,8 +24,7 @@ struct ContactsListFragment: View { @ObservedObject var contactsManager = ContactsManager.shared - @ObservedObject var contactViewModel: ContactViewModel - @ObservedObject var contactsListViewModel: ContactsListViewModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @Binding var showingSheet: Bool @@ -88,22 +87,21 @@ struct ContactsListFragment: View { SharedMainViewModel.shared.indexDisplayedFriend = index } - if index < contactsManager.lastSearch.count && contactsManager.lastSearch[index].friend != nil - && contactsManager.lastSearch[index].friend!.address != nil { - startCallFunc(contactsManager.lastSearch[index].friend!.address!) + if index < contactsManager.avatarListModel.count && contactsManager.avatarListModel[index].friend != nil + && contactsManager.avatarListModel[index].friend!.address != nil { + startCallFunc(contactsManager.avatarListModel[index].friend!.address!) + } + } + .onLongPressGesture(minimumDuration: 0.2) { + if index < contactsManager.avatarListModel.count && contactsManager.avatarListModel[index].friend != nil { + contactsListViewModel.selectedFriend = contactsManager.avatarListModel[index].friend + showingSheet.toggle() } - } - .onLongPressGesture(minimumDuration: 0.2) { - contactViewModel.selectedFriend = contactsManager.lastSearch[index].friend - showingSheet.toggle() } } } } #Preview { - ContactsListFragment(contactViewModel: ContactViewModel() - , contactsListViewModel: ContactsListViewModel() - , showingSheet: .constant(false) - , startCallFunc: {_ in }) + ContactsListFragment(showingSheet: .constant(false), startCallFunc: {_ in }) } diff --git a/Linphone/UI/Main/Contacts/Fragments/EditContactFragment.swift b/Linphone/UI/Main/Contacts/Fragments/EditContactFragment.swift index 9e25d63e5..d43cd7f0a 100644 --- a/Linphone/UI/Main/Contacts/Fragments/EditContactFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/EditContactFragment.swift @@ -23,14 +23,12 @@ import linphonesw // swiftlint:disable type_body_length struct EditContactFragment: View { - @ObservedObject var editContactViewModel: EditContactViewModel - @Environment(\.dismiss) var dismiss private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } @State private var orientation = UIDevice.current.orientation - var contactViewModel: ContactViewModel + @StateObject private var editContactViewModel: EditContactViewModel @Binding var isShowEditContactFragment: Bool @Binding var isShowDismissPopup: Bool @@ -48,6 +46,12 @@ struct EditContactFragment: View { @State private var selectedImage: UIImage? @State private var removedImage = false + init(friend: Friend? = nil, isShowEditContactFragment: Binding, isShowDismissPopup: Binding) { + _editContactViewModel = StateObject(wrappedValue: EditContactViewModel(friend: friend)) + self._isShowEditContactFragment = isShowEditContactFragment + self._isShowDismissPopup = isShowDismissPopup + } + var body: some View { ZStack { VStack(spacing: 1) { @@ -468,16 +472,13 @@ struct EditContactFragment: View { } .background(.white) - if editContactViewModel.removePopup { + if !isShowEditContactFragment { ZStack { }.onAppear { - if editContactViewModel.selectedEditFriend == nil { - delayColorDismiss() - } else { + if editContactViewModel.selectedEditFriend != nil { dismiss() } - editContactViewModel.removePopup = false } } } @@ -558,8 +559,6 @@ struct EditContactFragment: View { #Preview { EditContactFragment( - editContactViewModel: EditContactViewModel(), - contactViewModel: ContactViewModel(), isShowEditContactFragment: .constant(false), isShowDismissPopup: .constant(false) ) diff --git a/Linphone/UI/Main/Contacts/Fragments/FavoriteContactsListFragment.swift b/Linphone/UI/Main/Contacts/Fragments/FavoriteContactsListFragment.swift index 68338983e..38e56712d 100644 --- a/Linphone/UI/Main/Contacts/Fragments/FavoriteContactsListFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/FavoriteContactsListFragment.swift @@ -24,8 +24,7 @@ struct FavoriteContactsListFragment: View { @ObservedObject var contactsManager = ContactsManager.shared - @ObservedObject var contactViewModel: ContactViewModel - @ObservedObject var favoriteContactsListViewModel: FavoriteContactsListViewModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @Binding var showingSheet: Bool @@ -57,7 +56,7 @@ struct FavoriteContactsListFragment: View { } } .onLongPressGesture(minimumDuration: 0.2) { - contactViewModel.selectedFriend = contactsManager.lastSearch[index].friend + contactsListViewModel.selectedFriend = contactsManager.lastSearch[index].friend showingSheet.toggle() } .frame(minWidth: 70, maxWidth: 70) @@ -72,7 +71,5 @@ struct FavoriteContactsListFragment: View { #Preview { FavoriteContactsListFragment( - contactViewModel: ContactViewModel(), - favoriteContactsListViewModel: FavoriteContactsListViewModel(), showingSheet: .constant(false)) } diff --git a/Linphone/UI/Main/Contacts/Fragments/SipAddressesPopup.swift b/Linphone/UI/Main/Contacts/Fragments/SipAddressesPopup.swift index 30a5da3d3..f2e71bb91 100644 --- a/Linphone/UI/Main/Contacts/Fragments/SipAddressesPopup.swift +++ b/Linphone/UI/Main/Contacts/Fragments/SipAddressesPopup.swift @@ -24,8 +24,8 @@ struct SipAddressesPopup: View { @ObservedObject private var telecomManager = TelecomManager.shared - @ObservedObject var contactAvatarModel: ContactAvatarModel - @ObservedObject var contactViewModel: ContactViewModel + @EnvironmentObject var contactAvatarModel: ContactAvatarModel + @EnvironmentObject var contactsListViewModel: ContactsListViewModel @Binding var isShowSipAddressesPopup: Bool @Binding var isShowSipAddressesPopupType: Int @@ -80,7 +80,7 @@ struct SipAddressesPopup: View { } else { withAnimation { isShowSipAddressesPopup = false - contactViewModel.createOneToOneChatRoomWith(remote: address) + contactsListViewModel.createOneToOneChatRoomWith(remote: address) isShowSipAddressesPopupType = 0 } } @@ -104,8 +104,6 @@ struct SipAddressesPopup: View { #Preview { SipAddressesPopup( - contactAvatarModel: ContactAvatarModel(friend: nil, name: "", address: "", withPresence: false), - contactViewModel: ContactViewModel(), isShowSipAddressesPopup: .constant(true), isShowSipAddressesPopupType: .constant(0) ) diff --git a/Linphone/UI/Main/Contacts/ViewModel/ContactViewModel.swift b/Linphone/UI/Main/Contacts/ViewModel/ContactViewModel.swift deleted file mode 100644 index 9def1c007..000000000 --- a/Linphone/UI/Main/Contacts/ViewModel/ContactViewModel.swift +++ /dev/null @@ -1,215 +0,0 @@ -/* - * 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 . - */ - -import linphonesw -import Combine -import SwiftUI - -// swiftlint:disable line_length -class ContactViewModel: ObservableObject { - @Published var selectedEditFriend: Friend? - - var stringToCopy: String = "" - - var selectedFriend: Friend? - var selectedFriendToShare: Friend? - var selectedFriendToDelete: Friend? - - @Published var operationInProgress: Bool = false - @Published var displayedConversation: ConversationModel? - - private var contactChatRoomDelegate: ChatRoomDelegate? - - init() {} - - func createOneToOneChatRoomWith(remote: Address) { - CoreContext.shared.doOnCoreQueue { core in - let account = core.defaultAccount - if account == nil { - Log.error( - "\(ConversationForwardMessageViewModel.TAG) No default account found, can't create conversation with \(remote.asStringUriOnly())" - ) - return - } - - DispatchQueue.main.async { - self.operationInProgress = true - } - - do { - let params = try core.createConferenceParams(conference: nil) - params.chatEnabled = true - params.groupEnabled = false - params.subject = NSLocalizedString("conversation_one_to_one_hidden_subject", comment: "") - params.account = account - - guard let chatParams = params.chatParams else { return } - chatParams.ephemeralLifetime = 0 // Make sure ephemeral is disabled by default - - let sameDomain = remote.domain == CorePreferences.defaultDomain && remote.domain == account!.params?.domain - if account!.params != nil && (account!.params!.instantMessagingEncryptionMandatory && sameDomain) { - Log.info("\(ConversationForwardMessageViewModel.TAG) Account is in secure mode & domain matches, creating an E2E encrypted conversation") - chatParams.backend = ChatRoom.Backend.FlexisipChat - params.securityLevel = Conference.SecurityLevel.EndToEnd - } else if account!.params != nil && (!account!.params!.instantMessagingEncryptionMandatory) { - if LinphoneUtils.isEndToEndEncryptedChatAvailable(core: core) { - Log.info( - "\(ConversationForwardMessageViewModel.TAG) Account is in interop mode but LIME is available, creating an E2E encrypted conversation" - ) - chatParams.backend = ChatRoom.Backend.FlexisipChat - params.securityLevel = Conference.SecurityLevel.EndToEnd - } else { - Log.info( - "\(ConversationForwardMessageViewModel.TAG) Account is in interop mode but LIME isn't available, creating a SIP simple conversation" - ) - chatParams.backend = ChatRoom.Backend.Basic - params.securityLevel = Conference.SecurityLevel.None - } - } else { - Log.error( - "\(ConversationForwardMessageViewModel.TAG) Account is in secure mode, can't chat with SIP address of different domain \(remote.asStringUriOnly())" - ) - - DispatchQueue.main.async { - self.operationInProgress = false - ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error" - ToastViewModel.shared.displayToast = true - } - return - } - - let participants = [remote] - let localAddress = account?.params?.identityAddress - let existingChatRoom = core.searchChatRoom(params: params, localAddr: localAddress, remoteAddr: nil, participants: participants) - if existingChatRoom == nil { - Log.info( - "\(ConversationForwardMessageViewModel.TAG) No existing 1-1 conversation between local account \(localAddress?.asStringUriOnly() ?? "") and remote \(remote.asStringUriOnly()) was found for given parameters, let's create it" - ) - - do { - let chatRoom = try core.createChatRoom(params: params, participants: participants) - if chatParams.backend == ChatRoom.Backend.FlexisipChat { - let state = chatRoom.state - if state == ChatRoom.State.Created { - let chatRoomId = LinphoneUtils.getConversationId(chatRoom: chatRoom) - Log.info("\(ConversationForwardMessageViewModel.TAG) 1-1 conversation \(chatRoomId) has been created") - - let model = ConversationModel(chatRoom: chatRoom) - DispatchQueue.main.async { - self.displayedConversation = model - self.operationInProgress = false - } - } else { - Log.info("\(ConversationForwardMessageViewModel.TAG) Conversation isn't in Created state yet (state is \(state)), wait for it") - self.chatRoomAddDelegate(core: core, chatRoom: chatRoom) - } - } else { - let chatRoomId = LinphoneUtils.getConversationId(chatRoom: chatRoom) - Log.info("\(ConversationForwardMessageViewModel.TAG) Conversation successfully created \(chatRoomId)") - - let model = ConversationModel(chatRoom: chatRoom) - DispatchQueue.main.async { - self.displayedConversation = model - self.operationInProgress = false - } - } - } catch { - Log.error("\(ConversationForwardMessageViewModel.TAG) Failed to create 1-1 conversation with \(remote.asStringUriOnly())") - - DispatchQueue.main.async { - self.operationInProgress = false - ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error" - ToastViewModel.shared.displayToast = true - } - } - } else { - Log.warn( - "\(ConversationForwardMessageViewModel.TAG) A 1-1 conversation between local account \(localAddress?.asStringUriOnly() ?? "") and remote \(remote.asStringUriOnly()) for given parameters already exists!" - ) - let model = ConversationModel(chatRoom: existingChatRoom!) - DispatchQueue.main.async { - self.displayedConversation = model - self.operationInProgress = false - } - } - } catch { - } - } - } - - func chatRoomAddDelegate(core: Core, chatRoom: ChatRoom) { - contactChatRoomDelegate = ChatRoomDelegateStub(onStateChanged: { (chatRoom: ChatRoom, state: ChatRoom.State) in - let state = chatRoom.state - let id = LinphoneUtils.getChatRoomId(room: chatRoom) - if state == ChatRoom.State.CreationFailed { - Log.error("\(StartConversationViewModel.TAG) Conversation \(id) creation has failed!") - if let delegate = self.contactChatRoomDelegate { - chatRoom.removeDelegate(delegate: delegate) - self.contactChatRoomDelegate = nil - } - DispatchQueue.main.async { - self.operationInProgress = false - ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error" - ToastViewModel.shared.displayToast = true - } - } - }, onConferenceJoined: { (chatRoom: ChatRoom, _: EventLog) in - let state = chatRoom.state - let id = LinphoneUtils.getChatRoomId(room: chatRoom) - Log.info("\(StartConversationViewModel.TAG) Conversation \(id) \(chatRoom.subject ?? "") state changed: \(state)") - if state == ChatRoom.State.Created { - Log.info("\(StartConversationViewModel.TAG) Conversation \(id) successfully created") - if let delegate = self.contactChatRoomDelegate { - chatRoom.removeDelegate(delegate: delegate) - self.contactChatRoomDelegate = nil - } - let model = ConversationModel(chatRoom: chatRoom) - if self.operationInProgress == false { - DispatchQueue.main.async { - self.operationInProgress = true - } - - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - self.operationInProgress = false - self.displayedConversation = model - } - } else { - DispatchQueue.main.async { - self.operationInProgress = false - self.displayedConversation = model - } - } - } else if state == ChatRoom.State.CreationFailed { - Log.error("\(StartConversationViewModel.TAG) Conversation \(id) creation has failed!") - - if let delegate = self.contactChatRoomDelegate { - chatRoom.removeDelegate(delegate: delegate) - self.contactChatRoomDelegate = nil - } - DispatchQueue.main.async { - self.operationInProgress = false - ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error" - ToastViewModel.shared.displayToast = true - } - } - }) - chatRoom.addDelegate(delegate: contactChatRoomDelegate!) - } -} -// swiftlint:enable line_length diff --git a/Linphone/UI/Main/Contacts/ViewModel/ContactsListViewModel.swift b/Linphone/UI/Main/Contacts/ViewModel/ContactsListViewModel.swift index 5381e8d82..2509a9bc5 100644 --- a/Linphone/UI/Main/Contacts/ViewModel/ContactsListViewModel.swift +++ b/Linphone/UI/Main/Contacts/ViewModel/ContactsListViewModel.swift @@ -18,9 +18,198 @@ */ import linphonesw +import Combine import SwiftUI +// swiftlint:disable line_length class ContactsListViewModel: ObservableObject { + @Published var selectedEditFriend: Friend? - init() {} + var stringToCopy: String = "" + + var selectedFriend: Friend? + var selectedFriendToShare: Friend? + var selectedFriendToDelete: Friend? + + @Published var operationInProgress: Bool = false + @Published var displayedConversation: ConversationModel? + + private var contactChatRoomDelegate: ChatRoomDelegate? + + init() {} + + func createOneToOneChatRoomWith(remote: Address) { + CoreContext.shared.doOnCoreQueue { core in + let account = core.defaultAccount + if account == nil { + Log.error( + "\(ConversationForwardMessageViewModel.TAG) No default account found, can't create conversation with \(remote.asStringUriOnly())" + ) + return + } + + DispatchQueue.main.async { + self.operationInProgress = true + } + + do { + let params = try core.createConferenceParams(conference: nil) + params.chatEnabled = true + params.groupEnabled = false + params.subject = NSLocalizedString("conversation_one_to_one_hidden_subject", comment: "") + params.account = account + + guard let chatParams = params.chatParams else { return } + chatParams.ephemeralLifetime = 0 // Make sure ephemeral is disabled by default + + let sameDomain = remote.domain == CorePreferences.defaultDomain && remote.domain == account!.params?.domain + if account!.params != nil && (account!.params!.instantMessagingEncryptionMandatory && sameDomain) { + Log.info("\(ConversationForwardMessageViewModel.TAG) Account is in secure mode & domain matches, creating an E2E encrypted conversation") + chatParams.backend = ChatRoom.Backend.FlexisipChat + params.securityLevel = Conference.SecurityLevel.EndToEnd + } else if account!.params != nil && (!account!.params!.instantMessagingEncryptionMandatory) { + if LinphoneUtils.isEndToEndEncryptedChatAvailable(core: core) { + Log.info( + "\(ConversationForwardMessageViewModel.TAG) Account is in interop mode but LIME is available, creating an E2E encrypted conversation" + ) + chatParams.backend = ChatRoom.Backend.FlexisipChat + params.securityLevel = Conference.SecurityLevel.EndToEnd + } else { + Log.info( + "\(ConversationForwardMessageViewModel.TAG) Account is in interop mode but LIME isn't available, creating a SIP simple conversation" + ) + chatParams.backend = ChatRoom.Backend.Basic + params.securityLevel = Conference.SecurityLevel.None + } + } else { + Log.error( + "\(ConversationForwardMessageViewModel.TAG) Account is in secure mode, can't chat with SIP address of different domain \(remote.asStringUriOnly())" + ) + + DispatchQueue.main.async { + self.operationInProgress = false + ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error" + ToastViewModel.shared.displayToast = true + } + return + } + + let participants = [remote] + let localAddress = account?.params?.identityAddress + let existingChatRoom = core.searchChatRoom(params: params, localAddr: localAddress, remoteAddr: nil, participants: participants) + if existingChatRoom == nil { + Log.info( + "\(ConversationForwardMessageViewModel.TAG) No existing 1-1 conversation between local account \(localAddress?.asStringUriOnly() ?? "") and remote \(remote.asStringUriOnly()) was found for given parameters, let's create it" + ) + + do { + let chatRoom = try core.createChatRoom(params: params, participants: participants) + if chatParams.backend == ChatRoom.Backend.FlexisipChat { + let state = chatRoom.state + if state == ChatRoom.State.Created { + let chatRoomId = LinphoneUtils.getConversationId(chatRoom: chatRoom) + Log.info("\(ConversationForwardMessageViewModel.TAG) 1-1 conversation \(chatRoomId) has been created") + + let model = ConversationModel(chatRoom: chatRoom) + DispatchQueue.main.async { + self.displayedConversation = model + self.operationInProgress = false + } + } else { + Log.info("\(ConversationForwardMessageViewModel.TAG) Conversation isn't in Created state yet (state is \(state)), wait for it") + self.chatRoomAddDelegate(core: core, chatRoom: chatRoom) + } + } else { + let chatRoomId = LinphoneUtils.getConversationId(chatRoom: chatRoom) + Log.info("\(ConversationForwardMessageViewModel.TAG) Conversation successfully created \(chatRoomId)") + + let model = ConversationModel(chatRoom: chatRoom) + DispatchQueue.main.async { + self.displayedConversation = model + self.operationInProgress = false + } + } + } catch { + Log.error("\(ConversationForwardMessageViewModel.TAG) Failed to create 1-1 conversation with \(remote.asStringUriOnly())") + + DispatchQueue.main.async { + self.operationInProgress = false + ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error" + ToastViewModel.shared.displayToast = true + } + } + } else { + Log.warn( + "\(ConversationForwardMessageViewModel.TAG) A 1-1 conversation between local account \(localAddress?.asStringUriOnly() ?? "") and remote \(remote.asStringUriOnly()) for given parameters already exists!" + ) + let model = ConversationModel(chatRoom: existingChatRoom!) + DispatchQueue.main.async { + self.displayedConversation = model + self.operationInProgress = false + } + } + } catch { + } + } + } + + func chatRoomAddDelegate(core: Core, chatRoom: ChatRoom) { + contactChatRoomDelegate = ChatRoomDelegateStub(onStateChanged: { (chatRoom: ChatRoom, state: ChatRoom.State) in + let state = chatRoom.state + let id = LinphoneUtils.getChatRoomId(room: chatRoom) + if state == ChatRoom.State.CreationFailed { + Log.error("\(StartConversationViewModel.TAG) Conversation \(id) creation has failed!") + if let delegate = self.contactChatRoomDelegate { + chatRoom.removeDelegate(delegate: delegate) + self.contactChatRoomDelegate = nil + } + DispatchQueue.main.async { + self.operationInProgress = false + ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error" + ToastViewModel.shared.displayToast = true + } + } + }, onConferenceJoined: { (chatRoom: ChatRoom, _: EventLog) in + let state = chatRoom.state + let id = LinphoneUtils.getChatRoomId(room: chatRoom) + Log.info("\(StartConversationViewModel.TAG) Conversation \(id) \(chatRoom.subject ?? "") state changed: \(state)") + if state == ChatRoom.State.Created { + Log.info("\(StartConversationViewModel.TAG) Conversation \(id) successfully created") + if let delegate = self.contactChatRoomDelegate { + chatRoom.removeDelegate(delegate: delegate) + self.contactChatRoomDelegate = nil + } + let model = ConversationModel(chatRoom: chatRoom) + if self.operationInProgress == false { + DispatchQueue.main.async { + self.operationInProgress = true + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + self.operationInProgress = false + self.displayedConversation = model + } + } else { + DispatchQueue.main.async { + self.operationInProgress = false + self.displayedConversation = model + } + } + } else if state == ChatRoom.State.CreationFailed { + Log.error("\(StartConversationViewModel.TAG) Conversation \(id) creation has failed!") + + if let delegate = self.contactChatRoomDelegate { + chatRoom.removeDelegate(delegate: delegate) + self.contactChatRoomDelegate = nil + } + DispatchQueue.main.async { + self.operationInProgress = false + ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error" + ToastViewModel.shared.displayToast = true + } + } + }) + chatRoom.addDelegate(delegate: contactChatRoomDelegate!) + } } +// swiftlint:enable line_length diff --git a/Linphone/UI/Main/Contacts/ViewModel/EditContactViewModel.swift b/Linphone/UI/Main/Contacts/ViewModel/EditContactViewModel.swift index 0769741ae..33e7af592 100644 --- a/Linphone/UI/Main/Contacts/ViewModel/EditContactViewModel.swift +++ b/Linphone/UI/Main/Contacts/ViewModel/EditContactViewModel.swift @@ -22,7 +22,7 @@ import SwiftUI class EditContactViewModel: ObservableObject { - @Published var selectedEditFriend: Friend? + let selectedEditFriend: Friend? @Published var identifier: String = "" @Published var firstName: String = "" @@ -31,9 +31,9 @@ class EditContactViewModel: ObservableObject { @Published var phoneNumbers: [String] = [] @Published var company: String = "" @Published var jobTitle: String = "" - @Published var removePopup: Bool = false - init() { + init(friend: Friend? = nil) { + self.selectedEditFriend = friend resetValues() } diff --git a/Linphone/UI/Main/Contacts/ViewModel/FavoriteContactsListViewModel.swift b/Linphone/UI/Main/Contacts/ViewModel/FavoriteContactsListViewModel.swift deleted file mode 100644 index 8cd9f0224..000000000 --- a/Linphone/UI/Main/Contacts/ViewModel/FavoriteContactsListViewModel.swift +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 . - */ - -import linphonesw -import SwiftUI - -class FavoriteContactsListViewModel: ObservableObject { - - init() {} -} diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift index 84a04ef2b..97b99fb61 100644 --- a/Linphone/UI/Main/ContentView.swift +++ b/Linphone/UI/Main/ContentView.swift @@ -31,26 +31,33 @@ struct ContentView: View { @ObservedObject private var coreContext = CoreContext.shared @ObservedObject private var telecomManager = TelecomManager.shared + @ObservedObject private var contactsManager = ContactsManager.shared + @ObservedObject private var magicSearch = MagicSearchSingleton.shared + @ObservedObject private var sharedMainViewModel = SharedMainViewModel.shared - @ObservedObject var contactsManager = ContactsManager.shared - var magicSearch = MagicSearchSingleton.shared - - //@ObservedObject var editContactViewModel: EditContactViewModel + @State private var contactsListViewModel: ContactsListViewModel? //@ObservedObject var historyViewModel: HistoryViewModel //@ObservedObject var historyListViewModel: HistoryListViewModel + //@ObservedObject var startCallViewModel: StartCallViewModel //@ObservedObject var startConversationViewModel: StartConversationViewModel + //@ObservedObject var callViewModel: CallViewModel + //@ObservedObject var meetingWaitingRoomViewModel: MeetingWaitingRoomViewModel + //@ObservedObject var conversationsListViewModel: ConversationsListViewModel //@ObservedObject var conversationViewModel: ConversationViewModel + //@ObservedObject var meetingsListViewModel: MeetingsListViewModel //@ObservedObject var meetingViewModel: MeetingViewModel + //@ObservedObject var conversationForwardMessageViewModel: ConversationForwardMessageViewModel + //@ObservedObject var accountProfileViewModel: AccountProfileViewModel - @Binding var index: Int + //@Binding var index: Int @State private var orientation = UIDevice.current.orientation @State var sideMenuIsOpen: Bool = false @@ -62,6 +69,7 @@ struct ContentView: View { @State var isShowDeleteContactPopup = false @State var isShowDeleteAllHistoryPopup = false @State var isShowEditContactFragment = false + @State var isShowEditContactFragmentInContactDetails = false @State var isShowStartCallFragment = false @State var isShowStartConversationFragment = false @State var isShowDismissPopup = false @@ -142,19 +150,18 @@ struct ContentView: View { Spacer() Button(action: { - self.index = 0 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 0) - SharedMainViewModel.shared.displayedCall = nil - SharedMainViewModel.shared.displayedConversation = nil - SharedMainViewModel.shared.displayedMeeting = nil + sharedMainViewModel.changeIndexView(indexViewInt: 0) + sharedMainViewModel.displayedCall = nil + sharedMainViewModel.displayedConversation = nil + sharedMainViewModel.displayedMeeting = nil }, label: { VStack { Image("address-book") .renderingMode(.template) .resizable() - .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600) + .foregroundStyle(sharedMainViewModel.indexView == 0 ? Color.orangeMain500 : Color.grayMain2c600) .frame(width: 25, height: 25) - if self.index == 0 { + if sharedMainViewModel.indexView == 0 { Text("bottom_navigation_contacts_label") .default_text_style_700(styleSize: 10) } else { @@ -189,11 +196,10 @@ struct ContentView: View { } */ Button(action: { - self.index = 1 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 1) - SharedMainViewModel.shared.indexDisplayedFriend = nil - SharedMainViewModel.shared.displayedConversation = nil - SharedMainViewModel.shared.displayedMeeting = nil + sharedMainViewModel.changeIndexView(indexViewInt: 1) + sharedMainViewModel.indexDisplayedFriend = nil + sharedMainViewModel.displayedConversation = nil + sharedMainViewModel.displayedMeeting = nil /* if historyListViewModel.missedCallsCount > 0 { historyListViewModel.resetMissedCallsCount() @@ -204,9 +210,9 @@ struct ContentView: View { Image("phone") .renderingMode(.template) .resizable() - .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600) + .foregroundStyle(sharedMainViewModel.indexView == 1 ? Color.orangeMain500 : Color.grayMain2c600) .frame(width: 25, height: 25) - if self.index == 1 { + if sharedMainViewModel.indexView == 1 { Text("bottom_navigation_calls_label") .default_text_style_700(styleSize: 10) } else { @@ -242,20 +248,19 @@ struct ContentView: View { } */ Button(action: { - self.index = 2 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 2) - SharedMainViewModel.shared.indexDisplayedFriend = nil - SharedMainViewModel.shared.displayedCall = nil - SharedMainViewModel.shared.displayedMeeting = nil + sharedMainViewModel.changeIndexView(indexViewInt: 2) + sharedMainViewModel.indexDisplayedFriend = nil + sharedMainViewModel.displayedCall = nil + sharedMainViewModel.displayedMeeting = nil }, label: { VStack { Image("chat-teardrop-text") .renderingMode(.template) .resizable() - .foregroundStyle(self.index == 2 ? Color.orangeMain500 : Color.grayMain2c600) + .foregroundStyle(sharedMainViewModel.indexView == 2 ? Color.orangeMain500 : Color.grayMain2c600) .frame(width: 25, height: 25) - if self.index == 2 { + if sharedMainViewModel.indexView == 2 { Text("bottom_navigation_conversations_label") .default_text_style_700(styleSize: 10) } else { @@ -269,19 +274,18 @@ struct ContentView: View { .frame(height: geometry.size.height/4) Button(action: { - self.index = 3 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 3) - SharedMainViewModel.shared.indexDisplayedFriend = nil - SharedMainViewModel.shared.displayedCall = nil - SharedMainViewModel.shared.displayedConversation = nil + sharedMainViewModel.changeIndexView(indexViewInt: 3) + sharedMainViewModel.indexDisplayedFriend = nil + sharedMainViewModel.displayedCall = nil + sharedMainViewModel.displayedConversation = nil }, label: { VStack { Image("video-conference") .renderingMode(.template) .resizable() - .foregroundStyle(self.index == 3 ? Color.orangeMain500 : Color.grayMain2c600) + .foregroundStyle(sharedMainViewModel.indexView == 3 ? Color.orangeMain500 : Color.grayMain2c600) .frame(width: 25, height: 25) - if self.index == 0 { + if sharedMainViewModel.indexView == 0 { Text("bottom_navigation_meetings_label") .default_text_style_700(styleSize: 10) } else { @@ -329,7 +333,7 @@ struct ContentView: View { HStack { /* if let accountModelIndex = accountProfileViewModel.accountModelIndex, - accountModelIndex < CoreContext.shared.accounts.count { + accountModelIndex < coreContext.accounts.count { AsyncImage(url: imagePath) { image in switch image { case .empty: @@ -345,16 +349,16 @@ struct ContentView: View { imageTmp = image } case .failure: - if CoreContext.shared.accounts[accountModelIndex].avatarModel != nil { + if coreContext.accounts[accountModelIndex].avatarModel != nil { let tmpImage = contactsManager.textToImage( - firstName: CoreContext.shared.accounts[accountModelIndex].avatarModel!.name, + firstName: coreContext.accounts[accountModelIndex].avatarModel!.name, lastName: "") Image(uiImage: tmpImage) .resizable() .frame(width: avatarSize, height: avatarSize) .clipShape(Circle()) .onAppear { - accountProfileViewModel.saveImage(image: tmpImage, name: CoreContext.shared.accounts[accountModelIndex].avatarModel!.name, prefix: "-default") + accountProfileViewModel.saveImage(image: tmpImage, name: coreContext.accounts[accountModelIndex].avatarModel!.name, prefix: "-default") } } else if let cachedImage = imageTmp { cachedImage @@ -374,30 +378,30 @@ struct ContentView: View { openMenu() } .onAppear { - let imagePathTmp = CoreContext.shared.accounts[accountModelIndex].getImagePath() + let imagePathTmp = coreContext.accounts[accountModelIndex].getImagePath() if !(imagePathTmp.lastPathComponent.isEmpty || imagePathTmp.lastPathComponent == "Error" || imagePathTmp.lastPathComponent == "ImageError.png") { imagePath = imagePathTmp } } - .onChange(of: CoreContext.shared.accounts[accountModelIndex].usernaneAvatar) { username in + .onChange(of: coreContext.accounts[accountModelIndex].usernaneAvatar) { username in if !username.isEmpty { - let imagePathTmp = CoreContext.shared.accounts[accountModelIndex].getImagePath() + let imagePathTmp = coreContext.accounts[accountModelIndex].getImagePath() if !(imagePathTmp.lastPathComponent.isEmpty || imagePathTmp.lastPathComponent == "Error" || imagePathTmp.lastPathComponent == "ImageError.png") { - SharedMainViewModel.shared.changeDefaultAvatar(defaultAvatarURL: imagePathTmp) + sharedMainViewModel.changeDefaultAvatar(defaultAvatarURL: imagePathTmp) imagePath = imagePathTmp } } } .onReceive(imageChanged) { _ in - if !CoreContext.shared.accounts[accountModelIndex].usernaneAvatar.isEmpty { - let imagePathTmp = CoreContext.shared.accounts[accountModelIndex].getImagePath() - SharedMainViewModel.shared.changeDefaultAvatar(defaultAvatarURL: imagePathTmp) + if !coreContext.accounts[accountModelIndex].usernaneAvatar.isEmpty { + let imagePathTmp = coreContext.accounts[accountModelIndex].getImagePath() + sharedMainViewModel.changeDefaultAvatar(defaultAvatarURL: imagePathTmp) imagePath = imagePathTmp } } } */ - Text(String(localized: index == 0 ? "bottom_navigation_contacts_label" : (index == 1 ? "bottom_navigation_calls_label" : (index == 2 ? "bottom_navigation_conversations_label" : "bottom_navigation_meetings_label")))) + Text(String(localized: sharedMainViewModel.indexView == 0 ? "bottom_navigation_contacts_label" : (sharedMainViewModel.indexView == 1 ? "bottom_navigation_calls_label" : (sharedMainViewModel.indexView == 2 ? "bottom_navigation_conversations_label" : "bottom_navigation_meetings_label")))) .default_text_style_white_800(styleSize: 20) .padding(.leading, 10) @@ -415,9 +419,9 @@ struct ContentView: View { .frame(width: 25, height: 25, alignment: .leading) .padding(.all, 10) } - .padding(.trailing, index == 2 ? 10 : 0) + .padding(.trailing, sharedMainViewModel.indexView == 2 ? 10 : 0) - if index == 3 { + if sharedMainViewModel.indexView == 3 { Button { NotificationCenter.default.post(name: MeetingsListViewModel.ScrollToTodayNotification, object: nil) } label: { @@ -429,14 +433,14 @@ struct ContentView: View { .padding(.all, 10) } .padding(.trailing, 10) - } else if index != 2 { + } else if sharedMainViewModel.indexView != 2 { Menu { - if index == 0 { + if sharedMainViewModel.indexView == 0 { Button { - SharedMainViewModel.shared.indexDisplayedFriend = nil + sharedMainViewModel.indexDisplayedFriend = nil isMenuOpen = false magicSearch.allContact = true - MagicSearchSingleton.shared.searchForContacts( + magicSearch.searchForContacts( sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) } label: { HStack { @@ -452,10 +456,10 @@ struct ContentView: View { } Button { - SharedMainViewModel.shared.indexDisplayedFriend = nil + sharedMainViewModel.indexDisplayedFriend = nil isMenuOpen = false magicSearch.allContact = false - MagicSearchSingleton.shared.searchForContacts( + magicSearch.searchForContacts( sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) } label: { HStack { @@ -485,7 +489,7 @@ struct ContentView: View { } } } label: { - Image(index == 0 ? "funnel" : "dots-three-vertical") + Image(sharedMainViewModel.indexView == 0 ? "funnel" : "dots-three-vertical") .renderingMode(.template) .resizable() .foregroundStyle(.white) @@ -515,15 +519,15 @@ struct ContentView: View { text = "" - if index == 0 { + if sharedMainViewModel.indexView == 0 { magicSearch.currentFilter = "" - MagicSearchSingleton.shared.searchForContacts( + magicSearch.searchForContacts( sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - } else if index == 1 { + } else if sharedMainViewModel.indexView == 1 { //historyListViewModel.resetFilterCallLogs() - } else if index == 2 { + } else if sharedMainViewModel.indexView == 2 { //conversationsListViewModel.resetFilterConversations() - } else if index == 3 { + } else if sharedMainViewModel.indexView == 3 { //meetingsListViewModel.currentFilter = "" //meetingsListViewModel.computeMeetingsList() } @@ -561,23 +565,23 @@ struct ContentView: View { self.focusedField = true } .onChange(of: text) { newValue in - if index == 0 { + if sharedMainViewModel.indexView == 0 { magicSearch.currentFilter = newValue - MagicSearchSingleton.shared.searchForContacts( + magicSearch.searchForContacts( sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - } else if index == 1 { + } else if sharedMainViewModel.indexView == 1 { if text.isEmpty { //historyListViewModel.resetFilterCallLogs() } else { //historyListViewModel.filterCallLogs(filter: text) } - } else if index == 2 { + } else if sharedMainViewModel.indexView == 2 { if text.isEmpty { //conversationsListViewModel.resetFilterConversations() } else { //conversationsListViewModel.filterConversations(filter: text) } - } else if index == 3 { + } else if sharedMainViewModel.indexView == 3 { //meetingsListViewModel.currentFilter = text //meetingsListViewModel.computeMeetingsList() } @@ -604,15 +608,15 @@ struct ContentView: View { self.focusedField = true } .onChange(of: text) { newValue in - if index == 0 { + if sharedMainViewModel.indexView == 0 { magicSearch.currentFilter = newValue - MagicSearchSingleton.shared.searchForContacts( + magicSearch.searchForContacts( sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - } else if index == 1 { + } else if sharedMainViewModel.indexView == 1 { //historyListViewModel.filterCallLogs(filter: text) - } else if index == 2 { + } else if sharedMainViewModel.indexView == 2 { //conversationsListViewModel.filterConversations(filter: text) - } else if index == 3 { + } else if sharedMainViewModel.indexView == 3 { //meetingsListViewModel.currentFilter = text //meetingsListViewModel.computeMeetingsList() } @@ -639,26 +643,39 @@ struct ContentView: View { .roundedCorner(10, corners: [.bottomRight, .bottomLeft]) } - if self.index == 0 { - ContactsView( - //contactViewModel: contactViewModel, - //historyViewModel: historyViewModel, - //editContactViewModel: editContactViewModel, - isShowEditContactFragment: $isShowEditContactFragment, - isShowDeletePopup: $isShowDeleteContactPopup, - text: $text - ) - .environmentObject(ContactViewModel()) - .roundedCorner(25, corners: [.topRight, .topLeft]) - .shadow( - color: (orientation == .landscapeLeft - || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) - ? .white.opacity(0.0) - : .black.opacity(0.2), - radius: 25 - ) - } else if self.index == 1 { + if sharedMainViewModel.indexView == 0 { + if let contactsListVM = contactsListViewModel { + ContactsView( + isShowEditContactFragment: $isShowEditContactFragment, + isShowDeletePopup: $isShowDeleteContactPopup, + text: $text + ) + .environmentObject(contactsListVM) + .roundedCorner(25, corners: [.topRight, .topLeft]) + .shadow( + color: (orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) + ? .white.opacity(0.0) + : .black.opacity(0.2), + radius: 25 + ) + } else { + NavigationView { + VStack { + Spacer() + + ProgressView() + .controlSize(.large) + + Spacer() + } + .onAppear { + contactsListViewModel = ContactsListViewModel() + } + } + } + } else if sharedMainViewModel.indexView == 1 { //TODO a changer NavigationView { ZStack(alignment: .bottomTrailing) { @@ -669,7 +686,7 @@ struct ContentView: View { HistoryView( historyListViewModel: historyListViewModel, historyViewModel: historyViewModel, - contactViewModel: contactViewModel, + contactsListViewModel: contactsListViewModel, editContactViewModel: editContactViewModel, index: $index, isShowStartCallFragment: $isShowStartCallFragment, @@ -686,7 +703,7 @@ struct ContentView: View { radius: 25 ) */ - } else if self.index == 2 { + } else if sharedMainViewModel.indexView == 2 { //TODO a changer NavigationView { ZStack(alignment: .bottomTrailing) { @@ -710,7 +727,7 @@ struct ContentView: View { radius: 25 ) */ - } else if self.index == 3 { + } else if sharedMainViewModel.indexView == 3 { //TODO a changer NavigationView { ZStack(alignment: .bottomTrailing) { @@ -766,19 +783,18 @@ struct ContentView: View { Group { Spacer() Button(action: { - self.index = 0 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 0) - SharedMainViewModel.shared.displayedCall = nil - SharedMainViewModel.shared.displayedConversation = nil - SharedMainViewModel.shared.displayedMeeting = nil + sharedMainViewModel.changeIndexView(indexViewInt: 0) + sharedMainViewModel.displayedCall = nil + sharedMainViewModel.displayedConversation = nil + sharedMainViewModel.displayedMeeting = nil }, label: { VStack { Image("address-book") .renderingMode(.template) .resizable() - .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600) + .foregroundStyle(sharedMainViewModel.indexView == 0 ? Color.orangeMain500 : Color.grayMain2c600) .frame(width: 25, height: 25) - if self.index == 0 { + if sharedMainViewModel.indexView == 0 { Text("bottom_navigation_contacts_label") .default_text_style_700(styleSize: 10) } else { @@ -815,11 +831,10 @@ struct ContentView: View { } */ Button(action: { - self.index = 1 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 1) - SharedMainViewModel.shared.indexDisplayedFriend = nil - SharedMainViewModel.shared.displayedConversation = nil - SharedMainViewModel.shared.displayedMeeting = nil + sharedMainViewModel.changeIndexView(indexViewInt: 1) + sharedMainViewModel.indexDisplayedFriend = nil + sharedMainViewModel.displayedConversation = nil + sharedMainViewModel.displayedMeeting = nil /* if historyListViewModel.missedCallsCount > 0 { historyListViewModel.resetMissedCallsCount() @@ -830,9 +845,9 @@ struct ContentView: View { Image("phone") .renderingMode(.template) .resizable() - .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600) + .foregroundStyle(sharedMainViewModel.indexView == 1 ? Color.orangeMain500 : Color.grayMain2c600) .frame(width: 25, height: 25) - if self.index == 1 { + if sharedMainViewModel.indexView == 1 { Text("bottom_navigation_calls_label") .default_text_style_700(styleSize: 9) } else { @@ -870,20 +885,19 @@ struct ContentView: View { } */ Button(action: { - self.index = 2 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 2) - SharedMainViewModel.shared.indexDisplayedFriend = nil - SharedMainViewModel.shared.displayedCall = nil - SharedMainViewModel.shared.displayedMeeting = nil + sharedMainViewModel.changeIndexView(indexViewInt: 2) + sharedMainViewModel.indexDisplayedFriend = nil + sharedMainViewModel.displayedCall = nil + sharedMainViewModel.displayedMeeting = nil }, label: { VStack { Image("chat-teardrop-text") .renderingMode(.template) .resizable() - .foregroundStyle(self.index == 2 ? Color.orangeMain500 : Color.grayMain2c600) + .foregroundStyle(sharedMainViewModel.indexView == 2 ? Color.orangeMain500 : Color.grayMain2c600) .frame(width: 25, height: 25) - if self.index == 2 { + if sharedMainViewModel.indexView == 2 { Text("bottom_navigation_conversations_label") .default_text_style_700(styleSize: 9) } else { @@ -898,19 +912,18 @@ struct ContentView: View { Spacer() Button(action: { - self.index = 3 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 3) - SharedMainViewModel.shared.indexDisplayedFriend = nil - SharedMainViewModel.shared.displayedCall = nil - SharedMainViewModel.shared.displayedConversation = nil + sharedMainViewModel.changeIndexView(indexViewInt: 3) + sharedMainViewModel.indexDisplayedFriend = nil + sharedMainViewModel.displayedCall = nil + sharedMainViewModel.displayedConversation = nil }, label: { VStack { Image("video-conference") .renderingMode(.template) .resizable() - .foregroundStyle(self.index == 3 ? Color.orangeMain500 : Color.grayMain2c600) + .foregroundStyle(sharedMainViewModel.indexView == 3 ? Color.orangeMain500 : Color.grayMain2c600) .frame(width: 25, height: 25) - if self.index == 3 { + if sharedMainViewModel.indexView == 3 { Text("bottom_navigation_meetings_label") .default_text_style_700(styleSize: 9) } else { @@ -934,8 +947,8 @@ struct ContentView: View { } } - if SharedMainViewModel.shared.indexDisplayedFriend != nil || SharedMainViewModel.shared.displayedCall != nil || SharedMainViewModel.shared.displayedConversation != nil || - SharedMainViewModel.shared.displayedMeeting != nil { + if sharedMainViewModel.indexDisplayedFriend != nil || sharedMainViewModel.displayedCall != nil || sharedMainViewModel.displayedConversation != nil || + sharedMainViewModel.displayedMeeting != nil { HStack(spacing: 0) { Spacer() .frame(maxWidth: @@ -945,29 +958,27 @@ struct ContentView: View { ? (geometry.size.width/100*40) + 75 : 0 ) - if self.index == 0 { + if sharedMainViewModel.indexView == 0 && sharedMainViewModel.indexDisplayedFriend != nil && contactsManager.avatarListModel.count > sharedMainViewModel.indexDisplayedFriend! { + ContactFragment( + isShowDeletePopup: $isShowDeleteContactPopup, + isShowDismissPopup: $isShowDismissPopup, + isShowSipAddressesPopup: $isShowSipAddressesPopup, + isShowSipAddressesPopupType: $isShowSipAddressesPopupType, + isShowEditContactFragmentInContactDetails: $isShowEditContactFragmentInContactDetails + ) + .environmentObject(contactsListViewModel!) + .environmentObject(contactsManager.avatarListModel[sharedMainViewModel.indexDisplayedFriend!]) + .frame(maxWidth: .infinity) + .background(Color.gray100) + .ignoresSafeArea(.keyboard) + } else if sharedMainViewModel.indexView == 1 { /* - ContactFragment( - contactViewModel: contactViewModel, - editContactViewModel: editContactViewModel, - conversationViewModel: conversationViewModel, - isShowDeletePopup: $isShowDeleteContactPopup, - isShowDismissPopup: $isShowDismissPopup, - isShowSipAddressesPopup: $isShowSipAddressesPopup, - isShowSipAddressesPopupType: $isShowSipAddressesPopupType - ) - .frame(maxWidth: .infinity) - .background(Color.gray100) - .ignoresSafeArea(.keyboard) - */ - } else if self.index == 1 { - /* - if SharedMainViewModel.shared.displayedCall != nil && SharedMainViewModel.shared.displayedCall!.avatarModel != nil { + if sharedMainViewModel.displayedCall != nil && sharedMainViewModel.displayedCall!.avatarModel != nil { HistoryContactFragment( - contactAvatarModel: SharedMainViewModel.shared.displayedCall!.avatarModel!, + contactAvatarModel: sharedMainViewModel.displayedCall!.avatarModel!, historyViewModel: historyViewModel, historyListViewModel: historyListViewModel, - contactViewModel: contactViewModel, + contactsListViewModel: contactsListViewModel, editContactViewModel: editContactViewModel, isShowDeleteAllHistoryPopup: $isShowDeleteAllHistoryPopup, isShowEditContactFragment: $isShowEditContactFragment, @@ -978,13 +989,13 @@ struct ContentView: View { .ignoresSafeArea(.keyboard) } */ - } else if self.index == 2 { + } else if sharedMainViewModel.indexView == 2 { /* ConversationFragment( conversationViewModel: conversationViewModel, conversationsListViewModel: conversationsListViewModel, conversationForwardMessageViewModel: conversationForwardMessageViewModel, - contactViewModel: contactViewModel, + contactsListViewModel: contactsListViewModel, editContactViewModel: editContactViewModel, meetingViewModel: meetingViewModel, accountProfileViewModel: accountProfileViewModel, @@ -998,7 +1009,7 @@ struct ContentView: View { .background(Color.gray100) .ignoresSafeArea(.keyboard) */ - } else if self.index == 3 { + } else if sharedMainViewModel.indexView == 3 { /* MeetingFragment(meetingViewModel: meetingViewModel, meetingsListViewModel: meetingsListViewModel, isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup) .frame(maxWidth: .infinity) @@ -1061,21 +1072,21 @@ struct ContentView: View { .onAppear { } } + */ if isShowEditContactFragment { EditContactFragment( - editContactViewModel: editContactViewModel, - contactViewModel: contactViewModel, isShowEditContactFragment: $isShowEditContactFragment, isShowDismissPopup: $isShowDismissPopup ) .zIndex(3) .transition(.opacity.combined(with: .move(edge: .bottom))) .onAppear { - SharedMainViewModel.shared.indexDisplayedFriend = nil + sharedMainViewModel.indexDisplayedFriend = nil } } + /* if isShowStartCallFragment { if #available(iOS 16.4, *), idiom != .pad { StartCallFragment( @@ -1129,13 +1140,14 @@ struct ContentView: View { .zIndex(6) .transition(.opacity.combined(with: .move(edge: .bottom))) } + */ if isShowDeleteContactPopup { PopupView(isShowPopup: $isShowDeleteContactPopup, - title: Text(String(format: String(localized: "contact_dialog_delete_title"),contactViewModel.selectedFriend != nil - ? contactViewModel.selectedFriend!.name! - : (SharedMainViewModel.shared.indexDisplayedFriend != nil - ? contactsManager.lastSearch[SharedMainViewModel.shared.indexDisplayedFriend!].friend!.name! + title: Text(String(format: String(localized: "contact_dialog_delete_title"),contactsListViewModel!.selectedFriend != nil + ? contactsListViewModel!.selectedFriend!.name! + : (sharedMainViewModel.indexDisplayedFriend != nil + ? contactsManager.lastSearch[sharedMainViewModel.indexDisplayedFriend!].friend!.name! : "Error Name"))), content: Text("contact_dialog_delete_message"), titleFirstButton: Text("dialog_cancel"), @@ -1143,21 +1155,21 @@ struct ContentView: View { self.isShowDeleteContactPopup.toggle()}, titleSecondButton: Text("dialog_ok"), actionSecondButton: { - if contactViewModel.selectedFriendToDelete != nil { - if SharedMainViewModel.shared.indexDisplayedFriend != nil { + if contactsListViewModel!.selectedFriendToDelete != nil { + if sharedMainViewModel.indexDisplayedFriend != nil { withAnimation { - SharedMainViewModel.shared.indexDisplayedFriend = nil + sharedMainViewModel.indexDisplayedFriend = nil } } - contactViewModel.selectedFriendToDelete!.remove() - } else if SharedMainViewModel.shared.indexDisplayedFriend != nil { - let tmpIndex = SharedMainViewModel.shared.indexDisplayedFriend + contactsListViewModel!.selectedFriendToDelete!.remove() + } else if sharedMainViewModel.indexDisplayedFriend != nil { + let tmpIndex = sharedMainViewModel.indexDisplayedFriend withAnimation { - SharedMainViewModel.shared.indexDisplayedFriend = nil + sharedMainViewModel.indexDisplayedFriend = nil } contactsManager.lastSearch[tmpIndex!].friend!.remove() } - MagicSearchSingleton.shared.searchForContacts( + magicSearch.searchForContacts( sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) self.isShowDeleteContactPopup.toggle() }) @@ -1167,10 +1179,11 @@ struct ContentView: View { self.isShowDeleteContactPopup.toggle() } .onAppear { - contactViewModel.selectedFriendToDelete = contactViewModel.selectedFriend + contactsListViewModel!.selectedFriendToDelete = contactsListViewModel!.selectedFriend } } + /* if isShowDeleteAllHistoryPopup { PopupView(isShowPopup: $isShowDeleteContactPopup, title: Text("history_dialog_delete_all_call_logs_title"), @@ -1184,7 +1197,7 @@ struct ContentView: View { actionSecondButton: { historyListViewModel.removeCallLogs() self.isShowDeleteAllHistoryPopup.toggle() - SharedMainViewModel.shared.displayedCall = nil + sharedMainViewModel.displayedCall = nil ToastViewModel.shared.toastMessage = "Success_remove_call_logs" ToastViewModel.shared.displayToast.toggle() @@ -1195,6 +1208,7 @@ struct ContentView: View { self.isShowDeleteAllHistoryPopup.toggle() } } + */ if isShowDismissPopup { PopupView(isShowPopup: $isShowDismissPopup, @@ -1204,19 +1218,11 @@ struct ContentView: View { actionFirstButton: {self.isShowDismissPopup.toggle()}, titleSecondButton: Text("dialog_ok"), actionSecondButton: { - if editContactViewModel.selectedEditFriend == nil { - self.isShowDismissPopup.toggle() - editContactViewModel.removePopup = true - editContactViewModel.resetValues() - withAnimation { - isShowEditContactFragment.toggle() - } + self.isShowDismissPopup.toggle() + if isShowEditContactFragment { + isShowEditContactFragment = false } else { - self.isShowDismissPopup.toggle() - editContactViewModel.resetValues() - withAnimation { - editContactViewModel.removePopup = true - } + isShowEditContactFragmentInContactDetails = false } }) .background(.black.opacity(0.65)) @@ -1228,11 +1234,11 @@ struct ContentView: View { if isShowSipAddressesPopup { SipAddressesPopup( - contactAvatarModel: ContactsManager.shared.avatarListModel[SharedMainViewModel.shared.indexDisplayedFriend != nil ? SharedMainViewModel.shared.indexDisplayedFriend! : 0], - contactViewModel: contactViewModel, isShowSipAddressesPopup: $isShowSipAddressesPopup, isShowSipAddressesPopupType: $isShowSipAddressesPopupType ) + .environmentObject(contactsListViewModel!) + .environmentObject(contactsManager.avatarListModel[sharedMainViewModel.indexDisplayedFriend != nil ? sharedMainViewModel.indexDisplayedFriend! : 0]) .background(.black.opacity(0.65)) .zIndex(3) .onTapGesture { @@ -1240,21 +1246,21 @@ struct ContentView: View { } } - if contactViewModel.operationInProgress { + /* + if contactsListViewModel.operationInProgress { PopupLoadingView() .background(.black.opacity(0.65)) .zIndex(3) .onDisappear { - if contactViewModel.displayedConversation != nil { - SharedMainViewModel.shared.indexDisplayedFriend = nil - SharedMainViewModel.shared.displayedCall = nil - index = 2 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 2) + if contactsListViewModel.displayedConversation != nil { + sharedMainViewModel.indexDisplayedFriend = nil + sharedMainViewModel.displayedCall = nil + sharedMainViewModel.changeIndexView(indexViewInt: 2) DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { withAnimation { - self.conversationViewModel.changeDisplayedChatRoom(conversationModel: contactViewModel.displayedConversation!) + self.conversationViewModel.changeDisplayedChatRoom(conversationModel: contactsListViewModel.displayedConversation!) } - contactViewModel.displayedConversation = nil + contactsListViewModel.displayedConversation = nil } } } @@ -1306,13 +1312,13 @@ struct ContentView: View { content: Text("meeting_schedule_cancel_dialog_message"), titleFirstButton: Text("dialog_cancel"), actionFirstButton: { - SharedMainViewModel.shared.displayedMeeting = nil + sharedMainViewModel.displayedMeeting = nil meetingsListViewModel.deleteSelectedMeeting() self.isShowSendCancelMeetingNotificationPopup.toggle( ) }, titleSecondButton: Text("dialog_ok"), actionSecondButton: { - SharedMainViewModel.shared.displayedMeeting = nil + sharedMainViewModel.displayedMeeting = nil if let meetingToDelete = self.meetingsListViewModel.selectedMeetingToDelete { self.meetingViewModel.cancelMeetingWithNotifications(meeting: meetingToDelete) meetingsListViewModel.deleteSelectedMeeting() @@ -1337,8 +1343,8 @@ struct ContentView: View { }, titleSecondButton: Text("dialog_ok"), actionSecondButton: { - if SharedMainViewModel.shared.displayedConversation != nil { - SharedMainViewModel.shared.displayedConversation!.createGroupCall() + if sharedMainViewModel.displayedConversation != nil { + sharedMainViewModel.displayedConversation!.createGroupCall() } self.isShowStartCallGroupPopup.toggle() } @@ -1361,8 +1367,8 @@ struct ContentView: View { }, titleSecondButton: Text("dialog_ok"), actionSecondButton: { - if SharedMainViewModel.shared.displayedConversation != nil { - SharedMainViewModel.shared.displayedConversation!.createGroupCall() + if sharedMainViewModel.displayedConversation != nil { + sharedMainViewModel.displayedConversation!.createGroupCall() } self.isShowStartCallGroupPopup.toggle() } @@ -1398,7 +1404,7 @@ struct ContentView: View { conversationViewModel: conversationViewModel, conversationsListViewModel: conversationsListViewModel, conversationForwardMessageViewModel: conversationForwardMessageViewModel, - contactViewModel: contactViewModel, + contactsListViewModel: contactsListViewModel, editContactViewModel: editContactViewModel, meetingViewModel: meetingViewModel, accountProfileViewModel: accountProfileViewModel, @@ -1432,8 +1438,7 @@ struct ContentView: View { } .onChange(of: navigationManager.selectedCallId) { newCallId in if newCallId != nil { - self.index = 2 - SharedMainViewModel.shared.changeIndexView(indexViewInt: 2) + sharedMainViewModel.changeIndexView(indexViewInt: 2) } } .onReceive(contactLoaded) { _ in @@ -1458,13 +1463,11 @@ struct ContentView: View { } } .onRotate { newOrientation in - /* - if (SharedMainViewModel.shared.indexDisplayedFriend != nil || SharedMainViewModel.shared.displayedCall != nil || SharedMainViewModel.shared.displayedConversation != nil) && searchIsActive { + if (sharedMainViewModel.indexDisplayedFriend != nil || sharedMainViewModel.displayedCall != nil || sharedMainViewModel.displayedConversation != nil) && searchIsActive { self.focusedField = false } else if searchIsActive { self.focusedField = true } - */ orientation = newOrientation } .onChange(of: scenePhase) { newPhase in @@ -1496,8 +1499,6 @@ class NavigationManager: ObservableObject { #Preview { ContentView( - //contactViewModel: ContactViewModel(), - //editContactViewModel: EditContactViewModel(), //historyViewModel: HistoryViewModel(), //historyListViewModel: HistoryListViewModel(), //startCallViewModel: StartCallViewModel(), @@ -1510,7 +1511,7 @@ class NavigationManager: ObservableObject { //meetingViewModel: MeetingViewModel(), //conversationForwardMessageViewModel: ConversationForwardMessageViewModel(), //accountProfileViewModel: AccountProfileViewModel(), - index: .constant(0) + //index: .constant(0) ) } // swiftlint:enable type_body_length diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationForwardMessageFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationForwardMessageFragment.swift index df298f986..65bfa4ee8 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationForwardMessageFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationForwardMessageFragment.swift @@ -164,8 +164,7 @@ struct ConversationForwardMessageFragment: View { .padding(.horizontal, 16) } - ContactsListFragment(contactViewModel: ContactViewModel(), contactsListViewModel: ContactsListViewModel(), showingSheet: .constant(false) - , startCallFunc: { addr in + ContactsListFragment(showingSheet: .constant(false), startCallFunc: { addr in withAnimation { conversationForwardMessageViewModel.createOneToOneChatRoomWith(remote: addr) } diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift index 3a2eacf43..c5f1f3184 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationFragment.swift @@ -35,7 +35,7 @@ struct ConversationFragment: View { @ObservedObject var conversationViewModel: ConversationViewModel @ObservedObject var conversationsListViewModel: ConversationsListViewModel @ObservedObject var conversationForwardMessageViewModel: ConversationForwardMessageViewModel - @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var contactsListViewModel: ContactsListViewModel @ObservedObject var editContactViewModel: EditContactViewModel @ObservedObject var meetingViewModel: MeetingViewModel @ObservedObject var accountProfileViewModel: AccountProfileViewModel @@ -1081,7 +1081,7 @@ struct ConversationFragment: View { ConversationInfoFragment( conversationViewModel: conversationViewModel, conversationsListViewModel: conversationsListViewModel, - contactViewModel: contactViewModel, + contactsListViewModel: contactsListViewModel, editContactViewModel: editContactViewModel, meetingViewModel: meetingViewModel, accountProfileViewModel: accountProfileViewModel, diff --git a/Linphone/UI/Main/Conversations/Fragments/ConversationInfoFragment.swift b/Linphone/UI/Main/Conversations/Fragments/ConversationInfoFragment.swift index b5bd0b6b3..36b718f42 100644 --- a/Linphone/UI/Main/Conversations/Fragments/ConversationInfoFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/ConversationInfoFragment.swift @@ -27,7 +27,7 @@ struct ConversationInfoFragment: View { @ObservedObject var conversationViewModel: ConversationViewModel @ObservedObject var conversationsListViewModel: ConversationsListViewModel - @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var contactsListViewModel: ContactsListViewModel @ObservedObject var editContactViewModel: EditContactViewModel @ObservedObject var meetingViewModel: MeetingViewModel @ObservedObject var accountProfileViewModel: AccountProfileViewModel @@ -698,7 +698,7 @@ struct ConversationInfoFragment: View { ConversationInfoFragment( conversationViewModel: ConversationViewModel(), conversationsListViewModel: ConversationsListViewModel(), - contactViewModel: ContactViewModel(), + contactsListViewModel: ContactsListViewModel(), editContactViewModel: EditContactViewModel(), meetingViewModel: MeetingViewModel(), accountProfileViewModel: AccountProfileViewModel(), diff --git a/Linphone/UI/Main/Conversations/Fragments/StartConversationFragment.swift b/Linphone/UI/Main/Conversations/Fragments/StartConversationFragment.swift index c08df698f..6e77bb236 100644 --- a/Linphone/UI/Main/Conversations/Fragments/StartConversationFragment.swift +++ b/Linphone/UI/Main/Conversations/Fragments/StartConversationFragment.swift @@ -184,8 +184,7 @@ struct StartConversationFragment: View { .padding(.horizontal, 16) } - ContactsListFragment(contactViewModel: ContactViewModel(), contactsListViewModel: ContactsListViewModel(), showingSheet: .constant(false) - , startCallFunc: { addr in + ContactsListFragment(showingSheet: .constant(false), startCallFunc: { addr in startConversationViewModel.createOneToOneChatRoomWith(remote: addr) }) .padding(.horizontal, 16) diff --git a/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift b/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift index 3bdd5c51a..f73365116 100644 --- a/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift +++ b/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift @@ -32,7 +32,7 @@ struct HistoryContactFragment: View { @ObservedObject var contactAvatarModel: ContactAvatarModel @ObservedObject var historyViewModel: HistoryViewModel @ObservedObject var historyListViewModel: HistoryListViewModel - @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var contactsListViewModel: ContactsListViewModel @ObservedObject var editContactViewModel: EditContactViewModel @State var isMenuOpen = false @@ -286,7 +286,7 @@ struct HistoryContactFragment: View { Spacer() Button(action: { - contactViewModel.createOneToOneChatRoomWith(remote: SharedMainViewModel.shared.displayedCall!.addressLinphone) + contactsListViewModel.createOneToOneChatRoomWith(remote: SharedMainViewModel.shared.displayedCall!.addressLinphone) }, label: { VStack { HStack(alignment: .center) { @@ -452,7 +452,7 @@ struct HistoryContactFragment: View { contactAvatarModel: ContactAvatarModel(friend: nil, name: "", address: "", withPresence: false), historyViewModel: HistoryViewModel(), historyListViewModel: HistoryListViewModel(), - contactViewModel: ContactViewModel(), + contactsListViewModel: ContactsListViewModel(), editContactViewModel: EditContactViewModel(), isShowDeleteAllHistoryPopup: .constant(false), isShowEditContactFragment: .constant(false), diff --git a/Linphone/UI/Main/History/Fragments/HistoryFragment.swift b/Linphone/UI/Main/History/Fragments/HistoryFragment.swift index 1a4d8c6cc..fc93092c0 100644 --- a/Linphone/UI/Main/History/Fragments/HistoryFragment.swift +++ b/Linphone/UI/Main/History/Fragments/HistoryFragment.swift @@ -24,7 +24,7 @@ struct HistoryFragment: View { @ObservedObject var historyListViewModel: HistoryListViewModel @ObservedObject var historyViewModel: HistoryViewModel - @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var contactsListViewModel: ContactsListViewModel @ObservedObject var editContactViewModel: EditContactViewModel @State private var showingSheet = false @@ -39,7 +39,7 @@ struct HistoryFragment: View { .sheet(isPresented: $showingSheet) { HistoryListBottomSheet( historyViewModel: historyViewModel, - contactViewModel: contactViewModel, + contactsListViewModel: contactsListViewModel, editContactViewModel: editContactViewModel, historyListViewModel: historyListViewModel, showingSheet: $showingSheet, @@ -53,7 +53,7 @@ struct HistoryFragment: View { .halfSheet(showSheet: $showingSheet) { HistoryListBottomSheet( historyViewModel: historyViewModel, - contactViewModel: contactViewModel, + contactsListViewModel: contactsListViewModel, editContactViewModel: editContactViewModel, historyListViewModel: historyListViewModel, showingSheet: $showingSheet, @@ -70,7 +70,7 @@ struct HistoryFragment: View { HistoryFragment( historyListViewModel: HistoryListViewModel(), historyViewModel: HistoryViewModel(), - contactViewModel: ContactViewModel(), + contactsListViewModel: ContactsListViewModel(), editContactViewModel: EditContactViewModel(), index: .constant(1), isShowEditContactFragment: .constant(false), diff --git a/Linphone/UI/Main/History/Fragments/HistoryListBottomSheet.swift b/Linphone/UI/Main/History/Fragments/HistoryListBottomSheet.swift index 4e08bb73d..a5f64b8ad 100644 --- a/Linphone/UI/Main/History/Fragments/HistoryListBottomSheet.swift +++ b/Linphone/UI/Main/History/Fragments/HistoryListBottomSheet.swift @@ -29,7 +29,7 @@ struct HistoryListBottomSheet: View { @ObservedObject var contactsManager = ContactsManager.shared @ObservedObject var historyViewModel: HistoryViewModel - @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var contactsListViewModel: ContactsListViewModel @ObservedObject var editContactViewModel: EditContactViewModel @ObservedObject var historyListViewModel: HistoryListViewModel @@ -225,7 +225,7 @@ struct HistoryListBottomSheet: View { #Preview { HistoryListBottomSheet( historyViewModel: HistoryViewModel(), - contactViewModel: ContactViewModel(), + contactsListViewModel: ContactsListViewModel(), editContactViewModel: EditContactViewModel(), historyListViewModel: HistoryListViewModel(), showingSheet: .constant(false), diff --git a/Linphone/UI/Main/History/Fragments/StartCallFragment.swift b/Linphone/UI/Main/History/Fragments/StartCallFragment.swift index c644dfcf0..4053454d1 100644 --- a/Linphone/UI/Main/History/Fragments/StartCallFragment.swift +++ b/Linphone/UI/Main/History/Fragments/StartCallFragment.swift @@ -216,7 +216,7 @@ struct StartCallFragment: View { .padding(.horizontal, 16) } - ContactsListFragment(contactViewModel: ContactViewModel(), contactsListViewModel: ContactsListViewModel(), showingSheet: .constant(false) + ContactsListFragment(showingSheet: .constant(false) , startCallFunc: { addr in if callViewModel.isTransferInsteadCall { showingDialer = false diff --git a/Linphone/UI/Main/History/HistoryView.swift b/Linphone/UI/Main/History/HistoryView.swift index b60bbadba..57a8ccc58 100644 --- a/Linphone/UI/Main/History/HistoryView.swift +++ b/Linphone/UI/Main/History/HistoryView.swift @@ -24,7 +24,7 @@ struct HistoryView: View { @ObservedObject var historyListViewModel: HistoryListViewModel @ObservedObject var historyViewModel: HistoryViewModel - @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var contactsListViewModel: ContactsListViewModel @ObservedObject var editContactViewModel: EditContactViewModel @Binding var index: Int @@ -38,7 +38,7 @@ struct HistoryView: View { HistoryFragment( historyListViewModel: historyListViewModel, historyViewModel: historyViewModel, - contactViewModel: contactViewModel, + contactsListViewModel: contactsListViewModel, editContactViewModel: editContactViewModel, index: $index, isShowEditContactFragment: $isShowEditContactFragment, @@ -74,7 +74,7 @@ struct HistoryView: View { HistoryFragment( historyListViewModel: HistoryListViewModel(), historyViewModel: HistoryViewModel(), - contactViewModel: ContactViewModel(), + contactsListViewModel: ContactsListViewModel(), editContactViewModel: EditContactViewModel(), index: .constant(1), isShowEditContactFragment: .constant(false), diff --git a/LinphoneApp.xcodeproj/project.pbxproj b/LinphoneApp.xcodeproj/project.pbxproj index 7e16c8174..8df3e3e26 100644 --- a/LinphoneApp.xcodeproj/project.pbxproj +++ b/LinphoneApp.xcodeproj/project.pbxproj @@ -83,7 +83,6 @@ D719ABCC2ABC769C00B41C10 /* AssistantView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D719ABCB2ABC769C00B41C10 /* AssistantView.swift */; }; D719ABCF2ABC779A00B41C10 /* AccountLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D719ABCE2ABC779A00B41C10 /* AccountLoginViewModel.swift */; }; D71A0E192B485ADF0002C6CD /* ViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71A0E182B485ADF0002C6CD /* ViewExtension.swift */; }; - D71FCA7F2AE1397200D2E43E /* ContactsListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71FCA7E2AE1397200D2E43E /* ContactsListViewModel.swift */; }; D71FCA812AE14CFC00D2E43E /* ContactsListFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71FCA802AE14CFC00D2E43E /* ContactsListFragment.swift */; }; D71FCA832AE14D6E00D2E43E /* ContactFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71FCA822AE14D6E00D2E43E /* ContactFragment.swift */; }; D720E6AD2BAD822000DDFD87 /* ParticipantModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D720E6AC2BAD822000DDFD87 /* ParticipantModel.swift */; }; @@ -131,7 +130,7 @@ D777DBB32AE12C5900565A99 /* ContactsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D777DBB22AE12C5900565A99 /* ContactsManager.swift */; }; D77A080E2CB6BCAF0095D589 /* MessageConferenceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77A080D2CB6BCA10095D589 /* MessageConferenceInfo.swift */; }; D78290B82ADD3910004AA85C /* ContactsFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78290B72ADD3910004AA85C /* ContactsFragment.swift */; }; - D78290BB2ADD40B2004AA85C /* ContactViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78290BA2ADD40B2004AA85C /* ContactViewModel.swift */; }; + D78290BB2ADD40B2004AA85C /* ContactsListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78290BA2ADD40B2004AA85C /* ContactsListViewModel.swift */; }; D783028F2D414847009CCB60 /* DebugFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D783028E2D414845009CCB60 /* DebugFragment.swift */; }; D783C77C2B1089B200622CC2 /* assistant_linphone_default_values in Resources */ = {isa = PBXBuildFile; fileRef = D783C77A2B1089B200622CC2 /* assistant_linphone_default_values */; }; D783C77D2B1089B200622CC2 /* assistant_third_party_default_values in Resources */ = {isa = PBXBuildFile; fileRef = D783C77B2B1089B200622CC2 /* assistant_third_party_default_values */; }; @@ -189,7 +188,6 @@ D7E6ADF32B9875C20009A2BC /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E6ADF22B9875C20009A2BC /* Message.swift */; }; D7E6ADF52B9876ED0009A2BC /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E6ADF42B9876ED0009A2BC /* Attachment.swift */; }; D7E6D0492AE933AD00A57AAF /* FavoriteContactsListFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E6D0482AE933AD00A57AAF /* FavoriteContactsListFragment.swift */; }; - D7E6D04B2AE9347D00A57AAF /* FavoriteContactsListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E6D04A2AE9347D00A57AAF /* FavoriteContactsListViewModel.swift */; }; D7E6D04D2AEBD77600A57AAF /* CustomBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E6D04C2AEBD77600A57AAF /* CustomBottomSheet.swift */; }; D7E6D0512AEBDBD500A57AAF /* ContactsListBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E6D0502AEBDBD500A57AAF /* ContactsListBottomSheet.swift */; }; D7E6D0552AEBFCCE00A57AAF /* ContactsInnerFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E6D0542AEBFCCE00A57AAF /* ContactsInnerFragment.swift */; }; @@ -297,7 +295,6 @@ D719ABCB2ABC769C00B41C10 /* AssistantView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssistantView.swift; sourceTree = ""; }; D719ABCE2ABC779A00B41C10 /* AccountLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLoginViewModel.swift; sourceTree = ""; }; D71A0E182B485ADF0002C6CD /* ViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExtension.swift; sourceTree = ""; }; - D71FCA7E2AE1397200D2E43E /* ContactsListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsListViewModel.swift; sourceTree = ""; }; D71FCA802AE14CFC00D2E43E /* ContactsListFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsListFragment.swift; sourceTree = ""; }; D71FCA822AE14D6E00D2E43E /* ContactFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactFragment.swift; sourceTree = ""; }; D720E6AC2BAD822000DDFD87 /* ParticipantModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParticipantModel.swift; sourceTree = ""; }; @@ -345,7 +342,7 @@ D777DBB22AE12C5900565A99 /* ContactsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsManager.swift; sourceTree = ""; }; D77A080D2CB6BCA10095D589 /* MessageConferenceInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageConferenceInfo.swift; sourceTree = ""; }; D78290B72ADD3910004AA85C /* ContactsFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsFragment.swift; sourceTree = ""; }; - D78290BA2ADD40B2004AA85C /* ContactViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactViewModel.swift; sourceTree = ""; }; + D78290BA2ADD40B2004AA85C /* ContactsListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsListViewModel.swift; sourceTree = ""; }; D783028E2D414845009CCB60 /* DebugFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugFragment.swift; sourceTree = ""; }; D783C77A2B1089B200622CC2 /* assistant_linphone_default_values */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = assistant_linphone_default_values; sourceTree = ""; }; D783C77B2B1089B200622CC2 /* assistant_third_party_default_values */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = assistant_third_party_default_values; sourceTree = ""; }; @@ -398,7 +395,6 @@ D7E6ADF22B9875C20009A2BC /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; D7E6ADF42B9876ED0009A2BC /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; }; D7E6D0482AE933AD00A57AAF /* FavoriteContactsListFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteContactsListFragment.swift; sourceTree = ""; }; - D7E6D04A2AE9347D00A57AAF /* FavoriteContactsListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteContactsListViewModel.swift; sourceTree = ""; }; D7E6D04C2AEBD77600A57AAF /* CustomBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomBottomSheet.swift; sourceTree = ""; }; D7E6D0502AEBDBD500A57AAF /* ContactsListBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsListBottomSheet.swift; sourceTree = ""; }; D7E6D0542AEBFCCE00A57AAF /* ContactsInnerFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsInnerFragment.swift; sourceTree = ""; }; @@ -832,9 +828,7 @@ D78290B92ADD409D004AA85C /* ViewModel */ = { isa = PBXGroup; children = ( - D78290BA2ADD40B2004AA85C /* ContactViewModel.swift */, - D71FCA7E2AE1397200D2E43E /* ContactsListViewModel.swift */, - D7E6D04A2AE9347D00A57AAF /* FavoriteContactsListViewModel.swift */, + D78290BA2ADD40B2004AA85C /* ContactsListViewModel.swift */, D7C3650B2AF0084000FE6142 /* EditContactViewModel.swift */, ); path = ViewModel; @@ -1217,7 +1211,7 @@ C67586B02C09F247002E77BF /* URIHandler.swift in Sources */, C62817282C1B389700DBA646 /* SideMenuAccountRow.swift in Sources */, C60E8F192C0F649200A06DB8 /* UIApplicationExtension.swift in Sources */, - D78290BB2ADD40B2004AA85C /* ContactViewModel.swift in Sources */, + D78290BB2ADD40B2004AA85C /* ContactsListViewModel.swift in Sources */, D7E2E69F2CE356C90080DA0D /* PopupViewWithTextField.swift in Sources */, C67586B52C09F617002E77BF /* SingleSignOnManager.swift in Sources */, D7F4D9CB2B5FD27200CDCD76 /* CallsListFragment.swift in Sources */, @@ -1240,7 +1234,6 @@ D732A9152B04C7FE00DB42BA /* HistoryListViewModel.swift in Sources */, 6646A7A32BB2E224006B842A /* ScheduleMeetingFragment.swift in Sources */, D7C500402D27F16C00DD53EC /* AccountSettingsFragment.swift in Sources */, - D71FCA7F2AE1397200D2E43E /* ContactsListViewModel.swift in Sources */, D71FCA812AE14CFC00D2E43E /* ContactsListFragment.swift in Sources */, D734499B2BC694C900778C56 /* MeetingWaitingRoomViewModel.swift in Sources */, D719ABB72ABC67BF00B41C10 /* LinphoneApp.swift in Sources */, @@ -1325,7 +1318,6 @@ C62817342C1C7C7400DBA646 /* HelpView.swift in Sources */, D78E062C2BEA69BC00CE3783 /* CallStatisticsSheetBottomSheet.swift in Sources */, D7C365082AEFAB7F00FE6142 /* ContactListBottomSheet.swift in Sources */, - D7E6D04B2AE9347D00A57AAF /* FavoriteContactsListViewModel.swift in Sources */, D74C9CFA2ACACF2D0021626A /* WelcomePage2Fragment.swift in Sources */, D74C9CFF2ACAEC5E0021626A /* PopupView.swift in Sources */, D7DA67622ACCB2FA00E95002 /* LoginFragment.swift in Sources */,