Эх сурвалжийг харах

menyamakan state digixlite dengan nexilislite

alqindiirsyam 2 жил өмнө
parent
commit
839f5806d2
49 өөрчлөгдсөн 596 нэмэгдсэн , 315 устгасан
  1. 2 2
      appbuilder-ios/AppBuilder/AppBuilder/SecondTabViewController.swift
  2. 1 1
      appbuilder-ios/AppBuilder/AppBuilder/ViewController.swift
  3. BIN
      appbuilder-ios/DigiXLite/DigiXLite.xcworkspace/xcuserdata/akhmadalqindiirsyam.xcuserdatad/UserInterfaceState.xcuserstate
  4. 6 2
      appbuilder-ios/DigiXLite/DigiXLite/Source/Callback.swift
  5. 93 33
      appbuilder-ios/DigiXLite/DigiXLite/Source/DigiX.swift
  6. 42 19
      appbuilder-ios/DigiXLite/DigiXLite/Source/Download.swift
  7. 1 1
      appbuilder-ios/DigiXLite/DigiXLite/Source/Extension.swift
  8. 1 1
      appbuilder-ios/DigiXLite/DigiXLite/Source/FloatingButton/FloatingButton.swift
  9. 2 2
      appbuilder-ios/DigiXLite/DigiXLite/Source/IncomingThread.swift
  10. 32 9
      appbuilder-ios/DigiXLite/DigiXLite/Source/Network.swift
  11. 3 3
      appbuilder-ios/DigiXLite/DigiXLite/Source/OutgoingThread.swift
  12. 1 1
      appbuilder-ios/DigiXLite/DigiXLite/Source/Utils.swift
  13. 5 5
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/AudioViewController.swift
  14. 8 8
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/QmeraAudioConference.swift
  15. 7 7
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/QmeraAudioViewController.swift
  16. 9 9
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/QmeraVideoViewController.swift
  17. 9 9
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/VideoViewController.swift
  18. 92 37
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorGroup.swift
  19. 83 36
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorPersonal.swift
  20. 4 4
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorStarMessages.swift
  21. 3 3
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/BackupRestoreView.swift
  22. 3 3
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/BroadcastViewController.swift
  23. 2 2
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/ContactChatViewController.swift
  24. 1 1
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/GroupDetailViewController.swift
  25. 1 1
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/HistoryBroadcastViewController.swift
  26. 1 1
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/MessageInfo.swift
  27. 15 2
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/ProfileViewController.swift
  28. 2 2
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/SettingTableViewController.swift
  29. 4 4
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Streaming/QmeraStreamingViewController.swift
  30. 8 8
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Streaming/SeminarViewController.swift
  31. 3 3
      appbuilder-ios/DigiXLite/DigiXLite/Source/View/Streaming/StreamingViewController.swift
  32. 7 3
      appbuilder-ios/NexilisLite/NexilisLite/Source/Callback.swift
  33. 1 1
      appbuilder-ios/NexilisLite/NexilisLite/Source/FloatingButton/FloatingButton.swift
  34. 81 29
      appbuilder-ios/NexilisLite/NexilisLite/Source/Nexilis.swift
  35. 1 1
      appbuilder-ios/NexilisLite/NexilisLite/Source/Utils.swift
  36. 4 4
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/AudioViewController.swift
  37. 8 8
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/QmeraAudioConference.swift
  38. 7 7
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/QmeraAudioViewController.swift
  39. 9 9
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/QmeraVideoViewController.swift
  40. 9 9
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/VideoViewController.swift
  41. 2 2
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift
  42. 3 3
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift
  43. 1 1
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorStarMessages.swift
  44. 2 2
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/ContactChatViewController.swift
  45. 1 1
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/HistoryBroadcastViewController.swift
  46. 1 1
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/MessageInfo.swift
  47. 4 4
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Streaming/QmeraStreamingViewController.swift
  48. 8 8
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Streaming/SeminarViewController.swift
  49. 3 3
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Streaming/StreamingViewController.swift

+ 2 - 2
appbuilder-ios/AppBuilder/AppBuilder/SecondTabViewController.swift

@@ -123,8 +123,8 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
         
         definesPresentationContext = true
         
-        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onMember"), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onUpdatePersonInfo"), object: nil)
         

+ 1 - 1
appbuilder-ios/AppBuilder/AppBuilder/ViewController.swift

@@ -219,7 +219,7 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
             tabBar.selectionIndicatorImage = UIImage.imageWithColor(color: UIColor.gray, size: tabBarItemSize).resizableImage(withCapInsets: .zero)
         }
         let center: NotificationCenter = NotificationCenter.default
-        center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
         center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil)
         checkCounter()
     }

BIN
appbuilder-ios/DigiXLite/DigiXLite.xcworkspace/xcuserdata/akhmadalqindiirsyam.xcuserdatad/UserInterfaceState.xcuserstate


+ 6 - 2
appbuilder-ios/DigiXLite/DigiXLite/Source/Callback.swift

@@ -33,9 +33,13 @@ class Callback : CallBack {
     
     func callStateChanged(nState: Int!, sMessage: String!) -> Int {
         //print(nState,"/",sMessage)
-        if nState == 21 || nState == 31 {
+        if nState == DigiX.AUDIO_CALL_INCOMING || nState == DigiX.VIDEO_CALL_INCOMING {
             if let delegate = DigiX.shared.callDelegate {
-                delegate.onIncomingCall(state: nState, message: sMessage)
+                if !DigiX.showLibraryNotification {
+                    delegate.onStatusCall(state: nState, message: sMessage)
+                } else {
+                    delegate.onIncomingCall(state: nState, message: sMessage)
+                }
             }
         } else {
 //            if nState == 28 {

+ 93 - 33
appbuilder-ios/DigiXLite/DigiXLite/Source/DigiX.swift

@@ -54,6 +54,32 @@ public class DigiX: NSObject {
     
     public static var loadingAlert = LibAlertController()
     
+    public static let listenerReceiveChat = "onReceiveChatLibLite"
+    public static let listenerStatusChat = "onMessageChatLibLite"
+    public static let listenerTypingChat = "onTypingChatLibLite"
+    public static let listenerStatusCall = "onStatusCallLibLite"
+    public static var showLibraryNotification = true
+    
+    public static let STREAMING_SEMINAR_ENDED = 88
+    public static let VIDEO_CALL_END = 38
+    public static let VIDEO_CALL_MUTE_UNMUTE = 36
+    public static let VIDEO_CALL_ZOOM = 35
+    public static let VIDEO_CAMERA_PARAMS_CHANED = 34
+    public static let VIDEO_CALL_RINGING = 33
+    public static let VIDEO_CALL_OFFHOOK = 32
+    public static let VIDEO_CALL_INCOMING = 31
+    public static let AUDIO_CALL_END = 28
+    public static let AUDIO_CALL_RINGING = 23
+    public static let AUDIO_CALL_OFFHOOK = 22
+    public static let AUDIO_CALL_INCOMING = 21
+    public static let VIDEO_RINGING = 11
+    public static let ENDED = 8
+    public static let INITIATING = 4
+    public static let AUDIO_RINGING = 1
+    public static let OUTGOING_CALL = 0
+    public static let OFFLINE = -3
+    public static let BUSY = -4
+    
     private func createDelegate() {
         //print(("createDelegate...")
         callDelegate = self
@@ -148,7 +174,7 @@ public class DigiX: NSObject {
                                 let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
                                 let file = documentDir.appendingPathComponent(cursorData.string(forColumnIndex: 0)!)
                                 if !FileManager().fileExists(atPath: file.path) {
-                                    Download().start(forKey: cursorData.string(forColumnIndex: 0)!) { (name, progress) in}
+                                    Download().startHTTP(forKey: cursorData.string(forColumnIndex: 0)!) { (name, progress) in}
                                 }
                             } catch {}
                             cursorData.close()
@@ -382,6 +408,32 @@ public class DigiX: NSObject {
         }
     }
     
+    public static func apiSendChat(destination: String, message: String, isGroup: Bool, thumbnailName: String = "", imageName: String = "", videoName: String = "", fileName: String = "", audioName: String = "", replyMessageId : String = "") -> String {
+        let message = CoreMessage_TMessageBank.sendMessage(l_pin: destination, message_scope_id: isGroup ? "4" : "3", status: "3", message_text: message, credential: "", attachment_flag: !imageName.isEmpty ? "1" : !videoName.isEmpty ? "2" : !audioName.isEmpty ? "5" : !fileName.isEmpty ? "6" : "0", ex_blog_id: "", message_large_text: "", ex_format: "", image_id: imageName, audio_id: audioName, video_id: videoName, file_id: fileName, thumb_id: thumbnailName, reff_id: replyMessageId, read_receipts: "4", chat_id: "", is_call_center: "0", call_center_id: "", opposite_pin: User.getMyPin() ?? "")
+        addQueueMessage(message: message)
+        return message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
+    }
+    
+    public static func apiInitiateAudioCall(destination: String) {
+        API.initiateCCall(sParty: destination)
+    }
+    
+    public static func apiReceiveAudioCall(destination: String) {
+        API.receiveCCall(sParty: destination)
+    }
+    
+    public static func apiInitiateVideoCall(destination: String, backCamera: Bool = false, listRemoteViews: [UIImageView], localView: UIImageView, remoteViewSpeaker: UIImageView) {
+        API.initiateCCall(sParty: destination, nCamIdx: backCamera ? 0 : 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViews, ivLocalView: localView, ivRemoteZ: remoteViewSpeaker)
+    }
+    
+    public static func apiReceiveVideoCall(destination: String, backCamera: Bool = false, listRemoteViews: [UIImageView], localView: UIImageView, remoteViewSpeaker: UIImageView) {
+        API.receiveCCall(sParty: destination, nCamIdx: backCamera ? 0 : 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViews, ivLocalView: localView, ivRemoteZ: remoteViewSpeaker)
+    }
+    
+    public static func apiEndAllCall() {
+        API.terminateCall(sParty: nil)
+    }
+    
     public static func addQueueMessage(message: TMessage) {
 //        OutgoingThread.default.addQueue(message: message)
         InquiryThread.default.addQueue(message: message)
@@ -1267,6 +1319,14 @@ public class DigiX: NSObject {
         return _result
     }
     
+    static func removeDownload(forKey: String) -> Download? {
+        var _result: Download? = nil
+        downloadQueue.sync {
+            _result = self.DOWNLOAD_DICT.removeValue(forKey: forKey)
+        }
+        return _result
+    }
+    
     static func writeImageToFile(data: Data, fileName: String){
         guard let directory = FileManager.default.urls(for: .picturesDirectory, in: .userDomainMask).last else {
             return
@@ -1652,7 +1712,7 @@ extension DigiX: CallDelegate {
                     isShowAlert = 0
                 }
             }
-            if (state == 21 && message.split(separator: ",")[1] != "joining Ac.room on channel 0") {
+            if (state == DigiX.AUDIO_CALL_INCOMING && message.split(separator: ",")[1] != "joining Ac.room on channel 0") {
                 let data = User.getDataCanNil(pin: String(deviceId))
                 if data == nil {
                     DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
@@ -1686,7 +1746,7 @@ extension DigiX: CallDelegate {
                     UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
                 }
 //                    API.receiveCCall(sParty: String(deviceId))
-            } else if state == 31 {
+            } else if state == DigiX.VIDEO_CALL_INCOMING {
                 let dataUser = User.getDataCanNil(pin: String(deviceId))
                 if dataUser == nil {
                     DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
@@ -1720,32 +1780,32 @@ extension DigiX: CallDelegate {
     }
     
     public func onStatusCall(state: Int, message: String) {
-        let r = message.split(separator: ",")
-        if state == 23 {
-            if let call = callManager.call(with: String(r[0])) {
-                //print(("onStatusCall:connectingCall")
-                DispatchQueue.main.async {
-                    call.connectingCall()
-                }
-            }
-        } else if state == 22 {
-//            if let call = callManager.call(with: String(r[1])) {
-//                //print(("onStatusCall:answerCall")
+//        let r = message.split(separator: ",")
+//        if state == DigiX.AUDIO_CALL_RINGING {
+//            if let call = callManager.call(with: String(r[0])) {
+//                //print(("onStatusCall:connectingCall")
 //                DispatchQueue.main.async {
-//                    call.answerCall()
+//                    call.connectingCall()
 //                }
 //            }
-        } else if state == 28 {
-            DispatchQueue.main.async {
-                if QmeraAudioViewController().viewIfLoaded?.window == nil {
-                    DigiX.shared.callManager.end(call: Call(uuid: uuidOngoing))
-                }
-            }
-        }
+//        } else if state == DigiX.AUDIO_CALL_OFFHOOK {
+////            if let call = callManager.call(with: String(r[1])) {
+////                //print(("onStatusCall:answerCall")
+////                DispatchQueue.main.async {
+////                    call.answerCall()
+////                }
+////            }
+//        } else if state == DigiX.AUDIO_CALL_END {
+//            DispatchQueue.main.async {
+//                if QmeraAudioViewController().viewIfLoaded?.window == nil {
+//                    DigiX.shared.callManager.end(call: Call(uuid: uuidOngoing))
+//                }
+//            }
+//        }
         var dataCall: [AnyHashable : Any] = [:]
         dataCall["state"] = state
         dataCall["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onStatusCall"), object: nil, userInfo: dataCall)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: DigiX.listenerStatusCall), object: nil, userInfo: dataCall)
     }
     
 }
@@ -1933,7 +1993,7 @@ extension DigiX: MessageDelegate {
                                     UIApplication.shared.visibleViewController?.present(previewImageVC, animated: true, completion: nil)
                                 }
                             } else {
-                                Download().start(forKey: image) { (name, progress) in
+                                Download().startHTTP(forKey: image) { (name, progress) in
                                     guard progress == 100 else {
                                         return
                                     }
@@ -1982,7 +2042,7 @@ extension DigiX: MessageDelegate {
                                     UIApplication.shared.visibleViewController?.present(previewController, animated: true, completion: nil)
                                 }
                             } else {
-                                Download().start(forKey: file) { (name, progress) in
+                                Download().startHTTP(forKey: file) { (name, progress) in
                                     DispatchQueue.main.async {
                                         guard progress == 100 else {
                                             return
@@ -2018,7 +2078,7 @@ extension DigiX: MessageDelegate {
     public func onReceive(message: TMessage) {
         var dataMessage: [AnyHashable : Any] = [:]
         dataMessage["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil, userInfo: dataMessage)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil, userInfo: dataMessage)
         if message.getCode() == CoreMessage_TMessageCode.PUSH_CALL_CENTER {
             if User.getDataCanNil(pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN)) == nil {
                 DigiX.addFriendSilent(fpin: message.getBody(key: CoreMessage_TMessageKey.L_PIN))
@@ -2767,9 +2827,6 @@ extension DigiX: MessageDelegate {
             }
         } else if message.getCode() != CoreMessage_TMessageCode.PUSH_CALL_CENTER && message.getCode() != CoreMessage_TMessageCode.ACCEPT_CALL_CENTER && message.getCode() != CoreMessage_TMessageCode.END_CALL_CENTER && message.getCode() != CoreMessage_TMessageCode.TIMEOUT_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.ACCEPT_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.PUSH_MEMBER_ROOM_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.INVITE_END_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.INVITE_EXIT_CONTACT_CENTER || message.mBodies["MERNAM"] != nil {
             let m = message.mBodies
-//            if m[CoreMessage_TMessageKey.IS_CALL_CENTER] == "1" {
-//                return
-//            }
             if message.mBodies["MERNAM"] != nil {
                 DispatchQueue.main.async {
                     if !DigiX.broadcastList.isEmpty {
@@ -2781,6 +2838,9 @@ extension DigiX: MessageDelegate {
                 }
                 return
             }
+            if !DigiX.showLibraryNotification {
+                return
+            }
             let sender = m[CoreMessage_TMessageKey.F_PIN]!
             let me = UserDefaults.standard.string(forKey: "me")!
             if(sender != me) {
@@ -2959,7 +3019,7 @@ extension DigiX: MessageDelegate {
                                 profileImage.image = UIImage(contentsOfFile: file.path)
                                 profileImage.backgroundColor = .clear
                             } else {
-                                Download().start(forKey: profile) { (name, progress) in
+                                Download().startHTTP(forKey: profile) { (name, progress) in
                                     guard progress == 100 else {
                                         return
                                     }
@@ -3281,13 +3341,13 @@ extension DigiX: MessageDelegate {
     public func onReceive(message: [AnyHashable : Any?]) {
         var dataMessage: [AnyHashable : Any] = [:]
         dataMessage["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil, userInfo: dataMessage)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil, userInfo: dataMessage)
     }
     
     public func onMessage(message: TMessage) {
         var dataMessage: [AnyHashable : Any] = [:]
         dataMessage["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onMessageChat"), object: nil, userInfo: dataMessage)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: DigiX.listenerStatusChat), object: nil, userInfo: dataMessage)
     }
     
     public func onUpload(name: String, progress: Double) {
@@ -3300,7 +3360,7 @@ extension DigiX: MessageDelegate {
     public func onTyping(message: TMessage) {
         var dataMessage: [AnyHashable : Any] = [:]
         dataMessage["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onTypingChat"), object: nil, userInfo: dataMessage)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: DigiX.listenerTypingChat), object: nil, userInfo: dataMessage)
     }
     
 //    public static func faceDetect(fd: FaceDetector?,image: UIImage, completion: ((Bool) -> ())?){

+ 42 - 19
appbuilder-ios/DigiXLite/DigiXLite/Source/Download.swift

@@ -23,6 +23,7 @@ public class Download {
     
     var DOWNLOAD_BUFFER = [Data?]()
     var DOWNLOAD_SESSION = [Session]()
+    var DOWNLOAD_URL = "https://newuniverse.io/filepalio/image/"
     
     public func start(forKey: String, delegate: DownloadDelegate){
         self.delegate = delegate
@@ -44,28 +45,50 @@ public class Download {
         _ = DigiX.write(message: CoreMessage_TMessageBank.getImageDownload(p_image_id: forKey))
     }
     
-    public func startHTTP(filename: String, baseURL: String, onCompletion: ((Data) -> Void)? = nil, onError: (() -> Void)? = nil, onProgress: ((Progress) -> Void)? = nil) -> DownloadRequest {
-        var sep = ""
-        if baseURL.last != "/" {
-            sep = "/"
-        }
-        let fullURL = "\(baseURL)\(sep)\(filename)"
-        let downloadRequest = AF.download(fullURL)
-        .downloadProgress(queue: downloadBufferQueue) { progress in
-            onProgress?(progress)
-        }
-        .responseData { result in
-            if let successResponse = result.value as? Data{
-                //print(("Response success")
-                onCompletion?(successResponse)
+    public func startHTTP(forKey: String, completion: @escaping (String, Double)->()) {
+        _ = startHTTP(filename: forKey, baseURL: DOWNLOAD_URL, completion: completion)
+    }
+    
+    public func startHTTP(filename: String, baseURL: String, completion: @escaping (String, Double)->()) {
+        let download = DigiX.getDownload(forKey: filename)
+        if download == nil {
+            DigiX.addDownload(forKey: filename, download: self)
+            var sep = ""
+            if baseURL.last != "/" {
+                sep = "/"
             }
-            else {
-                let statusCode = result.response?.statusCode
-                //print(("Response fail: \(statusCode)")
-                onError?()
+            let fullURL = "\(baseURL)\(sep)\(filename)"
+            do {
+                let downloadRequest = AF.download(fullURL)
+                .downloadProgress(queue: downloadBufferQueue) { progress in
+                    let frac = progress.fractionCompleted*100
+                    if frac != 100.0 {
+                        completion(filename,frac)
+                    }
+                }
+                .responseData { result in
+                    if let successResponse = result.value {
+                        //print("Response success")
+                        do {
+                            let documentDir = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
+                            let url = documentDir.appendingPathComponent(filename)
+                            //print("write file \(url.path)")
+                            try successResponse.write(to: url)
+                            DigiX.removeDownload(forKey: filename)
+                            completion(filename,100)
+                        }
+                        catch {}
+                    }
+                    else {
+                        let statusCode = result.response?.statusCode
+                        //print("Response fail: \(statusCode)")
+                        completion(filename,0)
+                    }
+                }
             }
+            catch {}
         }
-        return downloadRequest
+        
     }
     
     func put(part: Int, buffer: Data){

+ 1 - 1
appbuilder-ios/DigiXLite/DigiXLite/Source/Extension.swift

@@ -286,7 +286,7 @@ extension NSObject {
                 completion(true, false, isCircle ? image?.circleMasked : image)
             } else {
                 completion(false, false, placeholderImage)
-                Download().start(forKey: url) { (name, progress) in
+                Download().startHTTP(forKey: url) { (name, progress) in
                     guard progress == 100 else {
                         return
                     }

+ 1 - 1
appbuilder-ios/DigiXLite/DigiXLite/Source/FloatingButton/FloatingButton.swift

@@ -113,7 +113,7 @@ public class FloatingButton: UIView {
         
         let center: NotificationCenter = NotificationCenter.default
         center.addObserver(self, selector: #selector(imageFBUpdate(notification:)), name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil)
-        center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil)
         center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil)
         let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideButton))
         tapGesture.cancelsTouchesInView = false

+ 2 - 2
appbuilder-ios/DigiXLite/DigiXLite/Source/IncomingThread.swift

@@ -410,7 +410,7 @@ class IncomingThread {
                                     profileImage.image = UIImage(contentsOfFile: file.path)
                                     profileImage.backgroundColor = .clear
                                 } else {
-                                    Download().start(forKey: profile) { (name, progress) in
+                                    Download().startHTTP(forKey: profile) { (name, progress) in
                                         guard progress == 100 else {
                                             return
                                         }
@@ -1087,7 +1087,7 @@ class IncomingThread {
             }
         }
         if (!thumb_id.isEmpty) {
-            Download().start(forKey: thumb_id) { (file, progress) in
+            Download().startHTTP(forKey: thumb_id) { (file, progress) in
                 print ("masuk download \(progress)")
                 if(progress == 100) {
                     DigiX.saveMessage(message: message, withStatus: false)

+ 32 - 9
appbuilder-ios/DigiXLite/DigiXLite/Source/Network.swift

@@ -17,6 +17,7 @@ public class Network {
     private var isCancel = false
     private var progress = 0.0
     private var CHUNK_SIZE = 200 * 1024
+    private var UPLOAD_URL = "https://newuniverse.io/uploader"
     
     public init() {}
     
@@ -183,9 +184,18 @@ public class Network {
         }
     }
     
-    public func uploadHTTP(_ endUrl: String, files: [URL] = [], filename: [String] = [], parameters: [String : Any] = [:], onCompletion: (([String : Any]) -> Void)? = nil, onError: (() -> Void)? = nil, onProgress: ((Progress) -> Void)? = nil) -> UploadRequest {
+    public func uploadHTTP(name: String, completion: @escaping (Bool, Double, [String:Any]?)->()) {
+        _ = uploadHTTP(UPLOAD_URL, filename: [name], completion: completion)
+    }
+    
+    public func uploadHTTP(fileUrl: URL, completion: @escaping (Bool, Double, [String:Any]?)->()) {
+        _ = uploadHTTP(UPLOAD_URL, files: [fileUrl], completion: completion)
+    }
+    
+    public func uploadHTTP(_ endUrl: String, files: [URL] = [], filename: [String] = [], parameters: [String : Any] = [:], completion: @escaping (Bool, Double, [String:Any]?)->()) -> UploadRequest {
         
-        var filesIn = files
+        var filesIn = [URL]()
+        filesIn.append(contentsOf: files)
         
         if !filename.isEmpty {
             do {
@@ -193,7 +203,11 @@ public class Network {
                 let documentDir = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
                 for name in filename {
                     let fileDir = documentDir.appendingPathComponent(name)
-                    filesIn.append(fileDir)
+                    let path = fileDir.path
+                    if FileManager.default.fileExists(atPath: path) {
+                        let fileURL = URL(fileURLWithPath: path)
+                        filesIn.append(fileURL)
+                    }
                 }
             }
             catch {}
@@ -206,24 +220,33 @@ public class Network {
             }
             
             for i in 0..<filesIn.count {
-                multipartFormData.append(filesIn[i], withName: "file\(i+1)")
+                multipartFormData.append(filesIn[i], withName: "file\(i+1)", fileName: filesIn[i].lastPathComponent, mimeType: "application/octet-stream")
+                DigiX.putUploadFile(forKey: filesIn[i].lastPathComponent, uploader: self)
                 //print(multipartFormData)
             }
             
         }, to: endUrl)
         .responseJSON { result in
             if let successResponse = result.value as? [String:Any] {
-                //print(("Response success")
-                onCompletion?(successResponse)
+                print("Response success")
+                for url in filesIn {
+                    DigiX.removeUploadFile(forKey: url.lastPathComponent)
+                }
+                completion(true,100,successResponse)
+                
             }
             else {
                 let statusCode = result.response?.statusCode
-                //print(("Response fail: \(statusCode)")
-                onError?()
+                print("Response fail: \(statusCode)")
+                completion(false,0,nil)
             }
         }
         .uploadProgress { progress in
-            onProgress?(progress)
+            print("Response progress: \(progress.fractionCompleted*100)")
+            let frac = progress.fractionCompleted*100
+            if frac != 100.0 {
+                completion(!progress.isCancelled,frac,nil)
+            }
         }
         
         return uploadRequest

+ 3 - 3
appbuilder-ios/DigiXLite/DigiXLite/Source/OutgoingThread.swift

@@ -136,7 +136,7 @@ class OutgoingThread {
         let isMedia = !fileName.isEmpty
         if isMedia {
             if (!message.getBody(key: CoreMessage_TMessageKey.THUMB_ID).isEmpty) {
-                Network().upload(name: message.getBody(key: CoreMessage_TMessageKey.THUMB_ID)) { (result, progress) in
+                Network().uploadHTTP(name: message.getBody(key: CoreMessage_TMessageKey.THUMB_ID)) { (result, progress, response) in
                     if result, progress == 100 {
                         do {
                             let fileManager = FileManager.default
@@ -148,7 +148,7 @@ class OutgoingThread {
                                 message.setMedia(media: [UInt8] (data))
                             }
                         } catch {}
-                        Network().upload(name: fileName) { (result, progress) in
+                        Network().uploadHTTP(name: fileName) { (result, progress, response) in
                             if result {
                                 if let delegate = DigiX.shared.messageDelegate {
                                     delegate.onUpload(name: fileName, progress: progress)
@@ -174,7 +174,7 @@ class OutgoingThread {
                     }
                 }
             } else {
-                Network().upload(name: fileName) { (result, progress) in
+                Network().uploadHTTP(name: fileName) { (result, progress, response) in
                     if result {
                         if let delegate = DigiX.shared.messageDelegate {
                             delegate.onUpload(name: fileName, progress: progress)

+ 1 - 1
appbuilder-ios/DigiXLite/DigiXLite/Source/Utils.swift

@@ -78,7 +78,7 @@ public final class Utils {
 //        return digestData
 //    }
     
-    static let callDurationFormatter: DateComponentsFormatter = {
+    public static let callDurationFormatter: DateComponentsFormatter = {
         let dateFormatter: DateComponentsFormatter
         dateFormatter = DateComponentsFormatter()
         dateFormatter.unitsStyle = .positional

+ 5 - 5
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/AudioViewController.swift

@@ -39,7 +39,7 @@ class AudioViewController: UIViewController {
         
         navigationController?.changeAppearance(clear: true)
         
-        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusCall), object: nil)
         
         speaker.circle()
         speaker.setBackgroundColor(.white, for: .highlighted)
@@ -119,11 +119,11 @@ class AudioViewController: UIViewController {
            let message = data["message"] as? String
         {
             let r = message.split(separator: ",")
-            if state == 23 {
+            if state == DigiX.AUDIO_CALL_RINGING {
                 DispatchQueue.main.async {
                     self.status.text = "Ringing..."
                 }
-            } else if state == 22 {
+            } else if state == DigiX.AUDIO_CALL_OFFHOOK {
                 DispatchQueue.main.async {
                     let connectDate = Date()
                     self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
@@ -132,7 +132,7 @@ class AudioViewController: UIViewController {
                     }
                     self.timer?.fire()
                 }
-            } else if state == 28 || state == -4 {
+            } else if state == DigiX.AUDIO_CALL_END || state == DigiX.BUSY {
                 DispatchQueue.main.async {
                     if self.isOutgoing {
                         self.navigationController?.popViewController(animated: true)
@@ -195,7 +195,7 @@ extension UIImageView {
                 self.image = UIImage(contentsOfFile: file.path)
                 self.backgroundColor = .clear
             } else {
-                Download().start(forKey: url) { (name, progress) in
+                Download().startHTTP(forKey: url) { (name, progress) in
                     print ("masuk download \(progress)")
                     guard progress == 100 else {
                         return

+ 8 - 8
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/QmeraAudioConference.swift

@@ -189,8 +189,8 @@ class QmeraAudioConference: UIViewController {
         name.anchor(top: profiles.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 5, paddingLeft: 20, paddingRight: 20, centerX: view.centerXAnchor)
         definesPresentationContext = true
         
-        NotificationCenter.default.addObserver(self, selector: #selector(onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusCall(_:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusCall), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil)
         
         if isOutgoing {
             users.append(User.getData(pin: UserDefaults.standard.string(forKey: "me")!)!)
@@ -469,7 +469,7 @@ class QmeraAudioConference: UIViewController {
            let message = data["message"] as? String {
             let arrayMessage = message.split(separator: ",")
             //print(("UYY \(state) \(message)")
-            if state == 22 {
+            if state == DigiX.AUDIO_CALL_OFFHOOK {
                 if users.count == 1 && firstCall {
                     DispatchQueue.main.async {
                         self.ongoingView()
@@ -502,13 +502,13 @@ class QmeraAudioConference: UIViewController {
                     }
                 }
             }
-//            if state == 23 {
+//            if state == DigiX.AUDIO_CALL_RINGING {
 //                if users.count == 1 {
 //                    DispatchQueue.main.async {
 //                        self.status.text = "Ringing..."
 //                    }
 //                }
-//            } else if state == 22 {
+//            } else if state == DigiX.AUDIO_CALL_OFFHOOK {
 //                if users.count == 1 && firstCall {
 //                    DispatchQueue.main.async {
 //                        self.ongoingView()
@@ -538,7 +538,7 @@ class QmeraAudioConference: UIViewController {
 //                        }
 //                    }
 //                }
-//            } else if state == 28 {
+//            } else if state == DigiX.AUDIO_CALL_END {
 //                let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
 //                if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
 //                    users.remove(at: index)
@@ -575,7 +575,7 @@ class QmeraAudioConference: UIViewController {
 //                        self.dismiss(animated: false, completion: nil)
 //                    }
 //                }
-//            } else if state == -3 { // Offline
+//            } else if state == DigiX.OFFLINE { // Offline
 //                let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
 //                if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
 //                    users.remove(at: index)
@@ -602,7 +602,7 @@ class QmeraAudioConference: UIViewController {
 //                        }
 //                    }
 //                }
-//            } else if state == -4 { // Busy
+//            } else if state == DigiX.BUSY { // Busy
 //                let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
 //                if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
 //                    users.remove(at: index)

+ 7 - 7
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/QmeraAudioViewController.swift

@@ -268,8 +268,8 @@ class QmeraAudioViewController: UIViewController {
         
         UIDevice.current.isProximityMonitoringEnabled = true
         
-        NotificationCenter.default.addObserver(self, selector: #selector(onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusCall(_:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusCall), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil)
         
         if let u = self.user {
             self.users.append(u)
@@ -759,13 +759,13 @@ class QmeraAudioViewController: UIViewController {
            let message = data["message"] as? String
         {
             let arrayMessage = message.split(separator: ",")
-            if state == 23 || (!ticketId.isEmpty && state == 33) {
+            if state == DigiX.AUDIO_CALL_RINGING || (!ticketId.isEmpty && state == DigiX.VIDEO_CALL_RINGING) {
                 if users.count == 1 {
                     DispatchQueue.main.async {
                         self.status.text = "Ringing..."
                     }
                 }
-            } else if state == 22 || (!ticketId.isEmpty && state == 32) {
+            } else if state == DigiX.AUDIO_CALL_OFFHOOK || (!ticketId.isEmpty && state == DigiX.VIDEO_CALL_OFFHOOK) {
                 if users.count == 1 && firstCall {
                     DispatchQueue.main.async {
                         if !self.ticketId.isEmpty {
@@ -807,7 +807,7 @@ class QmeraAudioViewController: UIViewController {
                         }
                     }
                 }
-            } else if state == 28 || (!ticketId.isEmpty && state == 38) {
+            } else if state == DigiX.AUDIO_CALL_END || (!ticketId.isEmpty && state == DigiX.VIDEO_CALL_END) {
                 let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
                 if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
                     users.remove(at: index)
@@ -873,7 +873,7 @@ class QmeraAudioViewController: UIViewController {
 //                        self.dismiss(animated: false, completion: nil)
 //                    }
 //                }
-            } else if state == -3 { // Offline
+            } else if state == DigiX.OFFLINE { // Offline
                 let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
                 if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
                     users.remove(at: index)
@@ -900,7 +900,7 @@ class QmeraAudioViewController: UIViewController {
                         }
                     }
                 }
-            } else if state == -4 { // Busy
+            } else if state == DigiX.BUSY { // Busy
                 let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
                 if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
                     users.remove(at: index)

+ 9 - 9
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/QmeraVideoViewController.swift

@@ -146,8 +146,8 @@ class QmeraVideoViewController: UIViewController {
         navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
         navigationController?.changeAppearance(clear: true)
         
-        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusCall), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil)
         
         view.backgroundColor = .clear
         navigationController?.navigationBar.topItem?.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
@@ -933,7 +933,7 @@ class QmeraVideoViewController: UIViewController {
         let message = (data?["message"] ?? "") as! String
         var remoteChannel = [String:String]()
         let arrayMessage = message.split(separator: ",")
-        if(state == 35){
+        if(state == DigiX.VIDEO_CALL_ZOOM){
             DispatchQueue.main.async {
                 if self.dataPerson.count > 1 {
                     if !self.transformZoomAfterNewUserMore2 {
@@ -943,7 +943,7 @@ class QmeraVideoViewController: UIViewController {
                 }
             }
         }
-        else if (state == 34){
+        else if (state == DigiX.VIDEO_CAMERA_PARAMS_CHANED){
             if(arrayMessage[3] == "0"){
                 DispatchQueue.main.async {
                     if self.dataPerson.count == 1 && arrayMessage[2] == "1" && arrayMessage[4] == "1" {
@@ -954,7 +954,7 @@ class QmeraVideoViewController: UIViewController {
                 }
             }
         }
-        else if (state == 32) {
+        else if (state == DigiX.VIDEO_CALL_OFFHOOK) {
             let channel = arrayMessage[3]
             remoteChannel[String(channel)] = String(arrayMessage[5])
             DispatchQueue.main.async {
@@ -1071,7 +1071,7 @@ class QmeraVideoViewController: UIViewController {
                     self.dataPerson[indexPerson!]["user_type"] = String(arrayMessage[5])
                 }
             }
-        } else if (state == 38 || state == 28) {
+        } else if (state == DigiX.VIDEO_CALL_END || state == DigiX.AUDIO_CALL_END) {
             let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
             if !onGoingCC.isEmpty {
                 let requester = onGoingCC.components(separatedBy: ",")[0]
@@ -1208,7 +1208,7 @@ class QmeraVideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == -3) {
+        } else if (state == DigiX.OFFLINE) {
             let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
             DispatchQueue.main.async {
                 if (self.dataPerson.count == 1) {
@@ -1274,7 +1274,7 @@ class QmeraVideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == -4) {
+        } else if (state == DigiX.BUSY) {
             let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
             DispatchQueue.main.async { [self] in
                 if (self.dataPerson.count == 1) {
@@ -1340,7 +1340,7 @@ class QmeraVideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == 33) {
+        } else if (state == DigiX.VIDEO_CALL_RINGING) {
             DispatchQueue.main.async {
                 if (self.dataPerson.count > 1) {
                     if (self.dataPerson.count == 2) {

+ 9 - 9
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Call/VideoViewController.swift

@@ -56,7 +56,7 @@ class VideoViewController: UIViewController {
     }
     
     override func viewDidDisappear(_ animated: Bool) {
-        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
+        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: DigiX.listenerStatusCall), object: nil)
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "afterAddParticipantVideo"), object: nil)
     }
     
@@ -76,7 +76,7 @@ class VideoViewController: UIViewController {
         self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
         self.navigationItem.setHidesBackButton(true, animated: false)
         NotificationCenter.default.addObserver(self, selector: #selector(self.addCallParticipant(_:)), name: NSNotification.Name(rawValue: "afterAddParticipantVideo"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusCall), object: nil)
         if (dataPerson.count > 0) {
             if (isInisiator) {
                 viewButtonDeclineAccept.isHidden = true
@@ -149,12 +149,12 @@ class VideoViewController: UIViewController {
         var remoteChannel = [String:String]()
         let arrayMessage = message.split(separator: ",")
         //        let me = UserDefaults.standard.string(forKey: "me")!
-        if(state == 35){
+        if(state == DigiX.VIDEO_CALL_ZOOM){
             DispatchQueue.main.async {
                 self.zoomView.transform   = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi * 3)/2)
             }
         }
-        else if (state == 34){
+        else if (state == DigiX.VIDEO_CAMERA_PARAMS_CHANED){
             let channel = arrayMessage[arrayMessage.count - 1]
             if(remoteChannel[String(channel)] != "2"){
                 DispatchQueue.main.async {
@@ -167,7 +167,7 @@ class VideoViewController: UIViewController {
                 }
             }
         }
-        else if (state == 32){
+        else if (state == DigiX.VIDEO_CALL_OFFHOOK){
             let channel = arrayMessage[3]
             remoteChannel[String(channel)] = String(arrayMessage[5])
             if (arrayMessage[5] == "2") {
@@ -206,7 +206,7 @@ class VideoViewController: UIViewController {
             }
             showButton(isShow: true)
             setStyleAppBar()
-        } else if (state == 38 || state == 28) {
+        } else if (state == DigiX.VIDEO_CALL_END || state == DigiX.AUDIO_CALL_END) {
             DispatchQueue.main.async {
                 if (self.dataPerson.count == 1) {
                     //                let channel = arrayMessage[1]
@@ -252,7 +252,7 @@ class VideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == -3) {
+        } else if (state == DigiX.OFFLINE) {
             DispatchQueue.main.async {
                 self.buttonEndCall.isHidden = true
                 self.labelStatusCall.text = "Offline"
@@ -265,7 +265,7 @@ class VideoViewController: UIViewController {
                     self.dismiss(animated: true, completion: nil)
                 }
             }
-        } else if (state == -4) {
+        } else if (state == DigiX.BUSY) {
             DispatchQueue.main.async {
                 if (self.dataPerson.count == 1) {
                     self.buttonEndCall.isHidden = true
@@ -295,7 +295,7 @@ class VideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == 33) {
+        } else if (state == DigiX.VIDEO_CALL_RINGING) {
             DispatchQueue.main.async {
                 if (self.dataPerson.count > 1) {
                     if (self.dataPerson.count == 2) {

+ 92 - 37
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorGroup.swift

@@ -86,10 +86,13 @@ public class EditorGroup: UIViewController {
     var timerCheckLink: Timer?
     var lastPositionCursorMention = 0
     var timerLongPressLink: Timer?
+    var timerFakeProgress: Timer?
     var lastTouchPoint: CGPoint = .zero
     var isLinkCopied = false
     var touchedSubview = UIView()
     var listViewOnSection: [UIView] = []
+    var fakeProgMultip = 0
+    let maxFakeProgMultip = 2
     
     public override func viewDidDisappear(_ animated: Bool) {
         if self.isMovingFromParent {
@@ -179,8 +182,8 @@ public class EditorGroup: UIViewController {
         let center: NotificationCenter = NotificationCenter.default
         center.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
         center.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
-        center.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
-        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
+        center.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil)
+        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusChat), object: nil)
         center.addObserver(self, selector: #selector(onUploadChat(notification:)), name: NSNotification.Name(rawValue: "onUploadChat"), object: nil)
         center.addObserver(self, selector: #selector(onMemberTopic(notification:)), name: NSNotification.Name(rawValue: "onMember"), object: nil)
         center.addObserver(self, selector: #selector(onGroup(notification:)), name: NSNotification.Name(rawValue: "onGroup"), object: nil)
@@ -598,12 +601,11 @@ public class EditorGroup: UIViewController {
         viewAppBar.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(seeProfileTapped)))
     }
     
-    @objc func onUploadChat(notification: NSNotification) {
-        let data:[AnyHashable : Any] = notification.userInfo!
+    func updateProgress(_ data: [AnyHashable: Any]){
         var isImage = false
-        var idx = dataMessages.lastIndex(where: { $0["video_id"] as! String == data["name"] as! String })
+        var idx = dataMessages.lastIndex(where: { $0["video_id"] as! String == data["name"] as! String || $0["video_id"] as? String == data["video_id"] as? String })
         if (idx == nil) {
-            idx = dataMessages.lastIndex(where: { $0["image_id"] as! String == data["name"] as! String })
+            idx = dataMessages.lastIndex(where: { $0["image_id"] as! String == data["name"] as! String || $0["image_id"] as? String == data["image_id"] as? String })
             isImage = true
         }
         if (idx != nil) {
@@ -617,6 +619,14 @@ public class EditorGroup: UIViewController {
             }
             DispatchQueue.main.async {
                 let indexPath = IndexPath(row: row!, section: section!)
+                if(self.fakeProgMultip < self.maxFakeProgMultip){
+                    self.fakeProgMultip = self.fakeProgMultip + 1
+                }
+                let fakeProgress = Double(self.fakeProgMultip) * (100.0 / Double(self.maxFakeProgMultip))
+                let progress = max(data["progress"] as! Double, fakeProgress)
+                if(data["progress"] as! Double == 100.0){
+                    self.fakeProgMultip = 0
+                }
                 if let cell = self.tableChatView.cellForRow(at: indexPath) {
                     for view in cell.contentView.subviews {
                         if !(view is UILabel) && !(view is UIImageView) {
@@ -625,17 +635,18 @@ public class EditorGroup: UIViewController {
                                     if viewInContainer.subviews.count == 0 {
                                         return
                                     }
-                                    var containerView = UIView()
+                                    var containerView : UIView?
                                     if (isImage) {
                                         containerView = viewInContainer.subviews[0]
-                                    } else {
+                                    } else if viewInContainer.subviews.count > 1 {
                                         containerView = viewInContainer.subviews[1]
                                     }
-                                    let loading = containerView.layer.sublayers![1] as! CAShapeLayer
-                                    loading.strokeEnd = CGFloat(data["progress"] as! Double / 100)
-                                    if (data["progress"] as! Double == 100.0) {
-                                        self.dataMessages[idx!]["progress"] = data["progress"]
-                                        self.tableChatView.reloadRows(at: [indexPath], with: .none)
+                                    if let loading = containerView?.layer.sublayers?[1] as? CAShapeLayer {
+                                        loading.strokeEnd = CGFloat(progress / 100)
+                                        if (progress == 100.0) {
+                                            self.dataMessages[idx!]["progress"] = progress
+                                            self.tableChatView.reloadRows(at: [indexPath], with: .none)
+                                        }
                                     }
                                 }
                             }
@@ -644,11 +655,19 @@ public class EditorGroup: UIViewController {
                 }
             }
         } else {
-            idx = dataMessages.lastIndex(where: { $0["file_id"] as! String == data["name"] as! String })
+            idx = dataMessages.lastIndex(where: { $0["file_id"] as! String == data["name"] as! String || $0["file_id"] as? String == data["file_id"] as? String })
             if (idx != nil) {
                 DispatchQueue.main.async {
                     let section = 0
                     let indexPath = IndexPath(row: idx!, section: section)
+                    if(self.fakeProgMultip < self.maxFakeProgMultip){
+                        self.fakeProgMultip = self.fakeProgMultip + 1
+                    }
+                    let fakeProgress = Double(self.fakeProgMultip) * (100.0 / Double(self.maxFakeProgMultip))
+                    let progress = max(data["progress"] as! Double, fakeProgress)
+                    if(data["progress"] as! Double == 100.0){
+                        self.fakeProgMultip = 0
+                    }
                     if let cell = self.tableChatView.cellForRow(at: indexPath) {
                         for view in cell.contentView.subviews {
                             if !(view is UILabel) && !(view is UIImageView) {
@@ -660,9 +679,9 @@ public class EditorGroup: UIViewController {
                                                     return
                                                 }
                                                 let loading = viewInContainer.layer.sublayers![1] as! CAShapeLayer
-                                                loading.strokeEnd = CGFloat(data["progress"] as! Double / 100)
-                                                if (data["progress"] as! Double == 100.0) {
-                                                    self.dataMessages[idx!]["progress"] = data["progress"]
+                                                loading.strokeEnd = CGFloat(progress / 100)
+                                                if (progress == 100.0) {
+                                                    self.dataMessages[idx!]["progress"] = progress
                                                     self.tableChatView.reloadRows(at: [indexPath], with: .none)
                                                 }
                                             }
@@ -677,6 +696,11 @@ public class EditorGroup: UIViewController {
         }
     }
     
+    @objc func onUploadChat(notification: NSNotification) {
+        let data:[AnyHashable : Any] = notification.userInfo!
+        updateProgress(data)
+    }
+    
     @objc func onReceiveMessage(notification: NSNotification) {
         DispatchQueue.main.async {
             let data:[AnyHashable : Any] = notification.userInfo!
@@ -1326,6 +1350,15 @@ public class EditorGroup: UIViewController {
                 self.tableChatView.endUpdates()
             }
         }
+        //        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+        //            self.timerFakeProgress = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
+        //                self.updateProgress(row as [AnyHashable : Any])
+        //                if self.fakeProgMultip == self.maxFakeProgMultip {
+        //                    self.timerFakeProgress?.invalidate()
+        //                    self.fakeProgMultip = 0
+        //                }
+        //            }
+        //        }
     }
     
     private func getCounter() {
@@ -1469,7 +1502,7 @@ public class EditorGroup: UIViewController {
             let auto = UserDefaults.standard.bool(forKey: "autoDownload")
             if auto {
                 if dataMessages[index]["image_id"] as? String != nil && !((dataMessages[index]["image_id"] as? String)!.isEmpty) {
-                    Download().start(forKey:dataMessages[index]["image_id"] as! String) { (name, progress) in
+                    Download().startHTTP(forKey:dataMessages[index]["image_id"] as! String) { (name, progress) in
                         guard progress == 100 else {
                             return
                         }
@@ -1485,30 +1518,52 @@ public class EditorGroup: UIViewController {
                             }
                         }
                         DispatchQueue.main.async { [self] in
-                            let section = self.dataDates.firstIndex(of: dataMessages[index]["chat_date"] as! String)
-                            let row = self.dataMessages.filter({$0["chat_date"] as! String == dataMessages[index]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == message_id})
+                            let section = dataDates.firstIndex(of: dataMessages[index]["chat_date"] as! String)
+                            let row = dataMessages.filter({$0["chat_date"] as! String == dataMessages[index]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == message_id})
                             if row != nil && section != nil{
                                 tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .automatic)
                             }
                         }
                     }
                 }  else if dataMessages[index]["video_id"] as? String != nil && !((dataMessages[index]["video_id"] as? String)!.isEmpty){
-                    let section = dataDates.firstIndex(of: dataMessages[index]["chat_date"] as! String)
-                    let row = dataMessages.filter({$0["chat_date"] as! String == dataMessages[index]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == message_id})
-                    if row != nil && section != nil{
-                        let indexPath = IndexPath(row: row!, section: section!)
-                        if let cell = tableChatView.cellForRow(at: indexPath) {
-                            for view in cell.contentView.subviews {
-                                if view is UIImageView {
-                                    let objectTap = ObjectGesture()
-                                    objectTap.video_id = dataMessages[index]["video_id"] as! String
-                                    objectTap.imageView = view as! UIImageView
-                                    objectTap.indexPath = indexPath
-                                    contentMessageTapped(objectTap)
-                                    break
+                    Download().startHTTP(forKey: dataMessages[index]["video_id"] as! String) { (name, progress) in
+                        guard progress == 100 else {
+                            return
+                        }
+                        let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
+                        let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
+                        let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
+                        if let dirPath = paths.first {
+                            let videoURL = URL(fileURLWithPath: dirPath).appendingPathComponent(self.dataMessages[index]["video_id"] as! String)
+                            let save = UserDefaults.standard.bool(forKey: "saveToGallery")
+                            if save {
+                                PHPhotoLibrary.shared().performChanges({
+                                    PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
+                                }) { saved, error in
+                                    
                                 }
                             }
                         }
+                        DispatchQueue.main.async { [self] in
+                            let section = dataDates.firstIndex(of: dataMessages[index]["chat_date"] as! String)
+                            let row = dataMessages.filter({$0["chat_date"] as! String == dataMessages[index]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == message_id})
+                            if row != nil && section != nil{
+                                tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .automatic)
+                            }
+                        }
+                    }
+                } else if dataMessages[index]["file_id"] as? String != nil && !((dataMessages[index]["file_id"] as? String)!.isEmpty) {
+                    Download().startHTTP(forKey: dataMessages[index]["file_id"] as! String) { (name, progress) in
+                        guard progress == 100 else {
+                            return
+                        }
+                        DispatchQueue.main.async { [self] in
+                            let section = dataDates.firstIndex(of: dataMessages[index]["chat_date"] as! String)
+                            let row = dataMessages.filter({$0["chat_date"] as! String == dataMessages[index]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == message_id})
+                            if row != nil && section != nil{
+                                tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .automatic)
+                            }
+                        }
                     }
                 }
             }
@@ -1543,7 +1598,7 @@ public class EditorGroup: UIViewController {
                 }
             }
             let indexPathFirst = tableChatView.indexPathsForVisibleRows?.first
-            if indexPathFirst != nil && listViewOnSection.count != 0 && listViewOnSection.count - 1 <= indexPathFirst!.section{
+            if indexPathFirst != nil && listViewOnSection.count != 0 && listViewOnSection.count - 1 >= indexPathFirst!.section{
                 let headerView = listViewOnSection[indexPathFirst!.section]
                 if headerView.isHidden {
                     headerView.isHidden = false
@@ -3949,7 +4004,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                                                        y: sender.imageView.frame.height/2)
                     activityIndicator.startAnimating()
                     sender.imageView.addSubview(activityIndicator)
-                    Download().start(forKey: sender.image_id) { (name, progress) in
+                    Download().startHTTP(forKey: sender.image_id) { (name, progress) in
                         guard progress == 100 else {
                             return
                         }
@@ -4013,7 +4068,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                     imageDownload.centerYAnchor.constraint(equalTo: sender.imageView.centerYAnchor).isActive = true
                     imageDownload.widthAnchor.constraint(equalToConstant: 30).isActive = true
                     imageDownload.heightAnchor.constraint(equalToConstant: 30).isActive = true
-                    Download().start(forKey: sender.video_id) { (name, progress) in
+                    Download().startHTTP(forKey: sender.video_id) { (name, progress) in
                         DispatchQueue.main.async {
                             guard progress == 100 else {
                                 shapeLoading.strokeEnd = CGFloat(progress / 100)
@@ -4084,7 +4139,7 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource {
                     imageupload.centerYAnchor.constraint(equalTo: containerLoading.centerYAnchor).isActive = true
                     imageupload.centerXAnchor.constraint(equalTo: containerLoading.centerXAnchor).isActive = true
                     
-                    Download().start(forKey: sender.file_id) { (name, progress) in
+                    Download().startHTTP(forKey: sender.file_id) { (name, progress) in
                         DispatchQueue.main.async {
                             guard progress == 100 else {
                                 shapeLoading.strokeEnd = CGFloat(progress / 100)

+ 83 - 36
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorPersonal.swift

@@ -96,6 +96,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     var isAlwaysHideLinkPreview = false
     var timerCheckLink: Timer?
     var timerLongPressLink: Timer?
+    var timerFakeProgress: Timer?
     var lastTouchPoint: CGPoint = .zero
     var isLinkCopied = false
     var touchedSubview = UIView()
@@ -103,6 +104,8 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     var fromVCAC = false
     var serviceIdCC = ""
     var isDirectCC = false
+    var fakeProgMultip = 0
+    let maxFakeProgMultip = 2
     
     public override func viewDidDisappear(_ animated: Bool) {
         if self.isMovingFromParent {
@@ -203,11 +206,11 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         let center: NotificationCenter = NotificationCenter.default
         center.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
         center.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
-        center.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
-        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
+        center.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil)
+        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusChat), object: nil)
         center.addObserver(self, selector: #selector(onUploadChat(notification:)), name: NSNotification.Name(rawValue: "onUploadChat"), object: nil)
         center.addObserver(self, selector: #selector(onUnfriend(notification:)), name: NSNotification.Name(rawValue: "onUpdatePersonInfo"), object: nil)
-        center.addObserver(self, selector: #selector(onTyping(notification:)), name: NSNotification.Name(rawValue: "onTypingChat"), object: nil)
+        center.addObserver(self, selector: #selector(onTyping(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerTypingChat), object: nil)
         
         if dataMessageForward != nil {
             for i in 0..<dataMessageForward!.count {
@@ -1165,12 +1168,11 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         }
     }
     
-    @objc func onUploadChat(notification: NSNotification) {
-        let data:[AnyHashable : Any] = notification.userInfo!
+    func updateProgress(_ data: [AnyHashable : Any]){
         var isImage = false
-        var idx = dataMessages.lastIndex(where: { $0["video_id"] as? String == data["name"] as? String })
+        var idx = dataMessages.lastIndex(where: { $0["video_id"] as? String == data["name"] as? String || $0["video_id"] as? String == data["video_id"] as? String })
         if (idx == nil) {
-            idx = dataMessages.lastIndex(where: { $0["image_id"] as? String == data["name"] as? String })
+            idx = dataMessages.lastIndex(where: { $0["image_id"] as? String == data["name"] as? String || $0["image_id"] as? String == data["image_id"] as? String })
             isImage = true
         }
         if (idx != nil) {
@@ -1184,6 +1186,14 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
             }
             DispatchQueue.main.async {
                 let indexPath = IndexPath(row: row!, section: section!)
+                if(self.fakeProgMultip < self.maxFakeProgMultip){
+                    self.fakeProgMultip = self.fakeProgMultip + 1
+                }
+                let fakeProgress = Double(self.fakeProgMultip) * (100.0 / Double(self.maxFakeProgMultip))
+                let progress = max(data["progress"] as! Double, fakeProgress)
+                if(data["progress"] as! Double == 100.0){
+                    self.fakeProgMultip = 0
+                }
                 if let cell = self.tableChatView.cellForRow(at: indexPath) {
                     for view in cell.contentView.subviews {
                         if !(view is UILabel) && !(view is UIImageView) {
@@ -1192,17 +1202,18 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                                     if viewInContainer.subviews.count == 0 {
                                         return
                                     }
-                                    var containerView = UIView()
+                                    var containerView : UIView?
                                     if (isImage) {
                                         containerView = viewInContainer.subviews[0]
-                                    } else {
+                                    } else if viewInContainer.subviews.count > 1 {
                                         containerView = viewInContainer.subviews[1]
                                     }
-                                    let loading = containerView.layer.sublayers![1] as! CAShapeLayer
-                                    loading.strokeEnd = CGFloat(data["progress"] as! Double / 100)
-                                    if (data["progress"] as! Double == 100.0) {
-                                        self.dataMessages[idx!]["progress"] = data["progress"]
-                                        self.tableChatView.reloadRows(at: [indexPath], with: .none)
+                                    if let loading = containerView?.layer.sublayers?[1] as? CAShapeLayer {
+                                        loading.strokeEnd = CGFloat(progress / 100)
+                                        if (progress == 100.0) {
+                                            self.dataMessages[idx!]["progress"] = progress
+                                            self.tableChatView.reloadRows(at: [indexPath], with: .none)
+                                        }
                                     }
                                 }
                             }
@@ -1211,7 +1222,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                 }
             }
         } else {
-            idx = dataMessages.lastIndex(where: { $0["file_id"] as? String == data["name"] as? String })
+            idx = dataMessages.lastIndex(where: { $0["file_id"] as? String == data["name"] as? String || $0["file_id"] as? String == data["file_id"] as? String })
             if (idx != nil) {
                 let section = dataDates.firstIndex(of: dataMessages[idx!]["chat_date"] as! String)
                 if section == nil {
@@ -1223,6 +1234,14 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                 }
                 DispatchQueue.main.async {
                     let indexPath = IndexPath(row: row!, section: section!)
+                    if(self.fakeProgMultip < self.maxFakeProgMultip){
+                        self.fakeProgMultip = self.fakeProgMultip + 1
+                    }
+                    let fakeProgress = Double(self.fakeProgMultip) * (100.0 / Double(self.maxFakeProgMultip))
+                    let progress = max(data["progress"] as! Double, fakeProgress)
+                    if(data["progress"] as! Double == 100.0){
+                        self.fakeProgMultip = 0
+                    }
                     if let cell = self.tableChatView.cellForRow(at: indexPath) {
                         for view in cell.contentView.subviews {
                             if !(view is UILabel) && !(view is UIImageView) {
@@ -1234,9 +1253,9 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                                                     return
                                                 }
                                                 let loading = viewInContainer.layer.sublayers![1] as! CAShapeLayer
-                                                loading.strokeEnd = CGFloat(data["progress"] as! Double / 100)
-                                                if (data["progress"] as! Double == 100.0) {
-                                                    self.dataMessages[idx!]["progress"] = data["progress"]
+                                                loading.strokeEnd = CGFloat(progress / 100)
+                                                if (progress == 100.0) {
+                                                    self.dataMessages[idx!]["progress"] = progress
                                                     self.tableChatView.reloadRows(at: [indexPath], with: .none)
                                                 }
                                             }
@@ -1251,6 +1270,11 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         }
     }
     
+    @objc func onUploadChat(notification: NSNotification) {
+        let data:[AnyHashable : Any] = notification.userInfo!
+        updateProgress(data)
+    }
+    
     
     @objc func onReceiveMessage(notification: NSNotification) {
         DispatchQueue.main.async { [self] in
@@ -2657,7 +2681,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
             let auto = UserDefaults.standard.bool(forKey: "autoDownload")
             if auto {
                 if dataMessages[index]["image_id"] as? String != nil && !((dataMessages[index]["image_id"] as? String)!.isEmpty) {
-                    Download().start(forKey:dataMessages[index]["image_id"] as! String) { (name, progress) in
+                    Download().startHTTP(forKey:dataMessages[index]["image_id"] as! String) { (name, progress) in
                         guard progress == 100 else {
                             return
                         }
@@ -2681,22 +2705,45 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                         }
                     }
                 } else if dataMessages[index]["video_id"] as? String != nil && !((dataMessages[index]["video_id"] as? String)!.isEmpty){
-                    let section = dataDates.firstIndex(of: dataMessages[index]["chat_date"] as! String)
-                    let row = dataMessages.filter({$0["chat_date"] as! String == dataMessages[index]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == message_id})
-                    if row != nil && section != nil{
-                        let indexPath = IndexPath(row: row!, section: section!)
-                        if let cell = tableChatView.cellForRow(at: indexPath) {
-                            for view in cell.contentView.subviews {
-                                if view is UIImageView{
-                                    let objectTap = ObjectGesture()
-                                    objectTap.video_id = dataMessages[index]["video_id"] as! String
-                                    objectTap.imageView = view as! UIImageView
-                                    objectTap.indexPath = indexPath
-                                    contentMessageTapped(objectTap)
-                                    break
+                    Download().startHTTP(forKey: dataMessages[index]["video_id"] as! String) { (name, progress) in
+                        guard progress == 100 else {
+                            return
+                        }
+                        let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
+                        let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
+                        let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
+                        if let dirPath = paths.first {
+                            let videoURL = URL(fileURLWithPath: dirPath).appendingPathComponent(self.dataMessages[index]["video_id"] as! String)
+                            let save = UserDefaults.standard.bool(forKey: "saveToGallery")
+                            if save {
+                                PHPhotoLibrary.shared().performChanges({
+                                    PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
+                                }) { saved, error in
+                                    
                                 }
                             }
                         }
+                        DispatchQueue.main.async { [self] in
+                            let section = dataDates.firstIndex(of: dataMessages[index]["chat_date"] as! String)
+                            let row = dataMessages.filter({$0["chat_date"] as! String == dataMessages[index]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == message_id})
+                            if row != nil && section != nil{
+                                tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
+                            }
+                        }
+                    }
+                }
+                else if dataMessages[index]["file_id"] as? String != nil && !((dataMessages[index]["file_id"] as? String)!.isEmpty) {
+                    Download().startHTTP(forKey: dataMessages[index]["file_id"] as! String) { (name, progress) in
+                        guard progress == 100 else {
+                            return
+                        }
+                        DispatchQueue.main.async { [self] in
+                            let section = dataDates.firstIndex(of: dataMessages[index]["chat_date"] as! String)
+                            let row = dataMessages.filter({$0["chat_date"] as! String == dataMessages[index]["chat_date"] as! String}).firstIndex(where: { $0["message_id"] as? String == message_id})
+                            if row != nil && section != nil{
+                                tableChatView.reloadRows(at: [IndexPath(row: row!, section: section!)], with: .none)
+                            }
+                        }
                     }
                 }
             }
@@ -2824,7 +2871,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                 }
             }
             let indexPathFirst = tableChatView.indexPathsForVisibleRows?.first
-            if indexPathFirst != nil && listViewOnSection.count != 0 && listViewOnSection.count - 1 <= indexPathFirst!.section{
+            if indexPathFirst != nil && listViewOnSection.count != 0 && listViewOnSection.count - 1 >= indexPathFirst!.section {
                 let headerView = listViewOnSection[indexPathFirst!.section]
                 if headerView.isHidden {
                     headerView.isHidden = false
@@ -5331,7 +5378,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                                                        y: sender.imageView.frame.height/2)
                     activityIndicator.startAnimating()
                     sender.imageView.addSubview(activityIndicator)
-                    Download().start(forKey: sender.image_id) { (name, progress) in
+                    Download().startHTTP(forKey: sender.image_id) { (name, progress) in
                         guard progress == 100 else {
                             return
                         }
@@ -5393,7 +5440,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                     imageDownload.centerYAnchor.constraint(equalTo: sender.imageView.centerYAnchor).isActive = true
                     imageDownload.widthAnchor.constraint(equalToConstant: 30).isActive = true
                     imageDownload.heightAnchor.constraint(equalToConstant: 30).isActive = true
-                    Download().start(forKey: sender.video_id) { (name, progress) in
+                    Download().startHTTP(forKey: sender.video_id) { (name, progress) in
                         DispatchQueue.main.async {
                             guard progress == 100 else {
                                 shapeLoading.strokeEnd = CGFloat(progress / 100)
@@ -5464,7 +5511,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
                     imageupload.centerYAnchor.constraint(equalTo: containerLoading.centerYAnchor).isActive = true
                     imageupload.centerXAnchor.constraint(equalTo: containerLoading.centerXAnchor).isActive = true
                     
-                    Download().start(forKey: sender.file_id) { (name, progress) in
+                    Download().startHTTP(forKey: sender.file_id) { (name, progress) in
                         DispatchQueue.main.async {
                             guard progress == 100 else {
                                 shapeLoading.strokeEnd = CGFloat(progress / 100)

+ 4 - 4
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Chat/EditorStarMessages.swift

@@ -63,7 +63,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
         tableChatView.reloadData()
         
         let center: NotificationCenter = NotificationCenter.default
-        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
+        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusChat), object: nil)
 
     }
     
@@ -762,7 +762,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                                                        y: sender.imageView.frame.height/2)
                     activityIndicator.startAnimating()
                     sender.imageView.addSubview(activityIndicator)
-                    Download().start(forKey: sender.image_id) { (name, progress) in
+                    Download().startHTTP(forKey: sender.image_id) { (name, progress) in
                         guard progress == 100 else {
                             return
                         }
@@ -826,7 +826,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                     imageDownload.centerYAnchor.constraint(equalTo: sender.imageView.centerYAnchor).isActive = true
                     imageDownload.widthAnchor.constraint(equalToConstant: 30).isActive = true
                     imageDownload.heightAnchor.constraint(equalToConstant: 30).isActive = true
-                    Download().start(forKey: sender.video_id) { (name, progress) in
+                    Download().startHTTP(forKey: sender.video_id) { (name, progress) in
                         DispatchQueue.main.async {
                             guard progress == 100 else {
                                 shapeLoading.strokeEnd = CGFloat(progress / 100)
@@ -897,7 +897,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
                     imageupload.centerYAnchor.constraint(equalTo: containerLoading.centerYAnchor).isActive = true
                     imageupload.centerXAnchor.constraint(equalTo: containerLoading.centerXAnchor).isActive = true
                     
-                    Download().start(forKey: sender.file_id) { (name, progress) in
+                    Download().startHTTP(forKey: sender.file_id) { (name, progress) in
                         DispatchQueue.main.async {
                             guard progress == 100 else {
                                 shapeLoading.strokeEnd = CGFloat(progress / 100)

+ 3 - 3
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/BackupRestoreView.swift

@@ -244,7 +244,7 @@ public class BackupRestoreView: UIViewController, UITableViewDataSource, UITable
             if let dirPath = paths.first {
                 let fileURL = URL(fileURLWithPath: dirPath).appendingPathComponent(getFileName(option: optionBackup, fileId: fileIdBackup))
                 if !FileManager.default.fileExists(atPath: fileURL.path) {
-                    Download().start(forKey: getFileName(option: optionBackup, fileId: fileIdBackup)) { (name, progress) in
+                    Download().startHTTP(forKey: getFileName(option: optionBackup, fileId: fileIdBackup)) { (name, progress) in
                         DispatchQueue.main.async { [self] in
                             guard progress == 100 else {
                                 labelRestoring.text = "Downloading...".localized() + "  \(progress)%"
@@ -469,7 +469,7 @@ public class BackupRestoreView: UIViewController, UITableViewDataSource, UITable
                     if let dirPath = paths.first {
                         let thumbURL = URL(fileURLWithPath: dirPath).appendingPathComponent(thumbId)
                         if !FileManager.default.fileExists(atPath: thumbURL.path) {
-                            Download().start(forKey: thumbId) { (name, progress) in}
+                            Download().startHTTP(forKey: thumbId) { (name, progress) in}
                         }
                     }
                 }
@@ -883,7 +883,7 @@ public class BackupRestoreView: UIViewController, UITableViewDataSource, UITable
                     //print(("Adding entry to ZIP archive failed with error:\(error)")
                 }
                 self.labelPreparing.text = "Uploading...".localized()
-                Network().upload(fileUrl: zipFiles, completion: { result,progress in
+                Network().uploadHTTP(fileUrl: zipFiles, completion: { result,progress, response in
                     if result {
                         DispatchQueue.main.async { [self] in
                             labelPreparing.text = "Uploading...".localized() + " \(progress)%"

+ 3 - 3
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/BroadcastViewController.swift

@@ -404,10 +404,10 @@ class BroadcastViewController: UITableViewController, UITextFieldDelegate, UITex
             clearAttachment()
         }
         if !thumbId.isEmpty {
-            Network().upload(name: String(thumbId)) { (result1, progress) in
+            Network().uploadHTTP(name: String(thumbId)) { (result1, progress, response1) in
                 if result1 {
                     if progress == 100 {
-                        Network().upload(name: String(self.fileId)) { (result2, progress) in
+                        Network().uploadHTTP(name: String(self.fileId)) { (result2, progress, response2) in
                             if result2 {
                                 if progress == 100 {
                                     self.sendMsg(startTime: startTime, endTime: endTime)
@@ -418,7 +418,7 @@ class BroadcastViewController: UITableViewController, UITextFieldDelegate, UITex
                 }
             }
         } else if !fileId.isEmpty {
-            Network().upload(name: String(fileId)) { (result2, progress) in
+            Network().uploadHTTP(name: String(fileId)) { (result2, progress, response2) in
                 if result2 {
                     if progress == 100 {
                         self.sendMsg(startTime: startTime, endTime: endTime)

+ 2 - 2
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/ContactChatViewController.swift

@@ -180,8 +180,8 @@ class ContactChatViewController: UITableViewController {
         segment.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 12.0)], for: .normal)
         Utils.inTabChats = true
         
-        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusChat), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onMember"), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onUpdatePersonInfo"), object: nil)
         

+ 1 - 1
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/GroupDetailViewController.swift

@@ -981,7 +981,7 @@ extension GroupDetailViewController: ImageVideoPickerDelegate {
                     DispatchQueue.main.async {
                         DigiX.showLoader()
                     }
-                    Network().upload(name: fileDir.lastPathComponent) { result, progress in
+                    Network().uploadHTTP(name: fileDir.lastPathComponent) { result, progress, response in
                         guard result, progress == 100 else {
                             return
                         }

+ 1 - 1
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/HistoryBroadcastViewController.swift

@@ -60,7 +60,7 @@ class HistoryBroadcastViewController: UIViewController, UITableViewDelegate, UIT
 //                self.historyTableView.reloadData()
 //            }
 //        }
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerReceiveChat), object: nil)
     }
     
     @objc func onReceiveMessage(notification: NSNotification) {

+ 1 - 1
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/MessageInfo.swift

@@ -38,7 +38,7 @@ class MessageInfo: UIViewController, UITableViewDelegate, UITableViewDataSource
         
         view.addSubview(tableStatus)
         tableStatus.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor)
-        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: DigiX.listenerStatusChat), object: nil)
     }
     
     @objc func onStatusChat(notification: NSNotification) {

+ 15 - 2
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/ProfileViewController.swift

@@ -675,8 +675,21 @@ extension ProfileViewController: ImageVideoPickerDelegate {
                     let fileDir = documentDir.appendingPathComponent("THUMB_\(me)\(Date().currentTimeMillis().toHex())")
                     if !FileManager.default.fileExists(atPath: fileDir.path), let data = resize.jpegData(compressionQuality: 0.8) {
                         try! data.write(to: fileDir)
-                        Network().upload(name: fileDir.lastPathComponent) { result, progress in
-                            guard result, progress == 100 else {
+                        Network().uploadHTTP(name: fileDir.lastPathComponent) { result, progress, response in
+                            guard result else {
+                                DispatchQueue.main.async {
+                                    DigiX.hideLoader(completion: { [self] in
+                                        let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                                        imageView.tintColor = .white
+                                        publicBanner.dismiss()
+                                        publicBanner = FloatingNotificationBanner(title: "Can't change profile picture, try again later".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .danger, colors: nil, iconPosition: .center)
+                                        publicBanner.show()
+                                        self.dismissImage?(image, fileDir.lastPathComponent)
+                                    })
+                                }
+                                return
+                            }
+                            guard progress == 100 else {
                                 return
                             }
                             if let response = DigiX.writeAndWait(message: CoreMessage_TMessageBank.getChangePersonImage(thumb_id: fileDir.lastPathComponent)), response.isOk() {

+ 2 - 2
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Control/SettingTableViewController.swift

@@ -149,7 +149,7 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                                     NotificationCenter.default.post(name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil, userInfo: dataImage)
                                 }
                             } else {
-                                Download().start(forKey: image!) { (name, progress) in
+                                Download().startHTTP(forKey: image!) { (name, progress) in
                                     guard progress == 100 else {
                                         return
                                     }
@@ -188,7 +188,7 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                             dataImage["name"] = imageSignIn
                             NotificationCenter.default.post(name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil, userInfo: dataImage)
                         } else {
-                            Download().start(forKey: imageSignIn) { (name, progress) in
+                            Download().startHTTP(forKey: imageSignIn) { (name, progress) in
                                 guard progress == 100 else {
                                     return
                                 }

+ 4 - 4
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Streaming/QmeraStreamingViewController.swift

@@ -514,7 +514,7 @@ extension QmeraStreamingViewController: UITableViewDataSource {
 extension QmeraStreamingViewController: LiveStreamingDelegate {
     
     func onStartLS(state: Int, message: String) {
-        if state == 0, message.contains("Initiating") {
+        if state == DigiX.OUTGOING_CALL, message.contains("Initiating") {
             DispatchQueue.main.async {
                 self.imageView.transform = CGAffineTransform.init(scaleX: 1.6, y: 1.6)
             }
@@ -524,7 +524,7 @@ extension QmeraStreamingViewController: LiveStreamingDelegate {
     }
     
     func onJoinLS(state: Int, message: String) {
-        if state == 22 {
+        if state == DigiX.AUDIO_CALL_OFFHOOK {
             let m = message.split(separator: ",")
             let _ = String(m[0])
             let _ = String(m[1])
@@ -540,7 +540,7 @@ extension QmeraStreamingViewController: LiveStreamingDelegate {
                 }
             }
             sendJoin()
-        } else if state == 23 {
+        } else if state == DigiX.AUDIO_CALL_RINGING {
             let m = message.split(separator: ",")
             let _ = String(m[0])
             let _ = String(m[1])
@@ -555,7 +555,7 @@ extension QmeraStreamingViewController: LiveStreamingDelegate {
                     self.imageView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 5)/2 : (CGFloat.pi)/2)
                 }
             }
-        } else if state == 88 {
+        } else if state == DigiX.STREAMING_SEMINAR_ENDED {
             DispatchQueue.main.async {
                 self.status.text = "Streaming ended".localized()
             }

+ 8 - 8
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Streaming/SeminarViewController.swift

@@ -717,7 +717,7 @@ extension SeminarViewController: UITableViewDataSource {
 extension SeminarViewController: SeminarDelegate {
     
     func onStartSeminar(state: Int, message: String) {
-        if state == 0, message.contains("Initiating") {
+        if state == DigiX.OUTGOING_CALL, message.contains("Initiating") {
             DispatchQueue.main.async {
                 self.tvCameraPreviewB.transform = CGAffineTransform.init(scaleX: 1.6, y: 1.6)
             }
@@ -727,7 +727,7 @@ extension SeminarViewController: SeminarDelegate {
     }
     
     func onJoinSeminar(state: Int, message: String) {
-        if state == 22 {
+        if state == DigiX.AUDIO_CALL_OFFHOOK {
             let m = message.split(separator: ",")
             let _ = String(m[0])
             let _ = String(m[1])
@@ -743,7 +743,7 @@ extension SeminarViewController: SeminarDelegate {
                 }
             }
             sendJoin()
-        } else if state == 23 {
+        } else if state == DigiX.AUDIO_CALL_RINGING {
             let m = message.split(separator: ",")
             let _ = String(m[0])
             let _ = String(m[1])
@@ -758,14 +758,14 @@ extension SeminarViewController: SeminarDelegate {
                     self.ivRemoteViewM.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 5)/2 : (CGFloat.pi)/2)
                 }
             }
-        } else if state == 32 { // initBCA (3* is from Broadcaster PoV)
+        } else if state == DigiX.VIDEO_CALL_OFFHOOK { // initBCA (3* is from Broadcaster PoV)
             DispatchQueue.main.async {
                 self.tvCameraPreviewB.removeConstraints(self.tvCameraPreviewB.constraints)
                 self.tvCameraPreviewB.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, bottom: self.view.bottomAnchor, right: self.view.rightAnchor)
                 self.view.bringSubviewToFront(self.tvCameraPreviewB)
                 self.btf()
             }
-        } else if state == 33 { // startAudience (3* is from Broadcaster PoV)
+        } else if state == DigiX.VIDEO_CALL_RINGING { // startAudience (3* is from Broadcaster PoV)
             let m = message.split(separator: ",")
             let f_pin = m[0]
             let camera = Int(m[1])
@@ -787,7 +787,7 @@ extension SeminarViewController: SeminarDelegate {
             viewers.first(where: {$0.f_pin == currentSpeakingBC})?.isSpeak = true
             // TODO: remove badge if no raise hand
             
-        } else if state == 34 { // endAudience (3* is from Broadcaster PoV)
+        } else if state == DigiX.VIDEO_CAMERA_PARAMS_CHANED { // endAudience (3* is from Broadcaster PoV)
             let m = message.split(separator: ",")
             let f_pin = m[0]
             if currentSpeakingBC == f_pin {
@@ -803,7 +803,7 @@ extension SeminarViewController: SeminarDelegate {
             }
             viewers.first(where: {$0.f_pin == f_pin})?.isRaise = false
             viewers.first(where: {$0.f_pin == f_pin})?.isSpeak = false
-        } else if state == 36 || state == 46 { // audience change camera (3* is from Broadcaster PoV)
+        } else if state == DigiX.VIDEO_CALL_MUTE_UNMUTE || state == 46 { // audience change camera (3* is from Broadcaster PoV)
             let m = message.split(separator: ",")
             let camera = Int(m[2])
             let rotation = camera == 1 ? CGFloat.pi * 2.5 : CGFloat.pi * 0.5
@@ -900,7 +900,7 @@ extension SeminarViewController: SeminarDelegate {
                 self.ivRemoteViewM.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: rotation - self.ivMRotation)
                 self.ivMRotation = rotation
             }
-        } else if state == 88 {
+        } else if state == DigiX.STREAMING_SEMINAR_ENDED {
             DispatchQueue.main.async {
                 self.status.text = "Seminar ended".localized()
             }

+ 3 - 3
appbuilder-ios/DigiXLite/DigiXLite/Source/View/Streaming/StreamingViewController.swift

@@ -56,7 +56,7 @@ extension StreamingViewController: LiveStreamingDelegate {
     }
     
     func onJoinLS(state: Int, message: String) {
-        if state == 22 {
+        if state == DigiX.AUDIO_CALL_OFFHOOK {
             let m = message.split(separator: ",")
             let from = String(m[0])
             let title = String(m[1])
@@ -67,7 +67,7 @@ extension StreamingViewController: LiveStreamingDelegate {
                     self.cameraView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 3)/2 : (CGFloat.pi)/2)
                 }
             }
-        } else if state == 23 {
+        } else if state == DigiX.AUDIO_CALL_RINGING {
             let m = message.split(separator: ",")
             let from = String(m[0])
             let title = String(m[1])
@@ -78,7 +78,7 @@ extension StreamingViewController: LiveStreamingDelegate {
                     self.cameraView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 3)/2 : (CGFloat.pi)/2)
                 }
             }
-        } else if state == 88 {
+        } else if state == DigiX.STREAMING_SEMINAR_ENDED {
             DispatchQueue.main.async {
                 self.status.text = "Streaming ended".localized()
             }

+ 7 - 3
appbuilder-ios/NexilisLite/NexilisLite/Source/Callback.swift

@@ -33,12 +33,16 @@ class Callback : CallBack {
     
     func callStateChanged(nState: Int!, sMessage: String!) -> Int {
         //print(nState,"/",sMessage)
-        if nState == 21 || nState == 31 {
+        if nState == Nexilis.AUDIO_CALL_INCOMING || nState == Nexilis.VIDEO_CALL_INCOMING {
             if let delegate = Nexilis.shared.callDelegate {
-                delegate.onIncomingCall(state: nState, message: sMessage)
+                if !Nexilis.showLibraryNotification {
+                    delegate.onStatusCall(state: nState, message: sMessage)
+                } else {
+                    delegate.onIncomingCall(state: nState, message: sMessage)
+                }
             }
         } else {
-//            if nState == 28 {
+//            if nstate == Nexilis.AUDIO_CALL_END {
 //                let pin = sMessage.split(separator: ",")[0]
 //                if let call = Palio.shared.callManager.call(with: String(pin)), !call.hasVideo, !call.hasEnded {
 //                    call.reconnectingCall()

+ 1 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/FloatingButton/FloatingButton.swift

@@ -113,7 +113,7 @@ public class FloatingButton: UIView {
         
         let center: NotificationCenter = NotificationCenter.default
         center.addObserver(self, selector: #selector(imageFBUpdate(notification:)), name: NSNotification.Name(rawValue: "imageFBUpdate"), object: nil)
-        center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
         center.addObserver(self, selector: #selector(checkCounter), name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil)
         let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hideButton))
         tapGesture.cancelsTouchesInView = false

+ 81 - 29
appbuilder-ios/NexilisLite/NexilisLite/Source/Nexilis.swift

@@ -54,6 +54,32 @@ public class Nexilis: NSObject {
     
     public static var loadingAlert = LibAlertController()
     
+    public static let listenerReceiveChat = "onReceiveChatLibLite"
+    public static let listenerStatusChat = "onMessageChatLibLite"
+    public static let listenerTypingChat = "onTypingChatLibLite"
+    public static let listenerStatusCall = "onStatusCallLibLite"
+    public static var showLibraryNotification = true
+    
+    public static let STREAMING_SEMINAR_ENDED = 88
+    public static let VIDEO_CALL_END = 38
+    public static let VIDEO_CALL_MUTE_UNMUTE = 36
+    public static let VIDEO_CALL_ZOOM = 35
+    public static let VIDEO_CAMERA_PARAMS_CHANED = 34
+    public static let VIDEO_CALL_RINGING = 33
+    public static let VIDEO_CALL_OFFHOOK = 32
+    public static let VIDEO_CALL_INCOMING = 31
+    public static let AUDIO_CALL_END = 28
+    public static let AUDIO_CALL_RINGING = 23
+    public static let AUDIO_CALL_OFFHOOK = 22
+    public static let AUDIO_CALL_INCOMING = 21
+    public static let VIDEO_RINGING = 11
+    public static let ENDED = 8
+    public static let INITIATING = 4
+    public static let AUDIO_RINGING = 1
+    public static let OUTGOING_CALL = 0
+    public static let OFFLINE = -3
+    public static let BUSY = -4
+    
     private func createDelegate() {
         //print("createDelegate...")
         callDelegate = self
@@ -382,6 +408,32 @@ public class Nexilis: NSObject {
         }
     }
     
+    public static func apiSendChat(destination: String, message: String, isGroup: Bool, thumbnailName: String = "", imageName: String = "", videoName: String = "", fileName: String = "", audioName: String = "", replyMessageId : String = "") -> String {
+        let message = CoreMessage_TMessageBank.sendMessage(l_pin: destination, message_scope_id: isGroup ? "4" : "3", status: "3", message_text: message, credential: "", attachment_flag: !imageName.isEmpty ? "1" : !videoName.isEmpty ? "2" : !audioName.isEmpty ? "5" : !fileName.isEmpty ? "6" : "0", ex_blog_id: "", message_large_text: "", ex_format: "", image_id: imageName, audio_id: audioName, video_id: videoName, file_id: fileName, thumb_id: thumbnailName, reff_id: replyMessageId, read_receipts: "4", chat_id: "", is_call_center: "0", call_center_id: "", opposite_pin: User.getMyPin() ?? "")
+        addQueueMessage(message: message)
+        return message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
+    }
+    
+    public static func apiInitiateAudioCall(destination: String) {
+        API.initiateCCall(sParty: destination)
+    }
+    
+    public static func apiReceiveAudioCall(destination: String) {
+        API.receiveCCall(sParty: destination)
+    }
+    
+    public static func apiInitiateVideoCall(destination: String, backCamera: Bool = false, listRemoteViews: [UIImageView], localView: UIImageView, remoteViewSpeaker: UIImageView) {
+        API.initiateCCall(sParty: destination, nCamIdx: backCamera ? 0 : 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViews, ivLocalView: localView, ivRemoteZ: remoteViewSpeaker)
+    }
+    
+    public static func apiReceiveVideoCall(destination: String, backCamera: Bool = false, listRemoteViews: [UIImageView], localView: UIImageView, remoteViewSpeaker: UIImageView) {
+        API.receiveCCall(sParty: destination, nCamIdx: backCamera ? 0 : 1, nResIdx: 2, nVQuality: 4, ivRemoteView: listRemoteViews, ivLocalView: localView, ivRemoteZ: remoteViewSpeaker)
+    }
+    
+    public static func apiEndAllCall() {
+        API.terminateCall(sParty: nil)
+    }
+    
     public static func addQueueMessage(message: TMessage) {
 //        OutgoingThread.default.addQueue(message: message)
         InquiryThread.default.addQueue(message: message)
@@ -1660,7 +1712,7 @@ extension Nexilis: CallDelegate {
                     isShowAlert = 0
                 }
             }
-            if (state == 21 && message.split(separator: ",")[1] != "joining Ac.room on channel 0") {
+            if (state == Nexilis.AUDIO_CALL_INCOMING && message.split(separator: ",")[1] != "joining Ac.room on channel 0") {
                 let data = User.getDataCanNil(pin: String(deviceId))
                 if data == nil {
                     DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
@@ -1694,7 +1746,7 @@ extension Nexilis: CallDelegate {
                     UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
                 }
 //                    API.receiveCCall(sParty: String(deviceId))
-            } else if state == 31 {
+            } else if state == Nexilis.VIDEO_CALL_INCOMING {
                 let dataUser = User.getDataCanNil(pin: String(deviceId))
                 if dataUser == nil {
                     DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
@@ -1728,32 +1780,32 @@ extension Nexilis: CallDelegate {
     }
     
     public func onStatusCall(state: Int, message: String) {
-        let r = message.split(separator: ",")
-        if state == 23 {
-            if let call = callManager.call(with: String(r[0])) {
-                //print("onStatusCall:connectingCall")
-                DispatchQueue.main.async {
-                    call.connectingCall()
-                }
-            }
-        } else if state == 22 {
-//            if let call = callManager.call(with: String(r[1])) {
-                //print("onStatusCall:answerCall")
+//        let r = message.split(separator: ",")
+//        if state == Nexilis.AUDIO_CALL_RINGING {
+//            if let call = callManager.call(with: String(r[0])) {
+//                //print("onStatusCall:connectingCall")
 //                DispatchQueue.main.async {
-//                    call.answerCall()
+//                    call.connectingCall()
 //                }
 //            }
-        } else if state == 28 {
-            DispatchQueue.main.async {
-                if QmeraAudioViewController().viewIfLoaded?.window == nil {
-                    Nexilis.shared.callManager.end(call: Call(uuid: uuidOngoing))
-                }
-            }
-        }
+//        } else if state == Nexilis.AUDIO_CALL_OFFHOOK {
+////            if let call = callManager.call(with: String(r[1])) {
+//                //print("onStatusCall:answerCall")
+////                DispatchQueue.main.async {
+////                    call.answerCall()
+////                }
+////            }
+//        } else if state == Nexilis.AUDIO_CALL_END {
+//            DispatchQueue.main.async {
+//                if QmeraAudioViewController().viewIfLoaded?.window == nil {
+//                    Nexilis.shared.callManager.end(call: Call(uuid: uuidOngoing))
+//                }
+//            }
+//        }
         var dataCall: [AnyHashable : Any] = [:]
         dataCall["state"] = state
         dataCall["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onStatusCall"), object: nil, userInfo: dataCall)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerStatusCall), object: nil, userInfo: dataCall)
     }
     
 }
@@ -2026,7 +2078,7 @@ extension Nexilis: MessageDelegate {
     public func onReceive(message: TMessage) {
         var dataMessage: [AnyHashable : Any] = [:]
         dataMessage["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil, userInfo: dataMessage)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil, userInfo: dataMessage)
         if message.getCode() == CoreMessage_TMessageCode.PUSH_CALL_CENTER {
             if User.getDataCanNil(pin: message.getBody(key: CoreMessage_TMessageKey.L_PIN)) == nil {
                 Nexilis.addFriendSilent(fpin: message.getBody(key: CoreMessage_TMessageKey.L_PIN))
@@ -2775,9 +2827,6 @@ extension Nexilis: MessageDelegate {
             }
         } else if message.getCode() != CoreMessage_TMessageCode.PUSH_CALL_CENTER && message.getCode() != CoreMessage_TMessageCode.ACCEPT_CALL_CENTER && message.getCode() != CoreMessage_TMessageCode.END_CALL_CENTER && message.getCode() != CoreMessage_TMessageCode.TIMEOUT_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.ACCEPT_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.PUSH_MEMBER_ROOM_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.INVITE_END_CONTACT_CENTER && message.getCode() != CoreMessage_TMessageCode.INVITE_EXIT_CONTACT_CENTER || message.mBodies["MERNAM"] != nil {
             let m = message.mBodies
-//            if m[CoreMessage_TMessageKey.IS_CALL_CENTER] == "1" {
-//                return
-//            }
             if message.mBodies["MERNAM"] != nil {
                 DispatchQueue.main.async {
                     if !Nexilis.broadcastList.isEmpty {
@@ -2789,6 +2838,9 @@ extension Nexilis: MessageDelegate {
                 }
                 return
             }
+            if !Nexilis.showLibraryNotification {
+                return
+            }
             let sender = m[CoreMessage_TMessageKey.F_PIN]!
             let me = UserDefaults.standard.string(forKey: "me")!
             if(sender != me) {
@@ -3289,13 +3341,13 @@ extension Nexilis: MessageDelegate {
     public func onReceive(message: [AnyHashable : Any?]) {
         var dataMessage: [AnyHashable : Any] = [:]
         dataMessage["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil, userInfo: dataMessage)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil, userInfo: dataMessage)
     }
     
     public func onMessage(message: TMessage) {
         var dataMessage: [AnyHashable : Any] = [:]
         dataMessage["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onMessageChat"), object: nil, userInfo: dataMessage)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil, userInfo: dataMessage)
     }
     
     public func onUpload(name: String, progress: Double) {
@@ -3308,7 +3360,7 @@ extension Nexilis: MessageDelegate {
     public func onTyping(message: TMessage) {
         var dataMessage: [AnyHashable : Any] = [:]
         dataMessage["message"] = message
-        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "onTypingChat"), object: nil, userInfo: dataMessage)
+        NotificationCenter.default.post(name: NSNotification.Name(rawValue: Nexilis.listenerTypingChat), object: nil, userInfo: dataMessage)
     }
     
 //    public static func faceDetect(fd: FaceDetector?,image: UIImage, completion: ((Bool) -> ())?){

+ 1 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/Utils.swift

@@ -78,7 +78,7 @@ public final class Utils {
 //        return digestData
 //    }
     
-    static let callDurationFormatter: DateComponentsFormatter = {
+    public static let callDurationFormatter: DateComponentsFormatter = {
         let dateFormatter: DateComponentsFormatter
         dateFormatter = DateComponentsFormatter()
         dateFormatter.unitsStyle = .positional

+ 4 - 4
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/AudioViewController.swift

@@ -39,7 +39,7 @@ class AudioViewController: UIViewController {
         
         navigationController?.changeAppearance(clear: true)
         
-        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusCall), object: nil)
         
         speaker.circle()
         speaker.setBackgroundColor(.white, for: .highlighted)
@@ -119,11 +119,11 @@ class AudioViewController: UIViewController {
            let message = data["message"] as? String
         {
             let r = message.split(separator: ",")
-            if state == 23 {
+            if state == Nexilis.AUDIO_CALL_RINGING {
                 DispatchQueue.main.async {
                     self.status.text = "Ringing..."
                 }
-            } else if state == 22 {
+            } else if state == Nexilis.AUDIO_CALL_OFFHOOK {
                 DispatchQueue.main.async {
                     let connectDate = Date()
                     self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
@@ -132,7 +132,7 @@ class AudioViewController: UIViewController {
                     }
                     self.timer?.fire()
                 }
-            } else if state == 28 || state == -4 {
+            } else if state == Nexilis.AUDIO_CALL_END || state == Nexilis.BUSY {
                 DispatchQueue.main.async {
                     if self.isOutgoing {
                         self.navigationController?.popViewController(animated: true)

+ 8 - 8
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/QmeraAudioConference.swift

@@ -189,8 +189,8 @@ class QmeraAudioConference: UIViewController {
         name.anchor(top: profiles.bottomAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 5, paddingLeft: 20, paddingRight: 20, centerX: view.centerXAnchor)
         definesPresentationContext = true
         
-        NotificationCenter.default.addObserver(self, selector: #selector(onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusCall(_:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusCall), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
         
         if isOutgoing {
             users.append(User.getData(pin: UserDefaults.standard.string(forKey: "me")!)!)
@@ -469,7 +469,7 @@ class QmeraAudioConference: UIViewController {
            let message = data["message"] as? String {
             let arrayMessage = message.split(separator: ",")
             //print("UYY \(state) \(message)")
-            if state == 22 {
+            if state == Nexilis.AUDIO_CALL_OFFHOOK {
                 if users.count == 1 && firstCall {
                     DispatchQueue.main.async {
                         self.ongoingView()
@@ -502,13 +502,13 @@ class QmeraAudioConference: UIViewController {
                     }
                 }
             }
-//            if state == 23 {
+//            if state == Nexilis.AUDIO_CALL_RINGING {
 //                if users.count == 1 {
 //                    DispatchQueue.main.async {
 //                        self.status.text = "Ringing..."
 //                    }
 //                }
-//            } else if state == 22 {
+//            } else if state == Nexilis.AUDIO_CALL_OFFHOOK {
 //                if users.count == 1 && firstCall {
 //                    DispatchQueue.main.async {
 //                        self.ongoingView()
@@ -538,7 +538,7 @@ class QmeraAudioConference: UIViewController {
 //                        }
 //                    }
 //                }
-//            } else if state == 28 {
+//            } else if state == Nexilis.AUDIO_CALL_END {
 //                let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
 //                if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
 //                    users.remove(at: index)
@@ -575,7 +575,7 @@ class QmeraAudioConference: UIViewController {
 //                        self.dismiss(animated: false, completion: nil)
 //                    }
 //                }
-//            } else if state == -3 { // Offline
+//            } else if state == Nexilis.OFFLINE { // Offline
 //                let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
 //                if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
 //                    users.remove(at: index)
@@ -602,7 +602,7 @@ class QmeraAudioConference: UIViewController {
 //                        }
 //                    }
 //                }
-//            } else if state == -4 { // Busy
+//            } else if state == Nexilis.BUSY { // Busy
 //                let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
 //                if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
 //                    users.remove(at: index)

+ 7 - 7
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/QmeraAudioViewController.swift

@@ -268,8 +268,8 @@ class QmeraAudioViewController: UIViewController {
         
         UIDevice.current.isProximityMonitoringEnabled = true
         
-        NotificationCenter.default.addObserver(self, selector: #selector(onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusCall(_:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusCall), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
         
         if let u = self.user {
             self.users.append(u)
@@ -759,13 +759,13 @@ class QmeraAudioViewController: UIViewController {
            let message = data["message"] as? String
         {
             let arrayMessage = message.split(separator: ",")
-            if state == 23 || (!ticketId.isEmpty && state == 33) {
+            if state == Nexilis.AUDIO_CALL_RINGING || (!ticketId.isEmpty && state == Nexilis.VIDEO_CALL_RINGING) {
                 if users.count == 1 {
                     DispatchQueue.main.async {
                         self.status.text = "Ringing..."
                     }
                 }
-            } else if state == 22 || (!ticketId.isEmpty && state == 32) {
+            } else if state == Nexilis.AUDIO_CALL_OFFHOOK || (!ticketId.isEmpty && state == Nexilis.VIDEO_CALL_OFFHOOK) {
                 if users.count == 1 && firstCall {
                     DispatchQueue.main.async {
                         if !self.ticketId.isEmpty {
@@ -807,7 +807,7 @@ class QmeraAudioViewController: UIViewController {
                         }
                     }
                 }
-            } else if state == 28 || (!ticketId.isEmpty && state == 38) {
+            } else if state == Nexilis.AUDIO_CALL_END || (!ticketId.isEmpty && state == Nexilis.VIDEO_CALL_END) {
                 let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
                 if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
                     users.remove(at: index)
@@ -873,7 +873,7 @@ class QmeraAudioViewController: UIViewController {
 //                        self.dismiss(animated: false, completion: nil)
 //                    }
 //                }
-            } else if state == -3 { // Offline
+            } else if state == Nexilis.OFFLINE { // Offline
                 let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
                 if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
                     users.remove(at: index)
@@ -900,7 +900,7 @@ class QmeraAudioViewController: UIViewController {
                         }
                     }
                 }
-            } else if state == -4 { // Busy
+            } else if state == Nexilis.BUSY { // Busy
                 let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
                 if let pin = arrayMessage.first, let index = users.firstIndex(of: User(pin: String(pin))) {
                     users.remove(at: index)

+ 9 - 9
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/QmeraVideoViewController.swift

@@ -146,8 +146,8 @@ class QmeraVideoViewController: UIViewController {
         navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
         navigationController?.changeAppearance(clear: true)
         
-        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusCall), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
         
         view.backgroundColor = .clear
         navigationController?.navigationBar.topItem?.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
@@ -933,7 +933,7 @@ class QmeraVideoViewController: UIViewController {
         let message = (data?["message"] ?? "") as! String
         var remoteChannel = [String:String]()
         let arrayMessage = message.split(separator: ",")
-        if(state == 35){
+        if(state == Nexilis.VIDEO_CALL_ZOOM){
             DispatchQueue.main.async {
                 if self.dataPerson.count > 1 {
                     if !self.transformZoomAfterNewUserMore2 {
@@ -943,7 +943,7 @@ class QmeraVideoViewController: UIViewController {
                 }
             }
         }
-        else if (state == 34){
+        else if (state == Nexilis.VIDEO_CAMERA_PARAMS_CHANED){
             if(arrayMessage[3] == "0"){
                 DispatchQueue.main.async {
                     if self.dataPerson.count == 1 && arrayMessage[2] == "1" && arrayMessage[4] == "1" {
@@ -954,7 +954,7 @@ class QmeraVideoViewController: UIViewController {
                 }
             }
         }
-        else if (state == 32) {
+        else if (state == Nexilis.VIDEO_CALL_OFFHOOK) {
             let channel = arrayMessage[3]
             remoteChannel[String(channel)] = String(arrayMessage[5])
             DispatchQueue.main.async {
@@ -1071,7 +1071,7 @@ class QmeraVideoViewController: UIViewController {
                     self.dataPerson[indexPerson!]["user_type"] = String(arrayMessage[5])
                 }
             }
-        } else if (state == 38 || state == 28) {
+        } else if (state == Nexilis.VIDEO_CALL_END || state == Nexilis.AUDIO_CALL_END) {
             let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
             if !onGoingCC.isEmpty {
                 let requester = onGoingCC.components(separatedBy: ",")[0]
@@ -1208,7 +1208,7 @@ class QmeraVideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == -3) {
+        } else if (state == Nexilis.OFFLINE) {
             let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
             DispatchQueue.main.async {
                 if (self.dataPerson.count == 1) {
@@ -1274,7 +1274,7 @@ class QmeraVideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == -4) {
+        } else if (state == Nexilis.BUSY) {
             let onGoingCC = UserDefaults.standard.string(forKey: "onGoingCC") ?? ""
             DispatchQueue.main.async { [self] in
                 if (self.dataPerson.count == 1) {
@@ -1340,7 +1340,7 @@ class QmeraVideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == 33) {
+        } else if (state == Nexilis.VIDEO_CALL_RINGING) {
             DispatchQueue.main.async {
                 if (self.dataPerson.count > 1) {
                     if (self.dataPerson.count == 2) {

+ 9 - 9
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/VideoViewController.swift

@@ -56,7 +56,7 @@ class VideoViewController: UIViewController {
     }
     
     override func viewDidDisappear(_ animated: Bool) {
-        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
+        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: Nexilis.listenerStatusCall), object: nil)
         NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "afterAddParticipantVideo"), object: nil)
     }
     
@@ -76,7 +76,7 @@ class VideoViewController: UIViewController {
         self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
         self.navigationItem.setHidesBackButton(true, animated: false)
         NotificationCenter.default.addObserver(self, selector: #selector(self.addCallParticipant(_:)), name: NSNotification.Name(rawValue: "afterAddParticipantVideo"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: "onStatusCall"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(self.onStatusCall(_:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusCall), object: nil)
         if (dataPerson.count > 0) {
             if (isInisiator) {
                 viewButtonDeclineAccept.isHidden = true
@@ -149,12 +149,12 @@ class VideoViewController: UIViewController {
         var remoteChannel = [String:String]()
         let arrayMessage = message.split(separator: ",")
         //        let me = UserDefaults.standard.string(forKey: "me")!
-        if(state == 35){
+        if(state == Nexilis.VIDEO_CALL_ZOOM){
             DispatchQueue.main.async {
                 self.zoomView.transform   = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: (CGFloat.pi * 3)/2)
             }
         }
-        else if (state == 34){
+        else if (state == Nexilis.VIDEO_CAMERA_PARAMS_CHANED){
             let channel = arrayMessage[arrayMessage.count - 1]
             if(remoteChannel[String(channel)] != "2"){
                 DispatchQueue.main.async {
@@ -167,7 +167,7 @@ class VideoViewController: UIViewController {
                 }
             }
         }
-        else if (state == 32){
+        else if (state == Nexilis.VIDEO_CALL_OFFHOOK){
             let channel = arrayMessage[3]
             remoteChannel[String(channel)] = String(arrayMessage[5])
             if (arrayMessage[5] == "2") {
@@ -206,7 +206,7 @@ class VideoViewController: UIViewController {
             }
             showButton(isShow: true)
             setStyleAppBar()
-        } else if (state == 38 || state == 28) {
+        } else if (state == Nexilis.VIDEO_CALL_END || state == Nexilis.AUDIO_CALL_END) {
             DispatchQueue.main.async {
                 if (self.dataPerson.count == 1) {
                     //                let channel = arrayMessage[1]
@@ -252,7 +252,7 @@ class VideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == -3) {
+        } else if (state == Nexilis.OFFLINE) {
             DispatchQueue.main.async {
                 self.buttonEndCall.isHidden = true
                 self.labelStatusCall.text = "Offline"
@@ -265,7 +265,7 @@ class VideoViewController: UIViewController {
                     self.dismiss(animated: true, completion: nil)
                 }
             }
-        } else if (state == -4) {
+        } else if (state == Nexilis.BUSY) {
             DispatchQueue.main.async {
                 if (self.dataPerson.count == 1) {
                     self.buttonEndCall.isHidden = true
@@ -295,7 +295,7 @@ class VideoViewController: UIViewController {
                     }
                 }
             }
-        } else if (state == 33) {
+        } else if (state == Nexilis.VIDEO_CALL_RINGING) {
             DispatchQueue.main.async {
                 if (self.dataPerson.count > 1) {
                     if (self.dataPerson.count == 2) {

+ 2 - 2
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -182,8 +182,8 @@ public class EditorGroup: UIViewController {
         let center: NotificationCenter = NotificationCenter.default
         center.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
         center.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
-        center.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
-        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
+        center.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
+        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil)
         center.addObserver(self, selector: #selector(onUploadChat(notification:)), name: NSNotification.Name(rawValue: "onUploadChat"), object: nil)
         center.addObserver(self, selector: #selector(onMemberTopic(notification:)), name: NSNotification.Name(rawValue: "onMember"), object: nil)
         center.addObserver(self, selector: #selector(onGroup(notification:)), name: NSNotification.Name(rawValue: "onGroup"), object: nil)

+ 3 - 3
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift

@@ -206,11 +206,11 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         let center: NotificationCenter = NotificationCenter.default
         center.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
         center.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
-        center.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
-        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
+        center.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
+        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil)
         center.addObserver(self, selector: #selector(onUploadChat(notification:)), name: NSNotification.Name(rawValue: "onUploadChat"), object: nil)
         center.addObserver(self, selector: #selector(onUnfriend(notification:)), name: NSNotification.Name(rawValue: "onUpdatePersonInfo"), object: nil)
-        center.addObserver(self, selector: #selector(onTyping(notification:)), name: NSNotification.Name(rawValue: "onTypingChat"), object: nil)
+        center.addObserver(self, selector: #selector(onTyping(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerTypingChat), object: nil)
         
         if dataMessageForward != nil {
             for i in 0..<dataMessageForward!.count {

+ 1 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorStarMessages.swift

@@ -63,7 +63,7 @@ public class EditorStarMessages: UIViewController, UITableViewDataSource, UITabl
         tableChatView.reloadData()
         
         let center: NotificationCenter = NotificationCenter.default
-        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
+        center.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil)
 
     }
     

+ 2 - 2
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/ContactChatViewController.swift

@@ -180,8 +180,8 @@ class ContactChatViewController: UITableViewController {
         segment.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 12.0)], for: .normal)
         Utils.inTabChats = true
         
-        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onMember"), object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(onReload(notification:)), name: NSNotification.Name(rawValue: "onUpdatePersonInfo"), object: nil)
         

+ 1 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/HistoryBroadcastViewController.swift

@@ -60,7 +60,7 @@ class HistoryBroadcastViewController: UIViewController, UITableViewDelegate, UIT
 //                self.historyTableView.reloadData()
 //            }
 //        }
-        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: "onReceiveChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onReceiveMessage(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerReceiveChat), object: nil)
     }
     
     @objc func onReceiveMessage(notification: NSNotification) {

+ 1 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/MessageInfo.swift

@@ -38,7 +38,7 @@ class MessageInfo: UIViewController, UITableViewDelegate, UITableViewDataSource
         
         view.addSubview(tableStatus)
         tableStatus.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor)
-        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: "onMessageChat"), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(onStatusChat(notification:)), name: NSNotification.Name(rawValue: Nexilis.listenerStatusChat), object: nil)
     }
     
     @objc func onStatusChat(notification: NSNotification) {

+ 4 - 4
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Streaming/QmeraStreamingViewController.swift

@@ -514,7 +514,7 @@ extension QmeraStreamingViewController: UITableViewDataSource {
 extension QmeraStreamingViewController: LiveStreamingDelegate {
     
     func onStartLS(state: Int, message: String) {
-        if state == 0, message.contains("Initiating") {
+        if state == Nexilis.OUTGOING_CALL, message.contains("Initiating") {
             DispatchQueue.main.async {
                 self.imageView.transform = CGAffineTransform.init(scaleX: 1.6, y: 1.6)
             }
@@ -524,7 +524,7 @@ extension QmeraStreamingViewController: LiveStreamingDelegate {
     }
     
     func onJoinLS(state: Int, message: String) {
-        if state == 22 {
+        if state == Nexilis.AUDIO_CALL_OFFHOOK {
             let m = message.split(separator: ",")
             let _ = String(m[0])
             let _ = String(m[1])
@@ -540,7 +540,7 @@ extension QmeraStreamingViewController: LiveStreamingDelegate {
                 }
             }
             sendJoin()
-        } else if state == 23 {
+        } else if state == Nexilis.AUDIO_CALL_RINGING {
             let m = message.split(separator: ",")
             let _ = String(m[0])
             let _ = String(m[1])
@@ -555,7 +555,7 @@ extension QmeraStreamingViewController: LiveStreamingDelegate {
                     self.imageView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 5)/2 : (CGFloat.pi)/2)
                 }
             }
-        } else if state == 88 {
+        } else if state == Nexilis.STREAMING_SEMINAR_ENDED {
             DispatchQueue.main.async {
                 self.status.text = "Streaming ended".localized()
             }

+ 8 - 8
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Streaming/SeminarViewController.swift

@@ -717,7 +717,7 @@ extension SeminarViewController: UITableViewDataSource {
 extension SeminarViewController: SeminarDelegate {
     
     func onStartSeminar(state: Int, message: String) {
-        if state == 0, message.contains("Initiating") {
+        if state == Nexilis.OUTGOING_CALL, message.contains("Initiating") {
             DispatchQueue.main.async {
                 self.tvCameraPreviewB.transform = CGAffineTransform.init(scaleX: 1.6, y: 1.6)
             }
@@ -727,7 +727,7 @@ extension SeminarViewController: SeminarDelegate {
     }
     
     func onJoinSeminar(state: Int, message: String) {
-        if state == 22 {
+        if state == Nexilis.AUDIO_CALL_OFFHOOK {
             let m = message.split(separator: ",")
             let _ = String(m[0])
             let _ = String(m[1])
@@ -743,7 +743,7 @@ extension SeminarViewController: SeminarDelegate {
                 }
             }
             sendJoin()
-        } else if state == 23 {
+        } else if state == Nexilis.AUDIO_CALL_RINGING {
             let m = message.split(separator: ",")
             let _ = String(m[0])
             let _ = String(m[1])
@@ -758,14 +758,14 @@ extension SeminarViewController: SeminarDelegate {
                     self.ivRemoteViewM.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 5)/2 : (CGFloat.pi)/2)
                 }
             }
-        } else if state == 32 { // initBCA (3* is from Broadcaster PoV)
+        } else if state == Nexilis.VIDEO_CALL_OFFHOOK { // initBCA (3* is from Broadcaster PoV)
             DispatchQueue.main.async {
                 self.tvCameraPreviewB.removeConstraints(self.tvCameraPreviewB.constraints)
                 self.tvCameraPreviewB.anchor(top: self.view.topAnchor, left: self.view.leftAnchor, bottom: self.view.bottomAnchor, right: self.view.rightAnchor)
                 self.view.bringSubviewToFront(self.tvCameraPreviewB)
                 self.btf()
             }
-        } else if state == 33 { // startAudience (3* is from Broadcaster PoV)
+        } else if state == Nexilis.VIDEO_CALL_RINGING { // startAudience (3* is from Broadcaster PoV)
             let m = message.split(separator: ",")
             let f_pin = m[0]
             let camera = Int(m[1])
@@ -787,7 +787,7 @@ extension SeminarViewController: SeminarDelegate {
             viewers.first(where: {$0.f_pin == currentSpeakingBC})?.isSpeak = true
             // TODO: remove badge if no raise hand
             
-        } else if state == 34 { // endAudience (3* is from Broadcaster PoV)
+        } else if state == Nexilis.VIDEO_CAMERA_PARAMS_CHANED { // endAudience (3* is from Broadcaster PoV)
             let m = message.split(separator: ",")
             let f_pin = m[0]
             if currentSpeakingBC == f_pin {
@@ -803,7 +803,7 @@ extension SeminarViewController: SeminarDelegate {
             }
             viewers.first(where: {$0.f_pin == f_pin})?.isRaise = false
             viewers.first(where: {$0.f_pin == f_pin})?.isSpeak = false
-        } else if state == 36 || state == 46 { // audience change camera (3* is from Broadcaster PoV)
+        } else if state == Nexilis.VIDEO_CALL_MUTE_UNMUTE || state == 46 { // audience change camera (3* is from Broadcaster PoV)
             let m = message.split(separator: ",")
             let camera = Int(m[2])
             let rotation = camera == 1 ? CGFloat.pi * 2.5 : CGFloat.pi * 0.5
@@ -900,7 +900,7 @@ extension SeminarViewController: SeminarDelegate {
                 self.ivRemoteViewM.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: rotation - self.ivMRotation)
                 self.ivMRotation = rotation
             }
-        } else if state == 88 {
+        } else if state == Nexilis.STREAMING_SEMINAR_ENDED {
             DispatchQueue.main.async {
                 self.status.text = "Seminar ended".localized()
             }

+ 3 - 3
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Streaming/StreamingViewController.swift

@@ -56,7 +56,7 @@ extension StreamingViewController: LiveStreamingDelegate {
     }
     
     func onJoinLS(state: Int, message: String) {
-        if state == 22 {
+        if state == Nexilis.AUDIO_CALL_OFFHOOK {
             let m = message.split(separator: ",")
             let from = String(m[0])
             let title = String(m[1])
@@ -67,7 +67,7 @@ extension StreamingViewController: LiveStreamingDelegate {
                     self.cameraView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 3)/2 : (CGFloat.pi)/2)
                 }
             }
-        } else if state == 23 {
+        } else if state == Nexilis.AUDIO_CALL_RINGING {
             let m = message.split(separator: ",")
             let from = String(m[0])
             let title = String(m[1])
@@ -78,7 +78,7 @@ extension StreamingViewController: LiveStreamingDelegate {
                     self.cameraView.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 3)/2 : (CGFloat.pi)/2)
                 }
             }
-        } else if state == 88 {
+        } else if state == Nexilis.STREAMING_SEMINAR_ENDED {
             DispatchQueue.main.async {
                 self.status.text = "Streaming ended".localized()
             }