Kaynağa Gözat

update call ios

alqindiirsyam 5 ay önce
ebeveyn
işleme
10b2681138

BIN
.DS_Store


+ 1 - 0
.gitignore

@@ -47,6 +47,7 @@ Podfile.lock
 # Carthage/Build
 
 .DS_Store
+AppBuilder/.DS_Store
 ExampleCode/ExampleCode.xcodeproj/xcshareddata/xcschemes/ExampleCode.xcscheme
 NexilisLite/.DS_Store
 ExampleCode/ExampleCode/Info.plist

BIN
AppBuilder/.DS_Store


+ 29 - 29
AppBuilder/AppBuilder.xcodeproj/project.pbxproj

@@ -14,6 +14,7 @@
 		2401CEA1275490DB00B323BB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2401CE9F275490DB00B323BB /* Main.storyboard */; };
 		2401CEA3275490E600B323BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2401CEA2275490E600B323BB /* Assets.xcassets */; };
 		2401CEA6275490E600B323BB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2401CEA4275490E600B323BB /* LaunchScreen.storyboard */; };
+		96B80D4A8C5412783B69D43B /* Pods_AppBuilder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A30E22DC0886B4154F6F01E5 /* Pods_AppBuilder.framework */; };
 		A413B18727EACB20006D16EB /* PrefsUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = A413B18627EACB20006D16EB /* PrefsUtil.swift */; };
 		A42ED92227F30BA200B0FAB7 /* FirstTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42ED92127F30BA200B0FAB7 /* FirstTabViewController.swift */; };
 		A42ED92427F3FC2F00B0FAB7 /* SecondTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42ED92327F3FC2F00B0FAB7 /* SecondTabViewController.swift */; };
@@ -32,7 +33,6 @@
 		CD9D59E32BEE1D30008014B4 /* nu_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = CD9D59D82BEE1D30008014B4 /* nu_icon.png */; };
 		CDFA682D2D841F6200A13E90 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDFA68292D841F6200A13E90 /* MainInterface.storyboard */; };
 		CDFA682E2D841F6200A13E90 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDFA682A2D841F6200A13E90 /* ShareViewController.swift */; };
-		D1E579A46512EF4E61108DA3 /* Pods_AppBuilder.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1DD646CE636AEAED9C2B9F1 /* Pods_AppBuilder.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -79,8 +79,9 @@
 		2401CEA2275490E600B323BB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		2401CEA5275490E600B323BB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 		2401CEA7275490E600B323BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		971BA5158836AF0479DD23C0 /* Pods-AppBuilder.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.release.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.release.xcconfig"; sourceTree = "<group>"; };
-		9A683397DBBCCA9123509CD6 /* Pods-AppBuilder.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.debug.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.debug.xcconfig"; sourceTree = "<group>"; };
+		342E481F45271A8F546A3439 /* Pods-AppBuilder.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.release.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.release.xcconfig"; sourceTree = "<group>"; };
+		39B5DF7983B180E7215C32F7 /* Pods-AppBuilder.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppBuilder.debug.xcconfig"; path = "Target Support Files/Pods-AppBuilder/Pods-AppBuilder.debug.xcconfig"; sourceTree = "<group>"; };
+		A30E22DC0886B4154F6F01E5 /* Pods_AppBuilder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppBuilder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		A413B18627EACB20006D16EB /* PrefsUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsUtil.swift; sourceTree = "<group>"; };
 		A42ED92127F30BA200B0FAB7 /* FirstTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstTabViewController.swift; sourceTree = "<group>"; };
 		A42ED92327F3FC2F00B0FAB7 /* SecondTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondTabViewController.swift; sourceTree = "<group>"; };
@@ -102,7 +103,6 @@
 		CDFA68272D841F6200A13E90 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		CDFA68282D841F6200A13E90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
 		CDFA682A2D841F6200A13E90 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
-		D1DD646CE636AEAED9C2B9F1 /* Pods_AppBuilder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppBuilder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -110,7 +110,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				D1E579A46512EF4E61108DA3 /* Pods_AppBuilder.framework in Frameworks */,
+				96B80D4A8C5412783B69D43B /* Pods_AppBuilder.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -129,9 +129,9 @@
 			children = (
 				2401CE98275490DB00B323BB /* AppBuilder */,
 				CDFA682B2D841F6200A13E90 /* AppBuilderShare */,
-				D555D5E529C625D02EB38D49 /* Frameworks */,
 				6E32BCCF4DE50EE1A90E8AAE /* Pods */,
 				2401CE97275490DB00B323BB /* Products */,
+				D3D46AA8BAC96331EAD320FC /* Frameworks */,
 			);
 			sourceTree = "<group>";
 		};
@@ -178,8 +178,8 @@
 		6E32BCCF4DE50EE1A90E8AAE /* Pods */ = {
 			isa = PBXGroup;
 			children = (
-				9A683397DBBCCA9123509CD6 /* Pods-AppBuilder.debug.xcconfig */,
-				971BA5158836AF0479DD23C0 /* Pods-AppBuilder.release.xcconfig */,
+				39B5DF7983B180E7215C32F7 /* Pods-AppBuilder.debug.xcconfig */,
+				342E481F45271A8F546A3439 /* Pods-AppBuilder.release.xcconfig */,
 			);
 			path = Pods;
 			sourceTree = "<group>";
@@ -195,10 +195,10 @@
 			path = AppBuilderShare;
 			sourceTree = "<group>";
 		};
-		D555D5E529C625D02EB38D49 /* Frameworks */ = {
+		D3D46AA8BAC96331EAD320FC /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				D1DD646CE636AEAED9C2B9F1 /* Pods_AppBuilder.framework */,
+				A30E22DC0886B4154F6F01E5 /* Pods_AppBuilder.framework */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -210,13 +210,13 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 2401CEC0275490E600B323BB /* Build configuration list for PBXNativeTarget "AppBuilder" */;
 			buildPhases = (
-				0FC96EABAB7E2B838F504E03 /* [CP] Check Pods Manifest.lock */,
+				93C598790EC62EDFDD159A1B /* [CP] Check Pods Manifest.lock */,
 				2401CE92275490DB00B323BB /* Sources */,
 				2401CE93275490DB00B323BB /* Frameworks */,
 				2401CE94275490DB00B323BB /* Resources */,
 				247E0A722796969200430E5F /* Embed Frameworks */,
 				CDEE3DD129B06E1E00B420E5 /* Embed Foundation Extensions */,
-				25AEE8905FF82EB55B58854D /* [CP] Embed Pods Frameworks */,
+				8676AB173528B9A1F4650145 /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -314,43 +314,43 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-		0FC96EABAB7E2B838F504E03 /* [CP] Check Pods Manifest.lock */ = {
+		8676AB173528B9A1F4650145 /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 			);
-			inputPaths = (
-				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
-				"${PODS_ROOT}/Manifest.lock",
-			);
-			name = "[CP] Check Pods Manifest.lock";
+			name = "[CP] Embed Pods Frameworks";
 			outputFileListPaths = (
-			);
-			outputPaths = (
-				"$(DERIVED_FILE_DIR)/Pods-AppBuilder-checkManifestLockResult.txt",
+				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-output-files.xcfilelist",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
-		25AEE8905FF82EB55B58854D /* [CP] Embed Pods Frameworks */ = {
+		93C598790EC62EDFDD159A1B /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 			);
-			name = "[CP] Embed Pods Frameworks";
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
 			outputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-AppBuilder-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AppBuilder/Pods-AppBuilder-frameworks.sh\"\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 /* End PBXShellScriptBuildPhase section */
@@ -535,7 +535,7 @@
 		};
 		2401CEC1275490E600B323BB /* Debug */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = 9A683397DBBCCA9123509CD6 /* Pods-AppBuilder.debug.xcconfig */;
+			baseConfigurationReference = 39B5DF7983B180E7215C32F7 /* Pods-AppBuilder.debug.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
@@ -571,7 +571,7 @@
 		};
 		2401CEC2275490E600B323BB /* Release */ = {
 			isa = XCBuildConfiguration;
-			baseConfigurationReference = 971BA5158836AF0479DD23C0 /* Pods-AppBuilder.release.xcconfig */;
+			baseConfigurationReference = 342E481F45271A8F546A3439 /* Pods-AppBuilder.release.xcconfig */;
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;

+ 1 - 1
AppBuilder/AppBuilder.xcodeproj/xcshareddata/xcschemes/AppBuilder.xcscheme

@@ -92,7 +92,7 @@
       buildConfiguration = "Debug">
    </AnalyzeAction>
    <ArchiveAction
-      buildConfiguration = "Debug"
+      buildConfiguration = "Release"
       revealArchiveInOrganizer = "YES">
    </ArchiveAction>
 </Scheme>

+ 1 - 0
AppBuilder/AppBuilder/AppDelegate.swift

@@ -35,6 +35,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
     
     func applicationWillTerminate(_ application: UIApplication) {
         APIS.willTerminate()
+        APIS.enterBackground()
     }
     
     private func registerForPushNotifications() {

+ 38 - 8
AppBuilder/AppBuilder/SecondTabViewController.swift

@@ -92,6 +92,7 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
     }()
     
     var fillteredData: [Any] = []
+    var fillteredMessages: [Chat] = []
     
     var isSearchBarEmpty: Bool {
         return searchController.searchBar.text!.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
@@ -117,11 +118,15 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
             default:
                 if selectedTag == 0 {
                     var group_id: String?
-                    if let filterGroupKey = self.chatGroupMaps.first(where: { $0.value.contains { $0.name.lowercased().contains(searchText.lowercased()) || $0.groupName.lowercased().contains(searchText.lowercased()) || $0.messageText.lowercased().contains(searchText.lowercased()) } } ) {
+                    if let filterGroupKey = self.chatGroupMaps.first(where: { $0.value.contains { $0.name.lowercased().contains(searchText.lowercased()) || $0.groupName.lowercased().contains(searchText.lowercased()) } } ) {
                         group_id = filterGroupKey.key
                     }
                     let deepCopyChats = self.chats.map{ $0.copy() }
-                    fillteredData = deepCopyChats.filter { $0.name.lowercased().contains(searchText.lowercased()) || $0.messageText.lowercased().contains(searchText.lowercased()) || $0.groupId == group_id }
+                    fillteredData = deepCopyChats.filter { $0.name.lowercased().contains(searchText.lowercased()) || $0.groupId == group_id }
+                    if searchText.count > 1 {
+//                        fillteredMessages = Chat.getMessageFromSearch(text: searchText)
+//                        print("SEKUTT \(fillteredMessages.count)")
+                    }
                 } else {
                     switch(selectedTag) {
                     case UNREAD_TAG :
@@ -1328,6 +1333,8 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
         if isFiltering {
             if segment.selectedSegmentIndex == 1 {
                 return fillteredData.count
+            } else if segment.selectedSegmentIndex == 0 && fillteredMessages.count > 0 {
+                return 2
             }
             return 1
         } else {
@@ -1338,6 +1345,27 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
         }
     }
     
+    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
+        if isFiltering && segment.selectedSegmentIndex == 0 && section == 1 && fillteredMessages.count > 0 {
+            return 20
+        }
+        return 0.0
+    }
+    
+    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+        let containerView = UIView()
+        containerView.backgroundColor = .clear
+        if isFiltering && segment.selectedSegmentIndex == 0 && section == 1 && fillteredMessages.count > 0 {
+            let titleMessages = UILabel()
+            titleMessages.text = "Messages".localized()
+            titleMessages.font = .systemFont(ofSize: 16, weight: .medium)
+            titleMessages.textColor = .label
+            containerView.addSubview(titleMessages)
+            titleMessages.anchor(left: containerView.leftAnchor, paddingLeft: 10, centerY: containerView.centerYAnchor)
+        }
+        return containerView
+    }
+    
     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         var value = 0
         if isFiltering {
@@ -1353,14 +1381,16 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                 } else {
                     value = 1
                 }
-            } else {
+            } else if segment.selectedSegmentIndex == 0 && section == 0 {
                 value = fillteredData.count
-            }
-            if value == 0 {
-                value = 1
-                tableView.separatorStyle = .none
+                if value == 0 {
+                    value = 1
+                    tableView.separatorStyle = .none
+                } else {
+                    tableView.separatorStyle = .singleLine
+                }
             } else {
-                tableView.separatorStyle = .singleLine
+                
             }
             return value
         }

BIN
NexilisLite/.DS_Store


+ 1 - 1
NexilisLite/NexilisLite.podspec

@@ -24,7 +24,7 @@ Pod::Spec.new do |spec|
   spec.resource_bundles = { 'NexilisLite' => ['NexilisLite/Resource/**/*']}
   spec.swift_version = '5.5.1'
   spec.dependency 'FMDB', '~> 2.7.12'
-  spec.dependency 'nuSDKService', '4.0.9'
+  spec.dependency 'nuSDKService', '4.0.17'
   spec.dependency 'NotificationBannerSwift'
   spec.dependency 'Alamofire', '~> 5.10.2'
   spec.dependency 'SDWebImage', '~> 5.20.0'

+ 14 - 21
NexilisLite/NexilisLite/Source/APIS.swift

@@ -907,27 +907,12 @@ public class APIS: NSObject {
     public static var uuidCall: UUID?
     public static var fpinCall: String?
     public static func showNotificationNexilis(_ userInfo: [AnyHashable : Any]) {
-//        let center = UNUserNotificationCenter.current()
-//        let content = UNMutableNotificationContent()
-//        content.title = "showNotificationNexilis"
-//        content.body = ""
-//        content.sound = .default
-//        content.userInfo = userInfo
-//        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
-//        let request = UNNotificationRequest(identifier: "HJK", content: content, trigger: trigger)
-//        center.add(request) { error in
-//            if let error = error {
-//                print("Error scheduling notification: \(error.localizedDescription)")
-//            }
-//        }
         if checkAppStateisBackground() {
             DispatchQueue.main.async {
                 if let payload = userInfo["payload"] as? [String: Any] {
                     if let messagePayload = payload["message"] as? [String: Any] {
                         if let data = messagePayload["data"] as? [String: Any] {
                             let code = data["nx_code"] as? String ?? ""
-                            while (!API.bnuSDKServiceReady() || API.nGetCLXConnState() == 0) {
-                            }
                             if code == "CL01" {
                                 if let message = data["bodies"] as? [String: String] {
                                     let messageToSave = TMessage()
@@ -953,6 +938,7 @@ public class APIS: NSObject {
                                     APIS.addNotificationNexilis(messageToSave)
                                 }
                             } else if code == "CL03" {
+                                print("Print notif call")
                                 let callFromName = data["call-from-name"] as? String ?? ""
                                 let callFrom = data["call-from"] as? String ?? ""
                                 let callType = data["call-type"] as? String ?? ""
@@ -966,7 +952,7 @@ public class APIS: NSObject {
     //                                            print("Incoming call reported successfully")
     //                                        }
     //                                    }
-                                copySoundToLocalPath("pb_call_in", false)
+                                copySoundToLocalPath("pb_call_in_ios", false)
                                 let center = UNUserNotificationCenter.current()
                                 let content = UNMutableNotificationContent()
                                 content.title = callFromName
@@ -976,7 +962,7 @@ public class APIS: NSObject {
                                     content.body = "Incoming Video Call".localized()
                                 }
                                 content.userInfo = ["id" : callFrom, "type" : code, "callType": callType]
-                                content.sound = UNNotificationSound(named: UNNotificationSoundName("pb_call_in.mp3"))
+                                content.sound = UNNotificationSound(named: UNNotificationSoundName("pb_call_in_ios.mp3"))
                                 let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
                                 let request = UNNotificationRequest(identifier: callFrom, content: content, trigger: trigger)
                                 center.add(request) { error in
@@ -1143,6 +1129,11 @@ public class APIS: NSObject {
                     } catch {
                         
                     }
+                } else {
+                    sourceURL = Bundle.resourceBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
+                    if sourceURL == nil {
+                        sourceURL = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: nameSound, withExtension: "mp3")
+                    }
                 }
             }
         } else {
@@ -1323,7 +1314,9 @@ public class APIS: NSObject {
     }
     
     public static func enterBackground() {
-        UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
+        if !API.bAVisOngoing() {
+            API.deinitConnection()
+        }
     }
     
     public static func enterForeground() {
@@ -1334,10 +1327,10 @@ public class APIS: NSObject {
                 UIApplication.shared.registerForRemoteNotifications()
             }
         })
-        DispatchQueue.global().async {
+        DispatchQueue.main.async {
             do {
-                if !Nexilis.afterConnect {
-                    var id = Utils.getConnectionID()
+                if !Nexilis.afterConnect && API.nGetCLXConnState() == 0 {
+                    let id = Utils.getConnectionID()
                     try API.initConnection(sAPIK: Nexilis.sAPIKey, cbiI: Callback(), sTCPAddr: Nexilis.ADDRESS, nTCPPort: Nexilis.PORT, sUserID: id, sStartWH: "09:00")
                 }
 //                listIdentifierNotif.removeAll()

+ 32 - 10
NexilisLite/NexilisLite/Source/Model/Chat.swift

@@ -127,15 +127,37 @@ public class Chat: Model {
         return ""
     }
     
-    public static func getMessageFromSearch(text: String = "") -> [String] {
-        var messages: [String] = []
+    public static func getMessageFromSearch(text: String = "") -> [Chat] {
+        var messages: [Chat] = []
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
             do {
-                let query = "select message_id FROM MESSAGE where message_text LIKE '%\(text)%'"
+                let query = "m.f_pin, m.l_pin, m.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.first_name || ' ' || ifnull(b.last_name, '') name, b.image_id profile, b.official_account, m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name from MESSAGE m, BUDDY b where m.l_pin = b.f_pin and m.is_call_center = 0 and message_text LIKE '%\(text)%'"
                 if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: query) {
                     while cursorData.next() {
                         let data = cursorData.string(forColumnIndex: 0) ?? ""
-                        messages.append(data)
+                        let chat = Chat(fpin: cursorData.string(forColumnIndex: 0) ?? "",
+                                        pin: cursorData.string(forColumnIndex: 1) ?? "",
+                                        messageId: cursorData.string(forColumnIndex: 2) ?? "",
+                                        counter: cursorData.string(forColumnIndex: 3) ?? "",
+                                        messageText: cursorData.string(forColumnIndex: 4) ?? "",
+                                        serverDate: cursorData.string(forColumnIndex: 5) ?? "",
+                                        image: cursorData.string(forColumnIndex: 6) ?? "",
+                                        video: cursorData.string(forColumnIndex: 7) ?? "",
+                                        file: cursorData.string(forColumnIndex: 8) ?? "",
+                                        attachmentFlag: cursorData.string(forColumnIndex: 9) ?? "",
+                                        messageScope: cursorData.string(forColumnIndex: 10) ?? "",
+                                        name: cursorData.string(forColumnIndex: 11) ?? "",
+                                        profile: cursorData.string(forColumnIndex: 12) ?? "",
+                                        official: cursorData.string(forColumnIndex: 13) ?? "",
+                                        status: cursorData.string(forColumnIndex: 14) ?? "",
+                                        credential: cursorData.string(forColumnIndex: 15) ?? "",
+                                        lock: cursorData.string(forColumnIndex: 16) ?? "",
+                                        thumb: "",
+                                        audio: cursorData.string(forColumnIndex: 17) ?? "",
+                                        gif: cursorData.string(forColumnIndex: 18) ?? "",
+                                        groupId: cursorData.string(forColumnIndex: 19) ?? "",
+                                        groupName: cursorData.string(forColumnIndex: 20) ?? "")
+                        messages.append(chat)
                     }
                     cursorData.close()
                 }
@@ -159,7 +181,7 @@ public class Chat: Model {
 //        })
 //    }
     
-    public static func getData(messageId: String = "", isImage: Bool = false, isDoc: Bool = false, isVideo: Bool = false, isGIF: Bool = false, isLink: Bool = false, isAudio: Bool = false) -> [Chat] {
+    public static func getData(isImage: Bool = false, isDoc: Bool = false, isVideo: Bool = false, isGIF: Bool = false, isLink: Bool = false, isAudio: Bool = false) -> [Chat] {
         var chats: [Chat] = []
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
             do {
@@ -178,15 +200,15 @@ public class Chat: Model {
                     lastQuery = "m.audio_id IS NOT NULL AND m.audio_id != ''"
                 }
                 var query = """
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.first_name || ' ' || ifnull(b.last_name, '') name, b.image_id profile, b.official_account, m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name from MESSAGE_SUMMARY ms, MESSAGE m, BUDDY b where ms.l_pin = b.f_pin and ms.message_id = m.message_id \(messageId.isEmpty ? "" : " and m.message_id = '\(messageId)'") and m.is_call_center = 0
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.first_name || ' ' || ifnull(b.last_name, '') name, b.image_id profile, b.official_account, m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name from MESSAGE_SUMMARY ms, MESSAGE m, BUDDY b where ms.l_pin = b.f_pin and ms.message_id = m.message_id and m.is_call_center = 0
                             union
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'Bot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name from MESSAGE_SUMMARY ms, MESSAGE m where ms.l_pin = '-999' and ms.message_id = m.message_id\(messageId.isEmpty ? "" : " and m.message_id = '\(messageId)'")
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'Bot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name from MESSAGE_SUMMARY ms, MESSAGE m where ms.l_pin = '-999' and ms.message_id = m.message_id
                             union
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'GPT SmartBot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name from MESSAGE_SUMMARY ms, MESSAGE m where ms.l_pin = '-997' and ms.message_id = m.message_id\(messageId.isEmpty ? "" : " and m.message_id = '\(messageId)'")
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'GPT SmartBot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name from MESSAGE_SUMMARY ms, MESSAGE m where ms.l_pin = '-997' and ms.message_id = m.message_id
                             union
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, '\("Lounge".localized())' name, b.image_id profile, b.official, m.status, m.credential, m.lock, m.audio_id, m.gif_id, b.group_id, b.f_name group_name from MESSAGE_SUMMARY ms, MESSAGE m, GROUPZ b where ms.l_pin = b.group_id and ms.message_id = m.message_id \(messageId.isEmpty ? "" : " and m.message_id = '\(messageId)'") and m.is_call_center = 0
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, '\("Lounge".localized())' name, b.image_id profile, b.official, m.status, m.credential, m.lock, m.audio_id, m.gif_id, b.group_id, b.f_name group_name from MESSAGE_SUMMARY ms, MESSAGE m, GROUPZ b where ms.l_pin = b.group_id and ms.message_id = m.message_id and m.is_call_center = 0
                             union
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.title, c.image_id profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, c.group_id, c.f_name group_name from MESSAGE_SUMMARY ms, MESSAGE m, DISCUSSION_FORUM b, GROUPZ c where b.group_id = c.group_id and ms.l_pin = b.chat_id and ms.message_id = m.message_id \(messageId.isEmpty ? "" : " and m.message_id = '\(messageId)'") and m.is_call_center = 0
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.title, c.image_id profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, c.group_id, c.f_name group_name from MESSAGE_SUMMARY ms, MESSAGE m, DISCUSSION_FORUM b, GROUPZ c where b.group_id = c.group_id and ms.l_pin = b.chat_id and ms.message_id = m.message_id and m.is_call_center = 0
                             order by 6 desc
                             """
                 if !lastQuery.isEmpty {

+ 35 - 68
NexilisLite/NexilisLite/Source/Nexilis.swift

@@ -178,6 +178,7 @@ public class Nexilis: NSObject {
                 if address.isEmpty {
                     return
                 }
+                print("HUHU>> \(API.sGetVersion())")
                 var id = Utils.getConnectionID()
                 Nexilis.ADDRESS = address.components(separatedBy: ":")[0]
                 Nexilis.PORT = Int(address.components(separatedBy: ":")[1]) ?? 0
@@ -312,13 +313,21 @@ public class Nexilis: NSObject {
             ringtonePath = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_call_in_ios", withExtension: "mp3")
         }
         if let a = ringtonePath {
-            AudioServicesCreateSystemSoundID(a as CFURL, &ringtoneID)
-            AudioServicesPlaySystemSound(ringtoneID)
+//            AudioServicesCreateSystemSoundID(a as CFURL, &ringtoneID)
+//            AudioServicesPlaySystemSound(ringtoneID)
+            do {
+                Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: a)
+                Nexilis.sharedAudioPlayer?.prepareToPlay()
+                Nexilis.sharedAudioPlayer?.play()
+            } catch {
+                
+            }
         }
     }
     
     public static func stopRingtoneCall() {
-        AudioServicesDisposeSystemSoundID(ringtoneID)
+//        AudioServicesDisposeSystemSoundID(ringtoneID)
+        Nexilis.sharedAudioPlayer?.stop()
     }
     
     private static var ringBackToneID: SystemSoundID = 0
@@ -329,13 +338,22 @@ public class Nexilis: NSObject {
             ringbacktonePath = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_call_out_ios", withExtension: "mp3")
         }
         if let a = ringbacktonePath {
-            AudioServicesCreateSystemSoundID(a as CFURL, &ringBackToneID)
-            AudioServicesPlaySystemSound(ringBackToneID)
+//            AudioServicesCreateSystemSoundID(a as CFURL, &ringBackToneID)
+//            AudioServicesPlaySystemSound(ringBackToneID)
+            do {
+                Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: a)
+                Nexilis.sharedAudioPlayer?.prepareToPlay()
+                Nexilis.sharedAudioPlayer?.play()
+                Nexilis.sharedAudioPlayer?.numberOfLoops = -1
+            } catch {
+                
+            }
         }
     }
     
     public static func stopRingbacktoneCall() {
-        AudioServicesDisposeSystemSoundID(ringBackToneID)
+//        AudioServicesDisposeSystemSoundID(ringBackToneID)
+        Nexilis.sharedAudioPlayer?.stop()
     }
     
     private static var busyToneID: SystemSoundID = 0
@@ -346,13 +364,21 @@ public class Nexilis: NSObject {
             busyPath = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_call_busy", withExtension: "mp3")
         }
         if let a = busyPath {
-            AudioServicesCreateSystemSoundID(a as CFURL, &busyToneID)
-            AudioServicesPlaySystemSound(busyToneID)
+//            AudioServicesCreateSystemSoundID(a as CFURL, &busyToneID)
+//            AudioServicesPlaySystemSound(busyToneID)
+            do {
+                Nexilis.sharedAudioPlayer = try AVAudioPlayer(contentsOf: a)
+                Nexilis.sharedAudioPlayer?.prepareToPlay()
+                Nexilis.sharedAudioPlayer?.play()
+            } catch {
+                
+            }
         }
     }
     
     public static func stopBusyCall() {
-        AudioServicesDisposeSystemSoundID(busyToneID)
+//        AudioServicesDisposeSystemSoundID(busyToneID)
+        Nexilis.sharedAudioPlayer?.stop()
     }
     
     public static func addFB(viewController: UIViewController, fromMAB: Bool) {
@@ -1049,65 +1075,6 @@ public class Nexilis: NSObject {
         }
     }
 
-    
-//    public static func initiateAudio() {
-//        do {
-//            try AVAudioSession.sharedInstance().setPreferredSampleRate(AVAudioSession.sharedInstance().sampleRate)
-//        } catch {
-//        }
-//    }
-    
-//    public static func startAudio(isVideo: Bool = true) {
-//        do {
-//            try AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: .defaultToSpeaker)
-//            try AVAudioSession.sharedInstance().setMode(.voiceChat)
-//            try AVAudioSession.sharedInstance().overrideOutputAudioPort(isVideo ? .speaker : .none)
-//            try AVAudioSession.sharedInstance().setActive(true)
-//        } catch {
-//        }
-//    }
-//
-//    public static func stopAudio() {
-//        do {
-//            try AVAudioSession.sharedInstance().setCategory(.soloAmbient)
-//            try AVAudioSession.sharedInstance().setMode(.default)
-//            try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
-//            try AVAudioSession.sharedInstance().setActive(true)
-//        } catch {
-//        }
-//    }
-    
-    public static func muteMicrophone(isMute: Bool!){
-        do {
-            if(isMute){
-                try AVAudioSession.sharedInstance().setCategory(.playback)
-            }
-            else{
-                try AVAudioSession.sharedInstance().setCategory(.playAndRecord)
-            }
-        }catch{
-            //print(error)
-        }
-    }
-    
-    public static func setSpeakerphoneOn(_ isOn: Bool){
-        let audioSession = AVAudioSession.sharedInstance()
-        
-        do {
-            try audioSession.setCategory(.playAndRecord, mode: .default, options: [])
-            
-            try audioSession.setActive(true)
-            
-            if isOn {
-                try audioSession.overrideOutputAudioPort(.speaker)
-            } else {
-                try audioSession.overrideOutputAudioPort(.none)
-            }
-        } catch {
-            print("Error setting up audio session: \(error.localizedDescription)")
-        }
-    }
-
     public static func buttonClicked(index: Int, id: String = "") {
         //print("BTNCLICK \(index) \(id)")
         if index == IDX_QUEUE_SYSTEM || index == IDX_NEWS || index == IDX_SOCIAL_COMMERCE {

+ 0 - 6
NexilisLite/NexilisLite/Source/View/Call/QmeraAudioConference.swift

@@ -279,12 +279,6 @@ class QmeraAudioConference: UIViewController {
     @objc func didSpeaker(sender: Any?) {
         isSpeaker = !isSpeaker
         speaker.isSelected = isSpeaker
-//        do {
-//            if "iPhone 6" == "\(UIDevice().type)" {
-//                try AVAudioSession.sharedInstance().overrideOutputAudioPort(isSpeaker ? .speaker : .none)
-//            }
-//        } catch {
-//        }
     }
     
     @objc func didInvite(sender: Any?) {

+ 73 - 28
NexilisLite/NexilisLite/Source/View/Call/QmeraAudioViewController.swift

@@ -13,11 +13,12 @@ import MediaPlayer
 
 class QmeraAudioViewController: UIViewController {
     
-    static private let nMaxSPOn: Float! = 100.0
-    static private let nMaxSPOff: Float! = 5.0
+    static private let nMaxSPOn: Float! = 10.0
+    static private let nMaxSPOff: Float! = 9.0
     static private var volumeView: MPVolumeView!
-    static private var bSpeakerPhone: Bool! = false
     static private var lastVolume: Float! = AVAudioSession.sharedInstance().outputVolume
+    static private var bSpeakerPhone: Bool! = false
+    static private var isLoop = false
     
     
     let stackViewToolbar2 = UIStackView()
@@ -84,7 +85,7 @@ class QmeraAudioViewController: UIViewController {
     
     private var firstCall: Bool = true
     
-    private var isSpeaker: Bool = true
+//    private var isSpeaker: Bool = false
     
     private var isMuted: Bool = false
     
@@ -261,47 +262,72 @@ class QmeraAudioViewController: UIViewController {
         return button
     }()
     
-    static func turnSpeakerOn(bSpeakerOn: Bool!) {
-        bSpeakerPhone = bSpeakerOn
+    static func turnSpeakerOn() {
+        bSpeakerPhone = !bSpeakerPhone
+        var bAudioEngineIsAvtive: Bool! = false
+        repeat {
+            API.turnSpeakerPhone(bSPon: bSpeakerPhone!)
+            bAudioEngineIsAvtive = API.bAudioEngineIsRunning()
+            print("Audio Session State: \(bAudioEngineIsAvtive ? "Active" : "Inactive" )")
+            if (bAudioEngineIsAvtive) {
+                break
+            }
+        } while (!bAudioEngineIsAvtive)
         var volume:Float! = 0
         if (bSpeakerPhone) {
+            UIDevice.current.isProximityMonitoringEnabled = false
             volume = lastVolume * nMaxSPOn
         } else {
+            UIDevice.current.isProximityMonitoringEnabled = true
             volume = lastVolume * nMaxSPOff
         }
         API.adjustVolume(fValue: volume)
     }
     
+//    static func toggleSpeakerPhone() {
+//        bSpeakerPhone = !bSpeakerPhone
+//        var volume:Float! = 0
+//        if (bSpeakerPhone) {
+//            volume = lastVolume * nMaxSPOn
+//        } else {
+//            volume = lastVolume * nMaxSPOff
+//        }
+//        API.adjustVolume(fValue: volume)
+//    }
+    
     override func viewWillDisappear(_ animated: Bool) {
         UIDevice.current.isProximityMonitoringEnabled = false
         Nexilis.floatingButton.isHidden = false
         Nexilis.callAPNActivated = false
+        backToDefaultAudioSession()
     }
     
     deinit {
-        print("DEINIT.....!!!!!!")
         UIDevice.current.isProximityMonitoringEnabled = false
         Nexilis.floatingButton.isHidden = false
         Nexilis.callAPNActivated = false
         NotificationCenter.default.removeObserver(self)
         AVAudioSession.sharedInstance().removeObserver(self, forKeyPath: "outputVolume")
+        QmeraAudioViewController.isLoop = false
+        backToDefaultAudioSession()
     }
     
-    override func viewDidAppear(_ animated: Bool) {
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onShowAC"), object: nil, userInfo: nil)
-    }
-    
-    override func viewDidLoad() {
-        super.viewDidLoad()
+    private func backToDefaultAudioSession() {
         do {
             let audioSession = AVAudioSession.sharedInstance()
-            try audioSession.setCategory(.playAndRecord, mode: .default)
+            try audioSession.setCategory(.playAndRecord, mode: .default, options: [.allowBluetooth])
             try audioSession.overrideOutputAudioPort(.speaker)
-            try audioSession.setPreferredSampleRate(48000.0)
             try audioSession.setActive(true)
         } catch {
-            print("Failed to configure audio session: \(error)")
         }
+    }
+    
+    override func viewDidAppear(_ animated: Bool) {
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onShowAC"), object: nil, userInfo: nil)
+    }
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
         QmeraAudioViewController.volumeView = MPVolumeView(frame: .zero)
         QmeraAudioViewController.volumeView.isHidden = true
 
@@ -467,7 +493,6 @@ class QmeraAudioViewController: UIViewController {
     }
     
     private func incomingView() {
-//        Nexilis.setSpeakerphoneOn(isSpeaker)
         Nexilis.playRingtoneCall()
         status.text = "Incoming..."
         
@@ -670,9 +695,8 @@ class QmeraAudioViewController: UIViewController {
     }
     
     @objc func didSpeaker(sender: Any?) {
-        isSpeaker = !isSpeaker
-        speaker.isSelected = isSpeaker
-        QmeraAudioViewController.turnSpeakerOn(bSpeakerOn: isSpeaker)
+        QmeraAudioViewController.turnSpeakerOn()
+        speaker.isSelected = QmeraAudioViewController.bSpeakerPhone
     }
     
     @objc func didMute(sender: Any?) {
@@ -846,9 +870,7 @@ class QmeraAudioViewController: UIViewController {
                     }
                 }
                 API.terminateCall(sParty: nil)
-                DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
-                    self.dismiss(animated: false, completion: nil)
-                }
+                self.dismiss(animated: false, completion: nil)
             } else {
 //                if let user = self.user, let call = Nexilis.shared.callManager.call(with: user.pin) {
 //                    Nexilis.shared.callManager.end(call: call)
@@ -930,6 +952,31 @@ class QmeraAudioViewController: UIViewController {
                         }
                     }
                 }
+            } else if state == Nexilis.STREAMING_SEMINAR_ENDED { // always call turnspeaker
+                QmeraAudioViewController.isLoop = true
+                DispatchQueue.global(qos: .userInitiated).async {
+                    repeat {
+                        Thread.sleep(forTimeInterval : 1)
+                        if (QmeraAudioViewController.isLoop && !API.bAudioEngineIsRunning()) {
+                            API.turnSpeakerPhone(bSPon: QmeraAudioViewController.bSpeakerPhone!)
+                        }
+                    } while (QmeraAudioViewController.isLoop)
+                }
+//                DispatchQueue.global().asyncAfter(deadline: .now() + 3, execute: {
+//                    API.turnSpeakerPhone(bSPon: QmeraAudioViewController.bSpeakerPhone!)
+//                })
+//                DispatchQueue.global().async {
+//                    var bAudioSessionIsAvtive: Bool! = false
+//                    repeat {
+//                        API.turnSpeakerPhone(bSPon: QmeraAudioViewController.bSpeakerPhone!)
+//                        let audioSession = AVAudioSession.sharedInstance()
+//                        bAudioSessionIsAvtive = !audioSession.secondaryAudioShouldBeSilencedHint
+//                        print("repeat turnSpeakerPhone >> \(bAudioSessionIsAvtive)")
+//                        if (bAudioSessionIsAvtive) {
+//                            break
+//                        }
+//                    } while (!bAudioSessionIsAvtive)
+//                }
             } else if state == Nexilis.AUDIO_CALL_RINGING || (!ticketId.isEmpty && state == Nexilis.VIDEO_CALL_RINGING) {
                 if users.count == 1 {
                     DispatchQueue.main.async {
@@ -997,6 +1044,7 @@ class QmeraAudioViewController: UIViewController {
                                 self.status.text = "Call Center Session has ended..."
                                 self.end.isEnabled = false
                             }
+                            QmeraAudioViewController.isLoop = false
                             DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                                 self.didEnd(sender: true)
                             }
@@ -1024,6 +1072,7 @@ class QmeraAudioViewController: UIViewController {
                             self.status.text = "Call Center Session has ended..."
                             self.end.isEnabled = false
                         }
+                        QmeraAudioViewController.isLoop = false
                         DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                             self.didEnd(sender: true)
                         }
@@ -1042,6 +1091,7 @@ class QmeraAudioViewController: UIViewController {
                                 controller!.dismiss(animated: true)
                             }
                         }
+                        QmeraAudioViewController.isLoop = false
                         DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                             self.didEnd(sender: true)
                         }
@@ -1053,11 +1103,6 @@ class QmeraAudioViewController: UIViewController {
                         }
                     }
                 }
-//                if users.count == 0 {
-//                    DispatchQueue.main.async {
-//                        self.dismiss(animated: false, completion: nil)
-//                    }
-//                }
             } else if state == Nexilis.OFFLINE { // Offline
                 DispatchQueue.main.async {
                     Nexilis.stopRingtoneCall()

+ 73 - 21
NexilisLite/NexilisLite/Source/View/Call/QmeraVideoViewController.swift

@@ -18,18 +18,19 @@ import MediaPlayer
 
 class QmeraVideoViewController: UIViewController {
     
-    static private let nMaxSPOn: Float! = 100.0
-    static private let nMaxSPOff: Float! = 5.0
+    static private let nMaxSPOn: Float! = 10.0
+    static private let nMaxSPOff: Float! = 9.0
     static private var volumeView: MPVolumeView!
-    static private var bSpeakerPhone: Bool! = false
     static private var lastVolume: Float! = AVAudioSession.sharedInstance().outputVolume
+    static private var bSpeakerPhone: Bool! = false
+    static private var isLoop = false
     
     
     var dataPerson: [[String: String?]] = []
     var fPin = ""
     var wbRoomId = ""
     var isInisiator = true
-    var isSpeaker = true
+//    var isSpeaker = false
     var isMuted = false
     var isPresent = false
     var callFCM = true
@@ -140,8 +141,17 @@ class QmeraVideoViewController: UIViewController {
         return button
     }()
     
-    static func turnSpeakerOn(bSpeakerOn: Bool!) {
-        bSpeakerPhone = bSpeakerOn
+    static func turnSpeakerOn() {
+        bSpeakerPhone = !bSpeakerPhone
+        var bAudioEngineIsAvtive: Bool! = false
+        repeat {
+            API.turnSpeakerPhone(bSPon: bSpeakerPhone!)
+            bAudioEngineIsAvtive = API.bAudioEngineIsRunning()
+            print("Audio Session State: \(bAudioEngineIsAvtive ? "Active" : "Inactive" )")
+            if (bAudioEngineIsAvtive) {
+                break
+            }
+        } while (!bAudioEngineIsAvtive)
         var volume:Float! = 0
         if (bSpeakerPhone) {
             volume = lastVolume * nMaxSPOn
@@ -150,6 +160,17 @@ class QmeraVideoViewController: UIViewController {
         }
         API.adjustVolume(fValue: volume)
     }
+
+//    static func toggleSpeakerPhone() {
+//        bSpeakerPhone = !bSpeakerPhone
+//        var volume:Float! = 0
+//        if (bSpeakerPhone) {
+//            volume = lastVolume * nMaxSPOn
+//        } else {
+//            volume = lastVolume * nMaxSPOff
+//        }
+//        API.adjustVolume(fValue: volume)
+//    }
     
     deinit {
         navigationController?.changeAppearance(clear: false)
@@ -160,6 +181,8 @@ class QmeraVideoViewController: UIViewController {
         NotificationCenter.default.removeObserver(self)
         Nexilis.floatingButton.isHidden = false
         Nexilis.callAPNActivated = false
+        QmeraVideoViewController.isLoop = false
+        backToDefaultAudioSession()
     }
     
     override func viewWillDisappear(_ animated: Bool) {
@@ -170,22 +193,24 @@ class QmeraVideoViewController: UIViewController {
             navigationController?.navigationBar.topItem?.backBarButtonItem = nil
             navigationController?.interactivePopGestureRecognizer?.isEnabled = true
             NotificationCenter.default.removeObserver(self)
+            backToDefaultAudioSession()
         }
         Nexilis.floatingButton.isHidden = false
         Nexilis.callAPNActivated = false
     }
-
-    override func viewDidLoad() {
-        super.viewDidLoad()
+    
+    private func backToDefaultAudioSession() {
         do {
             let audioSession = AVAudioSession.sharedInstance()
-            try audioSession.setCategory(.playAndRecord, mode: .default)
+            try audioSession.setCategory(.playAndRecord, mode: .default, options: .allowBluetooth)
             try audioSession.overrideOutputAudioPort(.speaker)
-            try audioSession.setPreferredSampleRate(48000.0)
             try audioSession.setActive(true)
         } catch {
-            print("Failed to configure audio session: \(error)")
         }
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
         QmeraVideoViewController.volumeView = MPVolumeView(frame: .zero)
         QmeraVideoViewController.volumeView.isHidden = true
         Nexilis.setWhiteboardReceiver(receiver: self)
@@ -710,7 +735,7 @@ class QmeraVideoViewController: UIViewController {
                     self.labelTimerVC.text = format
                 }
                 self.vcTimer.fire()
-                API.adjustVolume(fValue: 10.0)
+//                self.setSpeaker()
             }
         }
     }
@@ -888,9 +913,9 @@ class QmeraVideoViewController: UIViewController {
             buttonSpeaker.widthAnchor.constraint(equalToConstant: 70.0),
             buttonSpeaker.heightAnchor.constraint(equalToConstant: 70.0)
         ])
-        buttonSpeaker.setImage(UIImage(systemName: "speaker.wave.2", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
-        self.buttonSpeaker.backgroundColor = .lightGray
-        self.buttonSpeaker.tintColor = .mainColor
+        buttonSpeaker.backgroundColor = .secondaryColor
+        buttonSpeaker.tintColor = .mainColor
+        buttonSpeaker.setImage(UIImage(systemName: "speaker.slash", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
         buttonSpeaker.circle()
         buttonSpeaker.isHidden = true
         buttonSpeaker.addTarget(self, action: #selector(didTapSpeakerButton(sender:)), for: .touchUpInside)
@@ -1012,10 +1037,10 @@ class QmeraVideoViewController: UIViewController {
         dataPerson.removeAll()
     }
     
-    func setSpeaker(isSpeaker: Bool) {
-        QmeraVideoViewController.turnSpeakerOn(bSpeakerOn: isSpeaker)
+    func setSpeaker() {
         DispatchQueue.main.async {
-            if (isSpeaker) {
+            QmeraVideoViewController.turnSpeakerOn()
+            if (QmeraVideoViewController.bSpeakerPhone) {
                 self.buttonSpeaker.backgroundColor = .lightGray
                 self.buttonSpeaker.tintColor = .mainColor
                 self.buttonSpeaker.setImage(UIImage(systemName: "speaker.wave.2", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
@@ -1024,12 +1049,11 @@ class QmeraVideoViewController: UIViewController {
                 self.buttonSpeaker.tintColor = .mainColor
                 self.buttonSpeaker.setImage(UIImage(systemName: "speaker.slash", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
             }
-            self.isSpeaker = isSpeaker
         }
     }
     
     @objc func didTapSpeakerButton(sender: AnyObject){
-        setSpeaker(isSpeaker: !(self.isSpeaker))
+        setSpeaker()
     }
     
     @objc func didTapAddParticipantButton(sender: AnyObject){
@@ -1141,6 +1165,32 @@ class QmeraVideoViewController: UIViewController {
                 }
             }
         }
+        else if state == Nexilis.STREAMING_SEMINAR_ENDED { // always call turnspeaker
+            QmeraVideoViewController.isLoop = true
+            DispatchQueue.global(qos: .userInitiated).async {
+                repeat {
+                    Thread.sleep(forTimeInterval : 1)
+                    if (QmeraVideoViewController.isLoop && !API.bAudioEngineIsRunning()) {
+                        API.turnSpeakerPhone(bSPon: QmeraVideoViewController.bSpeakerPhone!)
+                    }
+                } while (QmeraVideoViewController.isLoop)
+            }
+//                DispatchQueue.global().asyncAfter(deadline: .now() + 3, execute: {
+//                    API.turnSpeakerPhone(bSPon: QmeraAudioViewController.bSpeakerPhone!)
+//                })
+//                DispatchQueue.global().async {
+//                    var bAudioSessionIsAvtive: Bool! = false
+//                    repeat {
+//                        API.turnSpeakerPhone(bSPon: QmeraAudioViewController.bSpeakerPhone!)
+//                        let audioSession = AVAudioSession.sharedInstance()
+//                        bAudioSessionIsAvtive = !audioSession.secondaryAudioShouldBeSilencedHint
+//                        print("repeat turnSpeakerPhone >> \(bAudioSessionIsAvtive)")
+//                        if (bAudioSessionIsAvtive) {
+//                            break
+//                        }
+//                    } while (!bAudioSessionIsAvtive)
+//                }
+        }
         else if (state == Nexilis.VIDEO_CALL_OFFHOOK) {
             DispatchQueue.main.async {
                 Nexilis.stopRingbacktoneCall()
@@ -1329,6 +1379,7 @@ class QmeraVideoViewController: UIViewController {
                         self.wbTimer.invalidate()
                         _ = Nexilis.getWhiteboardDelegate()?.terminate()
                     }
+                    QmeraVideoViewController.isLoop = false
                     DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                         self.endAllCall()
                         self.dismiss(animated: true, completion: nil)
@@ -1376,6 +1427,7 @@ class QmeraVideoViewController: UIViewController {
                     if controller != nil {
                         controller!.dismiss(animated: true)
                     }
+                    QmeraVideoViewController.isLoop = false
                     DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                         self.endAllCall()
                         if self.isInisiator && !self.isPresent {

+ 5 - 0
NexilisLite/NexilisLite/Source/View/Control/SettingTableViewController.swift

@@ -437,6 +437,7 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
     }
     
     public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        tableView.deselectRow(at: indexPath, animated: true)
         let item = Item.menuFor(section: indexPath.section)[indexPath.row]
         if item.title == "Personal Information".localized() {
             if(Nexilis.checkIsChangePerson()){
@@ -800,6 +801,10 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                 }
             }))
             self.present(alert, animated: true, completion: nil)
+        } else if item.title == "Version".localized() {
+            let alert = LibAlertController(title: "Version".localized(), message: API.sGetVersion() ?? "Unknown".localized(), preferredStyle: .alert)
+            alert.addAction(UIAlertAction(title: "Dismiss".localized(), style: UIAlertAction.Style.default, handler: nil))
+            self.present(alert, animated: true, completion: nil)
         }
     }
     

+ 1 - 1
NexilisLite/Podfile

@@ -7,7 +7,7 @@ target 'NexilisLite' do
 
   # Pods for NexilisLite
 
-  pod 'nuSDKService', '4.0.9'
+  pod 'nuSDKService', '4.0.17'
   pod 'FMDB', '~> 2.7.12'
   pod 'NotificationBannerSwift', :git => 'https://github.com/Daltron/NotificationBanner.git', :tag => '4.0.0'
   pod 'Alamofire', '~> 5.10.2'

BIN
StreamShield/.DS_Store


+ 1 - 1
StreamShield/Podfile

@@ -6,6 +6,6 @@ target 'StreamShield' do
   use_frameworks!
 
   # Pods for StreamShield
-  pod 'nuSDKService', '4.0.7'
+  pod 'nuSDKService', '~> 4.0.17'
 
 end

+ 1 - 1
StreamShield/StreamShield.podspec

@@ -22,7 +22,7 @@ Pod::Spec.new do |spec|
   spec.source_files = 'StreamShield/Source/**/*'
   spec.resource_bundles = { 'StreamShield' => ['StreamShield/Resource/**/*']}
   spec.swift_version = '5.5.1'
-  spec.dependency 'nuSDKService', '4.0.7'
+  spec.dependency 'nuSDKService', '~> 4.0.17'
   spec.ios.vendored_frameworks = "StreamShield.framework"
   spec.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
   spec.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64', 'ENABLE_BITCODE' => 'NO' }