diff --git a/Linphone.xcodeproj/project.pbxproj b/Linphone.xcodeproj/project.pbxproj index 8e8b78648..8cb2f5bbd 100644 --- a/Linphone.xcodeproj/project.pbxproj +++ b/Linphone.xcodeproj/project.pbxproj @@ -164,6 +164,8 @@ D7D24D182AC1B4E800C6F35B /* NotoSans-ExtraBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D7D24D122AC1B4E800C6F35B /* NotoSans-ExtraBold.ttf */; }; D7DA67622ACCB2FA00E95002 /* LoginFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DA67612ACCB2FA00E95002 /* LoginFragment.swift */; }; D7DA67642ACCB31700E95002 /* ProfileModeFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DA67632ACCB31700E95002 /* ProfileModeFragment.swift */; }; + D7DC096F2CFA1D7600A6D47C /* AccountProfileFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DC096E2CFA1D7400A6D47C /* AccountProfileFragment.swift */; }; + D7DC09712CFDBF9A00A6D47C /* AccountProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DC09702CFDBF8300A6D47C /* AccountProfileViewModel.swift */; }; D7E2E69F2CE356C90080DA0D /* PopupViewWithTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E2E69E2CE356C90080DA0D /* PopupViewWithTextField.swift */; }; D7E6ADF32B9875C20009A2BC /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E6ADF22B9875C20009A2BC /* Message.swift */; }; D7E6ADF52B9876ED0009A2BC /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E6ADF42B9876ED0009A2BC /* Attachment.swift */; }; @@ -358,6 +360,8 @@ D7D24D122AC1B4E800C6F35B /* NotoSans-ExtraBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NotoSans-ExtraBold.ttf"; sourceTree = ""; }; D7DA67612ACCB2FA00E95002 /* LoginFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginFragment.swift; sourceTree = ""; }; D7DA67632ACCB31700E95002 /* ProfileModeFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileModeFragment.swift; sourceTree = ""; }; + D7DC096E2CFA1D7400A6D47C /* AccountProfileFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountProfileFragment.swift; sourceTree = ""; }; + D7DC09702CFDBF8300A6D47C /* AccountProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountProfileViewModel.swift; sourceTree = ""; }; D7E2E69E2CE356C90080DA0D /* PopupViewWithTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupViewWithTextField.swift; sourceTree = ""; }; D7E6ADF22B9875C20009A2BC /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; D7E6ADF42B9876ED0009A2BC /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; }; @@ -602,6 +606,7 @@ D7A03FBE2ACC2E010081A588 /* History */, 66E56BC52BA45E49006CE56F /* Meetings */, 66D382032CEB7DB80063E1C5 /* Models */, + D7DC096A2CFA192200A6D47C /* Settings */, D7A2EDD42AC180FE005D90FC /* Viewmodel */, D719ABB82ABC67BF00B41C10 /* ContentView.swift */, ); @@ -909,6 +914,39 @@ path = Fragments; sourceTree = ""; }; + D7DC096A2CFA192200A6D47C /* Settings */ = { + isa = PBXGroup; + children = ( + D7DC096B2CFA192F00A6D47C /* Fragments */, + D7DC096C2CFA193B00A6D47C /* Models */, + D7DC096D2CFA194600A6D47C /* ViewModel */, + ); + path = Settings; + sourceTree = ""; + }; + D7DC096B2CFA192F00A6D47C /* Fragments */ = { + isa = PBXGroup; + children = ( + D7DC096E2CFA1D7400A6D47C /* AccountProfileFragment.swift */, + ); + path = Fragments; + sourceTree = ""; + }; + D7DC096C2CFA193B00A6D47C /* Models */ = { + isa = PBXGroup; + children = ( + ); + path = Models; + sourceTree = ""; + }; + D7DC096D2CFA194600A6D47C /* ViewModel */ = { + isa = PBXGroup; + children = ( + D7DC09702CFDBF8300A6D47C /* AccountProfileViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1132,6 +1170,7 @@ D7C2DA1D2CA44DE400A2441B /* EventModel.swift in Sources */, D719ABC92ABC6FD700B41C10 /* CoreContext.swift in Sources */, D70A26F22B7F5D95006CC8FC /* ConversationFragment.swift in Sources */, + D7DC096F2CFA1D7600A6D47C /* AccountProfileFragment.swift in Sources */, D717A10E2CEB772300849D92 /* ShareSheetController.swift in Sources */, 66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */, D70959F12B8DF3EC0014AC0B /* ConversationModel.swift in Sources */, @@ -1211,6 +1250,7 @@ D7CEE0382B7A214F00FD79B7 /* ConversationsListViewModel.swift in Sources */, D74C9CF82ACACECE0021626A /* WelcomePage1Fragment.swift in Sources */, 66E56BCE2BA9A1F8006CE56F /* MeetingModel.swift in Sources */, + D7DC09712CFDBF9A00A6D47C /* AccountProfileViewModel.swift in Sources */, D7E6D0552AEBFCCE00A57AAF /* ContactsInnerFragment.swift in Sources */, D72343362AD037AF009AA24E /* ToastView.swift in Sources */, D7FB55112AD447FD00A5AB15 /* RegisterFragment.swift in Sources */, diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index 0484bbc24..0991472b9 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -144,6 +144,7 @@ struct LinphoneApp: App { @State private var meetingsListViewModel: MeetingsListViewModel? @State private var meetingViewModel: MeetingViewModel? @State private var conversationForwardMessageViewModel: ConversationForwardMessageViewModel? + @State private var accountProfileViewModel: AccountProfileViewModel? var body: some Scene { WindowGroup { @@ -175,7 +176,8 @@ struct LinphoneApp: App { && conversationViewModel != nil && meetingsListViewModel != nil && meetingViewModel != nil - && conversationForwardMessageViewModel != nil { + && conversationForwardMessageViewModel != nil + && accountProfileViewModel != nil { ContentView( contactViewModel: contactViewModel!, editContactViewModel: editContactViewModel!, @@ -189,7 +191,8 @@ struct LinphoneApp: App { conversationViewModel: conversationViewModel!, meetingsListViewModel: meetingsListViewModel!, meetingViewModel: meetingViewModel!, - conversationForwardMessageViewModel: conversationForwardMessageViewModel! + conversationForwardMessageViewModel: conversationForwardMessageViewModel!, + accountProfileViewModel: accountProfileViewModel! ) .environmentObject(navigationManager) .onAppear { @@ -201,6 +204,8 @@ struct LinphoneApp: App { // Notify the app to navigate to the chat room navigationManager.openChatRoom(callId: callId, peerAddr: peerAddr, localAddr: localAddr) } + + accountProfileViewModel!.setAvatarModel() } .onOpenURL { url in URIHandler.handleURL(url: url) @@ -226,6 +231,7 @@ struct LinphoneApp: App { meetingsListViewModel = MeetingsListViewModel() meetingViewModel = MeetingViewModel() conversationForwardMessageViewModel = ConversationForwardMessageViewModel() + accountProfileViewModel = AccountProfileViewModel() }.onOpenURL { url in URIHandler.handleURL(url: url) } diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index 39112271b..9c39cdf01 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -2533,6 +2533,23 @@ } } }, + "drawer_menu_manage_account" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manage the profile" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Paramètres du profil" + } + } + } + }, "drawer_menu_no_account_configured_yet" : { "extractionState" : "manual", "localizations" : { @@ -2882,6 +2899,23 @@ } } }, + "manage_account_title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manage account" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Votre compte" + } + } + } + }, "Marquer comme non lu" : { }, diff --git a/Linphone/Ressources/linphonerc-default b/Linphone/Ressources/linphonerc-default index 80f2f4736..686a5f4ff 100644 --- a/Linphone/Ressources/linphonerc-default +++ b/Linphone/Ressources/linphonerc-default @@ -34,8 +34,8 @@ host= port=443 [misc] -log_collection_upload_server_url=https://www.linphone.org:444/lft.php -file_transfer_server_url=https://www.linphone.org:444/lft.php +log_collection_upload_server_url=https://files.linphone.org:443/http-file-transfer-server/hft.php +file_transfer_server_url=https://files.linphone.org:443/http-file-transfer-server/hft.php version_check_url_root=https://www.linphone.org/releases max_calls=10 conference_layout=1 diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift index 3a4a9e475..5df66befe 100644 --- a/Linphone/UI/Main/ContentView.swift +++ b/Linphone/UI/Main/ContentView.swift @@ -49,6 +49,7 @@ struct ContentView: View { @ObservedObject var meetingsListViewModel: MeetingsListViewModel @ObservedObject var meetingViewModel: MeetingViewModel @ObservedObject var conversationForwardMessageViewModel: ConversationForwardMessageViewModel + @ObservedObject var accountProfileViewModel: AccountProfileViewModel @State var index = 0 @State private var orientation = UIDevice.current.orientation @@ -70,6 +71,7 @@ struct ContentView: View { @State var isShowSipAddressesPopup = false @State var isShowSipAddressesPopupType = 0 // 0 to call, 1 to message, 2 to video call @State var isShowConversationFragment = false + @State var isShowAccountProfileFragment = false @State var fullscreenVideo = false @@ -79,54 +81,583 @@ struct ContentView: View { var body: some View { let pub = NotificationCenter.default .publisher(for: NSNotification.Name("ContactLoaded")) - - GeometryReader { geometry in - VStack(spacing: 0) { - if (telecomManager.callInProgress && !fullscreenVideo && ((!telecomManager.callDisplayed && callViewModel.callsCounter == 1) || callViewModel.callsCounter > 1)) || isShowConversationFragment { - HStack { - Image("phone") - .renderingMode(.template) - .resizable() - .foregroundStyle(.white) - .frame(width: 26, height: 26) - .padding(.leading, 10) - - if callViewModel.callsCounter > 1 { - Text("\(callViewModel.callsCounter) appels") - .default_text_style_white(styleSize: 16) - } else { - Text("\(callViewModel.displayName)") - .default_text_style_white(styleSize: 16) + NavigationView { + GeometryReader { geometry in + VStack(spacing: 0) { + if (telecomManager.callInProgress && !fullscreenVideo && ((!telecomManager.callDisplayed && callViewModel.callsCounter == 1) || callViewModel.callsCounter > 1)) || isShowConversationFragment { + HStack { + Image("phone") + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 26, height: 26) + .padding(.leading, 10) + + if callViewModel.callsCounter > 1 { + Text("\(callViewModel.callsCounter) appels") + .default_text_style_white(styleSize: 16) + } else { + Text("\(callViewModel.displayName)") + .default_text_style_white(styleSize: 16) + } + + Spacer() + + if callViewModel.callsCounter == 1 { + Text("\(callViewModel.isPaused || telecomManager.isPausedByRemote ? "En pause" : "Actif")") + .default_text_style_white(styleSize: 16) + .padding(.trailing, 10) + } } - - Spacer() - - if callViewModel.callsCounter == 1 { - Text("\(callViewModel.isPaused || telecomManager.isPausedByRemote ? "En pause" : "Actif")") - .default_text_style_white(styleSize: 16) - .padding(.trailing, 10) + .frame(maxWidth: .infinity) + .frame(height: 30) + .background(Color.greenSuccess500) + .onTapGesture { + withAnimation { + telecomManager.callDisplayed = true + } } } - .frame(maxWidth: .infinity) - .frame(height: 30) - .background(Color.greenSuccess500) - .onTapGesture { - withAnimation { - telecomManager.callDisplayed = true - } - } - } - - ZStack { - VStack(spacing: 0) { - HStack(spacing: 0) { - if orientation == .landscapeLeft - || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height { + + ZStack { + VStack(spacing: 0) { + HStack(spacing: 0) { + if orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height { + VStack(spacing: 0) { + Group { + Spacer() + + Button(action: { + self.index = 0 + historyViewModel.displayedCall = nil + conversationViewModel.displayedConversation = nil + meetingViewModel.displayedMeeting = nil + }, label: { + VStack { + Image("address-book") + .renderingMode(.template) + .resizable() + .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600) + .frame(width: 25, height: 25) + if self.index == 0 { + Text("Contacts") + .default_text_style_700(styleSize: 10) + } else { + Text("Contacts") + .default_text_style(styleSize: 10) + } + } + }) + .padding(.top) + .frame(height: geometry.size.height/4) + + ZStack { + if historyListViewModel.missedCallsCount > 0 { + VStack { + HStack { + Text( + historyListViewModel.missedCallsCount < 99 + ? String(historyListViewModel.missedCallsCount) + : "99+" + ) + .foregroundStyle(.white) + .default_text_style(styleSize: 10) + .lineLimit(1) + } + .frame(width: 18, height: 18) + .background(Color.redDanger500) + .cornerRadius(50) + } + .padding(.bottom, 30) + .padding(.leading, 30) + } + + Button(action: { + self.index = 1 + contactViewModel.indexDisplayedFriend = nil + conversationViewModel.displayedConversation = nil + meetingViewModel.displayedMeeting = nil + if historyListViewModel.missedCallsCount > 0 { + historyListViewModel.resetMissedCallsCount() + } + }, label: { + VStack { + Image("phone") + .renderingMode(.template) + .resizable() + .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600) + .frame(width: 25, height: 25) + if self.index == 1 { + Text("Calls") + .default_text_style_700(styleSize: 10) + } else { + Text("Calls") + .default_text_style(styleSize: 10) + } + } + }) + .padding(.top) + } + .frame(height: geometry.size.height/4) + + ZStack { + if conversationsListViewModel.unreadMessages > 0 { + VStack { + HStack { + Text( + conversationsListViewModel.unreadMessages < 99 + ? String(conversationsListViewModel.unreadMessages) + : "99+" + ) + .foregroundStyle(.white) + .default_text_style(styleSize: 10) + .lineLimit(1) + } + .frame(width: 18, height: 18) + .background(Color.redDanger500) + .cornerRadius(50) + } + .padding(.bottom, 30) + .padding(.leading, 30) + } + + Button(action: { + self.index = 2 + historyViewModel.displayedCall = nil + contactViewModel.indexDisplayedFriend = nil + meetingViewModel.displayedMeeting = nil + }, label: { + VStack { + Image("chat-teardrop-text") + .renderingMode(.template) + .resizable() + .foregroundStyle(self.index == 2 ? Color.orangeMain500 : Color.grayMain2c600) + .frame(width: 25, height: 25) + + if self.index == 2 { + Text("bottom_navigation_conversations_label") + .default_text_style_700(styleSize: 10) + } else { + Text("bottom_navigation_conversations_label") + .default_text_style(styleSize: 10) + } + } + }) + .padding(.top) + } + .frame(height: geometry.size.height/4) + + Button(action: { + self.index = 3 + contactViewModel.indexDisplayedFriend = nil + historyViewModel.displayedCall = nil + conversationViewModel.displayedConversation = nil + }, label: { + VStack { + Image("video-conference") + .renderingMode(.template) + .resizable() + .foregroundStyle(self.index == 3 ? Color.orangeMain500 : Color.grayMain2c600) + .frame(width: 25, height: 25) + if self.index == 0 { + Text("bottom_navigation_meetings_label") + .default_text_style_700(styleSize: 10) + } else { + Text("bottom_navigation_meetings_label") + .default_text_style(styleSize: 10) + } + } + }) + .padding(.top) + .frame(height: geometry.size.height/4) + + Spacer() + } + } + .frame(width: 75, height: geometry.size.height) + .padding(.leading, + orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0 + ? -geometry.safeAreaInsets.leading + : 0) + } + VStack(spacing: 0) { + Rectangle() + .foregroundColor(Color.orangeMain500) + .edgesIgnoringSafeArea(.top) + .frame(height: 1) + + ZStack { + VStack { + Rectangle() + .foregroundColor( + (orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) + ? Color.white + : Color.orangeMain500 + ) + .frame(height: 100) + + Spacer() + } + + VStack(spacing: 0) { + if searchIsActive == false { + HStack { + Image("profile-image-example") + .resizable() + .frame(width: 45, height: 45) + .clipShape(Circle()) + .onTapGesture { + openMenu() + } + + Text(index == 0 ? "bottom_navigation_contacts_label" : (index == 1 ? "bottom_navigation_calls_label" : (index == 2 ? "bottom_navigation_conversations_label" : "bottom_navigation_meetings_label"))) + .default_text_style_white_800(styleSize: 20) + .padding(.leading, 10) + + Spacer() + + Button { + withAnimation { + searchIsActive.toggle() + } + } label: { + Image("magnifying-glass") + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + } + .padding(.trailing, index == 2 ? 10 : 0) + + if index == 3 { + Button { + NotificationCenter.default.post(name: MeetingsListViewModel.ScrollToTodayNotification, object: nil) + } label: { + Image("calendar") + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + } + .padding(.trailing, 10) + } else if index != 2 { + Menu { + if index == 0 { + Button { + contactViewModel.indexDisplayedFriend = nil + isMenuOpen = false + magicSearch.allContact = true + MagicSearchSingleton.shared.searchForContacts( + sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) + } label: { + HStack { + Text("contacts_list_filter_popup_see_all") + Spacer() + if magicSearch.allContact { + Image("green-check") + .resizable() + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + } + } + } + + Button { + contactViewModel.indexDisplayedFriend = nil + isMenuOpen = false + magicSearch.allContact = false + MagicSearchSingleton.shared.searchForContacts( + sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) + } label: { + HStack { + Text(String(format: String(localized: "contacts_list_filter_popup_see_linphone_only"), Bundle.main.displayName)) + Spacer() + if !magicSearch.allContact { + Image("green-check") + .resizable() + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + } + } + } + } else { + Button(role: .destructive) { + isMenuOpen = false + isShowDeleteAllHistoryPopup.toggle() + } label: { + HStack { + Text("Delete all history") + Spacer() + Image("trash-simple-red") + .resizable() + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + } + } + } + } label: { + Image(index == 0 ? "funnel" : "dots-three-vertical") + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + } + .padding(.trailing, 10) + .onTapGesture { + isMenuOpen = true + } + } + } + .frame(maxWidth: .infinity) + .frame(height: 50) + .padding(.leading) + .padding(.top, 2.5) + .padding(.bottom, 2.5) + .background(Color.orangeMain500) + .roundedCorner(10, corners: [.bottomRight, .bottomLeft]) + } else { + HStack { + Button { + withAnimation { + self.focusedField = false + searchIsActive.toggle() + } + + text = "" + + if index == 0 { + magicSearch.currentFilter = "" + MagicSearchSingleton.shared.searchForContacts( + sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) + } else if index == 1 { + historyListViewModel.resetFilterCallLogs() + } else if index == 2 { + conversationsListViewModel.resetFilterConversations() + } else if index == 3 { + meetingsListViewModel.currentFilter = "" + meetingsListViewModel.computeMeetingsList() + } + } label: { + Image("caret-left") + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + .padding(.leading, -10) + } + + if #available(iOS 16.0, *) { + TextEditor(text: Binding( + get: { + return text + }, + set: { value in + var newValue = value + if value.contains("\n") { + newValue = value.replacingOccurrences(of: "\n", with: "") + } + text = newValue + } + )) + .default_text_style_white_700(styleSize: 15) + .padding(.all, 6) + .disableAutocorrection(true) + .autocapitalization(.none) + .accentColor(.white) + .scrollContentBackground(.hidden) + .focused($focusedField) + .onAppear { + self.focusedField = true + } + .onChange(of: text) { newValue in + if index == 0 { + magicSearch.currentFilter = newValue + MagicSearchSingleton.shared.searchForContacts( + sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) + } else if index == 1 { + if text.isEmpty { + historyListViewModel.resetFilterCallLogs() + } else { + historyListViewModel.filterCallLogs(filter: text) + } + } else if index == 2 { + if text.isEmpty { + conversationsListViewModel.resetFilterConversations() + } else { + conversationsListViewModel.filterConversations(filter: text) + } + } else if index == 3 { + meetingsListViewModel.currentFilter = text + meetingsListViewModel.computeMeetingsList() + } + } + } else { + TextEditor(text: Binding( + get: { + return text + }, + set: { value in + var newValue = value + if value.contains("\n") { + newValue = value.replacingOccurrences(of: "\n", with: "") + } + text = newValue + } + )) + .default_text_style_700(styleSize: 15) + .padding(.all, 6) + .focused($focusedField) + .disableAutocorrection(true) + .autocapitalization(.none) + .onAppear { + self.focusedField = true + } + .onChange(of: text) { newValue in + if index == 0 { + magicSearch.currentFilter = newValue + MagicSearchSingleton.shared.searchForContacts( + sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) + } else if index == 1 { + historyListViewModel.filterCallLogs(filter: text) + } else if index == 2 { + conversationsListViewModel.filterConversations(filter: text) + } else if index == 3 { + meetingsListViewModel.currentFilter = text + meetingsListViewModel.computeMeetingsList() + } + } + } + + Button { + text = "" + } label: { + Image("x") + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + } + .padding(.leading) + } + .frame(maxWidth: .infinity) + .frame(height: 50) + .padding(.horizontal) + .padding(.bottom, 5) + .background(Color.orangeMain500) + .roundedCorner(10, corners: [.bottomRight, .bottomLeft]) + } + + if self.index == 0 { + ContactsView( + contactViewModel: contactViewModel, + historyViewModel: historyViewModel, + editContactViewModel: editContactViewModel, + isShowEditContactFragment: $isShowEditContactFragment, + isShowDeletePopup: $isShowDeleteContactPopup, + text: $text + ) + .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 { + HistoryView( + historyListViewModel: historyListViewModel, + historyViewModel: historyViewModel, + contactViewModel: contactViewModel, + editContactViewModel: editContactViewModel, + index: $index, + isShowStartCallFragment: $isShowStartCallFragment, + isShowEditContactFragment: $isShowEditContactFragment, + text: $text + ) + .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 == 2 { + ConversationsView( + conversationViewModel: conversationViewModel, + conversationsListViewModel: conversationsListViewModel, + text: $text, + isShowStartConversationFragment: $isShowStartConversationFragment + ) + .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 == 3 { + MeetingsView( + meetingsListViewModel: meetingsListViewModel, + meetingViewModel: meetingViewModel, + isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, + isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup, + text: $text + ) + .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 + ) + } + } + } + } + .frame(maxWidth: + (orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) + ? geometry.size.width/100*40 + : .infinity + ) + .background( + Color.white + .shadow(color: Color.gray200, radius: 4, x: 0, y: 0) + .mask(Rectangle().padding(.horizontal, -8)) + ) + + if orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height { + Spacer() + } + } + + if !(orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) && !searchIsActive { + HStack { Group { Spacer() - Button(action: { self.index = 0 historyViewModel.displayedCall = nil @@ -149,7 +680,9 @@ struct ContentView: View { } }) .padding(.top) - .frame(height: geometry.size.height/4) + .frame(width: 66) + + Spacer() ZStack { if historyListViewModel.missedCallsCount > 0 { @@ -189,16 +722,18 @@ struct ContentView: View { .frame(width: 25, height: 25) if self.index == 1 { Text("Calls") - .default_text_style_700(styleSize: 10) + .default_text_style_700(styleSize: 9) } else { Text("Calls") - .default_text_style(styleSize: 10) + .default_text_style(styleSize: 9) } } }) .padding(.top) + .frame(width: 66) } - .frame(height: geometry.size.height/4) + + Spacer() ZStack { if conversationsListViewModel.unreadMessages > 0 { @@ -236,17 +771,18 @@ struct ContentView: View { if self.index == 2 { Text("bottom_navigation_conversations_label") - .default_text_style_700(styleSize: 10) + .default_text_style_700(styleSize: 9) } else { Text("bottom_navigation_conversations_label") - .default_text_style(styleSize: 10) + .default_text_style(styleSize: 9) } } }) .padding(.top) + .frame(width: 66) } - .frame(height: geometry.size.height/4) + Spacer() Button(action: { self.index = 3 contactViewModel.indexDisplayedFriend = nil @@ -259,1052 +795,529 @@ struct ContentView: View { .resizable() .foregroundStyle(self.index == 3 ? Color.orangeMain500 : Color.grayMain2c600) .frame(width: 25, height: 25) - if self.index == 0 { + if self.index == 3 { Text("bottom_navigation_meetings_label") - .default_text_style_700(styleSize: 10) + .default_text_style_700(styleSize: 9) } else { Text("bottom_navigation_meetings_label") - .default_text_style(styleSize: 10) + .default_text_style(styleSize: 9) } } }) .padding(.top) - .frame(height: geometry.size.height/4) + .frame(width: 66) Spacer() } } - .frame(width: 75, height: geometry.size.height) - .padding(.leading, - orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0 - ? -geometry.safeAreaInsets.leading - : 0) - } - - VStack(spacing: 0) { - Rectangle() - .foregroundColor(Color.orangeMain500) - .edgesIgnoringSafeArea(.top) - .frame(height: 1) - - ZStack { - VStack { - Rectangle() - .foregroundColor( - (orientation == .landscapeLeft - || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) - ? Color.white - : Color.orangeMain500 - ) - .frame(height: 100) - - Spacer() - } - - VStack(spacing: 0) { - if searchIsActive == false { - HStack { - Image("profile-image-example") - .resizable() - .frame(width: 45, height: 45) - .clipShape(Circle()) - .onTapGesture { - openMenu() - } - - Text(index == 0 ? "bottom_navigation_contacts_label" : (index == 1 ? "bottom_navigation_calls_label" : (index == 2 ? "bottom_navigation_conversations_label" : "bottom_navigation_meetings_label"))) - .default_text_style_white_800(styleSize: 20) - .padding(.leading, 10) - - Spacer() - - Button { - withAnimation { - searchIsActive.toggle() - } - } label: { - Image("magnifying-glass") - .renderingMode(.template) - .resizable() - .foregroundStyle(.white) - .frame(width: 25, height: 25, alignment: .leading) - .padding(.all, 10) - } - .padding(.trailing, index == 2 ? 10 : 0) - - if index == 3 { - Button { - NotificationCenter.default.post(name: MeetingsListViewModel.ScrollToTodayNotification, object: nil) - } label: { - Image("calendar") - .renderingMode(.template) - .resizable() - .foregroundStyle(.white) - .frame(width: 25, height: 25, alignment: .leading) - .padding(.all, 10) - } - .padding(.trailing, 10) - } else if index != 2 { - Menu { - if index == 0 { - Button { - contactViewModel.indexDisplayedFriend = nil - isMenuOpen = false - magicSearch.allContact = true - MagicSearchSingleton.shared.searchForContacts( - sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - } label: { - HStack { - Text("contacts_list_filter_popup_see_all") - Spacer() - if magicSearch.allContact { - Image("green-check") - .resizable() - .frame(width: 25, height: 25, alignment: .leading) - .padding(.all, 10) - } - } - } - - Button { - contactViewModel.indexDisplayedFriend = nil - isMenuOpen = false - magicSearch.allContact = false - MagicSearchSingleton.shared.searchForContacts( - sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - } label: { - HStack { - Text(String(format: String(localized: "contacts_list_filter_popup_see_linphone_only"), Bundle.main.displayName)) - Spacer() - if !magicSearch.allContact { - Image("green-check") - .resizable() - .frame(width: 25, height: 25, alignment: .leading) - .padding(.all, 10) - } - } - } - } else { - Button(role: .destructive) { - isMenuOpen = false - isShowDeleteAllHistoryPopup.toggle() - } label: { - HStack { - Text("Delete all history") - Spacer() - Image("trash-simple-red") - .resizable() - .frame(width: 25, height: 25, alignment: .leading) - .padding(.all, 10) - } - } - } - } label: { - Image(index == 0 ? "funnel" : "dots-three-vertical") - .renderingMode(.template) - .resizable() - .foregroundStyle(.white) - .frame(width: 25, height: 25, alignment: .leading) - .padding(.all, 10) - } - .padding(.trailing, 10) - .onTapGesture { - isMenuOpen = true - } - } - } - .frame(maxWidth: .infinity) - .frame(height: 50) - .padding(.leading) - .padding(.top, 2.5) - .padding(.bottom, 2.5) - .background(Color.orangeMain500) - .roundedCorner(10, corners: [.bottomRight, .bottomLeft]) - } else { - HStack { - Button { - withAnimation { - self.focusedField = false - searchIsActive.toggle() - } - - text = "" - - if index == 0 { - magicSearch.currentFilter = "" - MagicSearchSingleton.shared.searchForContacts( - sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - } else if index == 1 { - historyListViewModel.resetFilterCallLogs() - } else if index == 2 { - conversationsListViewModel.resetFilterConversations() - } else if index == 3 { - meetingsListViewModel.currentFilter = "" - meetingsListViewModel.computeMeetingsList() - } - } label: { - Image("caret-left") - .renderingMode(.template) - .resizable() - .foregroundStyle(.white) - .frame(width: 25, height: 25, alignment: .leading) - .padding(.all, 10) - .padding(.leading, -10) - } - - if #available(iOS 16.0, *) { - TextEditor(text: Binding( - get: { - return text - }, - set: { value in - var newValue = value - if value.contains("\n") { - newValue = value.replacingOccurrences(of: "\n", with: "") - } - text = newValue - } - )) - .default_text_style_white_700(styleSize: 15) - .padding(.all, 6) - .disableAutocorrection(true) - .autocapitalization(.none) - .accentColor(.white) - .scrollContentBackground(.hidden) - .focused($focusedField) - .onAppear { - self.focusedField = true - } - .onChange(of: text) { newValue in - if index == 0 { - magicSearch.currentFilter = newValue - MagicSearchSingleton.shared.searchForContacts( - sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - } else if index == 1 { - if text.isEmpty { - historyListViewModel.resetFilterCallLogs() - } else { - historyListViewModel.filterCallLogs(filter: text) - } - } else if index == 2 { - if text.isEmpty { - conversationsListViewModel.resetFilterConversations() - } else { - conversationsListViewModel.filterConversations(filter: text) - } - } else if index == 3 { - meetingsListViewModel.currentFilter = text - meetingsListViewModel.computeMeetingsList() - } - } - } else { - TextEditor(text: Binding( - get: { - return text - }, - set: { value in - var newValue = value - if value.contains("\n") { - newValue = value.replacingOccurrences(of: "\n", with: "") - } - text = newValue - } - )) - .default_text_style_700(styleSize: 15) - .padding(.all, 6) - .focused($focusedField) - .disableAutocorrection(true) - .autocapitalization(.none) - .onAppear { - self.focusedField = true - } - .onChange(of: text) { newValue in - if index == 0 { - magicSearch.currentFilter = newValue - MagicSearchSingleton.shared.searchForContacts( - sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - } else if index == 1 { - historyListViewModel.filterCallLogs(filter: text) - } else if index == 2 { - conversationsListViewModel.filterConversations(filter: text) - } else if index == 3 { - meetingsListViewModel.currentFilter = text - meetingsListViewModel.computeMeetingsList() - } - } - } - - Button { - text = "" - } label: { - Image("x") - .renderingMode(.template) - .resizable() - .foregroundStyle(.white) - .frame(width: 25, height: 25, alignment: .leading) - .padding(.all, 10) - } - .padding(.leading) - } - .frame(maxWidth: .infinity) - .frame(height: 50) - .padding(.horizontal) - .padding(.bottom, 5) - .background(Color.orangeMain500) - .roundedCorner(10, corners: [.bottomRight, .bottomLeft]) - } - - if self.index == 0 { - ContactsView( - contactViewModel: contactViewModel, - historyViewModel: historyViewModel, - editContactViewModel: editContactViewModel, - isShowEditContactFragment: $isShowEditContactFragment, - isShowDeletePopup: $isShowDeleteContactPopup, - text: $text - ) - .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 { - HistoryView( - historyListViewModel: historyListViewModel, - historyViewModel: historyViewModel, - contactViewModel: contactViewModel, - editContactViewModel: editContactViewModel, - index: $index, - isShowStartCallFragment: $isShowStartCallFragment, - isShowEditContactFragment: $isShowEditContactFragment, - text: $text - ) - .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 == 2 { - ConversationsView( - conversationViewModel: conversationViewModel, - conversationsListViewModel: conversationsListViewModel, - text: $text, - isShowStartConversationFragment: $isShowStartConversationFragment - ) - .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 == 3 { - MeetingsView( - meetingsListViewModel: meetingsListViewModel, - meetingViewModel: meetingViewModel, - isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, - isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup, - text: $text - ) - .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 - ) - } - } - } - } - .frame(maxWidth: - (orientation == .landscapeLeft - || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) - ? geometry.size.width/100*40 - : .infinity - ) - .background( - Color.white - .shadow(color: Color.gray200, radius: 4, x: 0, y: 0) - .mask(Rectangle().padding(.horizontal, -8)) - ) - - if orientation == .landscapeLeft - || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height { - Spacer() + .padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? 0 : 15) + .background( + Color.white + .shadow(color: Color.gray200, radius: 4, x: 0, y: 0) + .mask(Rectangle().padding(.top, -8)) + ) } } - if !(orientation == .landscapeLeft - || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) && !searchIsActive { - HStack { - Group { - Spacer() - Button(action: { - self.index = 0 - historyViewModel.displayedCall = nil - conversationViewModel.displayedConversation = nil - meetingViewModel.displayedMeeting = nil - }, label: { - VStack { - Image("address-book") - .renderingMode(.template) - .resizable() - .foregroundStyle(self.index == 0 ? Color.orangeMain500 : Color.grayMain2c600) - .frame(width: 25, height: 25) - if self.index == 0 { - Text("Contacts") - .default_text_style_700(styleSize: 10) - } else { - Text("Contacts") - .default_text_style(styleSize: 10) - } - } - }) - .padding(.top) - .frame(width: 66) - - Spacer() - - ZStack { - if historyListViewModel.missedCallsCount > 0 { - VStack { - HStack { - Text( - historyListViewModel.missedCallsCount < 99 - ? String(historyListViewModel.missedCallsCount) - : "99+" - ) - .foregroundStyle(.white) - .default_text_style(styleSize: 10) - .lineLimit(1) - } - .frame(width: 18, height: 18) - .background(Color.redDanger500) - .cornerRadius(50) - } - .padding(.bottom, 30) - .padding(.leading, 30) - } - - Button(action: { - self.index = 1 - contactViewModel.indexDisplayedFriend = nil - conversationViewModel.displayedConversation = nil - meetingViewModel.displayedMeeting = nil - if historyListViewModel.missedCallsCount > 0 { - historyListViewModel.resetMissedCallsCount() - } - }, label: { - VStack { - Image("phone") - .renderingMode(.template) - .resizable() - .foregroundStyle(self.index == 1 ? Color.orangeMain500 : Color.grayMain2c600) - .frame(width: 25, height: 25) - if self.index == 1 { - Text("Calls") - .default_text_style_700(styleSize: 9) - } else { - Text("Calls") - .default_text_style(styleSize: 9) - } - } - }) - .padding(.top) - .frame(width: 66) - } - - Spacer() - - ZStack { - if conversationsListViewModel.unreadMessages > 0 { - VStack { - HStack { - Text( - conversationsListViewModel.unreadMessages < 99 - ? String(conversationsListViewModel.unreadMessages) - : "99+" - ) - .foregroundStyle(.white) - .default_text_style(styleSize: 10) - .lineLimit(1) - } - .frame(width: 18, height: 18) - .background(Color.redDanger500) - .cornerRadius(50) - } - .padding(.bottom, 30) - .padding(.leading, 30) - } - - Button(action: { - self.index = 2 - historyViewModel.displayedCall = nil - contactViewModel.indexDisplayedFriend = nil - meetingViewModel.displayedMeeting = nil - }, label: { - VStack { - Image("chat-teardrop-text") - .renderingMode(.template) - .resizable() - .foregroundStyle(self.index == 2 ? Color.orangeMain500 : Color.grayMain2c600) - .frame(width: 25, height: 25) - - if self.index == 2 { - Text("bottom_navigation_conversations_label") - .default_text_style_700(styleSize: 9) - } else { - Text("bottom_navigation_conversations_label") - .default_text_style(styleSize: 9) - } - } - }) - .padding(.top) - .frame(width: 66) - } - - Spacer() - Button(action: { - self.index = 3 - contactViewModel.indexDisplayedFriend = nil - historyViewModel.displayedCall = nil - conversationViewModel.displayedConversation = nil - }, label: { - VStack { - Image("video-conference") - .renderingMode(.template) - .resizable() - .foregroundStyle(self.index == 3 ? Color.orangeMain500 : Color.grayMain2c600) - .frame(width: 25, height: 25) - if self.index == 3 { - Text("bottom_navigation_meetings_label") - .default_text_style_700(styleSize: 9) - } else { - Text("bottom_navigation_meetings_label") - .default_text_style(styleSize: 9) - } - } - }) - .padding(.top) - .frame(width: 66) - - Spacer() - } - } - .padding(.bottom, geometry.safeAreaInsets.bottom > 0 ? 0 : 15) - .background( - Color.white - .shadow(color: Color.gray200, radius: 4, x: 0, y: 0) - .mask(Rectangle().padding(.top, -8)) - ) - } - } - - if contactViewModel.indexDisplayedFriend != nil || historyViewModel.displayedCall != nil || conversationViewModel.displayedConversation != nil || - meetingViewModel.displayedMeeting != nil { - HStack(spacing: 0) { - Spacer() - .frame(maxWidth: - (orientation == .landscapeLeft - || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) - ? (geometry.size.width/100*40) + 75 - : 0 - ) - if self.index == 0 { - 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 historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.avatarModel != nil { - HistoryContactFragment( - contactAvatarModel: historyViewModel.displayedCall!.avatarModel!, - historyViewModel: historyViewModel, - historyListViewModel: historyListViewModel, + if contactViewModel.indexDisplayedFriend != nil || historyViewModel.displayedCall != nil || conversationViewModel.displayedConversation != nil || + meetingViewModel.displayedMeeting != nil { + HStack(spacing: 0) { + Spacer() + .frame(maxWidth: + (orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) + ? (geometry.size.width/100*40) + 75 + : 0 + ) + if self.index == 0 { + ContactFragment( contactViewModel: contactViewModel, editContactViewModel: editContactViewModel, - isShowDeleteAllHistoryPopup: $isShowDeleteAllHistoryPopup, - isShowEditContactFragment: $isShowEditContactFragment, - indexPage: $index + conversationViewModel: conversationViewModel, + isShowDeletePopup: $isShowDeleteContactPopup, + isShowDismissPopup: $isShowDismissPopup, + isShowSipAddressesPopup: $isShowSipAddressesPopup, + isShowSipAddressesPopupType: $isShowSipAddressesPopupType ) .frame(maxWidth: .infinity) .background(Color.gray100) .ignoresSafeArea(.keyboard) - } - } else if self.index == 2 { - ConversationFragment( - conversationViewModel: conversationViewModel, - conversationsListViewModel: conversationsListViewModel, - conversationForwardMessageViewModel: conversationForwardMessageViewModel, - contactViewModel: contactViewModel, - editContactViewModel: editContactViewModel, - meetingViewModel: meetingViewModel, - isShowConversationFragment: $isShowConversationFragment, - isShowStartCallGroupPopup: $isShowStartCallGroupPopup, - isShowEditContactFragment: $isShowEditContactFragment, - indexPage: $index, - isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment - ) - .frame(maxWidth: .infinity) - .background(Color.gray100) - .ignoresSafeArea(.keyboard) - } else if self.index == 3 { - MeetingFragment(meetingViewModel: meetingViewModel, meetingsListViewModel: meetingsListViewModel, isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup) - .frame(maxWidth: .infinity) - .background(Color.gray100) - .ignoresSafeArea(.keyboard) - } - - } - .onAppear { - if !(orientation == .landscapeLeft - || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) - && searchIsActive { - self.focusedField = false - } - } - .onDisappear { - if !(orientation == .landscapeLeft - || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) - && searchIsActive { - self.focusedField = true - } - } - .padding(.leading, - orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0 - ? -geometry.safeAreaInsets.leading - : 0) - .transition(.move(edge: .trailing)) - .zIndex(1) - } - - SideMenu( - width: geometry.size.width / 5 * 4, - isOpen: self.sideMenuIsOpen, - menuClose: self.openMenu, - safeAreaInsets: geometry.safeAreaInsets, - isShowLoginFragment: $isShowLoginFragment - ) - .ignoresSafeArea(.all) - .zIndex(2) - - if isShowLoginFragment { - LoginFragment( - accountLoginViewModel: AccountLoginViewModel(), - isShowBack: true, - onBackPressed: { - withAnimation { - isShowLoginFragment.toggle() - } - }) - .zIndex(3) - .transition(.move(edge: .bottom)) - .onAppear { - } - } - - if isShowEditContactFragment { - EditContactFragment( - editContactViewModel: editContactViewModel, - contactViewModel: contactViewModel, - isShowEditContactFragment: $isShowEditContactFragment, - isShowDismissPopup: $isShowDismissPopup - ) - .zIndex(3) - .transition(.opacity.combined(with: .move(edge: .bottom))) - .onAppear { - contactViewModel.indexDisplayedFriend = nil - } - } - - if isShowStartCallFragment { - if #available(iOS 16.4, *), idiom != .pad { - StartCallFragment( - callViewModel: callViewModel, - startCallViewModel: startCallViewModel, - isShowStartCallFragment: $isShowStartCallFragment, - showingDialer: $showingDialer, - resetCallView: {callViewModel.resetCallView()} - ) - .zIndex(6) - .transition(.opacity.combined(with: .move(edge: .bottom))) - .sheet(isPresented: $showingDialer) { - DialerBottomSheet( - startCallViewModel: startCallViewModel, - callViewModel: callViewModel, - isShowStartCallFragment: $isShowStartCallFragment, - showingDialer: $showingDialer, - currentCall: nil - ) - .presentationDetents([.medium]) - .presentationBackgroundInteraction(.enabled(upThrough: .medium)) - } - } else { - StartCallFragment( - callViewModel: callViewModel, - startCallViewModel: startCallViewModel, - isShowStartCallFragment: $isShowStartCallFragment, - showingDialer: $showingDialer, - resetCallView: {callViewModel.resetCallView()} - ) - .zIndex(6) - .transition(.opacity.combined(with: .move(edge: .bottom))) - .halfSheet(showSheet: $showingDialer) { - DialerBottomSheet( - startCallViewModel: startCallViewModel, - callViewModel: callViewModel, - isShowStartCallFragment: $isShowStartCallFragment, - showingDialer: $showingDialer, - currentCall: nil - ) - } onDismiss: {} - } - } - - if isShowStartConversationFragment { - StartConversationFragment( - startConversationViewModel: startConversationViewModel, - conversationViewModel: conversationViewModel, - isShowStartConversationFragment: $isShowStartConversationFragment - ) - .zIndex(6) - .transition(.opacity.combined(with: .move(edge: .bottom))) - } - - if isShowDeleteContactPopup { - PopupView(isShowPopup: $isShowDeleteContactPopup, - title: Text( - contactViewModel.selectedFriend != nil - ? "Delete \(contactViewModel.selectedFriend!.name!)?" - : (contactViewModel.indexDisplayedFriend != nil - ? "Delete \(contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.name!)?" - : "Error Name")), - content: Text("This contact will be deleted definitively."), - titleFirstButton: Text("Cancel"), - actionFirstButton: { - self.isShowDeleteContactPopup.toggle()}, - titleSecondButton: Text("Ok"), - actionSecondButton: { - if contactViewModel.selectedFriendToDelete != nil { - if contactViewModel.indexDisplayedFriend != nil { - withAnimation { - contactViewModel.indexDisplayedFriend = nil + } else if self.index == 1 { + if historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.avatarModel != nil { + HistoryContactFragment( + contactAvatarModel: historyViewModel.displayedCall!.avatarModel!, + historyViewModel: historyViewModel, + historyListViewModel: historyListViewModel, + contactViewModel: contactViewModel, + editContactViewModel: editContactViewModel, + isShowDeleteAllHistoryPopup: $isShowDeleteAllHistoryPopup, + isShowEditContactFragment: $isShowEditContactFragment, + indexPage: $index + ) + .frame(maxWidth: .infinity) + .background(Color.gray100) + .ignoresSafeArea(.keyboard) } + } else if self.index == 2 { + ConversationFragment( + conversationViewModel: conversationViewModel, + conversationsListViewModel: conversationsListViewModel, + conversationForwardMessageViewModel: conversationForwardMessageViewModel, + contactViewModel: contactViewModel, + editContactViewModel: editContactViewModel, + meetingViewModel: meetingViewModel, + isShowConversationFragment: $isShowConversationFragment, + isShowStartCallGroupPopup: $isShowStartCallGroupPopup, + isShowEditContactFragment: $isShowEditContactFragment, + indexPage: $index, + isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment + ) + .frame(maxWidth: .infinity) + .background(Color.gray100) + .ignoresSafeArea(.keyboard) + } else if self.index == 3 { + MeetingFragment(meetingViewModel: meetingViewModel, meetingsListViewModel: meetingsListViewModel, isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment, isShowSendCancelMeetingNotificationPopup: $isShowSendCancelMeetingNotificationPopup) + .frame(maxWidth: .infinity) + .background(Color.gray100) + .ignoresSafeArea(.keyboard) } - contactViewModel.selectedFriendToDelete!.remove() - } else if contactViewModel.indexDisplayedFriend != nil { - let tmpIndex = contactViewModel.indexDisplayedFriend - withAnimation { - contactViewModel.indexDisplayedFriend = nil - } - contactsManager.lastSearch[tmpIndex!].friend!.remove() + } - MagicSearchSingleton.shared.searchForContacts( - sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - self.isShowDeleteContactPopup.toggle() - }) - .background(.black.opacity(0.65)) - .zIndex(3) - .onTapGesture { - self.isShowDeleteContactPopup.toggle() - } - .onAppear { - contactViewModel.selectedFriendToDelete = contactViewModel.selectedFriend - } - } - - if isShowDeleteAllHistoryPopup { - PopupView(isShowPopup: $isShowDeleteContactPopup, - title: Text("Do you really want to delete all calls history?"), - content: Text("All calls will be removed from the history."), - titleFirstButton: Text("Cancel"), - actionFirstButton: { - self.isShowDeleteAllHistoryPopup.toggle() - historyListViewModel.callLogsAddressToDelete = "" - }, - titleSecondButton: Text("Ok"), - actionSecondButton: { - historyListViewModel.removeCallLogs() - self.isShowDeleteAllHistoryPopup.toggle() - historyViewModel.displayedCall = nil - - ToastViewModel.shared.toastMessage = "Success_remove_call_logs" - ToastViewModel.shared.displayToast.toggle() - }) - .background(.black.opacity(0.65)) - .zIndex(3) - .onTapGesture { - self.isShowDeleteAllHistoryPopup.toggle() - } - } - - if isShowDismissPopup { - PopupView(isShowPopup: $isShowDismissPopup, - title: Text("Don’t save modifications?"), - content: Text("All modifications will be canceled."), - titleFirstButton: Text("Cancel"), - actionFirstButton: {self.isShowDismissPopup.toggle()}, - titleSecondButton: Text("Ok"), - actionSecondButton: { - if editContactViewModel.selectedEditFriend == nil { - self.isShowDismissPopup.toggle() - editContactViewModel.removePopup = true - editContactViewModel.resetValues() - withAnimation { - isShowEditContactFragment.toggle() - } - } else { - self.isShowDismissPopup.toggle() - editContactViewModel.resetValues() - withAnimation { - editContactViewModel.removePopup = true + .onAppear { + if !(orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) + && searchIsActive { + self.focusedField = false } } - }) - .background(.black.opacity(0.65)) - .zIndex(3) - .onTapGesture { - self.isShowDismissPopup.toggle() - } - } - - if isShowSipAddressesPopup { - SipAddressesPopup( - contactAvatarModel: ContactsManager.shared.avatarListModel[contactViewModel.indexDisplayedFriend != nil ? contactViewModel.indexDisplayedFriend! : 0], - contactViewModel: contactViewModel, - isShowSipAddressesPopup: $isShowSipAddressesPopup, - isShowSipAddressesPopupType: $isShowSipAddressesPopupType - ) - .background(.black.opacity(0.65)) - .zIndex(3) - .onTapGesture { - isShowSipAddressesPopup.toggle() - } - } - - if contactViewModel.operationInProgress { - PopupLoadingView() - .background(.black.opacity(0.65)) - .zIndex(3) .onDisappear { - if contactViewModel.displayedConversation != nil { - contactViewModel.indexDisplayedFriend = nil - historyViewModel.displayedCall = nil - index = 2 - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - withAnimation { - self.conversationViewModel.changeDisplayedChatRoom(conversationModel: contactViewModel.displayedConversation!) - } - contactViewModel.displayedConversation = nil + if !(orientation == .landscapeLeft + || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) + && searchIsActive { + self.focusedField = true + } + } + .padding(.leading, + orientation == .landscapeRight && geometry.safeAreaInsets.bottom > 0 + ? -geometry.safeAreaInsets.leading + : 0) + .transition(.move(edge: .trailing)) + .zIndex(1) + } + + SideMenu( + width: geometry.size.width / 5 * 4, + isOpen: self.sideMenuIsOpen, + menuClose: self.openMenu, + safeAreaInsets: geometry.safeAreaInsets, + isShowLoginFragment: $isShowLoginFragment, + isShowAccountProfileFragment: $isShowAccountProfileFragment + ) + .ignoresSafeArea(.all) + .zIndex(2) + + if isShowLoginFragment { + LoginFragment( + accountLoginViewModel: AccountLoginViewModel(), + isShowBack: true, + onBackPressed: { + withAnimation { + isShowLoginFragment.toggle() } - } - } - } - - if isShowScheduleMeetingFragment { - ScheduleMeetingFragment( - meetingViewModel: meetingViewModel, - meetingsListViewModel: meetingsListViewModel, - isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment - ) - .zIndex(3) - .transition(.move(edge: .bottom)) - .onAppear { - } - } - - if isShowSendCancelMeetingNotificationPopup { - PopupView(isShowPopup: $isShowSendCancelMeetingNotificationPopup, - title: Text("The meeting will be cancelled"), - content: Text("Send notification to participants ?"), - titleFirstButton: Text("Cancel for me only"), - actionFirstButton: { - meetingViewModel.displayedMeeting = nil - meetingsListViewModel.deleteSelectedMeeting() - self.isShowSendCancelMeetingNotificationPopup.toggle( - ) }, - titleSecondButton: Text("Send cancellation notifications"), - actionSecondButton: { - meetingViewModel.displayedMeeting = nil - if let meetingToDelete = self.meetingsListViewModel.selectedMeetingToDelete { - self.meetingViewModel.cancelMeetingWithNotifications(meeting: meetingToDelete) - meetingsListViewModel.deleteSelectedMeeting() - self.isShowSendCancelMeetingNotificationPopup.toggle() - } - }) - .background(.black.opacity(0.65)) - .zIndex(3) - .onTapGesture { - self.isShowSendCancelMeetingNotificationPopup.toggle() - } - } - - if isShowStartCallGroupPopup { - PopupView( - isShowPopup: $isShowStartCallGroupPopup, - title: Text("conversation_info_confirm_start_group_call_dialog_title"), - content: Text("conversation_info_confirm_start_group_call_dialog_message"), - titleFirstButton: Text("Cancel"), - actionFirstButton: { - self.isShowStartCallGroupPopup.toggle() - }, - titleSecondButton: Text("Confirm"), - actionSecondButton: { - if conversationViewModel.displayedConversation != nil { - conversationViewModel.displayedConversation!.createGroupCall() - } - self.isShowStartCallGroupPopup.toggle() - } - ) - .background(.black.opacity(0.65)) - .zIndex(3) - .onTapGesture { - self.isShowStartCallGroupPopup.toggle() - } - } - - if isShowStartCallGroupPopup { - PopupView( - isShowPopup: $isShowStartCallGroupPopup, - title: Text("conversation_info_confirm_start_group_call_dialog_title"), - content: Text("conversation_info_confirm_start_group_call_dialog_message"), - titleFirstButton: Text("Cancel"), - actionFirstButton: { - self.isShowStartCallGroupPopup.toggle() - }, - titleSecondButton: Text("Confirm"), - actionSecondButton: { - if conversationViewModel.displayedConversation != nil { - conversationViewModel.displayedConversation!.createGroupCall() - } - self.isShowStartCallGroupPopup.toggle() - } - ) - .background(.black.opacity(0.65)) - .zIndex(3) - .onTapGesture { - self.isShowStartCallGroupPopup.toggle() - } - } - - if conversationViewModel.isShowConversationInfoPopup { - PopupViewWithTextField(conversationViewModel: conversationViewModel) - .background(.black.opacity(0.65)) + }) .zIndex(3) - .onTapGesture { - conversationViewModel.isShowConversationInfoPopup = false + .transition(.move(edge: .bottom)) + .onAppear { } - } - - if telecomManager.meetingWaitingRoomDisplayed { - MeetingWaitingRoomFragment(meetingWaitingRoomViewModel: meetingWaitingRoomViewModel) + } + + if isShowEditContactFragment { + EditContactFragment( + editContactViewModel: editContactViewModel, + contactViewModel: contactViewModel, + isShowEditContactFragment: $isShowEditContactFragment, + isShowDismissPopup: $isShowDismissPopup + ) .zIndex(3) .transition(.opacity.combined(with: .move(edge: .bottom))) .onAppear { - meetingWaitingRoomViewModel.resetMeetingRoomView() + contactViewModel.indexDisplayedFriend = nil } - } - - if telecomManager.callDisplayed && ((telecomManager.callInProgress && telecomManager.outgoingCallStarted) || telecomManager.callConnected) && !telecomManager.meetingWaitingRoomDisplayed { - CallView( - callViewModel: callViewModel, - conversationViewModel: conversationViewModel, - conversationsListViewModel: conversationsListViewModel, - conversationForwardMessageViewModel: conversationForwardMessageViewModel, - contactViewModel: contactViewModel, - editContactViewModel: editContactViewModel, - meetingViewModel: meetingViewModel, - fullscreenVideo: $fullscreenVideo, - isShowStartCallFragment: $isShowStartCallFragment, - isShowConversationFragment: $isShowConversationFragment, - isShowStartCallGroupPopup: $isShowStartCallGroupPopup, - isShowEditContactFragment: $isShowEditContactFragment, - indexPage: $index, - isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment - ) - .zIndex(5) - .transition(.scale.combined(with: .move(edge: .top))) - .onAppear { - UIApplication.shared.isIdleTimerDisabled = true - callViewModel.resetCallView() - if callViewModel.callsCounter >= 1 { - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { - callViewModel.resetCallView() + } + + if isShowStartCallFragment { + if #available(iOS 16.4, *), idiom != .pad { + StartCallFragment( + callViewModel: callViewModel, + startCallViewModel: startCallViewModel, + isShowStartCallFragment: $isShowStartCallFragment, + showingDialer: $showingDialer, + resetCallView: {callViewModel.resetCallView()} + ) + .zIndex(6) + .transition(.opacity.combined(with: .move(edge: .bottom))) + .sheet(isPresented: $showingDialer) { + DialerBottomSheet( + startCallViewModel: startCallViewModel, + callViewModel: callViewModel, + isShowStartCallFragment: $isShowStartCallFragment, + showingDialer: $showingDialer, + currentCall: nil + ) + .presentationDetents([.medium]) + .presentationBackgroundInteraction(.enabled(upThrough: .medium)) + } + } else { + StartCallFragment( + callViewModel: callViewModel, + startCallViewModel: startCallViewModel, + isShowStartCallFragment: $isShowStartCallFragment, + showingDialer: $showingDialer, + resetCallView: {callViewModel.resetCallView()} + ) + .zIndex(6) + .transition(.opacity.combined(with: .move(edge: .bottom))) + .halfSheet(showSheet: $showingDialer) { + DialerBottomSheet( + startCallViewModel: startCallViewModel, + callViewModel: callViewModel, + isShowStartCallFragment: $isShowStartCallFragment, + showingDialer: $showingDialer, + currentCall: nil + ) + } onDismiss: {} + } + } + + if isShowStartConversationFragment { + StartConversationFragment( + startConversationViewModel: startConversationViewModel, + conversationViewModel: conversationViewModel, + isShowStartConversationFragment: $isShowStartConversationFragment + ) + .zIndex(6) + .transition(.opacity.combined(with: .move(edge: .bottom))) + } + + if isShowDeleteContactPopup { + PopupView(isShowPopup: $isShowDeleteContactPopup, + title: Text( + contactViewModel.selectedFriend != nil + ? "Delete \(contactViewModel.selectedFriend!.name!)?" + : (contactViewModel.indexDisplayedFriend != nil + ? "Delete \(contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.name!)?" + : "Error Name")), + content: Text("This contact will be deleted definitively."), + titleFirstButton: Text("Cancel"), + actionFirstButton: { + self.isShowDeleteContactPopup.toggle()}, + titleSecondButton: Text("Ok"), + actionSecondButton: { + if contactViewModel.selectedFriendToDelete != nil { + if contactViewModel.indexDisplayedFriend != nil { + withAnimation { + contactViewModel.indexDisplayedFriend = nil + } + } + contactViewModel.selectedFriendToDelete!.remove() + } else if contactViewModel.indexDisplayedFriend != nil { + let tmpIndex = contactViewModel.indexDisplayedFriend + withAnimation { + contactViewModel.indexDisplayedFriend = nil + } + contactsManager.lastSearch[tmpIndex!].friend!.remove() + } + MagicSearchSingleton.shared.searchForContacts( + sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) + self.isShowDeleteContactPopup.toggle() + }) + .background(.black.opacity(0.65)) + .zIndex(3) + .onTapGesture { + self.isShowDeleteContactPopup.toggle() + } + .onAppear { + contactViewModel.selectedFriendToDelete = contactViewModel.selectedFriend + } + } + + if isShowDeleteAllHistoryPopup { + PopupView(isShowPopup: $isShowDeleteContactPopup, + title: Text("Do you really want to delete all calls history?"), + content: Text("All calls will be removed from the history."), + titleFirstButton: Text("Cancel"), + actionFirstButton: { + self.isShowDeleteAllHistoryPopup.toggle() + historyListViewModel.callLogsAddressToDelete = "" + }, + titleSecondButton: Text("Ok"), + actionSecondButton: { + historyListViewModel.removeCallLogs() + self.isShowDeleteAllHistoryPopup.toggle() + historyViewModel.displayedCall = nil + + ToastViewModel.shared.toastMessage = "Success_remove_call_logs" + ToastViewModel.shared.displayToast.toggle() + }) + .background(.black.opacity(0.65)) + .zIndex(3) + .onTapGesture { + self.isShowDeleteAllHistoryPopup.toggle() + } + } + + if isShowDismissPopup { + PopupView(isShowPopup: $isShowDismissPopup, + title: Text("Don’t save modifications?"), + content: Text("All modifications will be canceled."), + titleFirstButton: Text("Cancel"), + actionFirstButton: {self.isShowDismissPopup.toggle()}, + titleSecondButton: Text("Ok"), + actionSecondButton: { + if editContactViewModel.selectedEditFriend == nil { + self.isShowDismissPopup.toggle() + editContactViewModel.removePopup = true + editContactViewModel.resetValues() + withAnimation { + isShowEditContactFragment.toggle() + } + } else { + self.isShowDismissPopup.toggle() + editContactViewModel.resetValues() + withAnimation { + editContactViewModel.removePopup = true + } + } + }) + .background(.black.opacity(0.65)) + .zIndex(3) + .onTapGesture { + self.isShowDismissPopup.toggle() + } + } + + if isShowSipAddressesPopup { + SipAddressesPopup( + contactAvatarModel: ContactsManager.shared.avatarListModel[contactViewModel.indexDisplayedFriend != nil ? contactViewModel.indexDisplayedFriend! : 0], + contactViewModel: contactViewModel, + isShowSipAddressesPopup: $isShowSipAddressesPopup, + isShowSipAddressesPopupType: $isShowSipAddressesPopupType + ) + .background(.black.opacity(0.65)) + .zIndex(3) + .onTapGesture { + isShowSipAddressesPopup.toggle() + } + } + + if contactViewModel.operationInProgress { + PopupLoadingView() + .background(.black.opacity(0.65)) + .zIndex(3) + .onDisappear { + if contactViewModel.displayedConversation != nil { + contactViewModel.indexDisplayedFriend = nil + historyViewModel.displayedCall = nil + index = 2 + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + withAnimation { + self.conversationViewModel.changeDisplayedChatRoom(conversationModel: contactViewModel.displayedConversation!) + } + contactViewModel.displayedConversation = nil + } + } + } + } + + if isShowScheduleMeetingFragment { + ScheduleMeetingFragment( + meetingViewModel: meetingViewModel, + meetingsListViewModel: meetingsListViewModel, + isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment + ) + .zIndex(3) + .transition(.move(edge: .bottom)) + .onAppear { + } + } + + if isShowAccountProfileFragment { + AccountProfileFragment( + accountProfileViewModel: accountProfileViewModel, + isShowAccountProfileFragment: $isShowAccountProfileFragment + ) + .zIndex(3) + .transition(.move(edge: .trailing)) + } + + if isShowSendCancelMeetingNotificationPopup { + PopupView(isShowPopup: $isShowSendCancelMeetingNotificationPopup, + title: Text("The meeting will be cancelled"), + content: Text("Send notification to participants ?"), + titleFirstButton: Text("Cancel for me only"), + actionFirstButton: { + meetingViewModel.displayedMeeting = nil + meetingsListViewModel.deleteSelectedMeeting() + self.isShowSendCancelMeetingNotificationPopup.toggle( + ) }, + titleSecondButton: Text("Send cancellation notifications"), + actionSecondButton: { + meetingViewModel.displayedMeeting = nil + if let meetingToDelete = self.meetingsListViewModel.selectedMeetingToDelete { + self.meetingViewModel.cancelMeetingWithNotifications(meeting: meetingToDelete) + meetingsListViewModel.deleteSelectedMeeting() + self.isShowSendCancelMeetingNotificationPopup.toggle() + } + }) + .background(.black.opacity(0.65)) + .zIndex(3) + .onTapGesture { + self.isShowSendCancelMeetingNotificationPopup.toggle() + } + } + + if isShowStartCallGroupPopup { + PopupView( + isShowPopup: $isShowStartCallGroupPopup, + title: Text("conversation_info_confirm_start_group_call_dialog_title"), + content: Text("conversation_info_confirm_start_group_call_dialog_message"), + titleFirstButton: Text("Cancel"), + actionFirstButton: { + self.isShowStartCallGroupPopup.toggle() + }, + titleSecondButton: Text("Confirm"), + actionSecondButton: { + if conversationViewModel.displayedConversation != nil { + conversationViewModel.displayedConversation!.createGroupCall() + } + self.isShowStartCallGroupPopup.toggle() + } + ) + .background(.black.opacity(0.65)) + .zIndex(3) + .onTapGesture { + self.isShowStartCallGroupPopup.toggle() + } + } + + if isShowStartCallGroupPopup { + PopupView( + isShowPopup: $isShowStartCallGroupPopup, + title: Text("conversation_info_confirm_start_group_call_dialog_title"), + content: Text("conversation_info_confirm_start_group_call_dialog_message"), + titleFirstButton: Text("Cancel"), + actionFirstButton: { + self.isShowStartCallGroupPopup.toggle() + }, + titleSecondButton: Text("Confirm"), + actionSecondButton: { + if conversationViewModel.displayedConversation != nil { + conversationViewModel.displayedConversation!.createGroupCall() + } + self.isShowStartCallGroupPopup.toggle() + } + ) + .background(.black.opacity(0.65)) + .zIndex(3) + .onTapGesture { + self.isShowStartCallGroupPopup.toggle() + } + } + + if conversationViewModel.isShowConversationInfoPopup { + PopupViewWithTextField(conversationViewModel: conversationViewModel) + .background(.black.opacity(0.65)) + .zIndex(3) + .onTapGesture { + conversationViewModel.isShowConversationInfoPopup = false + } + } + + if telecomManager.meetingWaitingRoomDisplayed { + MeetingWaitingRoomFragment(meetingWaitingRoomViewModel: meetingWaitingRoomViewModel) + .zIndex(3) + .transition(.opacity.combined(with: .move(edge: .bottom))) + .onAppear { + meetingWaitingRoomViewModel.resetMeetingRoomView() + } + } + + if telecomManager.callDisplayed && ((telecomManager.callInProgress && telecomManager.outgoingCallStarted) || telecomManager.callConnected) && !telecomManager.meetingWaitingRoomDisplayed { + CallView( + callViewModel: callViewModel, + conversationViewModel: conversationViewModel, + conversationsListViewModel: conversationsListViewModel, + conversationForwardMessageViewModel: conversationForwardMessageViewModel, + contactViewModel: contactViewModel, + editContactViewModel: editContactViewModel, + meetingViewModel: meetingViewModel, + fullscreenVideo: $fullscreenVideo, + isShowStartCallFragment: $isShowStartCallFragment, + isShowConversationFragment: $isShowConversationFragment, + isShowStartCallGroupPopup: $isShowStartCallGroupPopup, + isShowEditContactFragment: $isShowEditContactFragment, + indexPage: $index, + isShowScheduleMeetingFragment: $isShowScheduleMeetingFragment + ) + .zIndex(5) + .transition(.scale.combined(with: .move(edge: .top))) + .onAppear { + UIApplication.shared.isIdleTimerDisabled = true + callViewModel.resetCallView() + if callViewModel.callsCounter >= 1 { + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + callViewModel.resetCallView() + } } } + .onDisappear { + UIApplication.shared.isIdleTimerDisabled = false + } } - .onDisappear { - UIApplication.shared.isIdleTimerDisabled = false - } + + ToastView() + .zIndex(6) } - - ToastView() - .zIndex(6) + } + .onAppear { + MagicSearchSingleton.shared.searchForContacts(sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) + } + .onChange(of: navigationManager.selectedCallId) { newCallId in + if newCallId != nil { + self.index = 2 + } + } + .onReceive(pub) { _ in + conversationsListViewModel.computeChatRoomsList(filter: "") + historyListViewModel.refreshHistoryAvatarModel() } } - .onAppear { - MagicSearchSingleton.shared.searchForContacts(sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) - } - .onChange(of: navigationManager.selectedCallId) { newCallId in - if newCallId != nil { - self.index = 2 + .overlay { + if isMenuOpen { + Color.white.opacity(0.001) + .ignoresSafeArea() + .frame(maxWidth: .infinity, maxHeight: .infinity) + .onTapGesture { + isMenuOpen = false + } } } - .onReceive(pub) { _ in - conversationsListViewModel.computeChatRoomsList(filter: "") - historyListViewModel.refreshHistoryAvatarModel() + .onRotate { newOrientation in + if (contactViewModel.indexDisplayedFriend != nil || historyViewModel.displayedCall != nil || conversationViewModel.displayedConversation != nil) && searchIsActive { + self.focusedField = false + } else if searchIsActive { + self.focusedField = true + } + orientation = newOrientation } - } - .overlay { - if isMenuOpen { - Color.white.opacity(0.001) - .ignoresSafeArea() - .frame(maxWidth: .infinity, maxHeight: .infinity) - .onTapGesture { - isMenuOpen = false - } + .onChange(of: scenePhase) { newPhase in + CoreContext.shared.enteredForeground = newPhase == .active + orientation = UIDevice.current.orientation } } - .onRotate { newOrientation in - if (contactViewModel.indexDisplayedFriend != nil || historyViewModel.displayedCall != nil || conversationViewModel.displayedConversation != nil) && searchIsActive { - self.focusedField = false - } else if searchIsActive { - self.focusedField = true - } - orientation = newOrientation - } - .onChange(of: scenePhase) { newPhase in - CoreContext.shared.enteredForeground = newPhase == .active - orientation = UIDevice.current.orientation - } } func openMenu() { @@ -1340,7 +1353,8 @@ class NavigationManager: ObservableObject { conversationViewModel: ConversationViewModel(), meetingsListViewModel: MeetingsListViewModel(), meetingViewModel: MeetingViewModel(), - conversationForwardMessageViewModel: ConversationForwardMessageViewModel() + conversationForwardMessageViewModel: ConversationForwardMessageViewModel(), + accountProfileViewModel: AccountProfileViewModel() ) } // swiftlint:enable type_body_length diff --git a/Linphone/UI/Main/Fragments/SideMenu.swift b/Linphone/UI/Main/Fragments/SideMenu.swift index 8db24dfb6..42609f3a1 100644 --- a/Linphone/UI/Main/Fragments/SideMenu.swift +++ b/Linphone/UI/Main/Fragments/SideMenu.swift @@ -28,6 +28,7 @@ struct SideMenu: View { let menuClose: () -> Void let safeAreaInsets: EdgeInsets @Binding var isShowLoginFragment: Bool + @Binding var isShowAccountProfileFragment: Bool @State private var showHelp = false var body: some View { @@ -66,7 +67,7 @@ struct SideMenu: View { List { ForEach(0... + */ + +import SwiftUI + +struct AccountProfileFragment: View { + + @ObservedObject var contactsManager = ContactsManager.shared + @ObservedObject private var sharedMainViewModel = SharedMainViewModel.shared + + @ObservedObject var accountProfileViewModel: AccountProfileViewModel + + @Binding var isShowAccountProfileFragment: Bool + @State var detailIsOpen: Bool = true + + @State private var showPhotoPicker = false + @State private var selectedImage: UIImage? + @State private var removedImage = false + + var body: some View { + GeometryReader { geometry in + VStack(spacing: 1) { + Rectangle() + .foregroundColor(Color.orangeMain500) + .edgesIgnoringSafeArea(.top) + .frame(height: 0) + + HStack { + Image("caret-left") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.orangeMain500) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + .padding(.top, 4) + .padding(.leading, -10) + .onTapGesture { + withAnimation { + if isShowAccountProfileFragment { + isShowAccountProfileFragment = false + } + } + } + + Text("manage_account_title") + .default_text_style_orange_800(styleSize: 16) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.top, 4) + .lineLimit(1) + + Spacer() + } + .frame(maxWidth: .infinity) + .frame(height: 50) + .padding(.horizontal) + .padding(.bottom, 4) + .background(.white) + + Spacer() + /* + ScrollView { + VStack(spacing: 0) { + VStack(spacing: 0) { + if #unavailable(iOS 16.0) { + Rectangle() + .foregroundColor(Color.gray100) + .frame(height: 7) + } + + if accountProfileViewModel.avatarModel != nil { + VStack(spacing: 0) { + if accountProfileViewModel.avatarModel != nil + && accountProfileViewModel.photoAvatarModel != nil + && !accountProfileViewModel.photoAvatarModel!.isEmpty && selectedImage == nil && !removedImage { + Avatar( + contactAvatarModel: ContactAvatarModel(accountProfileViewModel.avatarModel!), + avatarSize: 100 + ) + + } else if selectedImage == nil { + Image("profil-picture-default") + .resizable() + .frame(width: 100, height: 100) + .clipShape(Circle()) + } else { + Image(uiImage: selectedImage!) + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: 100, height: 100) + .clipShape(Circle()) + } + + if accountProfileViewModel.avatarModel != nil + && accountProfileViewModel.photoAvatarModel != nil + && !accountProfileViewModel.photoAvatarModel!.isEmpty + && (accountProfileViewModel.photoAvatarModel!.suffix(11) != "default.png" || selectedImage != nil) + && !removedImage { + HStack { + Spacer() + + Button(action: { + showPhotoPicker = true + }, label: { + HStack { + Image("pencil-simple") + .resizable() + .frame(width: 20, height: 20) + + Text("manage_account_edit_picture") + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + } + }) + .padding(.top, 10) + .padding(.trailing, 10) + .sheet(isPresented: $showPhotoPicker) { + PhotoPicker(filter: .images, limit: 1) { results in + PhotoPicker.convertToUIImageArray(fromResults: results) { imagesOrNil, errorOrNil in + if let error = errorOrNil { + print(error) + } + if let images = imagesOrNil { + if let first = images.first { + selectedImage = first + removedImage = false + } + } + } + } + .edgesIgnoringSafeArea(.all) + } + + Button(action: { + removedImage = true + selectedImage = nil + }, label: { + HStack { + Image("trash-simple") + .resizable() + .frame(width: 20, height: 20) + + Text("manage_account_remove_picture") + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + } + }) + .padding(.top, 10) + + Spacer() + } + } else { + Button(action: { + showPhotoPicker = true + }, label: { + HStack { + Image("camera") + .resizable() + .frame(width: 20, height: 20) + + Text("manage_account_add_picture") + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + } + }) + .padding(.top, 10) + .sheet(isPresented: $showPhotoPicker) { + PhotoPicker(filter: .images, limit: 1) { results in + PhotoPicker.convertToUIImageArray(fromResults: results) { imagesOrNil, errorOrNil in + if let error = errorOrNil { + print(error) + } + if let images = imagesOrNil { + if let first = images.first { + selectedImage = first + removedImage = false + } + } + } + } + .edgesIgnoringSafeArea(.all) + } + } + } + .frame(minHeight: 150) + .frame(maxWidth: .infinity) + .padding(.top, 10) + .padding(.bottom, 2) + .background(Color.gray100) + } + + HStack(alignment: .center) { + Text("conversation_info_participants_list_title") + .default_text_style_800(styleSize: 18) + .frame(maxWidth: .infinity, alignment: .leading) + + Spacer() + + Image(detailIsOpen ? "caret-up" : "caret-down") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.grayMain2c600) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.all, 10) + } + .padding(.top, 30) + .padding(.bottom, 10) + .padding(.horizontal, 20) + .background(Color.gray100) + .onTapGesture { + withAnimation { + detailIsOpen.toggle() + } + } + + if detailIsOpen { + VStack(spacing: 0) { + + } + .background(.white) + .cornerRadius(15) + .padding(.horizontal) + .zIndex(-1) + .transition(.move(edge: .top)) + } + } + .frame(maxWidth: sharedMainViewModel.maxWidth) + } + .frame(maxWidth: .infinity) + .padding(.top, 2) + } + .background(Color.gray100) + */ + } + .background(Color.gray100) + } + .navigationTitle("") + .navigationBarHidden(true) + } +} diff --git a/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift b/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift new file mode 100644 index 000000000..98e6c0b87 --- /dev/null +++ b/Linphone/UI/Main/Settings/ViewModel/AccountProfileViewModel.swift @@ -0,0 +1,40 @@ +/* + * 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 + +class AccountProfileViewModel: ObservableObject { + + @Published var avatarModel: ContactAvatarModel? + @Published var photoAvatarModel: String? + + init() {} + + func setAvatarModel() { + CoreContext.shared.doOnCoreQueue { core in + if core.defaultAccount != nil { + let displayNameTmp = core.defaultAccount!.displayName() + let contactAddressTmp = core.defaultAccount!.contactAddress?.asStringUriOnly() ?? "" + DispatchQueue.main.async { + self.avatarModel = ContactAvatarModel(friend: nil, name: displayNameTmp, address: contactAddressTmp, withPresence: false) + } + } + } + } +}