Browse Source

Merge remote-tracking branch 'origin/master'

kevin 2 years ago
parent
commit
73d66b0f18
25 changed files with 541 additions and 167 deletions
  1. 3 1
      appbuilder-ios/AppBuilder/AppBuilder/AppDelegate.swift
  2. 35 15
      appbuilder-ios/AppBuilder/AppBuilder/FirstTabViewController.swift
  3. 78 13
      appbuilder-ios/AppBuilder/AppBuilder/FourthTabViewController.swift
  4. 4 4
      appbuilder-ios/AppBuilder/AppBuilder/PrefsUtil.swift
  5. 40 13
      appbuilder-ios/AppBuilder/AppBuilder/SecondTabViewController.swift
  6. 41 11
      appbuilder-ios/AppBuilder/AppBuilder/ThirdTabViewController.swift
  7. 8 15
      appbuilder-ios/AppBuilder/AppBuilder/ViewController.swift
  8. 2 0
      appbuilder-ios/NexilisLite/NexilisLite/Resource/id.lproj/Localizable.strings
  9. 24 2
      appbuilder-ios/NexilisLite/NexilisLite/Source/CoreMessage_TMessageBank.swift
  10. 2 0
      appbuilder-ios/NexilisLite/NexilisLite/Source/CoreMessage_TMessageCode.swift
  11. 6 0
      appbuilder-ios/NexilisLite/NexilisLite/Source/Database.swift
  12. 1 1
      appbuilder-ios/NexilisLite/NexilisLite/Source/Extension.swift
  13. 50 0
      appbuilder-ios/NexilisLite/NexilisLite/Source/IncomingThread.swift
  14. 122 0
      appbuilder-ios/NexilisLite/NexilisLite/Source/InquiryThread.swift
  15. 48 42
      appbuilder-ios/NexilisLite/NexilisLite/Source/Nexilis.swift
  16. 5 8
      appbuilder-ios/NexilisLite/NexilisLite/Source/OutgoingThread.swift
  17. 1 1
      appbuilder-ios/NexilisLite/NexilisLite/Source/TMessage.swift
  18. 11 14
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift
  19. 16 11
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift
  20. 1 0
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/AddFriendTableViewController.swift
  21. 2 1
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/ChangeNamePassswordViewController.swift
  22. 20 10
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/ContactChatViewController.swift
  23. 13 1
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/GroupDetailViewController.swift
  24. 4 0
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/ProfileViewController.swift
  25. 4 4
      appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/ScannerViewController.swift

+ 3 - 1
appbuilder-ios/AppBuilder/AppBuilder/AppDelegate.swift

@@ -167,9 +167,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
             }
         }
         let tabBarAppearance: UITabBarAppearance = UITabBarAppearance()
-        tabBarAppearance.configureWithDefaultBackground()
+        tabBarAppearance.configureWithTransparentBackground()
         if Bundle.main.displayName == "DigiNetS" {
             tabBarAppearance.backgroundColor = .black.withAlphaComponent(0.7)
+        } else {
+            tabBarAppearance.backgroundColor = .white.withAlphaComponent(0.9)
         }
         if #available(iOS 13.0, *) {
             UITabBar.appearance().standardAppearance = tabBarAppearance

+ 35 - 15
appbuilder-ios/AppBuilder/AppBuilder/FirstTabViewController.swift

@@ -27,13 +27,10 @@ class FirstTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
     
     var dateRefresh: Date?
     public static var forceRefresh = false
+    public static var atFirstPage = true
     
     override func viewDidLoad() {
         super.viewDidLoad()
-        let cpaasMode = PrefsUtil.getCpaasMode()
-        let isBurger = cpaasMode == PrefsUtil.CPAAS_MODE_BURGER
-//        navigationController?.navigationBar.backgroundColor = .white
-        navigationController?.setNavigationBarHidden(!isBurger, animated: false)
         let tapGesture = UITapGestureRecognizer(target: self, action: #selector(collapseDocked))
         tapGesture.cancelsTouchesInView = false
         tapGesture.delegate = self
@@ -77,19 +74,19 @@ class FirstTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
         }
         switch(ViewController.sURL){
         case "0":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         case "1":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         case "2":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         case "3":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         case "4":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         default:
             if(!ViewController.sURL.isEmpty){
@@ -104,7 +101,8 @@ class FirstTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
             }
         }
         if let u = myURL {
-            if dateRefresh == nil || Int(Date().timeIntervalSince(dateRefresh!)) >= 60 || FirstTabViewController.forceRefresh {
+            self.webView.evaluateJavaScript("{window.localStorage.setItem('currentTab','\(ViewController.sURL)')}")
+            if (dateRefresh == nil || Int(Date().timeIntervalSince(dateRefresh!)) >= 60 || FirstTabViewController.forceRefresh) && FirstTabViewController.atFirstPage {
                 let myRequest = URLRequest(url: u)
                 webView.load(myRequest)
             }
@@ -163,6 +161,14 @@ class FirstTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
                 }
                 ViewController.removeMiddleButton()
             }
+        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+            DispatchQueue.main.async {
+                if let viewController = viewController as? ViewController {
+                    if !viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = true
+                    }
+                }
+            }
         }
     }
 
@@ -180,6 +186,14 @@ class FirstTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
                 viewController.tabBar.isHidden = false
                 ViewController.middleButton.isHidden = false
             }
+        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+            DispatchQueue.main.async {
+                if let viewController = viewController as? ViewController {
+                    if viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = false
+                    }
+                }
+            }
         }
     }
 
@@ -220,10 +234,8 @@ class FirstTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
                   let param1 = dict["param1"] as? Bool else {
                 return
             }
-            if param1 {
-                
-            } else {
-                
+            if !param1 {
+                self.webView.evaluateJavaScript("closeModal(true);")
             }
         } else if message.name == "toggleVoiceSearch" {
             if !isAllowSpeech {
@@ -441,6 +453,10 @@ class FirstTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
             print("audioEngine couldn't start because of an error.")
         }
     }
+    
+    func isUsingMyWebview() -> Bool{
+        return PrefsUtil.getURLFirstTab() == "0" || PrefsUtil.getURLFirstTab() == "1" || PrefsUtil.getURLFirstTab() == "2" || PrefsUtil.getURLFirstTab() == "3" || PrefsUtil.getURLFirstTab() == "4"
+    }
 
 }
 
@@ -460,9 +476,13 @@ extension FirstTabViewController: WKUIDelegate, WKNavigationDelegate {
             if let urlStr = navigationAction.request.url?.absoluteString {
                 print("url: \(urlStr)")
                 collapseDocked()
-                if urlStr.contains("nexilis/pages/tab1-main-only") || urlStr.contains("nexilis/pages/tab3-main-only") || urlStr.contains("nexilis/pages/tab1-main") || urlStr.contains("nexilis/pages/tab3-commerce") {
+                if urlStr.contains("nexilis/pages/tab1-main-only") || urlStr.contains("nexilis/pages/tab3-main-only") || urlStr.contains("nexilis/pages/tab1-main") || urlStr.contains("nexilis/pages/tab3-commerce") || urlStr.contains("nexilis/pages/tab1-video") {
                     ViewController.alwaysHideButton = false
                     showTabBar()
+                } else if isUsingMyWebview() {
+                    ViewController.alwaysHideButton = true
+                    hideTabBar()
+                    FirstTabViewController.atFirstPage = false
                 }
             }
 

+ 78 - 13
appbuilder-ios/AppBuilder/AppBuilder/FourthTabViewController.swift

@@ -86,8 +86,18 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
             if ViewController.middleButton.isHidden {
                 ViewController.isExpandButton = false
                 if let viewController = viewController as? ViewController {
-                    viewController.tabBar.isHidden = false
-                    ViewController.middleButton.isHidden = false
+                    if viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = false
+                        ViewController.middleButton.isHidden = false
+                    }
+                }
+            } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+                DispatchQueue.main.async {
+                    if let viewController = viewController as? ViewController {
+                        if viewController.tabBar.isHidden {
+                            viewController.tabBar.isHidden = false
+                        }
+                    }
                 }
             }
         })
@@ -137,18 +147,17 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                         Item(icon: UIImage(systemName: "person.fill"), title: "Personal Information".localized()),
                         Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
                         Item(icon: UIImage(systemName: "person.crop.rectangle"), title: "Change Admin / Internal Password".localized()),
-//                        Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Login to Nexilis Web".localized()),
+                        Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Login to Web".localized()),
                     ]
                 } else if cursorUser.string(forColumnIndex: 0) == "23" || cursorUser.string(forColumnIndex: 0) == "24" {
                     Item.menus["Personal"] = [
                         Item(icon: UIImage(systemName: "person.fill"), title: "Personal Information".localized()),
                         Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-//                        Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Login to Nexilis Web".localized()),
+                        Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Login to Web".localized()),
                     ]
                 } else {
                     Item.menus["Personal"] = [
                         Item(icon: UIImage(systemName: "person.fill"), title: "Personal Information".localized()),
-//                        Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Login to Nexilis Web".localized()),
                             Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
                         Item(icon: UIImage(systemName: "person.crop.rectangle"), title: "Access Admin / Internal Features".localized()),
                     ]
@@ -197,7 +206,6 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
             } else {
                 Item.menus["Personal"] = [
                     Item(icon: UIImage(systemName: "person.fill"), title: "Personal Information".localized()),
-//                        Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Login to Nexilis Web".localized()),
                         Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
                     Item(icon: UIImage(systemName: "person.crop.rectangle"), title: "Access Admin / Internal Features".localized()),
                     Item(icon: UIImage(systemName: "arrow.up.and.person.rectangle.portrait"), title: "Login".localized())
@@ -233,8 +241,8 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
         })
         
         Item.menus["Call"] = [
-            Item(icon: UIImage(systemName: "message"), title: "Incoming Message(s)".localized()),
-            Item(icon: UIImage(systemName: "phone"), title: "Incoming Call(s)".localized()),
+//            Item(icon: UIImage(systemName: "message"), title: "Incoming Message(s)".localized()),
+//            Item(icon: UIImage(systemName: "phone"), title: "Incoming Call(s)".localized()),
             Item(icon: UIImage(systemName: "iphone.homebutton.radiowaves.left.and.right"), title: "Vibrate Mode".localized()),
             Item(icon: UIImage(systemName: "photo.on.rectangle.angled"), title: "Save to Gallery".localized()),
             Item(icon: UIImage(systemName: "arrow.down.square"), title: "Auto Download".localized()),
@@ -256,7 +264,7 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 var bgChoosen = ""
                 let arrayBg = listBg.split(separator: ",")
                 bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
-                ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase()! + "/dashboardv2/uploads/background/" + bgChoosen)!) { data, response, error in
+                ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase() + "/dashboardv2/uploads/background/" + bgChoosen)!) { data, response, error in
                     guard let data = data, error == nil else { return }
                     // always update the UI from the main thread
                     DispatchQueue.main.async() { [self] in
@@ -318,7 +326,7 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 cell.accessoryType = .disclosureIndicator
             case "Access Admin / Internal Features".localized():
                 cell.accessoryType = .disclosureIndicator
-            case "Login to Nexilis Web".localized():
+            case "Login to Web".localized():
                 cell.accessoryType = .disclosureIndicator
             case "Login".localized():
                 cell.accessoryType = .disclosureIndicator
@@ -331,7 +339,8 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 let accessoryButton = UIButton(type: .custom)
                 accessoryButton.setTitle(UIApplication.appVersion, for: .normal)
                 accessoryButton.setTitleColor(.black, for: .normal)
-                accessoryButton.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
+                accessoryButton.contentHorizontalAlignment = .right;
+                accessoryButton.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
                 accessoryButton.contentMode = .scaleAspectFit
                 cell.accessoryView = accessoryButton as UIView
             case "Vibrate Mode".localized():
@@ -460,8 +469,9 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                             UserDefaults.standard.setValue(id, forKey: "me")
                             Utils.setProfile(value: false)
                             UserDefaults.standard.synchronize()
-                            // pos registration
-                            _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: id))
+                            if Utils.getForceAnonymous() {
+                                _ = Nexilis.write(message: CoreMessage_TMessageBank.getPostRegistration(p_pin: id))
+                            }
                             DispatchQueue.main.async {
                                 Nexilis.hideLoader()
                                 let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
@@ -474,6 +484,17 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                                 self.makeMenu()
                                 self.tableView.reloadData()
                             }
+                            if !Utils.getForceAnonymous() {
+                                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
+                                    var viewController = UIApplication.shared.windows.first!.rootViewController
+                                    if !(viewController is ViewController) {
+                                        viewController = self.parent
+                                    }
+                                    if let viewController = viewController as? ViewController {
+                                        viewController.viewWillAppear(false)
+                                    }
+                                })
+                            }
                         } else {
                             Nexilis.hideLoader()
                             let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
@@ -493,6 +514,50 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 }
             }))
             self.present(alert, animated: true, completion: nil)
+        } else if item.title == "Login to Web".localized() {
+            var permissionCheck = -1
+            if AVCaptureDevice.authorizationStatus(for: .video) ==  .authorized {
+                permissionCheck = 1
+            } else if AVCaptureDevice.authorizationStatus(for: .video) ==  .denied {
+                permissionCheck = 0
+            } else {
+                AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) -> Void in
+                    if granted == true {
+                        permissionCheck = 1
+                    } else {
+                        permissionCheck = 0
+                    }
+                })
+            }
+            
+            while permissionCheck == -1 {
+                sleep(1)
+            }
+            
+            if permissionCheck == 0 {
+                let alert = UIAlertController(title: "Attention!".localized(), message: "Please allow camera permission in your settings".localized(), preferredStyle: .alert)
+                alert.addAction(UIAlertAction(title: "OK".localized(), style: UIAlertAction.Style.default, handler: { _ in
+                    if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) {
+                        UIApplication.shared.open(url, options: [:], completionHandler: nil)
+                    }
+                }))
+                if UIApplication.shared.visibleViewController?.navigationController != nil {
+                    UIApplication.shared.visibleViewController?.navigationController?.present(alert, animated: true, completion: nil)
+                } else {
+                    UIApplication.shared.visibleViewController?.present(alert, animated: true, completion: nil)
+                }
+                return
+            }
+            let controller = ScannerViewController()
+            let navigationController = UINavigationController(rootViewController: controller)
+            navigationController.navigationBar.tintColor = .white
+            navigationController.navigationBar.barTintColor = .mainColor
+            navigationController.navigationBar.isTranslucent = false
+            let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
+            navigationController.navigationBar.titleTextAttributes = textAttributes
+            navigationController.view.backgroundColor = .mainColor
+            navigationController.modalPresentationStyle = .custom
+            self.present(navigationController, animated: true)
         }
     }
     

+ 4 - 4
appbuilder-ios/AppBuilder/AppBuilder/PrefsUtil.swift

@@ -49,8 +49,8 @@ class PrefsUtil {
     static func getURLThirdTab() -> String? {
         return UserDefaults.standard.string(forKey: "app_builder_url_third_tab")
     }
-    static func getURLBase() -> String? {
-        return UserDefaults.standard.string(forKey: "app_builder_url_base")
+    static func getURLBase() -> String {
+        return UserDefaults.standard.string(forKey: "app_builder_url_base") ?? "https://newuniverse.io/"
     }
     static func getURLQMS() -> String? {
         return UserDefaults.standard.string(forKey: "app_builder_url_qms")
@@ -68,10 +68,10 @@ class PrefsUtil {
         return UserDefaults.standard.string(forKey: "app_builder_compressor")
     }
     static func getUrlSS() -> String? {
-        return PrefsUtil.getURLBase()! + "dashboardv2/uploads/splashscreen/" + PrefsUtil.getIconSS()!
+        return PrefsUtil.getURLBase() + "dashboardv2/uploads/splashscreen/" + PrefsUtil.getIconSS()!
     }
     static func getUrlDock() -> String? {
-        return PrefsUtil.getURLBase()! + "dashboardv2/uploads/fb_icon/" + PrefsUtil.getIconDock()!
+        return PrefsUtil.getURLBase() + "dashboardv2/uploads/fb_icon/" + PrefsUtil.getIconDock()!
     }
     
     static func setURLFirstTab(value: String) {

+ 40 - 13
appbuilder-ios/AppBuilder/AppBuilder/SecondTabViewController.swift

@@ -117,6 +117,7 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
         
         
         tableView.tableHeaderView = segment
+        tableView.tableFooterView = UIView()
         
         pullBuddy()
         let cpaasMode = PrefsUtil.getCpaasMode()
@@ -278,8 +279,18 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
             if ViewController.middleButton.isHidden {
                 ViewController.isExpandButton = false
                 if let viewController = viewController as? ViewController {
-                    viewController.tabBar.isHidden = false
-                    ViewController.middleButton.isHidden = false
+                    if viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = false
+                        ViewController.middleButton.isHidden = false
+                    }
+                }
+            } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+                DispatchQueue.main.async {
+                    if let viewController = viewController as? ViewController {
+                        if viewController.tabBar.isHidden {
+                            viewController.tabBar.isHidden = false
+                        }
+                    }
                 }
             }
         })
@@ -309,7 +320,7 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
                 var bgChoosen = ""
                 let arrayBg = listBg.split(separator: ",")
                 bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
-                ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase()! + "/dashboardv2/uploads/background/" + bgChoosen)!) { data, response, error in
+                ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase() + "/dashboardv2/uploads/background/" + bgChoosen)!) { data, response, error in
                     guard let data = data, error == nil else { return }
                     // always update the UI from the main thread
                     DispatchQueue.main.async() { [self] in
@@ -323,10 +334,15 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
             segment.setTitle("Groups".localized(), forSegmentAt: 1)
         }
         searchController.searchBar.placeholder = "Search chats & messages".localized()
-        groupMap.removeAll()
+        removeAllData()
+        getData()
+    }
+    
+    func removeAllData() {
         groups.removeAll()
+        groupMap.removeAll()
+        chats.removeAll()
         tableView.reloadData()
-        getData()
     }
     
     override func viewWillDisappear(_ animated: Bool) {
@@ -365,6 +381,7 @@ class SecondTabViewController: UIViewController, UIScrollViewDelegate, UIGesture
         getChats {
             self.getContacts {
                 self.getGroups { g1 in
+                    self.groupMap.removeAll()
                     self.groups.removeAll()
                     self.groups.append(contentsOf: g1)
                     DispatchQueue.main.async {
@@ -584,8 +601,7 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                 dismiss(animated: true, completion: nil)
                 return
             }
-            let user = User.getData(pin: data.pin)
-            if user != nil || data.pin == "-999" {
+            if data.messageScope == "3" {
                 let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
                 editorPersonalVC.hidesBottomBarWhenPushed = true
                 editorPersonalVC.unique_l_pin = data.pin
@@ -602,7 +618,11 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                 if indexPath.row == 0 {
                     group = fillteredData[indexPath.section] as! Group
                 } else {
-                    group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
+                    if (fillteredData[indexPath.section] as! Group).childs.count > 0 {
+                        group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
+                    } else {
+                        return
+                    }
                 }
             } else {
                 if indexPath.row == 0 {
@@ -741,7 +761,7 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         var value = 0
         if isFilltering {
-            if segment.selectedSegmentIndex == 2, let groups = fillteredData as? [Group] {
+            if segment.selectedSegmentIndex == 1, let groups = fillteredData as? [Group] {
                 let group = groups[section]
                 if group.isSelected {
                     if let _ = groupMap[group.id] {
@@ -753,8 +773,10 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                 } else {
                     value = 1
                 }
+            } else {
+                value = fillteredData.count
             }
-            return fillteredData.count
+            return value
         }
         switch segment.selectedSegmentIndex {
         case 0:
@@ -807,8 +829,7 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                 imageView.heightAnchor.constraint(equalToConstant: 40.0)
             ])
             if data.profile.isEmpty && data.pin != "-999" {
-                let user = User.getData(pin: data.pin)
-                if user != nil {
+                if data.messageScope == "3" {
                     imageView.image = UIImage(named: "Profile---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
                 } else {
                     imageView.image = UIImage(named: "Conversation---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
@@ -938,9 +959,15 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
             let group: Group
             if isFilltering {
                 if indexPath.row == 0 {
+                    print("DATA GROUP1 \((fillteredData[indexPath.section] as! Group).name)")
                     group = fillteredData[indexPath.section] as! Group
                 } else {
-                    group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
+                    if (fillteredData[indexPath.section] as! Group).childs.count > 0 {
+                        print("DATA GROUP2 \((fillteredData[indexPath.section] as! Group).name)")
+                        group = (fillteredData[indexPath.section] as! Group).childs[indexPath.row - 1]
+                    } else {
+                        return cell
+                    }
                 }
             } else {
                 if indexPath.row == 0 {

+ 41 - 11
appbuilder-ios/AppBuilder/AppBuilder/ThirdTabViewController.swift

@@ -27,6 +27,8 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
     
     var dateRefresh: Date?
     public static var forceRefresh = false
+    public static var inView = false
+    public static var atFirstPage = true
     
     override func viewDidLoad() {
         super.viewDidLoad()
@@ -63,6 +65,10 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
     }
     
     override func viewWillAppear(_ animated: Bool) {
+        if ThirdTabViewController.inView {
+           return
+        }
+        ThirdTabViewController.inView = true
         let me = UserDefaults.standard.string(forKey: "me")
         
         var myURL : URL?
@@ -74,19 +80,19 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
         }
         switch(ViewController.tab3){
         case "0":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         case "1":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-main-only?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         case "2":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-main?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         case "3":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab3-commerce?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         case "4":
-            address = "\(PrefsUtil.getURLBase() ?? "https://qmera.io/")nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)"
+            address = "\(PrefsUtil.getURLBase())nexilis/pages/tab1-video?f_pin=\(me ?? "")&lang=\(intLang)"
             myURL = URL(string: address)
         default:
             if(!ViewController.tab3.isEmpty){
@@ -102,7 +108,8 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
         }
         print(address)
         if let u = myURL{
-            if dateRefresh == nil || Int(Date().timeIntervalSince(dateRefresh!)) >= 60 || ThirdTabViewController.forceRefresh {
+            self.webView.evaluateJavaScript("{window.localStorage.setItem('currentTab','\(ViewController.tab3)')}")
+            if (dateRefresh == nil || Int(Date().timeIntervalSince(dateRefresh!)) >= 60 || ThirdTabViewController.forceRefresh) && ThirdTabViewController.atFirstPage {
                 let myRequest = URLRequest(url: u)
                 webView.load(myRequest)
             }
@@ -127,6 +134,7 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
         self.webView.evaluateJavaScript("{if(pauseAll){pauseAll();}}")
         view.endEditing(true)
         resignFirstResponder()
+        ThirdTabViewController.inView = false
     }
     
     func scrollViewDidScroll(_ scrollView: UIScrollView) {
@@ -165,6 +173,14 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
                 }
                 ViewController.removeMiddleButton()
             }
+        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+            DispatchQueue.main.async {
+                if let viewController = viewController as? ViewController {
+                    if !viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = true
+                    }
+                }
+            }
         }
     }
 
@@ -182,6 +198,14 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
                 viewController.tabBar.isHidden = false
                 ViewController.middleButton.isHidden = false
             }
+        } else if PrefsUtil.getCpaasMode() != PrefsUtil.CPAAS_MODE_DOCKED {
+            DispatchQueue.main.async {
+                if let viewController = viewController as? ViewController {
+                    if viewController.tabBar.isHidden {
+                        viewController.tabBar.isHidden = false
+                    }
+                }
+            }
         }
     }
 
@@ -223,10 +247,8 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
                   let param1 = dict["param1"] as? Bool else {
                 return
             }
-            if param1 {
-                
-            } else {
-                
+            if !param1 {
+                self.webView.evaluateJavaScript("closeModal(true);")
             }
         } else if message.name == "toggleVoiceSearch" {
             if !isAllowSpeech {
@@ -444,6 +466,10 @@ class ThirdTabViewController: UIViewController, UIScrollViewDelegate, UIGestureR
             print("audioEngine couldn't start because of an error.")
         }
     }
+    
+    func isUsingMyWebview() -> Bool{
+        return PrefsUtil.getURLThirdTab() == "0" || PrefsUtil.getURLThirdTab() == "1" || PrefsUtil.getURLThirdTab() == "2" || PrefsUtil.getURLThirdTab() == "3" || PrefsUtil.getURLThirdTab() == "4"
+    }
 
 }
 
@@ -464,9 +490,13 @@ extension ThirdTabViewController: WKUIDelegate {
             if let urlStr = navigationAction.request.url?.absoluteString {
                 print("kacau \(urlStr)")
                 collapseDocked()
-                if urlStr.contains("nexilis/pages/tab1-main-only") || urlStr.contains("nexilis/pages/tab3-main-only") || urlStr.contains("nexilis/pages/tab1-main") || urlStr.contains("nexilis/pages/tab3-commerce") {
+                if urlStr.contains("nexilis/pages/tab1-main-only") || urlStr.contains("nexilis/pages/tab3-main-only") || urlStr.contains("nexilis/pages/tab1-main") || urlStr.contains("nexilis/pages/tab3-commerce") || urlStr.contains("nexilis/pages/tab1-video") {
                     ViewController.alwaysHideButton = false
                     showTabBar()
+                } else if isUsingMyWebview() {
+                    ViewController.alwaysHideButton = true
+                    hideTabBar()
+                    ThirdTabViewController.atFirstPage = false
                 }
             }
 

+ 8 - 15
appbuilder-ios/AppBuilder/AppBuilder/ViewController.swift

@@ -455,16 +455,9 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
             if PrefsUtil.getCpaasMode() == PrefsUtil.CPAAS_MODE_DOCKED {
                 ViewController.pullActionButton()
             }
-            let customTab = PrefsUtil.getCustomTab().split(separator: ",")
-            if customTab[0] == "1" {
-                firstTab?.viewWillAppear(false)
-            } else if customTab[0] == "2" {
-                secondTab?.viewWillAppear(false)
-            } else if customTab[0] == "3" {
-                thirdTab?.viewWillAppear(false)
-            } else if customTab[0] == "4" {
-                fourthTab?.viewWillAppear(false)
-            }
+            self.selectedViewController?.viewWillAppear(false)
+        } else {
+            self.selectedViewController?.viewWillAppear(false)
         }
     }
     
@@ -482,7 +475,7 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
                     var bgChoosen = ""
                     let arrayBg = listBg.split(separator: ",")
                     bgChoosen = String(arrayBg[Int.random(in: 0..<arrayBg.count)])
-                    ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase()! + "/dashboardv2/uploads/background/" + bgChoosen)!) { data, response, error in
+                    ViewController.getDataImageFromUrl(from: URL(string: PrefsUtil.getURLBase() + "/dashboardv2/uploads/background/" + bgChoosen)!) { data, response, error in
                         guard let data = data, error == nil else { return }
                         // always update the UI from the main thread
                         DispatchQueue.main.async() {
@@ -631,7 +624,7 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
                     }
                 }
             } else {
-                Nexilis.buttonClicked(index: 1)
+                Nexilis.buttonClicked(index: 9)
             }
         }
     }
@@ -666,7 +659,7 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
                     }
                 }
             } else {
-                Nexilis.buttonClicked(index: 4)
+                Nexilis.buttonClicked(index: 8)
             }
         }
     }
@@ -701,7 +694,7 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
                     }
                 }
             } else {
-                Nexilis.buttonClicked(index: 3)
+                Nexilis.buttonClicked(index: 7)
             }
         }
     }
@@ -736,7 +729,7 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
                     }
                 }
             } else {
-                Nexilis.buttonClicked(index: 2)
+                Nexilis.buttonClicked(index: 6)
             }
         }
     }

+ 2 - 0
appbuilder-ios/NexilisLite/NexilisLite/Resource/id.lproj/Localizable.strings

@@ -185,3 +185,5 @@
 "Please check your email and enter the code sent" = "Harap periksa email anda dan masukkan kode yang tertera";
 "Expired OTP" = "OTP telah kadaluarsa";
 "Invalid OTP" = "OTP tidak valid";
+"Successfully add friend" = "Berhasil menambahkan teman";
+"Login to Web" = "Masuk ke Web";

+ 24 - 2
appbuilder-ios/NexilisLite/NexilisLite/Source/CoreMessage_TMessageBank.swift

@@ -2057,8 +2057,30 @@ public class CoreMessage_TMessageBank {
         let tmessage = TMessage()
         let me = UserDefaults.standard.string(forKey: "me")!
         tmessage.mCode = CoreMessage_TMessageCode.GET_WORKING_AREA_CONTACT_CENTER
-        tmessage.mStatus = CoreMessage_TMessageUtil.getTID();
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
         tmessage.mPIN = me
-        return tmessage;
+        return tmessage
+    }
+    
+    public static func getInquiry(message_id: String, error_code: String, data: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.INQUIRY
+        tmessage.mStatus = message_id
+        tmessage.mPIN = "-1"
+        tmessage.mBodies[CoreMessage_TMessageKey._ID] = CoreMessage_TMessageUtil.getTID()
+        tmessage.mBodies[CoreMessage_TMessageKey.MESSAGE_ID] = message_id
+        tmessage.mBodies[CoreMessage_TMessageKey.ERRCOD] = error_code
+        tmessage.mBodies[CoreMessage_TMessageKey.DATA] = data
+        return tmessage
+    }
+
+    public static func getMobileInquiry(message_id: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.MOBILE_INQUIRY;
+        tmessage.mStatus = message_id
+        tmessage.mPIN = "-1";
+        tmessage.mBodies[CoreMessage_TMessageKey._ID] = CoreMessage_TMessageUtil.getTID()
+        tmessage.mBodies[CoreMessage_TMessageKey.MESSAGE_ID] = message_id
+        return tmessage
     }
 }

+ 2 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/CoreMessage_TMessageCode.swift

@@ -725,4 +725,6 @@ public class CoreMessage_TMessageCode {
     public static let PULL_FLOATING_BUTTON = "PFB";
     
     public static let GET_CUSTOMER_INFO = "GCI"; // sync
+    public static let INQUIRY = "INQ";
+    public static let MOBILE_INQUIRY = "MINQ";
 }

+ 6 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/Database.swift

@@ -322,6 +322,12 @@ public class Database {
                                 "'message' text" +
                                 ")", values: nil)
         
+        try fmdb.executeUpdate("CREATE TABLE IF NOT EXISTS 'INQUIRY' (" +
+                                "'id' text PRIMARY KEY NOT NULL," +
+                                "'status' integer NOT NULL default 0," +
+                                "'message' text" +
+                                ")", values: nil)
+        
         try fmdb.executeUpdate("CREATE TABLE IF NOT EXISTS 'FOLLOW' (" +
                                 "'f_pin' text PRIMARY KEY NOT NULL" +
                                 ")", values: nil)

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

@@ -83,7 +83,7 @@ extension UIApplication {
         return UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.rootViewController
     }
     
-    var visibleViewController: UIViewController? {
+    public var visibleViewController: UIViewController? {
         let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
         if var topController = keyWindow?.rootViewController {
             while let presentedViewController = topController.presentedViewController {

+ 50 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/IncomingThread.swift

@@ -140,6 +140,10 @@ class IncomingThread {
             endCall(message: message)
         } else if message.getCode() == CoreMessage_TMessageCode.PUSH_SERVICE_BNI {
             pushServiceBNI(message: message)
+        } else if message.getCode() == CoreMessage_TMessageCode.MOBILE_INQUIRY {
+            mobileInquiry(message: message)
+        } else if message.getCode() == CoreMessage_TMessageCode.INQUIRY {
+            inquiry(message: message)
         } else {
             print("unprocessed code", message.getCode())
             ack(message: message)
@@ -153,6 +157,52 @@ class IncomingThread {
      *
      */
     
+    private func inquiry(message: TMessage) {
+        let message_id = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID, default_value: "")
+        var err_code = "10"
+        if !message_id.isEmpty {
+            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select message_id from MESSAGE where message_id = '\(message_id)'") {
+                    if cursor.next() {
+                        err_code = "00"
+                    }
+                    _ = Nexilis.write(message: CoreMessage_TMessageBank.getInquiry(message_id: message_id, error_code: err_code, data: message_id))
+                    cursor.close()
+                }
+            })
+        }
+    }
+    
+    private func mobileInquiry(message: TMessage) {
+        var message_id = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
+        let err_code = message.getBody(key: CoreMessage_TMessageKey.ERRCOD)
+        if message_id.isEmpty {
+            message_id = message.getStatus()
+        }
+        if err_code == "00" {
+            self.updateInquiry(messageId: message_id)
+        } else {
+            print("MASUK MINQ SEND CHAT")
+            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select message from INQUIRY where id = '\(message_id)'"), cursor.next() {
+                    if let message = cursor.string(forColumnIndex: 0) {
+                        print("MASUK MINQ ADA MESSAGE")
+                        OutgoingThread.default.addQueue(message: TMessage(data: message))
+                    }
+                    cursor.close()
+                }
+            })
+        }
+    }
+    
+    private func updateInquiry(messageId: String) {
+        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+            _ = Database.shared.updateRecord(fmdb: fmdb, table: "INQUIRY", cvalues: [
+                "status" : "1"
+            ], _where: "id = '\(messageId)'")
+        })
+    }
+    
     private func endCall(message: TMessage) {
         if let call = Nexilis.shared.callManager.call(with: message.mPIN) {
             call.isReceiveEnd = true

+ 122 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/InquiryThread.swift

@@ -0,0 +1,122 @@
+//
+//  InquiryThread.swift
+//  NexilisLite
+//
+//  Created by Akhmad Al Qindi Irsyam on 23/11/22.
+//
+
+import Foundation
+import FMDB
+
+class InquiryThread {
+    static let `default` = InquiryThread()
+    
+    private var isRunning = false
+    
+    private var semaphore = DispatchSemaphore(value: 0)
+    
+    private var connection = DispatchSemaphore(value: 0)
+    
+    private var dispatchQueue = DispatchQueue(label: "InquiryThread")
+    
+    private var queue = [TMessage]()
+    
+    init() {
+        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+            if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select status, message from INQUIRY") {
+                while cursor.next() {
+                    let status = cursor.int(forColumnIndex: 0)
+                    if status == 1 {
+                        continue
+                    }
+                    if let message = cursor.string(forColumnIndex: 1) {
+                        addQueue(message: TMessage(data: message))
+                    }
+                }
+                cursor.close()
+            }
+        })
+    }
+    
+    func addQueue(message: TMessage) {
+        print("MASUK INQUIRY ADD")
+        addInquiry(message: message)
+        queue.append(message)
+        semaphore.signal()
+    }
+    
+    private func addQueue(_ message: TMessage, at: Int) {
+        Thread.sleep(forTimeInterval: 1)
+        queue.insert(message, at: at)
+        semaphore.signal()
+    }
+    
+    private func addInquiry(message: TMessage) {
+        DispatchQueue.global().async {
+            let messageId = message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)
+            if !messageId.isEmpty {
+                Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                    do {
+                        print("SIMPAN MESSAGE TO INQUIRY TABLE")
+                        _ = try Database.shared.insertRecord(fmdb: fmdb, table: "INQUIRY", cvalues: [
+                            "id" : messageId,
+                            "status" : 0,
+                            "message" : message.pack(),
+                        ], replace: true)
+                    } catch {
+                        rollback.pointee = true
+                        print(error)
+                    }
+                })
+            }
+        }
+    }
+    
+    private var isWait = false
+    
+    func set(wait: Bool) {
+        isWait = wait
+        if !isWait {
+            connection.signal()
+        }
+    }
+    
+    func getQueue() -> TMessage {
+        while queue.isEmpty || queue.count == 0 {
+            print("QUEUE INQUIRY.wait")
+            semaphore.wait()
+        }
+        return queue.remove(at: 0)
+    }
+    
+    func run() {
+        if (isRunning) {
+            return
+        }
+        isRunning = true
+        dispatchQueue.async {
+            while self.isRunning {
+                if self.isWait {
+                    print("CONNECTION INQUIRY.wait")
+                    self.connection.wait()
+                }
+                self.process(message: self.getQueue())
+            }
+        }
+    }
+    
+    private func process(message: TMessage) {
+        print("inquiry process", message.toLogString())
+        mobileInquiry(message: message)
+    }
+    
+    /**
+     *
+     */
+    
+    private func mobileInquiry(message: TMessage) {
+        Nexilis.saveMessage(message: message)
+        print("save message sendChat")
+        _ = Nexilis.write(message: CoreMessage_TMessageBank.getMobileInquiry(message_id: message.getBody(key: CoreMessage_TMessageKey.MESSAGE_ID)))
+    }
+}

+ 48 - 42
appbuilder-ios/NexilisLite/NexilisLite/Source/Nexilis.swift

@@ -73,8 +73,6 @@ public class Nexilis: NSObject {
             
             IncomingThread.default.run()
             
-            OutgoingThread.default.run()
-            
             if let _ = UserDefaults.standard.stringArray(forKey: "address") {
                 
             }
@@ -178,6 +176,9 @@ public class Nexilis: NSObject {
                 }
             }
             Nexilis.destroyAll()
+            OutgoingThread.default.run()
+            
+            InquiryThread.default.run()
         }
         catch {
             print(error)
@@ -262,7 +263,8 @@ public class Nexilis: NSObject {
     }
     
     public static func addQueueMessage(message: TMessage) {
-        OutgoingThread.default.addQueue(message: message)
+//        OutgoingThread.default.addQueue(message: message)
+        InquiryThread.default.addQueue(message: message)
     }
     
     private static var wbDelegate: WhiteboardDelegate?
@@ -860,9 +862,12 @@ public class Nexilis: NSObject {
         }
         message.mBodies[CoreMessage_TMessageKey.PACKET_ID] = packetId
         if let _ = waitQueue[message.getStatus()] {
-            waitQueue[message.getStatus()] = message
-            groupWait.leave()
-            return
+            print("MESSAGE \(message.toLogString())")
+            if message.mBodies.keys.contains(CoreMessage_TMessageKey.ERRCOD) {
+                waitQueue[message.getStatus()] = message
+                groupWait.leave()
+                return
+            }
         }
         IncomingThread.default.addQueue(message: message)
     }
@@ -879,15 +884,22 @@ public class Nexilis: NSObject {
         guard !f_pin.isEmpty else {
             return
         }
-        let l_pin = message.getBody(key : CoreMessage_TMessageKey.L_PIN, default_value : "")
-        let scope = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_SCOPE_ID, default_value : "3")
-        let status = message.getBody(key : CoreMessage_TMessageKey.STATUS, default_value : "")
-        let chat_id = message.getBody(key : CoreMessage_TMessageKey.CHAT_ID, default_value : "")
-        let broadcast_flag = message.getBody(key: CoreMessage_TMessageKey.BROADCAST_FLAG, default_value: "0")
-        let is_call_center = message.getBody(key: CoreMessage_TMessageKey.IS_CALL_CENTER, default_value: "0")
-        let call_center_id = message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID, default_value: "")
-        print("prepare save db")
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
+            if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select message_id from MESSAGE where message_id = '\(message_id)'") {
+                if cursor.next() {
+                    print("message exist")
+                    return
+                }
+                cursor.close()
+            }
+            let l_pin = message.getBody(key : CoreMessage_TMessageKey.L_PIN, default_value : "")
+            let scope = message.getBody(key : CoreMessage_TMessageKey.MESSAGE_SCOPE_ID, default_value : "3")
+            let status = message.getBody(key : CoreMessage_TMessageKey.STATUS, default_value : "")
+            let chat_id = message.getBody(key : CoreMessage_TMessageKey.CHAT_ID, default_value : "")
+            let broadcast_flag = message.getBody(key: CoreMessage_TMessageKey.BROADCAST_FLAG, default_value: "0")
+            let is_call_center = message.getBody(key: CoreMessage_TMessageKey.IS_CALL_CENTER, default_value: "0")
+            let call_center_id = message.getBody(key: CoreMessage_TMessageKey.CALL_CENTER_ID, default_value: "")
+            print("prepare save db")
             do {
                 _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
                     "message_id" : message_id,
@@ -923,10 +935,8 @@ public class Nexilis: NSObject {
                 rollback.pointee = true
                 print(error)
             }
-        })
-        
-        if withStatus {
-            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+            
+            if withStatus {
                 do {
                     if scope == "4" {
                         for pin in getGroupMembers(fmdb: fmdb, l_pin: l_pin) {
@@ -950,35 +960,31 @@ public class Nexilis: NSObject {
                     rollback.pointee = true
                     print(error)
                 }
-            })
-        }
-        var pin = l_pin
-        if l_pin == me {
-            pin = f_pin
-        }
-        if !chat_id.isEmpty {
-            pin = chat_id
-        }
-        var counter : Int? = nil
-        if l_pin == me || (scope == "4" && f_pin != me) {
-            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+            }
+            var pin = l_pin
+            if l_pin == me {
+                pin = f_pin
+            }
+            if !chat_id.isEmpty {
+                pin = chat_id
+            }
+            var counter : Int? = nil
+            if l_pin == me || (scope == "4" && f_pin != me) {
                 if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "select counter from MESSAGE_SUMMARY where l_pin = '\(pin)'"), cursor.next() {
                     counter = Int(cursor.int(forColumnIndex: 0))
                     counter! += 1
                     cursor.close()
                     print("select db message summary")
                 }
-            })
+                if counter == nil {
+                    counter = 1
+                    print("set counter message summary")
+                }
+            }
             if counter == nil {
-                counter = 1
-                print("set counter message summary")
+                counter = 0
             }
-        }
-        if counter == nil {
-            counter = 0
-        }
-        if is_call_center == "0" {
-            Database.shared.database?.inTransaction({ (fmdb, rollback) in
+            if is_call_center == "0" {
                 do {
                     _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", cvalues: [
                         "l_pin" : pin,
@@ -989,9 +995,9 @@ public class Nexilis: NSObject {
                     rollback.pointee = true
                     print(error)
                 }
-            })
-        }
-        print("insert db message summary \(message_id)")
+            }
+            print("insert db message summary \(message_id)")
+        })
         
     }
     

+ 5 - 8
appbuilder-ios/NexilisLite/NexilisLite/Source/OutgoingThread.swift

@@ -122,9 +122,6 @@ class OutgoingThread {
      */
     
     private func sendChat(message: TMessage) {
-        Nexilis.saveMessage(message: message)
-        print("save message sendChat")
-        
         // if media exist upload first
         var fileName = message.getBody(key: CoreMessage_TMessageKey.IMAGE_ID, default_value: "")
         if fileName.isEmpty {
@@ -167,11 +164,11 @@ class OutgoingThread {
                                             self.delOutgoing(fmdb: fmdb, messageId: messageId)
                                         })
                                     } else {
-                                        self.addQueue(message, at: 0)
+                                        InquiryThread.default.addQueue(message: message)
                                     }
                                 }
                             } else {
-                                self.addQueue(message, at: 0)
+                                InquiryThread.default.addQueue(message: message)
                             }
                         }
                     }
@@ -193,11 +190,11 @@ class OutgoingThread {
                                     self.delOutgoing(fmdb: fmdb, messageId: messageId)
                                 })
                             } else {
-                                self.addQueue(message, at: 0)
+                                InquiryThread.default.addQueue(message: message)
                             }
                         }
                     } else {
-                        self.addQueue(message, at: 0)
+                        InquiryThread.default.addQueue(message: message)
                     }
                 }
             }
@@ -212,7 +209,7 @@ class OutgoingThread {
                     self.delOutgoing(fmdb: fmdb, messageId: messageId)
                 })
             } else {
-                self.addQueue(message, at: 0)
+                InquiryThread.default.addQueue(message: message)
             }
         }
     }

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

@@ -43,7 +43,7 @@ public class TMessage {
         _ = unpack(data: data)
     }
     
-    init(type: String, version: String, code: String,status: String, pin: String, l_pin: String, bodies:[String: String], media:  [UInt8]) {
+    init(type: String, version: String = "1.0.106", code: String,status: String, pin: String, l_pin: String, bodies:[String: String], media:  [UInt8]) {
         mType = type
         mVersion = version
         mCode = code

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

@@ -92,10 +92,10 @@ public class EditorGroup: UIViewController {
         viewButton.layer.shadowRadius = 3
         
 //        buttonVoice.setImage(resizeImage(image: UIImage(named: "Voice-Record", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)), for: .normal)
-        buttonSendImage.setImage(resizeImage(image: UIImage(named: "Send-Image", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.red), for: .normal)
-        buttonSendPhoto.setImage(resizeImage(image: UIImage(named: "Camera", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.red), for: .normal)
-        buttonSendSticker.setImage(resizeImage(image: UIImage(named: "Sticker---Emoji", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.red), for: .normal)
-        buttonSendFile.setImage(resizeImage(image: UIImage(named: "File---Documents", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.red), for: .normal)
+        buttonSendImage.setImage(resizeImage(image: UIImage(named: "Send-Image", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.mainColor), for: .normal)
+        buttonSendPhoto.setImage(resizeImage(image: UIImage(named: "Camera", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.mainColor), for: .normal)
+        buttonSendSticker.setImage(resizeImage(image: UIImage(named: "Sticker---Emoji", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.mainColor), for: .normal)
+        buttonSendFile.setImage(resizeImage(image: UIImage(named: "File---Documents", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.mainColor), for: .normal)
         
         buttonSendChat.setImage(resizeImage(image: UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
         
@@ -165,16 +165,13 @@ public class EditorGroup: UIViewController {
                 alert.addAction(UIAlertAction(title: "Cancel".localized(), style: UIAlertAction.Style.default, handler: nil))
                 alert.addAction(UIAlertAction(title: "Delete".localized(), style: .destructive, handler: {(_) in
                     var l_pin = self.dataGroup["group_id"] as! String
-                    DispatchQueue.global().async {
-                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                            if (self.dataTopic["chat_id"] as! String != "") {
-                                l_pin = self.dataTopic["chat_id"] as! String
-                            }
-                            _ = Database.shared.deleteRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", _where: "l_pin='\(l_pin)'")
-                            _ = Database.shared.deleteRecord(fmdb: fmdb, table: "MESSAGE", _where: "(l_pin='\(self.dataGroup["group_id"]!!)' and chat_id='\(self.dataTopic["chat_id"]!!)') and message_scope_id='4'")
-                        })
-                        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
-                    }
+                    Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                        if (self.dataTopic["chat_id"] as! String != "") {
+                            l_pin = self.dataTopic["chat_id"] as! String
+                        }
+                        _ = Database.shared.deleteRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", _where: "l_pin='\(l_pin)'")
+                        _ = Database.shared.deleteRecord(fmdb: fmdb, table: "MESSAGE", _where: "(l_pin='\(self.dataGroup["group_id"]!!)' and chat_id='\(self.dataTopic["chat_id"]!!)') and message_scope_id='4'")
+                    })
                     if self.fromNotification {
                         self.didTapExit()
                     } else {

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

@@ -110,10 +110,10 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         viewButton.layer.shadowRadius = 3
         
 //        buttonVoice.setImage(resizeImage(image: UIImage(named: "Voice-Record", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)), for: .normal)
-        buttonSendImage.setImage(resizeImage(image: UIImage(named: "Send-Image", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.red), for: .normal)
-        buttonSendPhoto.setImage(resizeImage(image: UIImage(named: "Camera", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.red), for: .normal)
-        buttonSendSticker.setImage(resizeImage(image: UIImage(named: "Sticker---Emoji", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.red), for: .normal)
-        buttonSendFile.setImage(resizeImage(image: UIImage(named: "File---Documents", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.red), for: .normal)
+        buttonSendImage.setImage(resizeImage(image: UIImage(named: "Send-Image", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.mainColor), for: .normal)
+        buttonSendPhoto.setImage(resizeImage(image: UIImage(named: "Camera", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.mainColor), for: .normal)
+        buttonSendSticker.setImage(resizeImage(image: UIImage(named: "Sticker---Emoji", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.mainColor), for: .normal)
+        buttonSendFile.setImage(resizeImage(image: UIImage(named: "File---Documents", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(.mainColor), for: .normal)
         
         buttonSendChat.setImage(resizeImage(image: UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
         
@@ -221,13 +221,10 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                     let alert = UIAlertController(title: "", message: "Are you sure to delete all message in this conversation?".localized(), preferredStyle: .alert)
                     alert.addAction(UIAlertAction(title: "Cancel".localized(), style: UIAlertAction.Style.default, handler: nil))
                     alert.addAction(UIAlertAction(title: "Delete".localized(), style: .destructive, handler: {(_) in
-                        DispatchQueue.global().async {
-                            Database.shared.database?.inTransaction({ (fmdb, rollback) in
-                                _ = Database.shared.deleteRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", _where: "l_pin='\(self.dataPerson["f_pin"]!!)'")
-                                _ = Database.shared.deleteRecord(fmdb: fmdb, table: "MESSAGE", _where: "(f_pin='\(self.dataPerson["f_pin"]!!)' or l_pin='\(self.dataPerson["f_pin"]!!)') and (message_scope_id='3' or message_scope_id='18') and is_call_center = 0")
-                            })
-                            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
-                        }
+                        Database.shared.database?.inTransaction({ (fmdb, rollback) in
+                            _ = Database.shared.deleteRecord(fmdb: fmdb, table: "MESSAGE_SUMMARY", _where: "l_pin='\(self.dataPerson["f_pin"]!!)'")
+                            _ = Database.shared.deleteRecord(fmdb: fmdb, table: "MESSAGE", _where: "(f_pin='\(self.dataPerson["f_pin"]!!)' or l_pin='\(self.dataPerson["f_pin"]!!)') and (message_scope_id='3' or message_scope_id='18') and is_call_center = 0")
+                        })
                         if self.fromNotification {
                             self.didTapExit()
                         } else {
@@ -4534,6 +4531,14 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource {
     }
     
     @objc func tapAck(_ sender: ObjectGesture) {
+        if blocking == "1" {
+            self.view.makeToast("You blocked this user".localized())
+            return
+        }
+        if blocking == "-1" {
+            self.view.makeToast("You have been blocked by this user".localized())
+            return
+        }
         let indexPath = sender.indexPath
         let dataMessages = self.dataMessages.filter({ $0["chat_date"] as! String == dataDates[indexPath.section]})
         if dataMessages[indexPath.row]["status"] as! String == "8" {

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

@@ -64,6 +64,7 @@ class AddFriendTableViewController: UITableViewController {
         
         tableView.tableFooterView = UIView()
         
+        self.data.removeAll()
         getData { d in
             self.data = d
             DispatchQueue.main.async {

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

@@ -71,7 +71,8 @@ public class ChangeNamePassswordViewController: UIViewController {
             self.navigationController?.popViewController(animated: true)
             self.isSuccess?()
         } else {
-            self.dismiss(animated: true, completion: nil)
+            let vc = self.navigationController?.presentingViewController
+            vc?.dismiss(animated: true, completion: nil)
         }
     }
     

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

@@ -165,10 +165,15 @@ class ContactChatViewController: UITableViewController {
     }
     
     override func viewWillAppear(_ animated: Bool) {
-        groupMap.removeAll()
+        removeAllData()
+        getData()
+    }
+    
+    func removeAllData() {
         groups.removeAll()
+        groupMap.removeAll()
+        chats.removeAll()
         tableView.reloadData()
-        getData()
     }
     
     @objc func onReload(notification: NSNotification) {
@@ -227,6 +232,7 @@ class ContactChatViewController: UITableViewController {
         getChats {
             self.getContacts {
                 self.getGroups { g1 in
+                    self.groupMap.removeAll()
                     self.groups.removeAll()
                     self.groups.append(contentsOf: g1)
                     DispatchQueue.main.async {
@@ -453,8 +459,7 @@ extension ContactChatViewController {
                 dismiss(animated: true, completion: nil)
                 return
             }
-            let user = User.getData(pin: data.pin)
-            if user != nil || data.pin == "-999" {
+            if data.messageScope == "3" {
                 let editorPersonalVC = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "editorPersonalVC") as! EditorPersonal
                 editorPersonalVC.hidesBottomBarWhenPushed = true
                 editorPersonalVC.unique_l_pin = data.pin
@@ -512,7 +517,7 @@ extension ContactChatViewController {
                 var sects = 0
                 var sect = indexPath.section
                 var id = group.id
-                if let e = groupMap[id] {
+                if let _ = groupMap[id] {
                     var loooop = true
                     repeat {
                         let c = sect + 1
@@ -644,7 +649,7 @@ extension ContactChatViewController {
             if segment.selectedSegmentIndex == 2, let groups = fillteredData as? [Group] {
                 let group = groups[section]
                 if group.isSelected {
-                    if let g = groupMap[group.id] {
+                    if let _ = groupMap[group.id] {
                         value = 1
                     }
                     else {
@@ -653,8 +658,10 @@ extension ContactChatViewController {
                 } else {
                     value = 1
                 }
+            } else {
+                value = fillteredData.count
             }
-            return fillteredData.count
+            return value
         }
         switch segment.selectedSegmentIndex {
         case 0:
@@ -664,7 +671,7 @@ extension ContactChatViewController {
         case 2:
             let group = groups[section]
             if group.isSelected {
-                if let g = groupMap[group.id] {
+                if let _ = groupMap[group.id] {
                     value = 1
                 }
                 else {
@@ -689,10 +696,14 @@ extension ContactChatViewController {
             if content.subviews.count > 0 {
                 content.subviews.forEach { $0.removeFromSuperview() }
             }
+            if chats.count == 0 {
+                return cell
+            }
             let data: Chat
             if isFilltering {
                 data = fillteredData[indexPath.row] as! Chat
             } else {
+                print("DATA CHATS \(chats)")
                 data = chats[indexPath.row]
             }
             let imageView = UIImageView()
@@ -706,8 +717,7 @@ extension ContactChatViewController {
                 imageView.heightAnchor.constraint(equalToConstant: 40.0)
             ])
             if data.profile.isEmpty && data.pin != "-999" {
-                let user = User.getData(pin: data.pin)
-                if user != nil {
+                if data.messageScope == "3" {
                     imageView.image = UIImage(named: "Profile---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)
                 } else {
                     imageView.image = UIImage(named: "Conversation---Purple", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)

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

@@ -290,11 +290,21 @@ class GroupDetailViewController: UITableViewController {
                 } else {
                     currentAccess = "0"
                 }
+                Nexilis.showLoader()
                 self.changeOpenGroup(open: currentAccess) { result in
                     if result {
                         DispatchQueue.main.async {
                             g.isOpen = currentAccess
                             tableView.reloadRows(at: [indexPath], with: .none)
+                            Nexilis.hideLoader()
+                        }
+                    } else {
+                        DispatchQueue.main.async {
+                            Nexilis.hideLoader()
+                            let imageView = UIImageView(image: UIImage(systemName: "xmark.circle.fill"))
+                            imageView.tintColor = .white
+                            let banner = FloatingNotificationBanner(title: "Check your connection".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)
+                            banner.show()
                         }
                     }
                 }
@@ -647,7 +657,9 @@ class GroupDetailViewController: UITableViewController {
         DispatchQueue.global().async {
             var result: Bool = false
             if let g = self.group, let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getChangeGroupInfo(p_group_id: g.id, p_open: open)), response.isOk() {
-                result = true
+                    result = true
+            } else {
+                result = false
             }
             completion(result)
         }

+ 4 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/ProfileViewController.swift

@@ -453,6 +453,10 @@ public class ProfileViewController: UITableViewController {
         addFriend { result in
             DispatchQueue.main.async {
                 if result {
+                    let imageView = UIImageView(image: UIImage(systemName: "checkmark.circle.fill"))
+                    imageView.tintColor = .white
+                    let banner = FloatingNotificationBanner(title: "Successfully add friend".localized(), subtitle: nil, titleFont: UIFont.systemFont(ofSize: 16), titleColor: nil, titleTextAlign: .left, subtitleFont: nil, subtitleColor: nil, subtitleTextAlign: nil, leftView: imageView, rightView: nil, style: .success, colors: nil, iconPosition: .center)
+                    banner.show()
                     self.isDismiss?()
                     self.navigationController?.popViewController(animated: true)
                 } else {

+ 4 - 4
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Control/ScannerViewController.swift

@@ -10,7 +10,7 @@ import UIKit
 import NotificationBannerSwift
 import nuSDKService
 
-class ScannerViewController: UIViewController, QRScannerViewDelegate {
+public class ScannerViewController: UIViewController, QRScannerViewDelegate {
     
     var scannerView: QRScannerView = {
         let scannerView = QRScannerView()
@@ -26,14 +26,14 @@ class ScannerViewController: UIViewController, QRScannerViewDelegate {
         return titleInfo
     }()
     
-    override func viewDidDisappear(_ animated: Bool) {
+    public override func viewDidDisappear(_ animated: Bool) {
         if scannerView.isRunning {
             scannerView.stopScanning()
         }
         self.navigationController?.navigationBar.topItem?.title = nil
     }
 
-    override func viewDidLoad() {
+    public override func viewDidLoad() {
         super.viewDidLoad()
         
         self.view.backgroundColor = .white
@@ -53,7 +53,7 @@ class ScannerViewController: UIViewController, QRScannerViewDelegate {
         navigationController?.dismiss(animated: true, completion: nil)
     }
     
-    override func viewDidAppear(_ animated: Bool) {
+    public override func viewDidAppear(_ animated: Bool) {
         scannerView.startScanning()
     }