diff --git a/Linphone/Assets.xcassets/AppIcon.appiconset/1024.png b/Linphone/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 000000000..7b3df4579 Binary files /dev/null and b/Linphone/Assets.xcassets/AppIcon.appiconset/1024.png differ diff --git a/Linphone/Assets.xcassets/AppIcon.appiconset/Contents.json b/Linphone/Assets.xcassets/AppIcon.appiconset/Contents.json index 532cd729c..eab818e5a 100644 --- a/Linphone/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Linphone/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,6 +1,7 @@ { "images" : [ { + "filename" : "1024.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift index a07c6b926..a7a0abb4a 100644 --- a/Linphone/Core/CoreContext.swift +++ b/Linphone/Core/CoreContext.swift @@ -38,7 +38,7 @@ final class CoreContext: ObservableObject { private var mCore: Core! private var mIterateSuscription: AnyCancellable? private var mCoreSuscriptions = Set() - + private init() { do { try initialiseCore() @@ -68,17 +68,17 @@ final class CoreContext: ObservableObject { Factory.Instance.logCollectionPath = configDir Factory.Instance.enableLogCollection(state: LogCollectionState.Enabled) - let url = NSURL(fileURLWithPath: configDir) - if let pathComponent = url.appendingPathComponent("linphonerc") { - let filePath = pathComponent.path - let fileManager = FileManager.default - if !fileManager.fileExists(atPath: filePath) { - let path = Bundle.main.path(forResource: "linphonerc-default", ofType: nil) - if path != nil { - try? FileManager.default.copyItem(at: NSURL(fileURLWithPath: path!) as URL, to: pathComponent) - } - } - } + let url = NSURL(fileURLWithPath: configDir) + if let pathComponent = url.appendingPathComponent("linphonerc") { + let filePath = pathComponent.path + let fileManager = FileManager.default + if !fileManager.fileExists(atPath: filePath) { + let path = Bundle.main.path(forResource: "linphonerc-default", ofType: nil) + if path != nil { + try? FileManager.default.copyItem(at: NSURL(fileURLWithPath: path!) as URL, to: pathComponent) + } + } + } let config = try? Factory.Instance.createConfigWithFactory( path: "\(configDir)/linphonerc", @@ -87,7 +87,7 @@ final class CoreContext: ObservableObject { if config != nil { self.mCore = try? Factory.Instance.createCoreWithConfig(config: config!, systemContext: nil) } - + self.mCore.autoIterateEnabled = false self.mCore.callkitEnabled = true self.mCore.pushNotificationEnabled = true @@ -113,11 +113,14 @@ final class CoreContext: ObservableObject { NSLog("New configuration state is \(cbVal.status) = \(cbVal.message)\n") if cbVal.status == Config.ConfiguringState.Successful { ToastViewModel.shared.toastMessage = "Successful" - ToastViewModel.shared.displayToast.toggle() - } else { - ToastViewModel.shared.toastMessage = "Failed" - ToastViewModel.shared.displayToast.toggle() - } + ToastViewModel.shared.displayToast = true + } + /* + else { + ToastViewModel.shared.toastMessage = "Failed" + ToastViewModel.shared.displayToast = true + } + */ }) self.mCoreSuscriptions.insert(self.mCore.publisher?.onAccountRegistrationStateChanged?.postOnMainQueue { (cbVal: (core: Core, account: Account, state: RegistrationState, message: String)) in @@ -135,7 +138,7 @@ final class CoreContext: ObservableObject { self.loggingInProgress = true } else { ToastViewModel.shared.toastMessage = "Registration failed" - ToastViewModel.shared.displayToast.toggle() + ToastViewModel.shared.displayToast = true self.loggingInProgress = false self.loggedIn = false } @@ -166,9 +169,9 @@ final class CoreContext: ObservableObject { cbValue.info, forPasteboardType: UTType.plainText.identifier ) - + ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard" - ToastViewModel.shared.displayToast.toggle() + ToastViewModel.shared.displayToast = true } }) diff --git a/Linphone/Info.plist b/Linphone/Info.plist index 340c36eb2..33e2c5a4d 100644 --- a/Linphone/Info.plist +++ b/Linphone/Info.plist @@ -2,6 +2,8 @@ + UIUserInterfaceStyle + Light NSCameraUsageDescription Camera usage is required for video VOIP calls NSMicrophoneUsageDescription diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index 950f6722f..9596a76ce 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -38,8 +38,14 @@ struct LinphoneApp: App { if !sharedMainViewModel.welcomeViewDisplayed { WelcomeView() } else if coreContext.defaultAccount == nil || sharedMainViewModel.displayProfileMode { - AssistantView() + ZStack { + AssistantView() + + ToastView() + .zIndex(3) + } } else if coreContext.defaultAccount != nil + && coreContext.loggedIn && contactViewModel != nil && editContactViewModel != nil && historyViewModel != nil diff --git a/Linphone/TelecomManager/TelecomManager.swift b/Linphone/TelecomManager/TelecomManager.swift index 506ba21e4..aa93fd28a 100644 --- a/Linphone/TelecomManager/TelecomManager.swift +++ b/Linphone/TelecomManager/TelecomManager.swift @@ -120,10 +120,10 @@ class TelecomManager: ObservableObject { } } - func doCallWithCore(addr: Address) { + func doCallWithCore(addr: Address, isVideo: Bool) { CoreContext.shared.doOnCoreQueue { core in do { - try self.startCallCallKit(core: core, addr: addr, isSas: false, isVideo: false, isConference: false) + try self.startCallCallKit(core: core, addr: addr, isSas: false, isVideo: isVideo, isConference: false) } catch { Log.error("[TelecomManager] unable to create address for a new outgoing call : \(addr) \(error) ") } diff --git a/Linphone/UI/Assistant/Fragments/LoginFragment.swift b/Linphone/UI/Assistant/Fragments/LoginFragment.swift index 8ae3e46e1..51fbd099c 100644 --- a/Linphone/UI/Assistant/Fragments/LoginFragment.swift +++ b/Linphone/UI/Assistant/Fragments/LoginFragment.swift @@ -63,6 +63,8 @@ struct LoginFragment: View { TextField("username", text: $accountLoginViewModel.username) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .disabled(coreContext.loggedIn) .frame(height: 25) .padding(.horizontal, 20) @@ -90,6 +92,8 @@ struct LoginFragment: View { } else { TextField("password", text: $accountLoginViewModel.passwd) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .frame(height: 25) .focused($isPasswordFocused) } @@ -287,6 +291,8 @@ struct LoginFragment: View { .background(.black.opacity(0.65)) } } + .navigationTitle("") + .navigationBarHidden(true) } .navigationViewStyle(StackNavigationViewStyle()) } diff --git a/Linphone/UI/Assistant/Fragments/RegisterFragment.swift b/Linphone/UI/Assistant/Fragments/RegisterFragment.swift index 194bd5b5a..dbc339513 100644 --- a/Linphone/UI/Assistant/Fragments/RegisterFragment.swift +++ b/Linphone/UI/Assistant/Fragments/RegisterFragment.swift @@ -65,8 +65,11 @@ struct RegisterFragment: View { } } } + .navigationTitle("") + .navigationBarHidden(true) } .navigationViewStyle(StackNavigationViewStyle()) + .navigationTitle("") .navigationBarHidden(true) } } diff --git a/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountLoginFragment.swift b/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountLoginFragment.swift index 6bb7e3bd0..8a8d5aa0b 100644 --- a/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountLoginFragment.swift +++ b/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountLoginFragment.swift @@ -81,6 +81,8 @@ struct ThirdPartySipAccountLoginFragment: View { TextField("username", text: $accountLoginViewModel.username) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .disabled(coreContext.loggedIn) .frame(height: 25) .padding(.horizontal, 20) @@ -108,6 +110,8 @@ struct ThirdPartySipAccountLoginFragment: View { } else { TextField("password", text: $accountLoginViewModel.passwd) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .frame(height: 25) .focused($isPasswordFocused) } @@ -139,6 +143,8 @@ struct ThirdPartySipAccountLoginFragment: View { TextField("sip.linphone.org", text: $accountLoginViewModel.domain) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .disabled(coreContext.loggedIn) .frame(height: 25) .padding(.horizontal, 20) @@ -158,6 +164,8 @@ struct ThirdPartySipAccountLoginFragment: View { TextField("Display Name", text: $accountLoginViewModel.displayName) .default_text_style(styleSize: 15) + .disableAutocorrection(true) + .autocapitalization(.none) .disabled(coreContext.loggedIn) .frame(height: 25) .padding(.horizontal, 20) @@ -204,8 +212,6 @@ struct ThirdPartySipAccountLoginFragment: View { Button(action: { self.accountLoginViewModel.login() - accountLoginViewModel.domain = "sip.linphone.org" - accountLoginViewModel.transportType = "TLS" }, label: { Text(coreContext.loggedIn ? "Log out" : "assistant_account_login") .default_text_style_white_600(styleSize: 20) diff --git a/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountWarningFragment.swift b/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountWarningFragment.swift index a3aa14ad5..f9f9fb1f8 100644 --- a/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountWarningFragment.swift +++ b/Linphone/UI/Assistant/Fragments/ThirdPartySipAccountWarningFragment.swift @@ -171,8 +171,11 @@ struct ThirdPartySipAccountWarningFragment: View { .frame(minHeight: geometry.size.height) } } + .navigationTitle("") + .navigationBarHidden(true) } .navigationViewStyle(StackNavigationViewStyle()) + .navigationTitle("") .navigationBarHidden(true) } } diff --git a/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift b/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift index dd9149693..8cf56625f 100644 --- a/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift +++ b/Linphone/UI/Assistant/Viewmodel/AccountLoginViewModel.swift @@ -45,7 +45,7 @@ class AccountLoginViewModel: ObservableObject { core.loadConfigFromXml(xmlUri: assistantLinphone) } } - + // Get the transport protocol to use. // TLS is strongly recommended // Only use UDP if you don't have the choice @@ -106,6 +106,9 @@ class AccountLoginViewModel: ObservableObject { self.coreContext.defaultAccount = account } + self.domain = "sip.linphone.org" + self.transportType = "TLS" + } catch { NSLog(error.localizedDescription) } } } diff --git a/Linphone/UI/Call/CallView.swift b/Linphone/UI/Call/CallView.swift index 4c0bec411..8d06e91b6 100644 --- a/Linphone/UI/Call/CallView.swift +++ b/Linphone/UI/Call/CallView.swift @@ -427,18 +427,29 @@ struct CallView: View { .presentationDetents([.fraction(0.3)]) .frame(maxHeight: .infinity) } + } else { + innerView(geometry: geo) } } } @ViewBuilder + // swiftlint:disable:next cyclomatic_complexity func innerView(geometry: GeometryProxy) -> some View { VStack { if !fullscreenVideo { - Rectangle() - .foregroundColor(Color.orangeMain500) - .edgesIgnoringSafeArea(.top) - .frame(height: 0) + if #available(iOS 16.0, *) { + Rectangle() + .foregroundColor(Color.orangeMain500) + .edgesIgnoringSafeArea(.top) + .frame(height: 0) + } else if idiom != .pad && !(orientation == .landscapeLeft || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) { + Rectangle() + .foregroundColor(Color.orangeMain500) + .edgesIgnoringSafeArea(.top) + .frame(height: 1) + } HStack { if callViewModel.direction == .Outgoing { @@ -465,13 +476,8 @@ struct CallView: View { ZStack { Text(callViewModel.timeElapsed.convertDurationToString()) - .onAppear { - callViewModel.timeElapsed = 0 - startDate = Date.now - } .onReceive(callViewModel.timer) { firedDate in callViewModel.timeElapsed = Int(firedDate.timeIntervalSince(startDate)) - } .foregroundStyle(.white) .if(callViewModel.isPaused || telecomManager.isPausedByRemote) { view in @@ -646,6 +652,10 @@ struct CallView: View { callViewModel.timeElapsed = Int(firedDate.timeIntervalSince(startDate)) } + .onDisappear { + callViewModel.timeElapsed = 0 + startDate = Date.now + } .padding(.top) .foregroundStyle(.white) @@ -695,16 +705,101 @@ struct CallView: View { if !fullscreenVideo { if telecomManager.callStarted { - if telecomManager.callStarted && idiom != .pad && !(orientation == .landscapeLeft || orientation == .landscapeRight - || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) { - HStack(spacing: 12) { - HStack { - + if #available(iOS 16.0, *) { + if telecomManager.callStarted && idiom != .pad && !(orientation == .landscapeLeft || orientation == .landscapeRight + || UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) { + HStack(spacing: 12) { + HStack { + + } + .frame(height: 60) } - .frame(height: 60) + .padding(.horizontal, 25) + .padding(.top, 20) + } else { + HStack(spacing: 12) { + Button { + callViewModel.terminateCall() + } label: { + Image("phone-disconnect") + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 32, height: 32) + + } + .frame(width: 90, height: 60) + .background(Color.redDanger500) + .cornerRadius(40) + + Spacer() + + Button { + callViewModel.toggleVideo() + } label: { + Image(callViewModel.cameraDisplayed ? "video-camera" : "video-camera-slash") + .renderingMode(.template) + .resizable() + .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white) + .frame(width: 32, height: 32) + + } + .frame(width: 60, height: 60) + .background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : Color.gray500) + .cornerRadius(40) + .disabled(callViewModel.isPaused || telecomManager.isPausedByRemote) + + Button { + callViewModel.toggleMuteMicrophone() + } label: { + Image(callViewModel.micMutted ? "microphone-slash" : "microphone") + .renderingMode(.template) + .resizable() + .foregroundStyle(callViewModel.micMutted ? .black : .white) + .frame(width: 32, height: 32) + + } + .frame(width: 60, height: 60) + .background(callViewModel.micMutted ? .white : Color.gray500) + .cornerRadius(40) + + Button { + if AVAudioSession.sharedInstance().availableInputs != nil + && !AVAudioSession.sharedInstance().availableInputs!.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty { + + hideButtonsSheet = true + + DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { + audioRouteSheet = true + } + } else { + do { + try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty ? .speaker : .none) + } catch _ { + + } + } + + } label: { + Image(imageAudioRoute) + .renderingMode(.template) + .resizable() + .foregroundStyle(.white) + .frame(width: 32, height: 32) + .onAppear(perform: getAudioRouteImage) + .onReceive(pub) { _ in + self.getAudioRouteImage() + } + + } + .frame(width: 60, height: 60) + .background(Color.gray500) + .cornerRadius(40) + } + .frame(height: geometry.size.height * 0.15) + .padding(.horizontal, 20) + .padding(.top, -6) } - .padding(.horizontal, 25) - .padding(.top, 20) } else { HStack(spacing: 12) { Button { @@ -726,7 +821,7 @@ struct CallView: View { Button { callViewModel.toggleVideo() } label: { - Image("video-camera") + Image(callViewModel.cameraDisplayed ? "video-camera" : "video-camera-slash") .renderingMode(.template) .resizable() .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white) @@ -753,12 +848,32 @@ struct CallView: View { .cornerRadius(40) Button { + if AVAudioSession.sharedInstance().availableInputs != nil + && !AVAudioSession.sharedInstance().availableInputs!.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty { + + hideButtonsSheet = true + + DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { + audioRouteSheet = true + } + } else { + do { + try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty ? .speaker : .none) + } catch _ { + + } + } + } label: { - Image("speaker-high") + Image(imageAudioRoute) .renderingMode(.template) .resizable() .foregroundStyle(.white) .frame(width: 32, height: 32) + .onAppear(perform: getAudioRouteImage) + .onReceive(pub) { _ in + self.getAudioRouteImage() + } } .frame(width: 60, height: 60) diff --git a/Linphone/UI/Main/Contacts/ContactsView.swift b/Linphone/UI/Main/Contacts/ContactsView.swift index a8191f047..fea21d9c7 100644 --- a/Linphone/UI/Main/Contacts/ContactsView.swift +++ b/Linphone/UI/Main/Contacts/ContactsView.swift @@ -41,8 +41,10 @@ struct ContactsView: View { } } label: { Image("user-plus") + .renderingMode(.template) + .foregroundStyle(.white) .padding() - .background(.white) + .background(Color.orangeMain500) .clipShape(Circle()) .shadow(color: .black.opacity(0.2), radius: 4) diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift index 0e256c39e..f15e7bd3a 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactInnerActionsFragment.swift @@ -90,7 +90,7 @@ struct ContactInnerActionsFragment: View { .onTapGesture { withAnimation { telecomManager.doCallWithCore( - addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.addresses[index] + addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.addresses[index], isVideo: false ) } } @@ -272,7 +272,9 @@ struct ContactInnerActionsFragment: View { Button { if contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend != nil { contactViewModel.objectWillChange.send() + contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.edit() contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.starred.toggle() + contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.done() } } label: { HStack { diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift index a2627196a..72d4baece 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactInnerFragment.swift @@ -86,19 +86,19 @@ struct ContactInnerFragment: View { contactViewModel: contactViewModel, isShowEditContactFragment: .constant(false), isShowDismissPopup: $isShowDismissPopup)) { - Image("pencil-simple") - .renderingMode(.template) - .resizable() - .foregroundStyle(Color.orangeMain500) - .frame(width: 25, height: 25, alignment: .leading) - .padding(.top, 2) - } - .simultaneousGesture( - TapGesture().onEnded { - editContactViewModel.selectedEditFriend = contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend - editContactViewModel.resetValues() + Image("pencil-simple") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.orangeMain500) + .frame(width: 25, height: 25, alignment: .leading) + .padding(.top, 2) } - ) + .simultaneousGesture( + TapGesture().onEnded { + editContactViewModel.selectedEditFriend = contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend + editContactViewModel.resetValues() + } + ) } } .frame(maxWidth: .infinity) @@ -132,10 +132,10 @@ struct ContactInnerFragment: View { .frame(maxWidth: .infinity) .padding(.top, 10) - Text(contactAvatarModel.lastPresenceInfo) + Text(contactAvatarModel.lastPresenceInfo) .foregroundStyle(contactAvatarModel.lastPresenceInfo == "Online" - ? Color.greenSuccess500 - : Color.orangeWarning600) + ? Color.greenSuccess500 + : Color.orangeWarning600) .multilineTextAlignment(.center) .default_text_style_300(styleSize: 12) .frame(maxWidth: .infinity) @@ -151,7 +151,7 @@ struct ContactInnerFragment: View { Spacer() Button(action: { - telecomManager.doCallWithCore(addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.address!) + telecomManager.doCallWithCore(addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.address!, isVideo: false) }, label: { VStack { HStack(alignment: .center) { @@ -180,7 +180,8 @@ struct ContactInnerFragment: View { Image("chat-teardrop-text") .renderingMode(.template) .resizable() - .foregroundStyle(Color.grayMain2c600) + //.foregroundStyle(Color.grayMain2c600) + .foregroundStyle(Color.grayMain2c300) .frame(width: 25, height: 25) .onTapGesture { withAnimation { @@ -200,7 +201,7 @@ struct ContactInnerFragment: View { Spacer() Button(action: { - + telecomManager.doCallWithCore(addr: contactsManager.lastSearch[contactViewModel.indexDisplayedFriend!].friend!.address!, isVideo: true) }, label: { VStack { HStack(alignment: .center) { @@ -209,11 +210,6 @@ struct ContactInnerFragment: View { .resizable() .foregroundStyle(Color.grayMain2c600) .frame(width: 25, height: 25) - .onTapGesture { - withAnimation { - - } - } } .padding(16) .background(Color.grayMain2c200) @@ -229,7 +225,7 @@ struct ContactInnerFragment: View { .padding(.top, 20) .frame(maxWidth: .infinity) .background(Color.gray100) - + ContactInnerActionsFragment( contactViewModel: contactViewModel, editContactViewModel: editContactViewModel, diff --git a/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift index bf6a9645d..644e6f16c 100644 --- a/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift +++ b/Linphone/UI/Main/Contacts/Fragments/ContactsListBottomSheet.swift @@ -58,7 +58,9 @@ struct ContactsListBottomSheet: View { Spacer() Button { if contactViewModel.selectedFriend != nil { + contactViewModel.selectedFriend!.edit() contactViewModel.selectedFriend!.starred.toggle() + contactViewModel.selectedFriend!.done() } MagicSearchSingleton.shared.searchForContacts(sourceFlags: MagicSearch.Source.Friends.rawValue | MagicSearch.Source.LdapServers.rawValue) diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift index 69886fde9..267968710 100644 --- a/Linphone/UI/Main/ContentView.swift +++ b/Linphone/UI/Main/ContentView.swift @@ -151,6 +151,7 @@ struct ContentView: View { Menu { if index == 0 { Button { + contactViewModel.indexDisplayedFriend = nil isMenuOpen = false magicSearch.allContact = true MagicSearchSingleton.shared.searchForContacts( @@ -168,6 +169,7 @@ struct ContentView: View { } Button { + contactViewModel.indexDisplayedFriend = nil isMenuOpen = false magicSearch.allContact = false MagicSearchSingleton.shared.searchForContacts( @@ -282,9 +284,8 @@ struct ContentView: View { text = newValue } )) - .default_text_style_white_700(styleSize: 15) + .default_text_style_700(styleSize: 15) .padding(.all, 6) - .accentColor(.white) .focused($focusedField) .onAppear { self.focusedField = true @@ -671,10 +672,8 @@ struct ContentView: View { } } - // if sharedMainViewModel.displayToast { ToastView() .zIndex(3) - // } } } .overlay { @@ -698,12 +697,14 @@ struct ContentView: View { .onChange(of: scenePhase) { newPhase in if newPhase == .active { coreContext.onForeground() + /* if !isShowStartCallFragment { contactsManager.fetchContacts() DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { historyListViewModel.computeCallLogsList() } } + */ print("Active") } else if newPhase == .inactive { print("Inactive") diff --git a/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift b/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift index dc3915be6..f8d2b0ddd 100644 --- a/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift +++ b/Linphone/UI/Main/History/Fragments/DialerBottomSheet.swift @@ -275,7 +275,7 @@ struct DialerBottomSheet: View { if !startCallViewModel.searchField.isEmpty { do { let address = try Factory.Instance.createAddress(addr: String("sip:" + startCallViewModel.searchField + "@" + startCallViewModel.domain)) - telecomManager.doCallWithCore(addr: address) + telecomManager.doCallWithCore(addr: address, isVideo: false) } catch { } diff --git a/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift b/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift index 370009462..a2fd12066 100644 --- a/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift +++ b/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift @@ -32,15 +32,15 @@ struct HistoryContactFragment: View { @ObservedObject var contactAvatarModel: ContactAvatarModel @ObservedObject var historyViewModel: HistoryViewModel - @ObservedObject var historyListViewModel: HistoryListViewModel - @ObservedObject var contactViewModel: ContactViewModel - @ObservedObject var editContactViewModel: EditContactViewModel + @ObservedObject var historyListViewModel: HistoryListViewModel + @ObservedObject var contactViewModel: ContactViewModel + @ObservedObject var editContactViewModel: EditContactViewModel @State var isMenuOpen = false @Binding var isShowDeleteAllHistoryPopup: Bool - @Binding var isShowEditContactFragment: Bool - @Binding var indexPage: Int + @Binding var isShowEditContactFragment: Bool + @Binding var indexPage: Int var body: some View { NavigationView { @@ -72,25 +72,25 @@ struct HistoryContactFragment: View { Spacer() Menu { - let fromAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.fromAddress!) : nil - let toAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.toAddress!) : nil - let addressFriend = historyViewModel.displayedCall != nil ? (historyViewModel.displayedCall!.dir == .Incoming ? fromAddressFriend : toAddressFriend) : nil - + let fromAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.fromAddress!) : nil + let toAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.toAddress!) : nil + let addressFriend = historyViewModel.displayedCall != nil ? (historyViewModel.displayedCall!.dir == .Incoming ? fromAddressFriend : toAddressFriend) : nil + Button { isMenuOpen = false - - if contactsManager.getFriendWithAddress( - address: historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing - ? historyViewModel.displayedCall!.toAddress! - : historyViewModel.displayedCall!.fromAddress! - ) != nil { - let addressCall = historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing - ? historyViewModel.displayedCall!.toAddress! - : historyViewModel.displayedCall!.fromAddress! - - let friendIndex = contactsManager.lastSearch.firstIndex( - where: {$0.friend!.addresses.contains(where: {$0.asStringUriOnly() == addressCall.asStringUriOnly()})}) - if friendIndex != nil { + + if contactsManager.getFriendWithAddress( + address: historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing + ? historyViewModel.displayedCall!.toAddress! + : historyViewModel.displayedCall!.fromAddress! + ) != nil { + let addressCall = historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing + ? historyViewModel.displayedCall!.toAddress! + : historyViewModel.displayedCall!.fromAddress! + + let friendIndex = contactsManager.lastSearch.firstIndex( + where: {$0.friend!.addresses.contains(where: {$0.asStringUriOnly() == addressCall.asStringUriOnly()})}) + if friendIndex != nil { withAnimation { historyViewModel.displayedCall = nil @@ -98,28 +98,28 @@ struct HistoryContactFragment: View { contactViewModel.indexDisplayedFriend = friendIndex } - } - } else { - let addressCall = historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing - ? historyViewModel.displayedCall!.toAddress! - : historyViewModel.displayedCall!.fromAddress! - - withAnimation { + } + } else { + let addressCall = historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing + ? historyViewModel.displayedCall!.toAddress! + : historyViewModel.displayedCall!.fromAddress! + + withAnimation { historyViewModel.displayedCall = nil indexPage = 0 isShowEditContactFragment.toggle() - editContactViewModel.sipAddresses.removeAll() - editContactViewModel.sipAddresses.append(String(addressCall.asStringUriOnly().dropFirst(4))) + editContactViewModel.sipAddresses.removeAll() + editContactViewModel.sipAddresses.append(String(addressCall.asStringUriOnly().dropFirst(4))) editContactViewModel.sipAddresses.append("") - } - } - + } + } + } label: { HStack { - Text(addressFriend != nil ? "See contact" : "Add to contacts") + Text(addressFriend != nil ? "See contact" : "Add to contacts") Spacer() - Image(addressFriend != nil ? "user-circle" : "plus-circle") + Image(addressFriend != nil ? "user-circle" : "plus-circle") .resizable() .frame(width: 25, height: 25, alignment: .leading) } @@ -127,18 +127,18 @@ struct HistoryContactFragment: View { Button { isMenuOpen = false - - if historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing { - UIPasteboard.general.setValue( - historyViewModel.displayedCall!.toAddress!.asStringUriOnly().dropFirst(4), - forPasteboardType: UTType.plainText.identifier - ) - } else { - UIPasteboard.general.setValue( - historyViewModel.displayedCall!.fromAddress!.asStringUriOnly().dropFirst(4), - forPasteboardType: UTType.plainText.identifier - ) - } + + if historyViewModel.displayedCall != nil && historyViewModel.displayedCall!.dir == .Outgoing { + UIPasteboard.general.setValue( + historyViewModel.displayedCall!.toAddress!.asStringUriOnly().dropFirst(4), + forPasteboardType: UTType.plainText.identifier + ) + } else { + UIPasteboard.general.setValue( + historyViewModel.displayedCall!.fromAddress!.asStringUriOnly().dropFirst(4), + forPasteboardType: UTType.plainText.identifier + ) + } ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard" ToastViewModel.shared.displayToast.toggle() @@ -194,8 +194,12 @@ struct HistoryContactFragment: View { ScrollView { VStack(spacing: 0) { VStack(spacing: 0) { + if #unavailable(iOS 16.0) { + Rectangle() + .foregroundColor(Color.gray100) + .frame(height: 7) + } VStack(spacing: 0) { - let fromAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.fromAddress!) : nil let toAddressFriend = historyViewModel.displayedCall != nil ? contactsManager.getFriendWithAddress(address: historyViewModel.displayedCall!.toAddress!) : nil let addressFriend = historyViewModel.displayedCall != nil ? (historyViewModel.displayedCall!.dir == .Incoming ? fromAddressFriend : toAddressFriend) : nil @@ -223,13 +227,13 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) + + Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) Text("") .multilineTextAlignment(.center) @@ -252,13 +256,13 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) + + Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) Text("") .multilineTextAlignment(.center) @@ -284,14 +288,14 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) - + + Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) + Text("") .multilineTextAlignment(.center) .default_text_style_300(styleSize: 12) @@ -313,14 +317,14 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) - + + Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) + Text("") .multilineTextAlignment(.center) .default_text_style_300(styleSize: 12) @@ -338,22 +342,22 @@ struct HistoryContactFragment: View { .default_text_style(styleSize: 14) .frame(maxWidth: .infinity) .padding(.top, 10) - - if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { - Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) - } else if historyViewModel.displayedCall!.fromAddress != nil { - Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) - .foregroundStyle(Color.grayMain2c700) - .multilineTextAlignment(.center) - .default_text_style(styleSize: 14) - .frame(maxWidth: .infinity) - .padding(.top, 5) - } + + if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { + Text(historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) + } else if historyViewModel.displayedCall!.fromAddress != nil { + Text(historyViewModel.displayedCall!.fromAddress!.asStringUriOnly()) + .foregroundStyle(Color.grayMain2c700) + .multilineTextAlignment(.center) + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity) + .padding(.top, 5) + } Text(contactAvatarModel.lastPresenceInfo) .foregroundStyle(contactAvatarModel.lastPresenceInfo == "Online" @@ -369,21 +373,22 @@ struct HistoryContactFragment: View { .frame(minHeight: 150) .frame(maxWidth: .infinity) .padding(.top, 10) + .padding(.bottom, 2) .background(Color.gray100) HStack { Spacer() Button(action: { - if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { - telecomManager.doCallWithCore( - addr: historyViewModel.displayedCall!.toAddress! - ) - } else if historyViewModel.displayedCall!.dir == .Incoming && historyViewModel.displayedCall!.fromAddress != nil { - telecomManager.doCallWithCore( - addr: historyViewModel.displayedCall!.fromAddress! - ) - } + if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { + telecomManager.doCallWithCore( + addr: historyViewModel.displayedCall!.toAddress!, isVideo: false + ) + } else if historyViewModel.displayedCall!.dir == .Incoming && historyViewModel.displayedCall!.fromAddress != nil { + telecomManager.doCallWithCore( + addr: historyViewModel.displayedCall!.fromAddress!, isVideo: false + ) + } }, label: { VStack { HStack(alignment: .center) { @@ -399,6 +404,7 @@ struct HistoryContactFragment: View { Text("Appel") .default_text_style(styleSize: 14) + .frame(minWidth: 80) } }) @@ -412,7 +418,8 @@ struct HistoryContactFragment: View { Image("chat-teardrop-text") .renderingMode(.template) .resizable() - .foregroundStyle(Color.grayMain2c600) + //.foregroundStyle(Color.grayMain2c600) + .foregroundStyle(Color.grayMain2c300) .frame(width: 25, height: 25) .onTapGesture { withAnimation { @@ -426,13 +433,22 @@ struct HistoryContactFragment: View { Text("Message") .default_text_style(styleSize: 14) + .frame(minWidth: 80) } }) Spacer() Button(action: { - + if historyViewModel.displayedCall!.dir == .Outgoing && historyViewModel.displayedCall!.toAddress != nil { + telecomManager.doCallWithCore( + addr: historyViewModel.displayedCall!.toAddress!, isVideo: true + ) + } else if historyViewModel.displayedCall!.dir == .Incoming && historyViewModel.displayedCall!.fromAddress != nil { + telecomManager.doCallWithCore( + addr: historyViewModel.displayedCall!.fromAddress!, isVideo: true + ) + } }, label: { VStack { HStack(alignment: .center) { @@ -441,11 +457,6 @@ struct HistoryContactFragment: View { .resizable() .foregroundStyle(Color.grayMain2c600) .frame(width: 25, height: 25) - .onTapGesture { - withAnimation { - - } - } } .padding(16) .background(Color.grayMain2c200) @@ -453,71 +464,75 @@ struct HistoryContactFragment: View { Text("Video Call") .default_text_style(styleSize: 14) + .frame(minWidth: 80) } }) Spacer() } .padding(.top, 20) + .padding(.bottom, 10) .frame(maxWidth: .infinity) .background(Color.gray100) VStack(spacing: 0) { - - let addressFriend = historyViewModel.displayedCall != nil - ? (historyViewModel.displayedCall!.dir == .Incoming ? historyViewModel.displayedCall!.fromAddress!.asStringUriOnly() - : historyViewModel.displayedCall!.toAddress!.asStringUriOnly()) : nil - - let callLogsFilter = historyListViewModel.callLogs.filter({ $0.dir == .Incoming - ? $0.fromAddress!.asStringUriOnly() == addressFriend - : $0.toAddress!.asStringUriOnly() == addressFriend }) - - ForEach(0..