diff --git a/GoogleService-Info.plist b/GoogleService-Info.plist
new file mode 100644
index 000000000..f996be8f2
--- /dev/null
+++ b/GoogleService-Info.plist
@@ -0,0 +1,36 @@
+
+
+
+
+ CLIENT_ID
+ 221368768663-0ufgu96cel0auk4v0me863lgm252b9n2.apps.googleusercontent.com
+ REVERSED_CLIENT_ID
+ com.googleusercontent.apps.221368768663-0ufgu96cel0auk4v0me863lgm252b9n2
+ API_KEY
+ AIzaSyDJTtlRCM7IqdVUU2dSIYq2YIsTz6bqnkI
+ GCM_SENDER_ID
+ 221368768663
+ PLIST_VERSION
+ 1
+ BUNDLE_ID
+ org.linphone.phone
+ PROJECT_ID
+ linphone-iphone
+ STORAGE_BUCKET
+ linphone-iphone.appspot.com
+ IS_ADS_ENABLED
+
+ IS_ANALYTICS_ENABLED
+
+ IS_APPINVITE_ENABLED
+
+ IS_GCM_ENABLED
+
+ IS_SIGNIN_ENABLED
+
+ GOOGLE_APP_ID
+ 1:221368768663:ios:a2c822bc087b5a219431d2
+ DATABASE_URL
+ https://linphone-iphone.firebaseio.com
+
+
diff --git a/Linphone.xcodeproj/project.pbxproj b/Linphone.xcodeproj/project.pbxproj
index c49a03650..b4c229e18 100644
--- a/Linphone.xcodeproj/project.pbxproj
+++ b/Linphone.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
+ 660D8A712B517D260092694D /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 660D8A702B517D260092694D /* GoogleService-Info.plist */; };
662B69D92B25DE18007118BF /* TelecomManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662B69D82B25DE18007118BF /* TelecomManager.swift */; };
662B69DB2B25DE25007118BF /* ProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662B69DA2B25DE25007118BF /* ProviderDelegate.swift */; };
66C491F92B24D25B00CEA16D /* ConfigExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */; };
@@ -97,6 +98,7 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
+ 660D8A702B517D260092694D /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
662B69D82B25DE18007118BF /* TelecomManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelecomManager.swift; sourceTree = ""; };
662B69DA2B25DE25007118BF /* ProviderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderDelegate.swift; sourceTree = ""; };
66C491F82B24D25A00CEA16D /* ConfigExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigExtension.swift; sourceTree = ""; };
@@ -249,6 +251,7 @@
D719ABAA2ABC67BF00B41C10 = {
isa = PBXGroup;
children = (
+ 660D8A702B517D260092694D /* GoogleService-Info.plist */,
D719ABB52ABC67BF00B41C10 /* Linphone */,
D719ABB42ABC67BF00B41C10 /* Products */,
A31AF2AB8C6A3D7B7EA3B424 /* Pods */,
@@ -600,6 +603,7 @@
D732A90D2B0376F500DB42BA /* linphonerc-factory in Resources */,
D783C77C2B1089B200622CC2 /* assistant_linphone_default_values in Resources */,
D70C93DE2AC2D0F60063CA3B /* Localizable.xcstrings in Resources */,
+ 660D8A712B517D260092694D /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -835,16 +839,22 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = Linphone/Linphone.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 4;
DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "\"Linphone/Preview Content\"";
DEVELOPMENT_TEAM = Z2V957B3D6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "DEBUG=1",
+ );
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Linphone/Info.plist;
- INFOPLIST_KEY_NSCameraUsageDescription = "Share photos with your friends and customize avatars";
+ INFOPLIST_KEY_NSCameraUsageDescription = "Camera usage is required for video VOIP calls";
INFOPLIST_KEY_NSContactsUsageDescription = "Make calls with your friends";
+ INFOPLIST_KEY_NSMicrophoneUsageDescription = "Microphone usage is required for VOIP calls";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Share photos with your friends and customize avatars";
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
@@ -856,15 +866,17 @@
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+ INFOPLIST_KEY_UIUserInterfaceStyle = Light;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 13.3;
- MARKETING_VERSION = 1.0;
+ MARKETING_VERSION = 6.0;
+ OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -879,16 +891,18 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = Linphone/Linphone.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 4;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"Linphone/Preview Content\"";
DEVELOPMENT_TEAM = Z2V957B3D6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Linphone/Info.plist;
- INFOPLIST_KEY_NSCameraUsageDescription = "Share photos with your friends and customize avatars";
+ INFOPLIST_KEY_NSCameraUsageDescription = "Camera usage is required for video VOIP calls";
INFOPLIST_KEY_NSContactsUsageDescription = "Make calls with your friends";
+ INFOPLIST_KEY_NSMicrophoneUsageDescription = "Microphone usage is required for VOIP calls";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Share photos with your friends and customize avatars";
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
@@ -900,15 +914,17 @@
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+ INFOPLIST_KEY_UIUserInterfaceStyle = Light;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 13.3;
- MARKETING_VERSION = 1.0;
+ MARKETING_VERSION = 6.0;
+ OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = auto;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
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/Assets.xcassets/phone-list.imageset/Contents.json b/Linphone/Assets.xcassets/phone-list.imageset/Contents.json
new file mode 100644
index 000000000..93d7f6f6b
--- /dev/null
+++ b/Linphone/Assets.xcassets/phone-list.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "phone-list.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Linphone/Assets.xcassets/phone-list.imageset/phone-list.svg b/Linphone/Assets.xcassets/phone-list.imageset/phone-list.svg
new file mode 100644
index 000000000..d070e2710
--- /dev/null
+++ b/Linphone/Assets.xcassets/phone-list.imageset/phone-list.svg
@@ -0,0 +1,6 @@
+
diff --git a/Linphone/Assets.xcassets/phone-transfer.imageset/Contents.json b/Linphone/Assets.xcassets/phone-transfer.imageset/Contents.json
new file mode 100644
index 000000000..702f535c8
--- /dev/null
+++ b/Linphone/Assets.xcassets/phone-transfer.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "phone-transfer.svg",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Linphone/Assets.xcassets/phone-transfer.imageset/phone-transfer.svg b/Linphone/Assets.xcassets/phone-transfer.imageset/phone-transfer.svg
new file mode 100644
index 000000000..c63342fd6
--- /dev/null
+++ b/Linphone/Assets.xcassets/phone-transfer.imageset/phone-transfer.svg
@@ -0,0 +1,4 @@
+
diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift
index 98bdb7127..f69d10386 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,11 +87,13 @@ 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
+ self.mCore.setUserAgent(name: "Linphone iOS 6.0 Beta (\(UIDevice.current.localizedModel)) - Linphone SDK : \(self.coreVersion)", version: "6.0")
+
self.mCoreSuscriptions.insert(self.mCore.publisher?.onGlobalStateChanged?.postOnMainQueue { (cbVal: (core: Core, state: GlobalState, message: String)) in
if cbVal.state == GlobalState.On {
self.defaultAccount = self.mCore.defaultAccount
@@ -102,15 +104,25 @@ final class CoreContext: ObservableObject {
}
})
+ self.mCoreSuscriptions.insert(self.mCore.publisher?.onGlobalStateChanged?.postOnCoreQueue { (cbVal: (core: Core, state: GlobalState, message: String)) in
+ if cbVal.state == GlobalState.On {
+#if DEBUG
+ let pushEnvironment = ".dev"
+#else
+ let pushEnvironment = ""
+#endif
+ for account in cbVal.core.accountList where account.params?.pushNotificationConfig?.provider != ("apns" + pushEnvironment) {
+ let newParams = account.params?.clone()
+ Log.info("Account \(String(describing: newParams?.identityAddress?.asStringUriOnly())) - updating apple push provider from \(String(describing: newParams?.pushNotificationConfig?.provider)) to apns\(pushEnvironment)")
+ newParams?.pushNotificationConfig?.provider = "apns" + pushEnvironment
+ account.params = newParams
+ }
+ }
+ })
+
self.mCore.videoCaptureEnabled = true
self.mCore.videoDisplayEnabled = true
- self.mCore.recordAwareEnabled = true
- let videoActivationPolicy = self.mCore.videoActivationPolicy!
- videoActivationPolicy.automaticallyAccept = true
- self.mCore.videoActivationPolicy! = videoActivationPolicy
-
- try? self.mCore.start()
// Create a Core listener to listen for the callback we need
// In this case, we want to know about the account registration status
@@ -118,11 +130,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
@@ -140,7 +155,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
}
@@ -171,9 +186,11 @@ final class CoreContext: ObservableObject {
cbValue.info,
forPasteboardType: UTType.plainText.identifier
)
-
- ToastViewModel.shared.toastMessage = "Success_copied_into_clipboard"
- ToastViewModel.shared.displayToast.toggle()
+
+ DispatchQueue.main.async {
+ ToastViewModel.shared.toastMessage = "Success_send_logs"
+ ToastViewModel.shared.displayToast = true
+ }
}
})
@@ -184,6 +201,7 @@ final class CoreContext: ObservableObject {
self.mCore.iterate()
}
+ try? self.mCore.start()
}
}
diff --git a/Linphone/Info.plist b/Linphone/Info.plist
index 340c36eb2..0cc800b37 100644
--- a/Linphone/Info.plist
+++ b/Linphone/Info.plist
@@ -2,10 +2,10 @@
- NSCameraUsageDescription
- Camera usage is required for video VOIP calls
- NSMicrophoneUsageDescription
- Microphone usage is required for VOIP calls
+ ITSAppUsesNonExemptEncryption
+
+ ITSEncryptionExportComplianceCode
+ b5cb085f-772a-4a4f-8c77-5d1332b1f93f
UIAppFonts
NotoSans-Light.ttf
diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift
index 61e22bdf3..0930db967 100644
--- a/Linphone/LinphoneApp.swift
+++ b/Linphone/LinphoneApp.swift
@@ -18,6 +18,9 @@
*/
import SwiftUI
+#if USE_CRASHLYTICS
+import Firebase
+#endif
@main
struct LinphoneApp: App {
@@ -30,6 +33,13 @@ struct LinphoneApp: App {
@State private var historyViewModel: HistoryViewModel?
@State private var historyListViewModel: HistoryListViewModel?
@State private var startCallViewModel: StartCallViewModel?
+ @State private var callViewModel: CallViewModel?
+
+ init() {
+#if USE_CRASHLYTICS
+ FirebaseApp.configure()
+#endif
+ }
var body: some Scene {
WindowGroup {
@@ -37,19 +47,27 @@ 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
&& historyListViewModel != nil
- && startCallViewModel != nil {
+ && startCallViewModel != nil
+ && callViewModel != nil {
ContentView(
contactViewModel: contactViewModel!,
editContactViewModel: editContactViewModel!,
historyViewModel: historyViewModel!,
historyListViewModel: historyListViewModel!,
- startCallViewModel: startCallViewModel!
+ startCallViewModel: startCallViewModel!,
+ callViewModel: callViewModel!
)
} else {
SplashScreen()
@@ -62,6 +80,7 @@ struct LinphoneApp: App {
historyViewModel = HistoryViewModel()
historyListViewModel = HistoryListViewModel()
startCallViewModel = StartCallViewModel()
+ callViewModel = CallViewModel()
}
}
}
diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings
index 467b2feee..ec823b015 100644
--- a/Linphone/Localizable.xcstrings
+++ b/Linphone/Localizable.xcstrings
@@ -107,6 +107,9 @@
},
"+" : {
+ },
+ "|" : {
+
},
"0" : {
@@ -268,6 +271,9 @@
},
"Deny all" : {
+ },
+ "Dialer" : {
+
},
"Display Name" : {
@@ -365,7 +371,10 @@
"Log out" : {
},
- "Logout" : {
+ "Logs cleared" : {
+
+ },
+ "Logs URL copied into clipboard" : {
},
"Message" : {
@@ -376,9 +385,6 @@
},
"Missed call" : {
- },
- "My Profile" : {
-
},
"New call" : {
@@ -415,9 +421,6 @@
},
"Outgoing Call" : {
- },
- "Participants" : {
-
},
"password" : {
"extractionState" : "manual",
@@ -438,6 +441,12 @@
},
"Pause" : {
+ },
+ "Paused" : {
+
+ },
+ "Paused by remote" : {
+
},
"Personnalize your profil mode" : {
@@ -474,9 +483,6 @@
},
"Scan QR code" : {
- },
- "Screen share" : {
-
},
"Search contact or history call" : {
@@ -540,6 +546,9 @@
},
"to Linphone" : {
+ },
+ "Transfer" : {
+
},
"Transport" : {
diff --git a/Linphone/Ressources/linphonerc-factory b/Linphone/Ressources/linphonerc-factory
index 4074322fe..0abf8269d 100644
--- a/Linphone/Ressources/linphonerc-factory
+++ b/Linphone/Ressources/linphonerc-factory
@@ -31,6 +31,8 @@ ec_calibrator_cool_tones=1
[video]
auto_resize_preview_to_keep_ratio=1
max_conference_size=vga
+automatically_accept=1
+automatically_initiate=0
[misc]
enable_basic_to_client_group_chat_room_migration=0
diff --git a/Linphone/TelecomManager/ProviderDelegate.swift b/Linphone/TelecomManager/ProviderDelegate.swift
index c12cbed92..44ef6095e 100644
--- a/Linphone/TelecomManager/ProviderDelegate.swift
+++ b/Linphone/TelecomManager/ProviderDelegate.swift
@@ -1,21 +1,21 @@
/*
-* Copyright (c) 2010-2020 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 .
-*/
+ * Copyright (c) 2010-2020 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 .
+ */
// swiftlint:disable line_length
import Foundation
@@ -56,19 +56,19 @@ class CallInfo {
}
/*
-* A delegate to support callkit.
-*/
+ * A delegate to support callkit.
+ */
class ProviderDelegate: NSObject {
let provider: CXProvider
var uuids: [String: UUID] = [:]
var callInfos: [UUID: CallInfo] = [:]
-
+
override init() {
provider = CXProvider(configuration: ProviderDelegate.providerConfiguration)
super.init()
provider.setDelegate(self, queue: nil)
}
-
+
static var providerConfiguration: CXProviderConfiguration {
get {
let providerConfiguration = CXProviderConfiguration()
@@ -97,18 +97,18 @@ class ProviderDelegate: NSObject {
let callId = callInfo?.callId ?? ""
/*
- if (ConfigManager.instance().config?.hasEntry(section: "app", key: "max_calls") == 1) { // moved from misc to app section intentionally upon app start or remote configuration
- if let maxCalls = ConfigManager.instance().config?.getInt(section: "app",key: "max_calls",defaultValue: 10), Core.get().callsNb > maxCalls {
- Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: declining call, as max calls (\(maxCalls)) reached call-id: [\(String(describing: callId))] and UUID: [\(uuid.description)]")
- decline(uuid: uuid)
-
- CoreContext.shared.doOnCoreQueue(synchronous: true) { core in
- try? call?.decline(reason: .Busy)
- }
- return
- }
- }
- */
+ if (ConfigManager.instance().config?.hasEntry(section: "app", key: "max_calls") == 1) { // moved from misc to app section intentionally upon app start or remote configuration
+ if let maxCalls = ConfigManager.instance().config?.getInt(section: "app",key: "max_calls",defaultValue: 10), Core.get().callsNb > maxCalls {
+ Log.directLog(BCTBX_LOG_MESSAGE, text: "CallKit: declining call, as max calls (\(maxCalls)) reached call-id: [\(String(describing: callId))] and UUID: [\(uuid.description)]")
+ decline(uuid: uuid)
+
+ CoreContext.shared.doOnCoreQueue(synchronous: true) { core in
+ try? call?.decline(reason: .Busy)
+ }
+ return
+ }
+ }
+ */
Log.info("CallKit: report new incoming call with call-id: [\(callId)] and UUID: [\(uuid.description)]")
// TelecomManager.instance().setHeldOtherCalls(exceptCallid: callId ?? "") // ALREADY COMMENTED ON LINPHONE-IPHONE 5.2
@@ -140,7 +140,7 @@ class ProviderDelegate: NSObject {
}
}
}
-
+
func updateCall(uuid: UUID, handle: String, hasVideo: Bool = false, displayName: String) {
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: handle)
@@ -148,11 +148,11 @@ class ProviderDelegate: NSObject {
update.hasVideo = hasVideo
provider.reportCall(with: uuid, updated: update)
}
-
+
func reportOutgoingCallStartedConnecting(uuid: UUID) {
provider.reportOutgoingCall(with: uuid, startedConnectingAt: nil)
}
-
+
func reportOutgoingCallConnected(uuid: UUID) {
provider.reportOutgoingCall(with: uuid, connectedAt: nil)
}
@@ -164,7 +164,7 @@ class ProviderDelegate: NSObject {
func decline(uuid: UUID) {
provider.reportCall(with: uuid, endedAt: .init(), reason: .unanswered)
}
-
+
func endCallNotExist(uuid: UUID, timeout: DispatchTime) {
DispatchQueue.main.asyncAfter(deadline: timeout) {
CoreContext.shared.doOnCoreQueue(synchronous: true) { core in
@@ -188,7 +188,7 @@ extension ProviderDelegate: CXProviderDelegate {
let uuid = action.callUUID
let callId = callInfos[uuid]?.callId
-
+
// remove call infos first, otherwise CXEndCallAction will be called more than onece
if callId != nil {
uuids.removeValue(forKey: callId!)
@@ -203,15 +203,17 @@ extension ProviderDelegate: CXProviderDelegate {
action.fulfill()
}
}
-
+
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
let uuid = action.callUUID
let callInfo = callInfos[uuid]
let callId = callInfo?.callId ?? ""
- DispatchQueue.main.async {
- withAnimation {
- TelecomManager.shared.callInProgress = true
+ if TelecomManager.shared.callInProgress == false {
+ DispatchQueue.main.async {
+ withAnimation {
+ TelecomManager.shared.callInProgress = true
+ }
}
}
CoreContext.shared.doOnCoreQueue { core in
@@ -219,15 +221,17 @@ extension ProviderDelegate: CXProviderDelegate {
let call = core.getCallByCallid(callId: callId)
- if UIApplication.shared.applicationState != .active {
- TelecomManager.shared.backgroundContextCall = call
- TelecomManager.shared.backgroundContextCameraIsEnabled = call?.params?.videoEnabled == true || call?.callLog?.wasConference() == true
- if #available(iOS 16.0, *) {
- if call?.cameraEnabled == true {
- call?.cameraEnabled = AVCaptureSession().isMultitaskingCameraAccessSupported
+ DispatchQueue.main.async() {
+ if UIApplication.shared.applicationState != .active {
+ TelecomManager.shared.backgroundContextCall = call
+ TelecomManager.shared.backgroundContextCameraIsEnabled = call?.params?.videoEnabled == true || call?.callLog?.wasConference() == true
+ if #available(iOS 16.0, *) {
+ if call?.cameraEnabled == true {
+ call?.cameraEnabled = AVCaptureSession().isMultitaskingCameraAccessSupported
+ }
+ } else {
+ call?.cameraEnabled = false // Disable camera while app is not on foreground
}
- } else {
- call?.cameraEnabled = false // Disable camera while app is not on foreground
}
}
TelecomManager.shared.callkitAudioSessionActivated = false
@@ -240,7 +244,7 @@ extension ProviderDelegate: CXProviderDelegate {
action.fulfill()
}
}
-
+
func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {
let uuid = action.callUUID
let callId = callInfos[uuid]?.callId ?? ""
@@ -273,29 +277,29 @@ extension ProviderDelegate: CXProviderDelegate {
action.fulfill()
} else {
if call?.conference != nil && core.callsNb > 1 {/*
- try TelecomManager.shared.lc?.enterConference()
- action.fulfill()
- NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self)
- */} else {
- try call!.resume()
- // We'll notify callkit that the action is fulfilled when receiving the 200Ok, which is the point
- // where we actually start the media streams.
- TelecomManager.shared.actionToFulFill = action
- // HORRIBLE HACK HERE - PLEASE APPLE FIX THIS !!
- // When resuming a SIP call after a native call has ended remotely, didActivate: audioSession
- // is never called.
- // It looks like in this case, it is implicit.
- // As a result we have to notify the Core that the AudioSession is active.
- // The SpeakerBox demo application written by Apple exhibits this behavior.
- // https://developer.apple.com/documentation/callkit/making_and_receiving_voip_calls_with_callkit
- // We can clearly see there that startAudio() is called immediately in the CXSetHeldCallAction
- // handler, while it is called from didActivate: audioSession otherwise.
- // Callkit's design is not consistent, or its documentation imcomplete, wich is somewhat disapointing.
- //
- Log.info("Assuming AudioSession is active when executing a CXSetHeldCallAction with isOnHold=false.")
- core.activateAudioSession(actived: true)
- TelecomManager.shared.callkitAudioSessionActivated = true
- }
+ try TelecomManager.shared.lc?.enterConference()
+ action.fulfill()
+ NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self)
+ */} else {
+ try call!.resume()
+ // We'll notify callkit that the action is fulfilled when receiving the 200Ok, which is the point
+ // where we actually start the media streams.
+ TelecomManager.shared.actionToFulFill = action
+ // HORRIBLE HACK HERE - PLEASE APPLE FIX THIS !!
+ // When resuming a SIP call after a native call has ended remotely, didActivate: audioSession
+ // is never called.
+ // It looks like in this case, it is implicit.
+ // As a result we have to notify the Core that the AudioSession is active.
+ // The SpeakerBox demo application written by Apple exhibits this behavior.
+ // https://developer.apple.com/documentation/callkit/making_and_receiving_voip_calls_with_callkit
+ // We can clearly see there that startAudio() is called immediately in the CXSetHeldCallAction
+ // handler, while it is called from didActivate: audioSession otherwise.
+ // Callkit's design is not consistent, or its documentation imcomplete, wich is somewhat disapointing.
+ //
+ Log.info("Assuming AudioSession is active when executing a CXSetHeldCallAction with isOnHold=false.")
+ core.activateAudioSession(actived: true)
+ TelecomManager.shared.callkitAudioSessionActivated = true
+ }
}
}
} catch {
@@ -330,7 +334,7 @@ extension ProviderDelegate: CXProviderDelegate {
}
}
}
-
+
func provider(_ provider: CXProvider, perform action: CXSetGroupCallAction) {
CoreContext.shared.doOnCoreQueue { core in
Log.info("CallKit: Call grouped callUUid : \(action.callUUID) with callUUID: \(String(describing: action.callUUIDToGroupWith)).")
@@ -338,7 +342,7 @@ extension ProviderDelegate: CXProviderDelegate {
action.fulfill()
}
}
-
+
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
let uuid = action.callUUID
let callId = callInfos[uuid]?.callId
@@ -348,7 +352,7 @@ extension ProviderDelegate: CXProviderDelegate {
action.fulfill()
}
}
-
+
func provider(_ provider: CXProvider, perform action: CXPlayDTMFCallAction) {
let uuid = action.callUUID
let callId = callInfos[uuid]?.callId ?? ""
@@ -366,18 +370,18 @@ extension ProviderDelegate: CXProviderDelegate {
action.fulfill()
}
}
-
+
func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {
let uuid = action.uuid
let callId = callInfos[uuid]?.callId
Log.error("CallKit: Call time out with call-id: \(String(describing: callId)) an UUID: \(uuid.description).")
action.fulfill()
}
-
+
func providerDidReset(_ provider: CXProvider) {
Log.info("CallKit: did reset.")
}
-
+
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
CoreContext.shared.doOnCoreQueue { core in
Log.info("CallKit: audio session activated.")
@@ -385,7 +389,7 @@ extension ProviderDelegate: CXProviderDelegate {
TelecomManager.shared.callkitAudioSessionActivated = true
}
}
-
+
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
CoreContext.shared.doOnCoreQueue { core in
Log.info("CallKit: audio session deactivated.")
diff --git a/Linphone/TelecomManager/TelecomManager.swift b/Linphone/TelecomManager/TelecomManager.swift
index 855e70305..aa93fd28a 100644
--- a/Linphone/TelecomManager/TelecomManager.swift
+++ b/Linphone/TelecomManager/TelecomManager.swift
@@ -41,7 +41,11 @@ class TelecomManager: ObservableObject {
let callController: CXCallController // to support callkit
@Published var callInProgress: Bool = false
- @Published var callStarted: Bool = false
+ @Published var callStarted: Bool = false
+ @Published var outgoingCallStarted: Bool = false
+ @Published var remoteVideo: Bool = false
+ @Published var isRecordingByRemote: Bool = false
+ @Published var isPausedByRemote: Bool = false
var actionToFulFill: CXCallAction?
var callkitAudioSessionActivated: Bool?
@@ -116,34 +120,47 @@ class TelecomManager: ObservableObject {
}
}
- func doCallWithCore(addr: Address) {
- CoreContext.shared.doOnCoreQueue { core in
+ 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) ")
}
- }
- }
-
+ }
+ }
+
+ private func makeRecordFilePath() -> String{
+ var filePath = "recording_"
+ let now = Date()
+ let dateFormat = DateFormatter()
+ dateFormat.dateFormat = "E-d-MMM-yyyy-HH-mm-ss"
+ let date = dateFormat.string(from: now)
+ filePath = filePath.appending("\(date).mkv")
+
+ let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
+ let writablePath = paths[0]
+ return writablePath.appending("/\(filePath)")
+ }
+
func doCall(core: Core, addr: Address, isSas: Bool, isVideo: Bool, isConference: Bool = false) throws {
// let displayName = FastAddressBook.displayName(for: addr.getCobject)
let lcallParams = try core.createCallParams(call: nil)
/*
- if ConfigManager.instance().lpConfigBoolForKey(key: "edge_opt_preference") && AppManager.network() == .network_2g {
- Log.directLog(BCTBX_LOG_MESSAGE, text: "Enabling low bandwidth mode")
- lcallParams.lowBandwidthEnabled = true
- }
-
- if (displayName != nil) {
- try addr.setDisplayname(newValue: displayName!)
- }
-
- if(ConfigManager.instance().lpConfigBoolForKey(key: "override_domain_with_default_one")) {
- try addr.setDomain(newValue: ConfigManager.instance().lpConfigStringForKey(key: "domain", section: "assistant"))
- }
- */
+ if ConfigManager.instance().lpConfigBoolForKey(key: "edge_opt_preference") && AppManager.network() == .network_2g {
+ Log.directLog(BCTBX_LOG_MESSAGE, text: "Enabling low bandwidth mode")
+ lcallParams.lowBandwidthEnabled = true
+ }
+
+ if (displayName != nil) {
+ try addr.setDisplayname(newValue: displayName!)
+ }
+
+ if(ConfigManager.instance().lpConfigBoolForKey(key: "override_domain_with_default_one")) {
+ try addr.setDomain(newValue: ConfigManager.instance().lpConfigStringForKey(key: "domain", section: "assistant"))
+ }
+ */
if nextCallIsTransfer {
let call = core.currentCall
@@ -154,17 +171,20 @@ class TelecomManager: ObservableObject {
// let writablePath = AppManager.recordingFilePathFromCall(address: addr.username! )
// Log.directLog(BCTBX_LOG_DEBUG, text: "record file path: \(writablePath)")
// lcallParams.recordFile = writablePath
+
+ lcallParams.recordFile = makeRecordFilePath()
+
if isSas {
lcallParams.mediaEncryption = .ZRTP
}
if isConference {
- /* if (ConferenceWaitingRoomViewModel.sharedModel.joinLayout.value! != .AudioOnly) {
- lcallParams.videoEnabled = true
- lcallParams.videoDirection = ConferenceWaitingRoomViewModel.sharedModel.isVideoEnabled.value == true ? .SendRecv : .RecvOnly
- lcallParams.conferenceVideoLayout = ConferenceWaitingRoomViewModel.sharedModel.joinLayout.value! == .Grid ? .Grid : .ActiveSpeaker
- } else {
- lcallParams.videoEnabled = false
- }*/
+ /* if (ConferenceWaitingRoomViewModel.sharedModel.joinLayout.value! != .AudioOnly) {
+ lcallParams.videoEnabled = true
+ lcallParams.videoDirection = ConferenceWaitingRoomViewModel.sharedModel.isVideoEnabled.value == true ? .SendRecv : .RecvOnly
+ lcallParams.conferenceVideoLayout = ConferenceWaitingRoomViewModel.sharedModel.joinLayout.value! == .Grid ? .Grid : .ActiveSpeaker
+ } else {
+ lcallParams.videoEnabled = false
+ }*/
} else {
lcallParams.videoEnabled = isVideo
}
@@ -184,9 +204,12 @@ class TelecomManager: ObservableObject {
}
DispatchQueue.main.async {
+ self.outgoingCallStarted = true
self.callStarted = true
- withAnimation {
- self.callInProgress = true
+ if self.callInProgress == false {
+ withAnimation {
+ self.callInProgress = true
+ }
}
}
}
@@ -195,14 +218,16 @@ class TelecomManager: ObservableObject {
func acceptCall(core: Core, call: Call, hasVideo: Bool) {
do {
let callParams = try core.createCallParams(call: call)
+
+ callParams.recordFile = makeRecordFilePath()
callParams.videoEnabled = hasVideo
/*if (ConfigManager.instance().lpConfigBoolForKey(key: "edge_opt_preference")) {
- let low_bandwidth = (AppManager.network() == .network_2g)
- if (low_bandwidth) {
- Log.directLog(BCTBX_LOG_MESSAGE, text: "Low bandwidth mode")
- }
- callParams.lowBandwidthEnabled = low_bandwidth
- }*/
+ let low_bandwidth = (AppManager.network() == .network_2g)
+ if (low_bandwidth) {
+ Log.directLog(BCTBX_LOG_MESSAGE, text: "Low bandwidth mode")
+ }
+ callParams.lowBandwidthEnabled = low_bandwidth
+ }*/
// We set the record file name here because we can't do it after the call is started.
// let address = call.callLog?.fromAddress
@@ -211,10 +236,10 @@ class TelecomManager: ObservableObject {
// callParams.recordFile = writablePath
/*
- if let chatView : ChatConversationView = PhoneMainView.instance().VIEW(ChatConversationView.compositeViewDescription()), chatView.isVoiceRecording {
- Log.directLog(BCTBX_LOG_MESSAGE, text: "Voice recording in progress, stopping it befoce accepting the call.")
- chatView.stopVoiceRecording()
- }*/
+ if let chatView : ChatConversationView = PhoneMainView.instance().VIEW(ChatConversationView.compositeViewDescription()), chatView.isVoiceRecording {
+ Log.directLog(BCTBX_LOG_MESSAGE, text: "Voice recording in progress, stopping it befoce accepting the call.")
+ chatView.stopVoiceRecording()
+ }*/
if call.callLog?.wasConference() == true {
// Prevent incoming group call to start in audio only layout
@@ -226,9 +251,9 @@ class TelecomManager: ObservableObject {
try call.acceptWithParams(params: callParams)
- DispatchQueue.main.async {
- self.callStarted = true
- }
+ DispatchQueue.main.async {
+ self.callStarted = true
+ }
} catch {
Log.error("accept call failed \(error)")
}
@@ -311,10 +336,52 @@ class TelecomManager: ObservableObject {
if cstate == .PushIncomingReceived {
displayIncomingCall(call: call, handle: "Calling", hasVideo: false, callId: callId, displayName: "Calling")
} else {
- let video = (core.videoActivationPolicy?.automaticallyAccept ?? false) && (call.remoteParams?.videoEnabled ?? false)
- if video {
- Log.info("[Call] Remote video is activated")
+ DispatchQueue.main.async {
+ self.remoteVideo = (core.videoActivationPolicy?.automaticallyAccept ?? false) && (call.remoteParams?.videoEnabled ?? false)
+
+ if self.remoteVideo {
+ Log.info("[Call] Remote video is activated")
+ }
+
+ self.isRecordingByRemote = call.remoteParams?.isRecording ?? false
+
+ if self.isRecordingByRemote && ToastViewModel.shared.toastMessage.isEmpty {
+
+ var displayName = ""
+ let friend = ContactsManager.shared.getFriendWithAddress(address: call.remoteAddress!)
+ if friend != nil && friend!.address != nil && friend!.address!.displayName != nil {
+ displayName = friend!.address!.displayName!
+ } else {
+ if call.remoteAddress!.displayName != nil {
+ displayName = call.remoteAddress!.displayName!
+ } else if call.remoteAddress!.username != nil {
+ displayName = call.remoteAddress!.username!
+ }
+ }
+
+ ToastViewModel.shared.toastMessage = "\(displayName) is recording"
+ ToastViewModel.shared.displayToast = true
+
+ Log.info("[Call] Call is recording by \(call.remoteAddress!.asStringUriOnly())")
+ }
+
+ if !self.isRecordingByRemote && ToastViewModel.shared.toastMessage.contains("is recording") {
+
+ withAnimation {
+ ToastViewModel.shared.toastMessage = ""
+ ToastViewModel.shared.displayToast = false
+ }
+
+ Log.info("[Call] Recording is stopped by \(call.remoteAddress!.asStringUriOnly())")
+ }
+
+ switch call.state {
+ case Call.State.PausedByRemote:
+ self.isPausedByRemote = true
+ default:
+ self.isPausedByRemote = false
+ }
}
if call.userData == nil {
@@ -322,24 +389,28 @@ class TelecomManager: ObservableObject {
TelecomManager.setAppData(sCall: call, appData: appData)
}
/*
- if let conference = call.conference, ConferenceViewModel.shared.conference.value == nil {
- Log.info("[Call] Found conference attached to call and no conference in dedicated view model, init & configure it")
- ConferenceViewModel.shared.initConference(conference)
- ConferenceViewModel.shared.configureConference(conference)
- }
- */
+ if let conference = call.conference, ConferenceViewModel.shared.conference.value == nil {
+ Log.info("[Call] Found conference attached to call and no conference in dedicated view model, init & configure it")
+ ConferenceViewModel.shared.initConference(conference)
+ ConferenceViewModel.shared.configureConference(conference)
+ }
+ */
switch cstate {
case .IncomingReceived:
let addr = call.remoteAddress
let displayName = incomingDisplayName(call: call)
- #if targetEnvironment(simulator)
+#if targetEnvironment(simulator)
DispatchQueue.main.async {
- withAnimation {
- TelecomManager.shared.callInProgress = true
+ self.outgoingCallStarted = false
+ self.callStarted = true
+ if self.callInProgress == false {
+ withAnimation {
+ self.callInProgress = true
+ }
}
}
- #endif
+#endif
if call.replacedCall != nil {
endCallKitReplacedCall = false
@@ -351,22 +422,22 @@ class TelecomManager: ObservableObject {
providerDelegate.callInfos.updateValue(callInfo!, forKey: uuid!)
providerDelegate.uuids.removeValue(forKey: callId)
providerDelegate.uuids.updateValue(uuid!, forKey: callInfo!.callId)
- providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName)
+ providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: remoteVideo, displayName: displayName)
}
} else if TelecomManager.callKitEnabled(core: core) {
/*
let isConference = isConferenceCall(call: call)
- let isEarlyConference = isConference && CallsViewModel.shared.currentCallData.value??.isConferenceCall.value != true // Conference info not be received yet.
- if (isEarlyConference) {
- CallsViewModel.shared.currentCallData.readCurrentAndObserve { _ in
- let uuid = providerDelegate.uuids["\(callId)"]
- if (uuid != nil) {
- displayName = "\(VoipTexts.conference_incoming_title): \(CallsViewModel.shared.currentCallData.value??.remoteConferenceSubject.value ?? "") (\(CallsViewModel.shared.currentCallData.value??.conferenceParticipantsCountLabel.value ?? ""))"
- providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName)
- }
- }
- }
- */
+ let isEarlyConference = isConference && CallsViewModel.shared.currentCallData.value??.isConferenceCall.value != true // Conference info not be received yet.
+ if (isEarlyConference) {
+ CallsViewModel.shared.currentCallData.readCurrentAndObserve { _ in
+ let uuid = providerDelegate.uuids["\(callId)"]
+ if (uuid != nil) {
+ displayName = "\(VoipTexts.conference_incoming_title): \(CallsViewModel.shared.currentCallData.value??.remoteConferenceSubject.value ?? "") (\(CallsViewModel.shared.currentCallData.value??.conferenceParticipantsCountLabel.value ?? ""))"
+ providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName)
+ }
+ }
+ }
+ */
let uuid = providerDelegate.uuids["\(callId)"]
if call.replacedCall == nil {
TelecomManager.uuidReplacedCall = callId
@@ -374,23 +445,28 @@ class TelecomManager: ObservableObject {
if uuid != nil {
// Tha app is now registered, updated the call already existed.
- providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: video, displayName: displayName)
+ providerDelegate.updateCall(uuid: uuid!, handle: addr!.asStringUriOnly(), hasVideo: remoteVideo, displayName: displayName)
} else {
- displayIncomingCall(call: call, handle: addr!.asStringUriOnly(), hasVideo: video, callId: callId, displayName: displayName)
+ displayIncomingCall(call: call, handle: addr!.asStringUriOnly(), hasVideo: remoteVideo, callId: callId, displayName: displayName)
}
} /* else if UIApplication.shared.applicationState != .active {
- // not support callkit , use notif
- let content = UNMutableNotificationContent()
- content.title = NSLocalizedString("Incoming call", comment: "")
- content.body = displayName
- content.sound = UNNotificationSound.init(named: UNNotificationSoundName.init("notes_of_the_optimistic.caf"))
- content.categoryIdentifier = "call_cat"
- content.userInfo = ["CallId": callId]
- let req = UNNotificationRequest.init(identifier: "call_request", content: content, trigger: nil)
- UNUserNotificationCenter.current().add(req, withCompletionHandler: nil)
- } */
+ // not support callkit , use notif
+ let content = UNMutableNotificationContent()
+ content.title = NSLocalizedString("Incoming call", comment: "")
+ content.body = displayName
+ content.sound = UNNotificationSound.init(named: UNNotificationSoundName.init("notes_of_the_optimistic.caf"))
+ content.categoryIdentifier = "call_cat"
+ content.userInfo = ["CallId": callId]
+ let req = UNNotificationRequest.init(identifier: "call_request", content: content, trigger: nil)
+ UNUserNotificationCenter.current().add(req, withCompletionHandler: nil)
+ } */
case .StreamsRunning:
if TelecomManager.callKitEnabled(core: core) {
+
+ DispatchQueue.main.async {
+ self.outgoingCallStarted = false
+ }
+
let uuid = providerDelegate.uuids["\(callId)"]
if uuid != nil {
let callInfo = providerDelegate.callInfos[uuid!]
@@ -404,10 +480,10 @@ class TelecomManager: ObservableObject {
}
/*
- if speakerBeforePause {
- speakerBeforePause = false
- AudioRouteUtils.routeAudioToSpeaker(core: core)
- }
+ if speakerBeforePause {
+ speakerBeforePause = false
+ AudioRouteUtils.routeAudioToSpeaker(core: core)
+ }
*/
actionToFulFill?.fulfill()
@@ -432,12 +508,12 @@ class TelecomManager: ObservableObject {
providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid!)
} else {
if false { /* isConferenceCall(call: call) {
- let uuid = UUID()
- let callInfo = CallInfo.newOutgoingCallInfo(addr: call.remoteAddress!, isSas: call.params?.mediaEncryption == .ZRTP, displayName: VoipTexts.conference_default_title, isVideo: call.params?.videoEnabled == true, isConference:true)
- providerDelegate.callInfos.updateValue(callInfo, forKey: uuid)
- providerDelegate.uuids.updateValue(uuid, forKey: "")
- providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid)
- Core.get().activateAudioSession(actived: true) */
+ let uuid = UUID()
+ let callInfo = CallInfo.newOutgoingCallInfo(addr: call.remoteAddress!, isSas: call.params?.mediaEncryption == .ZRTP, displayName: VoipTexts.conference_default_title, isVideo: call.params?.videoEnabled == true, isConference:true)
+ providerDelegate.callInfos.updateValue(callInfo, forKey: uuid)
+ providerDelegate.uuids.updateValue(uuid, forKey: "")
+ providerDelegate.reportOutgoingCallStartedConnecting(uuid: uuid)
+ Core.get().activateAudioSession(actived: true) */
} else {
referedToCall = callId
}
@@ -446,19 +522,6 @@ class TelecomManager: ObservableObject {
case .End,
.Error:
- DispatchQueue.main.async {
- withAnimation {
- self.callInProgress = false
- self.callStarted = false
- }
- }
- var displayName = "Unknown"
- if call.dir == .Incoming {
- displayName = incomingDisplayName(call: call)
- } else { // if let addr = call.remoteAddress, let contactName = FastAddressBook.displayName(for: addr.getCobject) {
- displayName = "TODOContactName"
- }
-
UIDevice.current.isProximityMonitoringEnabled = false
if core.callsNb == 0 {
core.outputAudioDevice = core.defaultOutputAudioDevice
@@ -468,18 +531,34 @@ class TelecomManager: ObservableObject {
// bluetoothEnabled = false
}
- if UIApplication.shared.applicationState != .active && (callLog == nil || callLog?.status == .Missed || callLog?.status == .Aborted || callLog?.status == .EarlyAborted) {
- // Configure the notification's payload.
- let content = UNMutableNotificationContent()
- content.title = NSString.localizedUserNotificationString(forKey: NSLocalizedString("Missed call", comment: ""), arguments: nil)
- content.body = NSString.localizedUserNotificationString(forKey: displayName, arguments: nil)
+ DispatchQueue.main.async {
+ withAnimation {
+ self.outgoingCallStarted = false
+ self.callInProgress = false
+ self.callStarted = false
+ }
- // Deliver the notification.
- let request = UNNotificationRequest(identifier: "call_request", content: content, trigger: nil) // Schedule the notification.
- let center = UNUserNotificationCenter.current()
- center.add(request) { (error: Error?) in
- if error != nil {
- Log.info("Error while adding notification request : \(error!.localizedDescription)")
+ var displayName = "Unknown"
+ if call.dir == .Incoming {
+ displayName = self.incomingDisplayName(call: call)
+ } else { // if let addr = call.remoteAddress, let contactName = FastAddressBook.displayName(for: addr.getCobject) {
+ displayName = "TODOContactName"
+ }
+
+
+ if UIApplication.shared.applicationState != .active && (callLog == nil || callLog?.status == .Missed || callLog?.status == .Aborted || callLog?.status == .EarlyAborted) {
+ // Configure the notification's payload.
+ let content = UNMutableNotificationContent()
+ content.title = NSString.localizedUserNotificationString(forKey: NSLocalizedString("Missed call", comment: ""), arguments: nil)
+ content.body = NSString.localizedUserNotificationString(forKey: displayName, arguments: nil)
+
+ // Deliver the notification.
+ let request = UNNotificationRequest(identifier: "call_request", content: content, trigger: nil) // Schedule the notification.
+ let center = UNUserNotificationCenter.current()
+ center.add(request) { (error: Error?) in
+ if error != nil {
+ Log.info("Error while adding notification request : \(error!.localizedDescription)")
+ }
}
}
}
@@ -524,22 +603,6 @@ class TelecomManager: ObservableObject {
default:
break
}
-
- // AudioRouteUtils.isBluetoothAvailable(core: core)
- // AudioRouteUtils.isHeadsetAudioRouteAvailable(core: core)
- // AudioRouteUtils.isBluetoothAudioRouteAvailable(core: core)
-
- /*
- let readyForRoutechange = callkitAudioSessionActivated == nil || (callkitAudioSessionActivated == true)
- if readyForRoutechange && (cstate == .IncomingReceived || cstate == .OutgoingInit || cstate == .Connected || cstate == .StreamsRunning) {
- if (call.currentParams?.videoEnabled ?? false) && AudioRouteUtils.isReceiverEnabled(core: core) && call.conference == nil {
- AudioRouteUtils.routeAudioToSpeaker(core: core, call: call)
- } else if AudioRouteUtils.isBluetoothAvailable(core: core) {
- // Use bluetooth device by default if one is available
- AudioRouteUtils.routeAudioToBluetooth(core: core, call: call)
- }
- }
- */
}
// post Notification kLinphoneCallUpdate
NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self, userInfo: [
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..819931bd3 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
@@ -91,7 +91,12 @@ class AccountLoginViewModel: ObservableObject {
accountParams.registerEnabled = true
accountParams.pushNotificationAllowed = true
accountParams.remotePushNotificationAllowed = false
- accountParams.pushNotificationConfig?.provider = "apns.dev"
+#if DEBUG
+ let pushEnvironment = ".dev"
+#else
+ let pushEnvironment = ""
+#endif
+ accountParams.pushNotificationConfig?.provider = "apns" + pushEnvironment
// Now that our AccountParams is configured, we can create the Account object
let account = try core.createAccount(params: accountParams)
@@ -106,6 +111,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 cd23af51e..709a814df 100644
--- a/Linphone/UI/Call/CallView.swift
+++ b/Linphone/UI/Call/CallView.swift
@@ -18,16 +18,17 @@
*/
// swiftlint:disable type_body_length
+// swiftlint:disable line_length
import SwiftUI
import CallKit
import AVFAudio
import linphonesw
struct CallView: View {
-
- @ObservedObject private var coreContext = CoreContext.shared
- @ObservedObject private var telecomManager = TelecomManager.shared
- @ObservedObject private var contactsManager = ContactsManager.shared
+
+ @ObservedObject private var coreContext = CoreContext.shared
+ @ObservedObject private var telecomManager = TelecomManager.shared
+ @ObservedObject private var contactsManager = ContactsManager.shared
@ObservedObject var callViewModel: CallViewModel
@@ -35,8 +36,8 @@ struct CallView: View {
@State private var orientation = UIDevice.current.orientation
let pub = NotificationCenter.default.publisher(for: AVAudioSession.routeChangeNotification)
-
- @State var startDate = Date.now
+
+ @State var startDate = Date.now
@State var audioRouteSheet: Bool = false
@State var hideButtonsSheet: Bool = false
@State var options: Int = 1
@@ -45,10 +46,10 @@ struct CallView: View {
@State var angleDegree = 0.0
@State var fullscreenVideo = false
-
- var body: some View {
- GeometryReader { geo in
- if #available(iOS 16.4, *) {
+
+ var body: some View {
+ GeometryReader { geo in
+ if #available(iOS 16.4, *) {
innerView(geometry: geo)
.sheet(isPresented:
.constant(
@@ -60,54 +61,55 @@ struct CallView: View {
)
) {
GeometryReader { _ in
- VStack(spacing: 0) {
- HStack(spacing: 12) {
- Button {
+ VStack(spacing: 0) {
+ 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 {
+ } 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(.white)
- .frame(width: 32, height: 32)
-
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
-
- Button {
+ } label: {
+ Image(telecomManager.remoteVideo ? "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: {
+ } label: {
Image(callViewModel.micMutted ? "microphone-slash" : "microphone")
- .renderingMode(.template)
- .resizable()
+ .renderingMode(.template)
+ .resizable()
.foregroundStyle(callViewModel.micMutted ? .black : .white)
- .frame(width: 32, height: 32)
-
- }
- .frame(width: 60, height: 60)
+ .frame(width: 32, height: 32)
+
+ }
+ .frame(width: 60, height: 60)
.background(callViewModel.micMutted ? .white : Color.gray500)
- .cornerRadius(40)
-
- Button {
- if AVAudioSession.sharedInstance().availableInputs != nil
+ .cornerRadius(40)
+
+ Button {
+ if AVAudioSession.sharedInstance().availableInputs != nil
&& !AVAudioSession.sharedInstance().availableInputs!.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty {
hideButtonsSheet = true
@@ -123,200 +125,210 @@ struct CallView: View {
}
}
- } label: {
+ } label: {
Image(imageAudioRoute)
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
.onAppear(perform: getAudioRouteImage)
- .onReceive(pub) { (output) in
+ .onReceive(pub) { _ in
self.getAudioRouteImage()
}
-
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
- }
- .frame(height: geo.size.height * 0.15)
- .padding(.horizontal, 20)
+
+ }
+ .frame(width: 60, height: 60)
+ .background(Color.gray500)
+ .cornerRadius(40)
+ }
+ .frame(height: geo.size.height * 0.15)
+ .padding(.horizontal, 20)
.padding(.top, -6)
-
- HStack(spacing: 0) {
- VStack {
- Button {
- } label: {
- Image("screencast")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
-
- Text("Screen share")
- .foregroundStyle(.white)
- .default_text_style(styleSize: 15)
- }
- .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
-
- VStack {
- Button {
- } label: {
- Image("users")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
-
- Text("Participants")
- .foregroundStyle(.white)
- .default_text_style(styleSize: 15)
- }
- .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
-
- VStack {
- Button {
- } label: {
- Image("chat-teardrop-text")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
-
- Text("Messages")
- .foregroundStyle(.white)
- .default_text_style(styleSize: 15)
- }
- .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
-
- VStack {
- Button {
- } label: {
- Image("notebook")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
-
- Text("Disposition")
- .foregroundStyle(.white)
- .default_text_style(styleSize: 15)
- }
- .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
- }
- .frame(height: geo.size.height * 0.15)
-
- HStack(spacing: 0) {
- VStack {
- Button {
- } label: {
- Image("phone-call")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
-
- Text("Call list")
- .foregroundStyle(.white)
- .default_text_style(styleSize: 15)
- }
- .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
-
- VStack {
- Button {
+
+ HStack(spacing: 0) {
+ VStack {
+ Button {
+ } label: {
+ Image("phone-transfer")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.gray500)
+ .frame(width: 32, height: 32)
+ }
+ .frame(width: 60, height: 60)
+ .background(Color.gray600)
+ .cornerRadius(40)
+ .disabled(true)
+
+ Text("Transfer")
+ .foregroundStyle(.white)
+ .default_text_style(styleSize: 15)
+ }
+ .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
+
+ VStack {
+ Button {
+ } label: {
+ Image("phone-plus")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.gray500)
+ .frame(width: 32, height: 32)
+ }
+ .frame(width: 60, height: 60)
+ .background(Color.gray600)
+ .cornerRadius(40)
+ .disabled(true)
+
+ Text("New call")
+ .foregroundStyle(.white)
+ .default_text_style(styleSize: 15)
+ }
+ .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
+
+ VStack {
+ Button {
+ } label: {
+ Image("phone-list")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.gray500)
+ .frame(width: 32, height: 32)
+ }
+ .frame(width: 60, height: 60)
+ .background(Color.gray600)
+ .cornerRadius(40)
+ .disabled(true)
+
+ Text("Call list")
+ .foregroundStyle(.white)
+ .default_text_style(styleSize: 15)
+ }
+ .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
+
+ VStack {
+ Button {
+ } label: {
+ Image("dialer")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.gray500)
+ .frame(width: 32, height: 32)
+ }
+ .frame(width: 60, height: 60)
+ .background(Color.gray600)
+ .cornerRadius(40)
+ .disabled(true)
+
+ Text("Dialer")
+ .foregroundStyle(.white)
+ .default_text_style(styleSize: 15)
+ }
+ .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
+ }
+ .frame(height: geo.size.height * 0.15)
+
+ HStack(spacing: 0) {
+ VStack {
+ Button {
+ } label: {
+ Image("chat-teardrop-text")
+ .renderingMode(.template)
+ .resizable()
+ //.foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
+ .foregroundStyle(Color.gray500)
+ .frame(width: 32, height: 32)
+ }
+ .frame(width: 60, height: 60)
+ //.background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : Color.gray500)
+ .background(Color.gray600)
+ .cornerRadius(40)
+ //.disabled(callViewModel.isPaused || telecomManager.isPausedByRemote)
+ .disabled(true)
+
+ Text("Messages")
+ .foregroundStyle(.white)
+ .default_text_style(styleSize: 15)
+ }
+ .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
+
+ VStack {
+ Button {
callViewModel.togglePause()
- } label: {
- Image("pause")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
-
- Text("Pause")
- .foregroundStyle(.white)
- .default_text_style(styleSize: 15)
- }
- .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
-
- VStack {
- Button {
+ } label: {
+ Image(callViewModel.isPaused ? "play" : "pause")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(telecomManager.isPausedByRemote ? Color.gray500 : .white)
+ .frame(width: 32, height: 32)
+ }
+ .frame(width: 60, height: 60)
+ .background(telecomManager.isPausedByRemote ? Color.gray600 : (callViewModel.isPaused ? Color.greenSuccess500 : Color.gray500))
+ .cornerRadius(40)
+ .disabled(telecomManager.isPausedByRemote)
+
+ Text("Pause")
+ .foregroundStyle(.white)
+ .default_text_style(styleSize: 15)
+ }
+ .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
+
+ VStack {
+ Button {
callViewModel.toggleRecording()
- } label: {
- Image("record-fill")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
-
- Text("Record")
- .foregroundStyle(.white)
- .default_text_style(styleSize: 15)
- }
- .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
-
- VStack {
- Button {
- } label: {
- Image("video-camera")
- .renderingMode(.template)
- .resizable()
- .foregroundStyle(.white)
- .frame(width: 32, height: 32)
- }
- .frame(width: 60, height: 60)
- .background(Color.gray500)
- .cornerRadius(40)
-
- Text("Disposition")
- .foregroundStyle(.white)
- .default_text_style(styleSize: 15)
- }
- .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
- .hidden()
- }
- .frame(height: geo.size.height * 0.15)
-
- Spacer()
- }
- .frame(maxHeight: .infinity, alignment: .top)
+ } label: {
+ Image("record-fill")
+ .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 : (callViewModel.isRecording ? Color.redDanger500 : Color.gray500))
+ .cornerRadius(40)
+ .disabled(callViewModel.isPaused || telecomManager.isPausedByRemote)
+
+ Text("Record")
+ .foregroundStyle(.white)
+ .default_text_style(styleSize: 15)
+ }
+ .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
+
+ VStack {
+ Button {
+ } label: {
+ Image("video-camera")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(.white)
+ .frame(width: 32, height: 32)
+ }
+ .frame(width: 60, height: 60)
+ .background(Color.gray500)
+ .cornerRadius(40)
+
+ Text("Disposition")
+ .foregroundStyle(.white)
+ .default_text_style(styleSize: 15)
+ }
+ .frame(width: geo.size.width * 0.25, height: geo.size.width * 0.25)
+ .hidden()
+ }
+ .frame(height: geo.size.height * 0.15)
+
+ Spacer()
+ }
+ .frame(maxHeight: .infinity, alignment: .top)
.presentationBackground(.black)
- .presentationDetents([.fraction(0.1), .medium])
- .interactiveDismissDisabled()
- .presentationBackgroundInteraction(.enabled)
- }
- }
- .sheet(isPresented: $audioRouteSheet, onDismiss: {
+ .presentationDetents([.fraction(0.1), .fraction(0.45)])
+ .interactiveDismissDisabled()
+ .presentationBackgroundInteraction(.enabled)
+ }
+ }
+ .sheet(isPresented: $audioRouteSheet, onDismiss: {
audioRouteSheet = false
hideButtonsSheet = false
- }) {
+ }) {
VStack(spacing: 0) {
Button(action: {
options = 1
@@ -346,9 +358,9 @@ struct CallView: View {
Image(!callViewModel.isHeadPhoneAvailable() ? "ear" : "headset")
.renderingMode(.template)
- .resizable()
+ .resizable()
.foregroundStyle(.white)
- .frame(width: 25, height: 25, alignment: .leading)
+ .frame(width: 25, height: 25, alignment: .leading)
}
})
.frame(maxHeight: .infinity)
@@ -416,21 +428,32 @@ struct CallView: View {
}
.padding(.horizontal, 20)
.presentationBackground(Color.gray600)
- .presentationDetents([.fraction(0.3)])
+ .presentationDetents([.fraction(0.3)])
.frame(maxHeight: .infinity)
}
- }
- }
- }
-
- @ViewBuilder
+ } else {
+ innerView(geometry: geo)
+ }
+ }
+ }
+
+ @ViewBuilder
+ // swiftlint:disable:next cyclomatic_complexity
func innerView(geometry: GeometryProxy) -> some View {
- VStack {
+ 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 {
@@ -451,9 +474,33 @@ struct CallView: View {
.foregroundStyle(.white)
}
+ if !telecomManager.outgoingCallStarted && telecomManager.callInProgress {
+ Text("|")
+ .foregroundStyle(.white)
+
+ ZStack {
+ Text(callViewModel.timeElapsed.convertDurationToString())
+ .onReceive(callViewModel.timer) { firedDate in
+ callViewModel.timeElapsed = Int(firedDate.timeIntervalSince(startDate))
+ }
+ .foregroundStyle(.white)
+ .if(callViewModel.isPaused || telecomManager.isPausedByRemote) { view in
+ view.hidden()
+ }
+
+ if callViewModel.isPaused {
+ Text("Paused")
+ .foregroundStyle(.white)
+ } else if telecomManager.isPausedByRemote {
+ Text("Paused by remote")
+ .foregroundStyle(.white)
+ }
+ }
+ }
+
Spacer()
- if callViewModel.cameraDisplayed {
+ if telecomManager.remoteVideo {
Button {
callViewModel.switchCamera()
} label: {
@@ -469,65 +516,65 @@ struct CallView: View {
.frame(height: 40)
.zIndex(1)
}
-
- ZStack {
- VStack {
- Spacer()
-
- if callViewModel.remoteAddress != nil {
- let addressFriend = contactsManager.getFriendWithAddress(address: callViewModel.remoteAddress!)
-
- let contactAvatarModel = addressFriend != nil
- ? ContactsManager.shared.avatarListModel.first(where: {
- ($0.friend!.consolidatedPresence == .Online || $0.friend!.consolidatedPresence == .Busy)
- && $0.friend!.name == addressFriend!.name
- && $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
- })
- : ContactAvatarModel(friend: nil, withPresence: false)
-
- if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
- if contactAvatarModel != nil {
- Avatar(contactAvatarModel: contactAvatarModel!, avatarSize: 100, hidePresence: true)
- }
- } else {
- if callViewModel.remoteAddress!.displayName != nil {
- Image(uiImage: contactsManager.textToImage(
- firstName: callViewModel.remoteAddress!.displayName!,
- lastName: callViewModel.remoteAddress!.displayName!.components(separatedBy: " ").count > 1
- ? callViewModel.remoteAddress!.displayName!.components(separatedBy: " ")[1]
- : ""))
- .resizable()
- .frame(width: 100, height: 100)
- .clipShape(Circle())
-
- } else {
- Image(uiImage: contactsManager.textToImage(
- firstName: callViewModel.remoteAddress!.username ?? "Username Error",
- lastName: callViewModel.remoteAddress!.username!.components(separatedBy: " ").count > 1
- ? callViewModel.remoteAddress!.username!.components(separatedBy: " ")[1]
- : ""))
- .resizable()
- .frame(width: 100, height: 100)
- .clipShape(Circle())
- }
-
- }
- } else {
- Image("profil-picture-default")
- .resizable()
- .frame(width: 100, height: 100)
- .clipShape(Circle())
- }
-
- Text(callViewModel.displayName)
- .padding(.top)
- .foregroundStyle(.white)
-
- Text(callViewModel.remoteAddressString)
- .foregroundStyle(.white)
-
- Spacer()
- }
+
+ ZStack {
+ VStack {
+ Spacer()
+
+ if callViewModel.remoteAddress != nil {
+ let addressFriend = contactsManager.getFriendWithAddress(address: callViewModel.remoteAddress!)
+
+ let contactAvatarModel = addressFriend != nil
+ ? ContactsManager.shared.avatarListModel.first(where: {
+ ($0.friend!.consolidatedPresence == .Online || $0.friend!.consolidatedPresence == .Busy)
+ && $0.friend!.name == addressFriend!.name
+ && $0.friend!.address!.asStringUriOnly() == addressFriend!.address!.asStringUriOnly()
+ })
+ : ContactAvatarModel(friend: nil, withPresence: false)
+
+ if addressFriend != nil && addressFriend!.photo != nil && !addressFriend!.photo!.isEmpty {
+ if contactAvatarModel != nil {
+ Avatar(contactAvatarModel: contactAvatarModel!, avatarSize: 100, hidePresence: true)
+ }
+ } else {
+ if callViewModel.remoteAddress!.displayName != nil {
+ Image(uiImage: contactsManager.textToImage(
+ firstName: callViewModel.remoteAddress!.displayName!,
+ lastName: callViewModel.remoteAddress!.displayName!.components(separatedBy: " ").count > 1
+ ? callViewModel.remoteAddress!.displayName!.components(separatedBy: " ")[1]
+ : ""))
+ .resizable()
+ .frame(width: 100, height: 100)
+ .clipShape(Circle())
+
+ } else {
+ Image(uiImage: contactsManager.textToImage(
+ firstName: callViewModel.remoteAddress!.username ?? "Username Error",
+ lastName: callViewModel.remoteAddress!.username!.components(separatedBy: " ").count > 1
+ ? callViewModel.remoteAddress!.username!.components(separatedBy: " ")[1]
+ : ""))
+ .resizable()
+ .frame(width: 100, height: 100)
+ .clipShape(Circle())
+ }
+
+ }
+ } else {
+ Image("profil-picture-default")
+ .resizable()
+ .frame(width: 100, height: 100)
+ .clipShape(Circle())
+ }
+
+ Text(callViewModel.displayName)
+ .padding(.top)
+ .foregroundStyle(.white)
+
+ Text(callViewModel.remoteAddressString)
+ .foregroundStyle(.white)
+
+ Spacer()
+ }
LinphoneVideoViewHolder { view in
coreContext.doOnCoreQueue { core in
@@ -535,7 +582,7 @@ struct CallView: View {
}
}
.frame(
- width:
+ width:
angleDegree == 0
? 120 * ((geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom) / 160)
: 120 * ((geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) / 120),
@@ -547,10 +594,12 @@ struct CallView: View {
.scaledToFill()
.clipped()
.onTapGesture {
- fullscreenVideo.toggle()
+ if telecomManager.remoteVideo {
+ fullscreenVideo.toggle()
+ }
}
- if callViewModel.cameraDisplayed {
+ if telecomManager.remoteVideo {
HStack {
Spacer()
VStack {
@@ -572,31 +621,65 @@ struct CallView: View {
)
}
- if !telecomManager.callStarted && !fullscreenVideo {
- VStack {
- ActivityIndicator()
- .frame(width: 20, height: 20)
- .padding(.top, 100)
-
+ if callViewModel.isRecording {
+ HStack {
+ VStack {
+ Image("record-fill")
+ .renderingMode(.template)
+ .resizable()
+ .foregroundStyle(Color.redDanger500)
+ .frame(width: 32, height: 32)
+ .padding(10)
+ .if(fullscreenVideo) { view in
+ view.padding(.top, 30)
+ }
+ Spacer()
+ }
+ Spacer()
+ }
+ .frame(
+ maxWidth: fullscreenVideo ? geometry.size.width : geometry.size.width - 8,
+ maxHeight: fullscreenVideo ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - 140
+ )
+ }
+
+ if telecomManager.outgoingCallStarted {
+ VStack {
+ ActivityIndicator()
+ .frame(width: 20, height: 20)
+ .padding(.top, 100)
+
Text(callViewModel.counterToMinutes())
+ .onAppear {
+ callViewModel.timeElapsed = 0
+ startDate = Date.now
+ }
.onReceive(callViewModel.timer) { firedDate in
callViewModel.timeElapsed = Int(firedDate.timeIntervalSince(startDate))
-
- }
- .padding(.top)
- .foregroundStyle(.white)
-
- Spacer()
- }
- .background(.clear)
- }
- }
+
+ }
+ .onDisappear {
+ callViewModel.timeElapsed = 0
+ startDate = Date.now
+ }
+ .padding(.top)
+ .foregroundStyle(.white)
+
+ Spacer()
+ }
+ .frame(
+ maxWidth: fullscreenVideo ? geometry.size.width : geometry.size.width - 8,
+ maxHeight: fullscreenVideo ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - 140
+ )
+ .background(.clear)
+ }
+ }
.frame(
maxWidth: fullscreenVideo ? geometry.size.width : geometry.size.width - 8,
maxHeight: fullscreenVideo ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - 140
)
- .background(Color.gray600)
- .cornerRadius(20)
+ .background(Color.gray600)
+ .cornerRadius(20)
.padding(.horizontal, fullscreenVideo ? 0 : 4)
.onRotate { newOrientation in
orientation = newOrientation
@@ -625,19 +708,104 @@ struct CallView: View {
callViewModel.orientationUpdate(orientation: orientation)
}
-
+
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(telecomManager.remoteVideo ? "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 {
@@ -659,16 +827,17 @@ struct CallView: View {
Button {
callViewModel.toggleVideo()
} label: {
- Image("video-camera")
+ Image(telecomManager.remoteVideo ? "video-camera" : "video-camera-slash")
.renderingMode(.template)
.resizable()
- .foregroundStyle(.white)
+ .foregroundStyle((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray500 : .white)
.frame(width: 32, height: 32)
}
.frame(width: 60, height: 60)
- .background(Color.gray500)
+ .background((callViewModel.isPaused || telecomManager.isPausedByRemote) ? Color.gray600 : Color.gray500)
.cornerRadius(40)
+ .disabled(callViewModel.isPaused || telecomManager.isPausedByRemote)
Button {
callViewModel.toggleMuteMicrophone()
@@ -685,12 +854,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)
@@ -742,13 +931,13 @@ struct CallView: View {
.padding(.top, 20)
}
}
- }
- .frame(maxWidth: .infinity, maxHeight: .infinity)
- .background(Color.gray900)
+ }
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
+ .background(Color.gray900)
.if(fullscreenVideo) { view in
view.ignoresSafeArea(.all)
}
- }
+ }
func getAudioRouteImage() {
imageAudioRoute = AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty
@@ -769,3 +958,4 @@ struct CallView: View {
CallView(callViewModel: CallViewModel())
}
// swiftlint:enable type_body_length
+// swiftlint:enable line_length
diff --git a/Linphone/UI/Call/ViewModel/CallViewModel.swift b/Linphone/UI/Call/ViewModel/CallViewModel.swift
index 834b8874b..b6abd4aa5 100644
--- a/Linphone/UI/Call/ViewModel/CallViewModel.swift
+++ b/Linphone/UI/Call/ViewModel/CallViewModel.swift
@@ -33,14 +33,16 @@ class CallViewModel: ObservableObject {
@Published var avatarModel: ContactAvatarModel?
@Published var micMutted: Bool = false
@Published var cameraDisplayed: Bool = false
- @State var timeElapsed: Int = 0
+ @Published var isRecording: Bool = false
+ @Published var isRemoteRecording: Bool = false
+ @Published var isPaused: Bool = false
+ @Published var timeElapsed: Int = 0
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var currentCall: Call?
init() {
-
do {
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .voiceChat, options: .allowBluetooth)
try AVAudioSession.sharedInstance().setActive(true)
@@ -48,6 +50,10 @@ class CallViewModel: ObservableObject {
}
+ resetCallView()
+ }
+
+ func resetCallView() {
coreContext.doOnCoreQueue { core in
if core.currentCall != nil && core.currentCall!.remoteAddress != nil {
self.currentCall = core.currentCall
@@ -69,7 +75,9 @@ class CallViewModel: ObservableObject {
//self.avatarModel = ???
self.micMutted = self.currentCall!.microphoneMuted
- self.cameraDisplayed = self.currentCall!.cameraEnabled == true
+ self.isRecording = self.currentCall!.params!.isRecording
+ self.isPaused = self.isCallPaused()
+ self.timeElapsed = 0
}
}
}
@@ -77,8 +85,9 @@ class CallViewModel: ObservableObject {
func terminateCall() {
withAnimation {
- telecomManager.callInProgress = false
+ telecomManager.outgoingCallStarted = false
telecomManager.callStarted = false
+ telecomManager.callInProgress = false
}
coreContext.doOnCoreQueue { _ in
@@ -92,6 +101,7 @@ class CallViewModel: ObservableObject {
func acceptCall() {
withAnimation {
+ telecomManager.outgoingCallStarted = false
telecomManager.callInProgress = true
telecomManager.callStarted = true
}
@@ -128,8 +138,6 @@ class CallViewModel: ObservableObject {
"[CallViewModel] Updating call with video enabled set to \(params.videoEnabled)"
)
try self.currentCall!.update(params: params)
-
- self.cameraDisplayed = self.currentCall!.cameraEnabled == true
} catch {
}
@@ -164,10 +172,9 @@ class CallViewModel: ObservableObject {
} else {
Log.info("[CallViewModel] Starting call recording \(self.currentCall!.params!.isRecording)")
self.currentCall!.startRecording()
- Log.info("[CallViewModel] Starting call recording \(self.currentCall!.params!.isRecording)")
}
- //var recording = self.currentCall!.params!.isRecording
- //isRecording.postValue(recording)
+
+ self.isRecording = self.currentCall!.params!.isRecording
}
}
}
@@ -179,9 +186,11 @@ class CallViewModel: ObservableObject {
if self.isCallPaused() {
Log.info("[CallViewModel] Resuming call \(self.currentCall!.remoteAddress!.asStringUriOnly())")
try self.currentCall!.resume()
+ self.isPaused = false
} else {
Log.info("[CallViewModel] Pausing call \(self.currentCall!.remoteAddress!.asStringUriOnly())")
try self.currentCall!.pause()
+ self.isPaused = true
}
} catch _ {
@@ -190,7 +199,7 @@ class CallViewModel: ObservableObject {
}
}
- private func isCallPaused() -> Bool {
+ func isCallPaused() -> Bool {
var result = false
if self.currentCall != nil {
switch self.currentCall!.state {
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/Contacts/Fragments/ContactsListFragment.swift b/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift
index 41bfc686b..3f594f977 100644
--- a/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift
+++ b/Linphone/UI/Main/Contacts/Fragments/ContactsListFragment.swift
@@ -98,5 +98,8 @@ struct ContactsListFragment: View {
}
#Preview {
- ContactsListFragment(contactViewModel: ContactViewModel(), contactsListViewModel: ContactsListViewModel(), showingSheet: .constant(false), startCallFunc: {_ in })
+ ContactsListFragment(contactViewModel: ContactViewModel()
+ , contactsListViewModel: ContactsListViewModel()
+ , showingSheet: .constant(false)
+ , startCallFunc: {_ in })
}
diff --git a/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift b/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift
index fb469c160..efd2e1426 100644
--- a/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift
+++ b/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift
@@ -44,7 +44,8 @@ class ContactAvatarModel: ObservableObject {
if friend!.consolidatedPresence == .Online || friend!.consolidatedPresence == .Busy {
if friend!.consolidatedPresence == .Online || friend!.presenceModel!.latestActivityTimestamp != -1 {
- self.lastPresenceInfo = friend!.consolidatedPresence == .Online ? "Online" : getCallTime(startDate: friend!.presenceModel!.latestActivityTimestamp)
+ self.lastPresenceInfo = (friend!.consolidatedPresence == .Online) ?
+ "Online" : getCallTime(startDate: friend!.presenceModel!.latestActivityTimestamp)
} else {
self.lastPresenceInfo = "Away"
}
@@ -68,7 +69,8 @@ class ContactAvatarModel: ObservableObject {
self.presenceStatus = cbValue.consolidatedPresence
if cbValue.consolidatedPresence == .Online || cbValue.consolidatedPresence == .Busy {
if cbValue.consolidatedPresence == .Online || cbValue.presenceModel!.latestActivityTimestamp != -1 {
- self.lastPresenceInfo = cbValue.consolidatedPresence == .Online ? "Online" : self.getCallTime(startDate: cbValue.presenceModel!.latestActivityTimestamp)
+ self.lastPresenceInfo = cbValue.consolidatedPresence == .Online ?
+ "Online" : self.getCallTime(startDate: cbValue.presenceModel!.latestActivityTimestamp)
} else {
self.lastPresenceInfo = "Away"
}
diff --git a/Linphone/UI/Main/ContentView.swift b/Linphone/UI/Main/ContentView.swift
index 64f63dc5b..267968710 100644
--- a/Linphone/UI/Main/ContentView.swift
+++ b/Linphone/UI/Main/ContentView.swift
@@ -18,6 +18,7 @@
*/
// swiftlint:disable type_body_length
+// swiftlint:disable line_length
import SwiftUI
import linphonesw
@@ -38,6 +39,7 @@ struct ContentView: View {
@ObservedObject var historyViewModel: HistoryViewModel
@ObservedObject var historyListViewModel: HistoryListViewModel
@ObservedObject var startCallViewModel: StartCallViewModel
+ @ObservedObject var callViewModel: CallViewModel
@State var index = 0
@State private var orientation = UIDevice.current.orientation
@@ -149,6 +151,7 @@ struct ContentView: View {
Menu {
if index == 0 {
Button {
+ contactViewModel.indexDisplayedFriend = nil
isMenuOpen = false
magicSearch.allContact = true
MagicSearchSingleton.shared.searchForContacts(
@@ -166,6 +169,7 @@ struct ContentView: View {
}
Button {
+ contactViewModel.indexDisplayedFriend = nil
isMenuOpen = false
magicSearch.allContact = false
MagicSearchSingleton.shared.searchForContacts(
@@ -280,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
@@ -661,15 +664,16 @@ struct ContentView: View {
}
if telecomManager.callInProgress {
- CallView(callViewModel: CallViewModel())
+ CallView(callViewModel: callViewModel)
.zIndex(3)
.transition(.scale.combined(with: .move(edge: .top)))
+ .onAppear {
+ callViewModel.resetCallView()
+ }
}
- // if sharedMainViewModel.displayToast {
ToastView()
.zIndex(3)
- // }
}
}
.overlay {
@@ -693,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")
@@ -722,7 +728,9 @@ struct ContentView: View {
editContactViewModel: EditContactViewModel(),
historyViewModel: HistoryViewModel(),
historyListViewModel: HistoryListViewModel(),
- startCallViewModel: StartCallViewModel()
+ startCallViewModel: StartCallViewModel(),
+ callViewModel: CallViewModel()
)
}
// swiftlint:enable type_body_length
+// swiftlint:enable line_length
diff --git a/Linphone/UI/Main/Fragments/SideMenu.swift b/Linphone/UI/Main/Fragments/SideMenu.swift
index 029f90ff1..e9fdc8d70 100644
--- a/Linphone/UI/Main/Fragments/SideMenu.swift
+++ b/Linphone/UI/Main/Fragments/SideMenu.swift
@@ -43,19 +43,44 @@ struct SideMenu: View {
HStack {
List {
- Text("My Profile").onTapGesture {
- print("My Profile")
- }
- Text("Send logs").onTapGesture {
- sendLogs()
- }
- Text("Clear logs").onTapGesture {
- print("Clear logs")
- Core.resetLogCollection()
- }
- Text("Logout").onTapGesture {
- print("Logout")
- }
+ /*
+ Text("My Profile")
+ .frame(height: 40)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .background(Color.white)
+ .onTapGesture {
+ print("My Profile")
+ self.menuClose()
+ }
+ */
+ Text("Send logs")
+ .frame(height: 40)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .background(Color.white)
+ .onTapGesture {
+ print("Send logs")
+ sendLogs()
+ self.menuClose()
+ }
+ Text("Clear logs")
+ .frame(height: 40)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .background(Color.white)
+ .onTapGesture {
+ print("Clear logs")
+ clearLogs()
+ self.menuClose()
+ }
+ /*
+ Text("Logout")
+ .frame(height: 40)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .background(Color.white)
+ .onTapGesture {
+ print("Logout")
+ self.menuClose()
+ }
+ */
}
.frame(width: self.width - safeAreaInsets.leading)
.background(Color.white)
@@ -75,4 +100,14 @@ struct SideMenu: View {
core.uploadLogCollection()
}
}
+
+ func clearLogs() {
+ coreContext.doOnCoreQueue { core in
+ Core.resetLogCollection()
+ DispatchQueue.main.async {
+ ToastViewModel.shared.toastMessage = "Success_clear_logs"
+ ToastViewModel.shared.displayToast = true
+ }
+ }
+ }
}
diff --git a/Linphone/UI/Main/Fragments/ToastView.swift b/Linphone/UI/Main/Fragments/ToastView.swift
index 40d5e7e16..565128b7e 100644
--- a/Linphone/UI/Main/Fragments/ToastView.swift
+++ b/Linphone/UI/Main/Fragments/ToastView.swift
@@ -48,12 +48,33 @@ struct ToastView: View {
.default_text_style(styleSize: 15)
.padding(8)
+ case "Success_clear_logs":
+ Text("Logs cleared")
+ .multilineTextAlignment(.center)
+ .foregroundStyle(Color.greenSuccess500)
+ .default_text_style(styleSize: 15)
+ .padding(8)
+
+ case "Success_send_logs":
+ Text("Logs URL copied into clipboard")
+ .multilineTextAlignment(.center)
+ .foregroundStyle(Color.greenSuccess500)
+ .default_text_style(styleSize: 15)
+ .padding(8)
+
case "Success_copied_into_clipboard":
Text("SIP address copied into clipboard")
.multilineTextAlignment(.center)
.foregroundStyle(Color.greenSuccess500)
.default_text_style(styleSize: 15)
.padding(8)
+
+ case let str where str.contains("is recording"):
+ Text(toastViewModel.toastMessage)
+ .multilineTextAlignment(.center)
+ .foregroundStyle(Color.redDanger500)
+ .default_text_style(styleSize: 15)
+ .padding(8)
case "Failed":
Text("Invalid QR code!")
@@ -93,19 +114,22 @@ struct ToastView: View {
.stroke(toastViewModel.toastMessage.contains("Success") ? Color.greenSuccess500 : Color.redDanger500, lineWidth: 1)
)
.onTapGesture {
- withAnimation {
- toastViewModel.toastMessage = ""
- toastViewModel.displayToast = false
- }
- }
- .onAppear {
- DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
+ if !toastViewModel.toastMessage.contains("is recording") {
withAnimation {
toastViewModel.toastMessage = ""
toastViewModel.displayToast = false
}
}
}
+ .onAppear {
+ if !toastViewModel.toastMessage.contains("is recording") {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
+ withAnimation {
+ toastViewModel.toastMessage = ""
+ toastViewModel.displayToast = false
+ }
+ }
+ } }
Spacer()
}
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 7ebc04890..a2fd12066 100644
--- a/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift
+++ b/Linphone/UI/Main/History/Fragments/HistoryContactFragment.swift
@@ -17,6 +17,8 @@
* along with this program. If not, see .
*/
+// swiftlint:disable line_length
+
import SwiftUI
import UniformTypeIdentifiers
@@ -30,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 {
@@ -70,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
@@ -96,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)
}
@@ -125,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()
@@ -192,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
@@ -221,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)
@@ -250,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)
@@ -282,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)
@@ -311,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)
@@ -336,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"
@@ -367,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) {
@@ -397,6 +404,7 @@ struct HistoryContactFragment: View {
Text("Appel")
.default_text_style(styleSize: 14)
+ .frame(minWidth: 80)
}
})
@@ -410,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 {
@@ -424,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) {
@@ -439,11 +457,6 @@ struct HistoryContactFragment: View {
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25)
- .onTapGesture {
- withAnimation {
-
- }
- }
}
.padding(16)
.background(Color.grayMain2c200)
@@ -451,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...
*/
+// swiftlint:disable line_length
+
import SwiftUI
import linphonesw
@@ -164,11 +166,11 @@ struct HistoryListFragment: View {
withAnimation {
if historyListViewModel.callLogs[index].dir == .Outgoing && historyListViewModel.callLogs[index].toAddress != nil {
telecomManager.doCallWithCore(
- addr: historyListViewModel.callLogs[index].toAddress!
+ addr: historyListViewModel.callLogs[index].toAddress!, isVideo: false
)
} else if historyListViewModel.callLogs[index].fromAddress != nil {
telecomManager.doCallWithCore(
- addr: historyListViewModel.callLogs[index].fromAddress!
+ addr: historyListViewModel.callLogs[index].fromAddress!, isVideo: false
)
}
historyViewModel.displayedCall = nil
@@ -211,9 +213,13 @@ struct HistoryListFragment: View {
.padding(.all)
)
}
+ .navigationTitle("")
+ .navigationBarHidden(true)
}
}
#Preview {
HistoryListFragment(historyListViewModel: HistoryListViewModel(), historyViewModel: HistoryViewModel(), showingSheet: .constant(false))
}
+
+// swiftlint:enable line_length
diff --git a/Linphone/UI/Main/History/Fragments/StartCallFragment.swift b/Linphone/UI/Main/History/Fragments/StartCallFragment.swift
index 60ff5196d..7a391f3de 100644
--- a/Linphone/UI/Main/History/Fragments/StartCallFragment.swift
+++ b/Linphone/UI/Main/History/Fragments/StartCallFragment.swift
@@ -90,6 +90,9 @@ struct StartCallFragment: View {
magicSearch.currentFilterSuggestions = newValue
magicSearch.searchForSuggestions()
}
+ .simultaneousGesture(TapGesture().onEnded {
+ showingDialer = false
+ })
HStack {
Button(action: {
@@ -105,10 +108,18 @@ struct StartCallFragment: View {
if startCallViewModel.searchField.isEmpty {
Button(action: {
- isSearchFieldFocused = false
-
- DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
- showingDialer.toggle()
+ if !showingDialer {
+ isSearchFieldFocused = false
+
+ DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
+ showingDialer = true
+ }
+ } else {
+ showingDialer = false
+
+ DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
+ isSearchFieldFocused = true
+ }
}
}, label: {
Image(!showingDialer ? "dialer" : "keyboard")
@@ -155,7 +166,7 @@ struct StartCallFragment: View {
.padding(.horizontal, 16)
}
- ContactsListFragment(contactViewModel: ContactViewModel(), contactsListViewModel: ContactsListViewModel(), showingSheet: .constant(false), startCallFunc: { addr in
+ ContactsListFragment(contactViewModel: ContactViewModel(), contactsListViewModel: ContactsListViewModel(), showingSheet: .constant(false), startCallFunc: { addr in
showingDialer = false
DispatchQueue.global().asyncAfter(deadline: .now() + 0.2) {
@@ -169,10 +180,10 @@ struct StartCallFragment: View {
withAnimation {
isShowStartCallFragment.toggle()
- telecomManager.doCallWithCore(addr: addr)
+ telecomManager.doCallWithCore(addr: addr, isVideo: false)
}
})
- .padding(.horizontal, 16)
+ .padding(.horizontal, 16)
HStack(alignment: .center) {
Text("Suggestions")
@@ -208,6 +219,25 @@ struct StartCallFragment: View {
var suggestionsList: some View {
ForEach(0.. 5.3.0-alpha'
+ pod 'linphone-sdk', '~> 5.4.0-alpha'
else
pod 'linphone-sdk', :path => ENV['PODFILE_PATH'] # local sdk
end
-
+
+ crashlytics
end
-
+def crashlytics
+ if not ENV['USE_CRASHLYTICS'].nil?
+ pod 'Firebase/Analytics'
+ pod 'Firebase/Crashlytics'
+ end
+end
target 'Linphone' do
# Comment the next line if you don't want to use dynamic frameworks
@@ -25,9 +31,35 @@ target 'Linphone' do
end
post_install do |installer|
- installer.pods_project.targets.each do |target|
- target.build_configurations.each do |config|
- config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
- end
- end
-end
\ No newline at end of file
+ app_project = Xcodeproj::Project.open(Dir.glob("*.xcodeproj")[0])
+ app_project.native_targets.each do |target|
+ target.build_configurations.each do |config|
+ if target.name == "Linphone" || target.name == 'msgNotificationService' || target.name == 'msgNotificationContent'
+ if ENV['USE_CRASHLYTICS'].nil?
+ if config.name == "Debug" then
+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) DEBUG=1'
+ else
+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited)'
+ end
+ config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited)'
+ else
+ # activate crashlytics
+ if config.name == "Debug" then
+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) DEBUG=1 USE_CRASHLYTICS=1'
+ else
+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) USE_CRASHLYTICS=1'
+ end
+ config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -DUSE_CRASHLYTICS'
+ end
+ end
+
+ app_project.save
+ end
+ end
+ installer.pods_project.targets.each do |target|
+ target.build_configurations.each do |config|
+ config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
+ end
+ end
+end
+