瀏覽代碼

update fix bugs for ios 26 and release for 50.61

alqindiirsyam 3 周之前
父節點
當前提交
19bd6b03ba
共有 21 個文件被更改,包括 218 次插入85 次删除
  1. 4 4
      AppBuilder/AppBuilder.xcodeproj/project.pbxproj
  2. 6 5
      AppBuilder/AppBuilder/SecondTabViewController.swift
  3. 22 20
      AppBuilder/AppBuilder/ViewController.swift
  4. 7 2
      NexilisLite/NexilisLite/Source/CoreMessage_TMessageBank.swift
  5. 1 1
      NexilisLite/NexilisLite/Source/Extension.swift
  6. 2 2
      NexilisLite/NexilisLite/Source/Nexilis.swift
  7. 2 2
      NexilisLite/NexilisLite/Source/Utils.swift
  8. 2 2
      NexilisLite/NexilisLite/Source/View/Chat/ArchivedChatView.swift
  9. 1 1
      NexilisLite/NexilisLite/Source/View/Chat/MessageInfo.swift
  10. 6 3
      NexilisLite/NexilisLite/Source/View/Contact/ContactCallViewController.swift
  11. 6 3
      NexilisLite/NexilisLite/Source/View/Control/AddFriendTableViewController.swift
  12. 10 2
      NexilisLite/NexilisLite/Source/View/Control/BackupRestoreView.swift
  13. 6 3
      NexilisLite/NexilisLite/Source/View/Control/BroadcastMembersTableViewController.swift
  14. 1 1
      NexilisLite/NexilisLite/Source/View/Control/BroadcastViewController.swift
  15. 61 13
      NexilisLite/NexilisLite/Source/View/Control/ChangeDeviceViewController.swift
  16. 6 3
      NexilisLite/NexilisLite/Source/View/Control/ContactChatViewController.swift
  17. 1 1
      NexilisLite/NexilisLite/Source/View/Control/ProfileViewController.swift
  18. 1 1
      NexilisLite/NexilisLite/Source/View/Control/SetInternalCSAccount.swift
  19. 61 12
      NexilisLite/NexilisLite/Source/View/Control/SignUpSignIn.swift
  20. 6 1
      NexilisLite/NexilisLite/Source/View/Control/VerifyEmail.swift
  21. 6 3
      NexilisLite/NexilisLite/Source/View/Streaming/SeminarListViewController.swift

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

@@ -568,7 +568,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 5.0.60;
+				MARKETING_VERSION = 5.0.61;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -604,7 +604,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 5.0.60;
+				MARKETING_VERSION = 5.0.61;
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -640,7 +640,7 @@
 					"@executable_path/../../Frameworks",
 				);
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
-				MARKETING_VERSION = 5.0.60;
+				MARKETING_VERSION = 5.0.61;
 				OTHER_CFLAGS = "-fstack-protector-strong";
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder.AppBuilderShare;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -679,7 +679,7 @@
 					"@executable_path/../../Frameworks",
 				);
 				LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
-				MARKETING_VERSION = 5.0.60;
+				MARKETING_VERSION = 5.0.61;
 				OTHER_CFLAGS = "-fstack-protector-strong";
 				PRODUCT_BUNDLE_IDENTIFIER = io.nexilis.appbuilder.AppBuilderShare;
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 6 - 5
AppBuilder/AppBuilder/SecondTabViewController.swift

@@ -1509,7 +1509,7 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
             if self.archivedChats.count > 0 && indexPath.row == 0 {
                 return nil
             }
-            let archiveAction = UIContextualAction(style: .normal, title: nil) { (_, _, completionHandler) in
+            let archiveAction = UIContextualAction(style: .normal, title: "Archive".localized()) { (_, _, completionHandler) in
                 DispatchQueue.global().async {
                     Database.shared.database?.inTransaction({ (fmdb, rollback) in
                         do {
@@ -1533,8 +1533,8 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                 }
                 completionHandler(true)
             }
+            let archiveIcon = UIImage(systemName: "archivebox.fill")!
             archiveAction.backgroundColor = .mainColor
-            let archiveIcon = UIImage(systemName: "archivebox.fill")!.createCustomIconWithText(text: "Archive".localized())
             archiveAction.image = archiveIcon
 
             var textPinned = "Pin".localized()
@@ -1584,8 +1584,8 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                 }
                 completionHandler(true)
             }
+            let pinIcon = imagePinned
             unpinAction.backgroundColor = .darkGray
-            let pinIcon = imagePinned.rotateImage(byDegrees: 45).createCustomIconWithText(text: textPinned, color: .white)
             unpinAction.image = pinIcon
 
             let configuration = UISwipeActionsConfiguration(actions: [archiveAction, unpinAction])
@@ -2790,8 +2790,9 @@ extension SecondTabViewController: UISearchControllerDelegate, UISearchBarDelega
     
     func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
         searchBar.showsCancelButton = true
-        let cBtn = searchBar.value(forKey: "cancelButton") as! UIButton
-        cBtn.setTitle("Cancel".localized(), for: .normal)
+        if let cBtn = searchBar.value(forKey: "cancelButton") as? UIButton {
+            cBtn.setTitle("Cancel".localized(), for: .normal)
+        }
     }
     
     func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {

+ 22 - 20
AppBuilder/AppBuilder/ViewController.swift

@@ -271,31 +271,33 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
         let center: NotificationCenter = NotificationCenter.default
         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)
-        if !Utils.getIndicatorTabImage().isEmpty {
-            let indicatorImage = Utils.getIndicatorTabImage()
-            let fullUrl = "\(PrefsUtil.getURLBase())get_file_from_path?img=\(indicatorImage)"
-            if let cachedImage = ImageCache.shared.image(forKey: fullUrl) {
-                DispatchQueue.main.async() { [self] in
-                    imageIndicator = cachedImage
-                    addCustomViewAboveTabBarItem(at: Utils.getLastTabSelected(), image: imageIndicator)
-                }
-            } else {
-                Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: fullUrl)!) { data, response, error in
-                    guard let data = data, error == nil else { return }
-                    // always update the UI from the main thread
+        if #unavailable(iOS 26.0) {
+            if !Utils.getIndicatorTabImage().isEmpty {
+                let indicatorImage = Utils.getIndicatorTabImage()
+                let fullUrl = "\(PrefsUtil.getURLBase())get_file_from_path?img=\(indicatorImage)"
+                if let cachedImage = ImageCache.shared.image(forKey: fullUrl) {
                     DispatchQueue.main.async() { [self] in
-                        if UIImage(data: data) != nil {
-                            imageIndicator = UIImage(data: data)!
-                            addCustomViewAboveTabBarItem(at: Utils.getLastTabSelected(), image: imageIndicator)
-                            ImageCache.shared.save(image: UIImage(data: data)!, forKey: fullUrl)
+                        imageIndicator = cachedImage
+                        addCustomViewAboveTabBarItem(at: Utils.getLastTabSelected(), image: imageIndicator)
+                    }
+                } else {
+                    Utils.fetchDataWithCookiesAndUserAgent(from: URL(string: fullUrl)!) { 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
+                            if UIImage(data: data) != nil {
+                                imageIndicator = UIImage(data: data)!
+                                addCustomViewAboveTabBarItem(at: Utils.getLastTabSelected(), image: imageIndicator)
+                                ImageCache.shared.save(image: UIImage(data: data)!, forKey: fullUrl)
+                            }
                         }
                     }
                 }
+            } else {
+                isDefaultIndicator = true
+                imageIndicator = UIImage(named: "indicator_default_tab")!
+                addCustomViewAboveTabBarItem(at: Utils.getLastTabSelected(), image: imageIndicator)
             }
-        } else {
-            isDefaultIndicator = true
-            imageIndicator = UIImage(named: "indicator_default_tab")!
-            addCustomViewAboveTabBarItem(at: Utils.getLastTabSelected(), image: imageIndicator)
         }
         DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: { [self] in
             checkCounter()

+ 7 - 2
NexilisLite/NexilisLite/Source/CoreMessage_TMessageBank.swift

@@ -1425,13 +1425,18 @@ public class CoreMessage_TMessageBank {
         return tmessage
     }
     
-    public static func getSendOTPLogin(p_email: String) -> TMessage {
+    public static func getSendOTPLogin(p_email: String = "", p_number: String = "") -> TMessage {
         let me = User.getMyPin()!
         let tmessage = TMessage()
         tmessage.mCode = CoreMessage_TMessageCode.SEND_OTP_LOGIN
         tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
         tmessage.mPIN = me
-        tmessage.mBodies[CoreMessage_TMessageKey.EMAIL] = p_email
+        if !p_email.isEmpty {
+            tmessage.mBodies[CoreMessage_TMessageKey.EMAIL] = p_email
+        }
+        if !p_number.isEmpty {
+            tmessage.mBodies[CoreMessage_TMessageKey.PHONE_NUMBER] = p_number
+        }
         tmessage.mBodies[CoreMessage_TMessageKey.ANDROID_APP_NAME] = APIS.getAppNm()
         tmessage.mBodies[CoreMessage_TMessageKey.CPAAS_VERSION] = Utils.CPAAS_VERSION
         tmessage.mBodies[CoreMessage_TMessageKey.ANDROID_PACKAGE_NAME] = (Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String) ?? ""

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

@@ -1900,7 +1900,7 @@ extension UIApplication {
         if let button = sender as? UIButton {
             let title = button.titleLabel?.text ?? "Unnamed Button"
             DataCaptured.action = "CLICKED"
-            DataCaptured.textAction = "\(title)"
+            DataCaptured.textAction = title
             DispatchQueue.global().async {
                 DataCaptured.sendLogMonitorAction()
             }

+ 2 - 2
NexilisLite/NexilisLite/Source/Nexilis.swift

@@ -19,7 +19,7 @@ import CryptoKit
 import WebKit
 
 public class Nexilis: NSObject {
-    public static var cpaasVersion = "5.0.60"
+    public static var cpaasVersion = "5.0.61"
     public static var sAPIKey = ""
     
     public static var ADDRESS = ""
@@ -173,7 +173,7 @@ public class Nexilis: NSObject {
         imageCache.countLimit = 100
         imageCache.totalCostLimit = 1024 * 1024 * 200
         
-        DispatchQueue.global().async {
+        DispatchQueue.global(qos: .userInitiated).async {
             do {
                 func forceShowFB() {
                     DispatchQueue.main.async {

+ 2 - 2
NexilisLite/NexilisLite/Source/Utils.swift

@@ -2784,7 +2784,7 @@ public class ValidationTransactionLimit: UIViewController, UITextFieldDelegate {
         super.viewDidLoad()
         
         navigationController?.navigationBar.tintColor = .white
-        navigationController?.navigationBar.topItem?.backButtonTitle = "Back".localized()
+        navigationController?.navigationBar.topItem?.backButtonTitle = ""
         
         let title = UILabel()
         title.text = "Set a transation validation amount".localized()
@@ -2817,7 +2817,7 @@ public class ValidationTransactionLimit: UIViewController, UITextFieldDelegate {
     }
     
     public override func viewDidAppear(_ animated: Bool) {
-        navigationController?.navigationBar.topItem?.backButtonTitle = "Back".localized()
+        navigationController?.navigationBar.topItem?.backButtonTitle = ""
         
         navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Submit".localized(), style: .plain, target: self, action: #selector(submit))
         

+ 2 - 2
NexilisLite/NexilisLite/Source/View/Chat/ArchivedChatView.swift

@@ -437,7 +437,7 @@ public class ArchivedChatView: UIViewController, UITableViewDataSource, UITableV
     public func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
         let data = archivedChats[indexPath.row]
         if !data.isParent {
-            let archiveAction = UIContextualAction(style: .normal, title: nil) { (_, _, completionHandler) in
+            let archiveAction = UIContextualAction(style: .normal, title: "Unarchive".localized()) { (_, _, completionHandler) in
                 DispatchQueue.global().async {
                     Database.shared.database?.inTransaction({ (fmdb, rollback) in
                         do {
@@ -461,7 +461,7 @@ public class ArchivedChatView: UIViewController, UITableViewDataSource, UITableV
                 completionHandler(true)
             }
             archiveAction.backgroundColor = .mainColor
-            let archiveIcon = UIImage(systemName: "arrow.up.bin.fill")!.createCustomIconWithText(text: "Unarchive".localized())
+            let archiveIcon = UIImage(systemName: "arrow.up.bin.fill")!
             archiveAction.image = archiveIcon
 
             let configuration = UISwipeActionsConfiguration(actions: [archiveAction])

+ 1 - 1
NexilisLite/NexilisLite/Source/View/Chat/MessageInfo.swift

@@ -30,7 +30,7 @@ class MessageInfo: UIViewController, UITableViewDelegate, UITableViewDataSource,
         title = "Message Info".localized()
         view.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
         navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
-        navigationController?.navigationBar.topItem?.backButtonTitle = "Back".localized()
+        navigationController?.navigationBar.topItem?.backButtonTitle = ""
         
         tableStatus = UITableView(frame: .zero, style: .grouped)
         tableStatus.register(UITableViewCell.self, forCellReuseIdentifier: "cellStatus")

+ 6 - 3
NexilisLite/NexilisLite/Source/View/Contact/ContactCallViewController.swift

@@ -99,7 +99,9 @@ class ContactCallViewController: UIViewController {
 //        searchController.searchBar.setMagnifyingGlassColorTo(color: .white)
         searchController.searchBar.setImage(UIImage(), for: .search, state: .normal)
         searchController.searchBar.setPositionAdjustment(UIOffset(horizontal: 10, vertical: 0), for: .search)
-        searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        if #unavailable(iOS 26.0) {
+            searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        }
         searchController.searchBar.tintColor = .mainColor
         
         navigationItem.searchController = searchController
@@ -452,8 +454,9 @@ extension ContactCallViewController: UISearchControllerDelegate, UISearchBarDele
     
     func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
         searchBar.showsCancelButton = true
-        let cBtn = searchBar.value(forKey: "cancelButton") as! UIButton
-        cBtn.setTitle("Cancel".localized(), for: .normal)
+        if let cBtn = searchBar.value(forKey: "cancelButton") as? UIButton {
+            cBtn.setTitle("Cancel".localized(), for: .normal)
+        }
     }
     
     func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {

+ 6 - 3
NexilisLite/NexilisLite/Source/View/Control/AddFriendTableViewController.swift

@@ -70,7 +70,9 @@ class AddFriendTableViewController: UITableViewController {
 //        searchController.searchBar.setMagnifyingGlassColorTo(color: .white)
         searchController.searchBar.setImage(UIImage(), for: .search, state: .normal)
         searchController.searchBar.setPositionAdjustment(UIOffset(horizontal: 10, vertical: 0), for: .search)
-        searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        if #unavailable(iOS 26.0) {
+            searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        }
         searchController.searchBar.tintColor = .mainColor
         
         definesPresentationContext = true
@@ -174,8 +176,9 @@ class AddFriendTableViewController: UITableViewController {
     
     func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
         searchBar.showsCancelButton = true
-        let cBtn = searchBar.value(forKey: "cancelButton") as! UIButton
-        cBtn.setTitle("Cancel".localized(), for: .normal)
+        if let cBtn = searchBar.value(forKey: "cancelButton") as? UIButton {
+            cBtn.setTitle("Cancel".localized(), for: .normal)
+        }
     }
     
     func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {

+ 10 - 2
NexilisLite/NexilisLite/Source/View/Control/BackupRestoreView.swift

@@ -43,7 +43,7 @@ public class BackupRestoreView: UIViewController, UITableViewDataSource, UITable
     public override func viewDidLoad() {
         super.viewDidLoad()
         
-        navigationController?.navigationBar.topItem?.backButtonTitle = "Back".localized()
+        navigationController?.navigationBar.topItem?.backButtonTitle = ""
         
         tableView = UITableView()
         tableView.backgroundColor = .clear
@@ -957,7 +957,15 @@ public class BackupRestoreView: UIViewController, UITableViewDataSource, UITable
                     Network().uploadHTTP(fileUrl: zipFiles, completion: { result,progress in
                         if result {
                             DispatchQueue.main.async { [self] in
-                                labelPreparing.text = "Uploading...".localized() + " \(progress)%"
+                                let formatter = NumberFormatter()
+                                formatter.minimumFractionDigits = 1
+                                formatter.maximumFractionDigits = 1
+                                
+                                var prog = ""
+                                if let formatted = formatter.string(from: NSNumber(value: progress)) {
+                                    prog = formatted
+                                }
+                                labelPreparing.text = "Uploading...".localized() + " \(prog.isEmpty ? "\(progress)" : prog)%"
                                 if progress == 100 {
                                     do {
                                         let path = zipFiles.path

+ 6 - 3
NexilisLite/NexilisLite/Source/View/Control/BroadcastMembersTableViewController.swift

@@ -36,8 +36,9 @@ class BroadcastMembersTableViewController: UITableViewController, UISearchContro
     
     func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
         searchBar.showsCancelButton = true
-        let cBtn = searchBar.value(forKey: "cancelButton") as! UIButton
-        cBtn.setTitle("Cancel".localized(), for: .normal)
+        if let cBtn = searchBar.value(forKey: "cancelButton") as? UIButton {
+            cBtn.setTitle("Cancel".localized(), for: .normal)
+        }
     }
     
     func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
@@ -84,7 +85,9 @@ class BroadcastMembersTableViewController: UITableViewController, UISearchContro
 //        searchController.searchBar.setMagnifyingGlassColorTo(color: .white)
         searchController.searchBar.setImage(UIImage(), for: .search, state: .normal)
         searchController.searchBar.setPositionAdjustment(UIOffset(horizontal: 10, vertical: 0), for: .search)
-        searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        if #unavailable(iOS 26.0) {
+            searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        }
         searchController.searchBar.tintColor = .mainColor
         UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], for: .normal)
         

+ 1 - 1
NexilisLite/NexilisLite/Source/View/Control/BroadcastViewController.swift

@@ -91,7 +91,7 @@ class BroadcastViewController: UITableViewController, UITextFieldDelegate, UITex
     var loadingView = UIViewController()
     
     override func viewWillAppear(_ animated: Bool) {
-        let backButton = UIBarButtonItem(title: "Back".localized(), style: .plain, target: nil, action: nil)
+        let backButton = UIBarButtonItem(title: "".localized(), style: .plain, target: nil, action: nil)
         let attributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
         
         backButton.setTitleTextAttributes(attributes, for: .normal)

+ 61 - 13
NexilisLite/NexilisLite/Source/View/Control/ChangeDeviceViewController.swift

@@ -144,7 +144,6 @@ public class ChangeDeviceViewController: UIViewController {
         Nexilis.showLoader()
         DispatchQueue.global().async {
             if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getCheckMSISDN(number: number)) {
-                print("KUKU: \(response.toLogString())")
                 if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") != "00" {
                     DispatchQueue.main.async {
                         self.showFailedSignUpIn(title: "Unregistered phone number".localized())
@@ -152,7 +151,7 @@ public class ChangeDeviceViewController: UIViewController {
                 } else {
                     DispatchQueue.main.async {
                         Nexilis.hideLoader(completion: {
-                            self.sendOTP(to: number)
+                            self.showOTPSelectionAlert(self, number)
                         })
                     }
                 }
@@ -164,6 +163,43 @@ public class ChangeDeviceViewController: UIViewController {
         }
     }
     
+    func showOTPSelectionAlert(_ viewController: UIViewController, _ number: String) {
+        let alert = UIAlertController(title: "Choose OTP Method".localized(),
+                                      message: "Select how you want to receive your OTP".localized(),
+                                      preferredStyle: .actionSheet) // use .alert if you want centered popup
+        
+        alert.addAction(UIAlertAction(title: "📩 SMS", style: .default, handler: { _ in
+            self.sendOTP(to: number)
+        }))
+        
+        alert.addAction(UIAlertAction(title: "💬 WhatsApp", style: .default, handler: { _ in
+            Nexilis.showLoader()
+            DispatchQueue.global().async {
+                if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSendOTPLogin(p_number: number), timeout: 30 * 1000) {
+                    if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") != "00" {
+                        DispatchQueue.main.async {
+                            self.showFailedSignUpIn(title: "Unregistered phone number".localized())
+                        }
+                    } else {
+                        DispatchQueue.main.async {
+                            Nexilis.hideLoader(completion: {
+                                self.showPageOTP(phone: number, method: 1)
+                            })
+                        }
+                    }
+                } else {
+                    DispatchQueue.main.async {
+                        self.showFailedSignUpIn(title: "Unable to access servers. Try again later".localized())
+                    }
+                }
+            }
+        }))
+        
+        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
+        
+        viewController.present(alert, animated: true)
+    }
+    
     func sendOTP(to phoneNumber: String) {
         PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { verificationID, error in
             if let error = error {
@@ -176,20 +212,27 @@ public class ChangeDeviceViewController: UIViewController {
         }
     }
     
-    func verifyOTP(_ code: String, number: String, privateKey: SecKey) {
+    func verifyOTP(_ code: String, number: String, privateKey: SecKey, method: Int) {
         let verificationID = Utils.getUserMSISDN()
         let credential = PhoneAuthProvider.provider().credential(
             withVerificationID: verificationID,
             verificationCode: code
         )
 
-        Auth.auth().signIn(with: credential) { authResult, error in
-            if error != nil {
-                self.showFailedSignUpIn(title: "Invalid OTP".localized())
-                self.showPageOTP(phone: number)
-                return
+        if method == 0 {
+            Auth.auth().signIn(with: credential) { authResult, error in
+                if error != nil {
+                    self.showFailedSignUpIn(title: "Invalid OTP".localized())
+                    self.showPageOTP(phone: number)
+                    return
+                }
+                sendSVL()
             }
-
+        } else {
+            sendSVL()
+        }
+        
+        func sendSVL() {
             DispatchQueue.global().async {
                 if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getChalanger()) {
                     if response.isOk() {
@@ -211,9 +254,13 @@ public class ChangeDeviceViewController: UIViewController {
                         if let publicKey = KeyManagerNexilis.getRSAX509PublicKeyBase64(privateKey: privateKey) {
                             pk = publicKey
                         }
-                        if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSendVerifyChangeDevice(p_email: "", p_vercode: "", number: number, deviceFingerprint: df, publicKey: pk, signature: sign), timeout: 30 * 1000) {
+                        if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSendVerifyChangeDevice(p_email: "", p_vercode: method == 0 ? "" : code, number: number, deviceFingerprint: df, publicKey: pk, signature: sign), timeout: 30 * 1000) {
                             if !response.isOk() {
-                                DispatchQueue.main.async {
+                                if method == 1 {
+                                    DispatchQueue.main.async {
+                                        self.showPageOTP(phone: number, errCode: response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99"), method: method)
+                                    }
+                                } else {
                                     DispatchQueue.main.async {
                                         self.showFailedSignUpIn(title: "Failed".localized())
                                     }
@@ -240,12 +287,13 @@ public class ChangeDeviceViewController: UIViewController {
         }
     }
     
-    func showPageOTP(email: String = "", phone: String = "", errCode:String = "") {
+    func showPageOTP(email: String = "", phone: String = "", errCode:String = "", method: Int = 0) {
         let showOTPVC = VerifyEmail()
         showOTPVC.email = email
         showOTPVC.msisdn = phone
         showOTPVC.isMSISDN = !phone.isEmpty
         showOTPVC.showWrongOTP = errCode
+        showOTPVC.method = method
         showOTPVC.isDismiss = { code in
             if !CheckConnection.isConnectedToNetwork() || API.nGetCLXConnState() == 0 {
                 self.showFailedSignUpIn(title: "Check your connection".localized(), withLoader: false)
@@ -271,7 +319,7 @@ public class ChangeDeviceViewController: UIViewController {
             }
             Nexilis.showLoader()
             if !phone.isEmpty {
-                self.verifyOTP(code, number: phone, privateKey: privateKey)
+                self.verifyOTP(code, number: phone, privateKey: privateKey, method: method)
                 return
             }
             DispatchQueue.global().async {

+ 6 - 3
NexilisLite/NexilisLite/Source/View/Control/ContactChatViewController.swift

@@ -180,7 +180,9 @@ class ContactChatViewController: UITableViewController {
 //        searchController.searchBar.updateHeight(height: 36, radius: 18)
         searchController.searchBar.setImage(UIImage(), for: .search, state: .normal)
         searchController.searchBar.setPositionAdjustment(UIOffset(horizontal: 10, vertical: 0), for: .search)
-        searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        if #unavailable(iOS 26.0) {
+            searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        }
         searchController.searchBar.tintColor = .mainColor
         searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "Search".localized(), attributes: [NSAttributedString.Key.foregroundColor: UIColor.gray, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)])
         
@@ -1963,8 +1965,9 @@ extension ContactChatViewController: UISearchControllerDelegate, UISearchBarDele
     
     func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
         searchBar.showsCancelButton = true
-        let cBtn = searchBar.value(forKey: "cancelButton") as! UIButton
-        cBtn.setTitle("Cancel".localized(), for: .normal)
+        if let cBtn = searchBar.value(forKey: "cancelButton") as? UIButton {
+            cBtn.setTitle("Cancel".localized(), for: .normal)
+        }
     }
     
     func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {

+ 1 - 1
NexilisLite/NexilisLite/Source/View/Control/ProfileViewController.swift

@@ -245,7 +245,7 @@ public class ProfileViewController: UITableViewController, UITextFieldDelegate {
         labelAcceptCall.text = "Accept Call".localized()
         buttonHistoryCC.setAttributedTitle(NSAttributedString(string: "Call Center History".localized(), attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16), NSAttributedString.Key.foregroundColor : self.traitCollection.userInterfaceStyle == .dark ? UIColor.blackDarkMode : UIColor.white]), for: .normal)
 //        buttonQRCode.setAttributedTitle(NSAttributedString(string: "Show QR Code".localized(), attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16), NSAttributedString.Key.foregroundColor : self.traitCollection.userInterfaceStyle == .dark ? UIColor.blackDarkMode : UIColor.white]), for: .normal)
-        navigationController?.navigationBar.topItem?.backButtonTitle = "Back".localized()
+        navigationController?.navigationBar.topItem?.backButtonTitle = ""
         
         switchPrivateAccount.onTintColor = .mainColor
         switchAcceptCall.onTintColor = .mainColor

+ 1 - 1
NexilisLite/NexilisLite/Source/View/Control/SetInternalCSAccount.swift

@@ -29,7 +29,7 @@ public class SetInternalCSAccount: UITableViewController {
     public override func viewDidLoad() {
         super.viewDidLoad()
         
-        navigationController?.navigationBar.topItem?.backButtonTitle = "Back".localized()
+        navigationController?.navigationBar.topItem?.backButtonTitle = ""
         tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellCSInternal")
         
         searchController = UISearchController(searchResultsController: nil)

+ 61 - 12
NexilisLite/NexilisLite/Source/View/Control/SignUpSignIn.swift

@@ -159,7 +159,44 @@ public class SignUpSignIn: UIViewController {
             self.showFailedSignUpIn(title: "Check your connection".localized(), withLoader: false)
             return
         }
-        self.sendOTP(to: number)
+        self.showOTPSelectionAlert(self, number)
+    }
+    
+    func showOTPSelectionAlert(_ viewController: UIViewController, _ number: String) {
+        let alert = UIAlertController(title: "Choose OTP Method".localized(),
+                                      message: "Select how you want to receive your OTP".localized(),
+                                      preferredStyle: .actionSheet) // use .alert if you want centered popup
+        
+        alert.addAction(UIAlertAction(title: "📩 SMS", style: .default, handler: { _ in
+            self.sendOTP(to: number)
+        }))
+        
+        alert.addAction(UIAlertAction(title: "💬 WhatsApp", style: .default, handler: { _ in
+            Nexilis.showLoader()
+            DispatchQueue.global().async {
+                if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSendOTPLogin(p_number: number), timeout: 30 * 1000) {
+                    if response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99") != "00" {
+                        DispatchQueue.main.async {
+                            self.showFailedSignUpIn(title: "Unregistered phone number".localized())
+                        }
+                    } else {
+                        DispatchQueue.main.async {
+                            Nexilis.hideLoader(completion: {
+                                self.showPageOTP(phone: number, method: 1)
+                            })
+                        }
+                    }
+                } else {
+                    DispatchQueue.main.async {
+                        self.showFailedSignUpIn(title: "Unable to access servers. Try again later".localized())
+                    }
+                }
+            }
+        }))
+        
+        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
+        
+        viewController.present(alert, animated: true)
     }
     
     func sendOTP(to phoneNumber: String) {
@@ -174,20 +211,27 @@ public class SignUpSignIn: UIViewController {
         }
     }
     
-    func verifyOTP(_ code: String, number: String, privateKey: SecKey) {
+    func verifyOTP(_ code: String, number: String, privateKey: SecKey, method: Int) {
         let verificationID = Utils.getUserMSISDN()
         let credential = PhoneAuthProvider.provider().credential(
             withVerificationID: verificationID,
             verificationCode: code
         )
 
-        Auth.auth().signIn(with: credential) { authResult, error in
-            if error != nil {
-                self.showFailedSignUpIn(title: "Invalid OTP".localized())
-                self.showPageOTP(phone: number)
-                return
+        if method == 0 {
+            Auth.auth().signIn(with: credential) { authResult, error in
+                if error != nil {
+                    self.showFailedSignUpIn(title: "Invalid OTP".localized())
+                    self.showPageOTP(phone: number)
+                    return
+                }
+                sendSVL()
             }
-
+        } else {
+            sendSVL()
+        }
+        
+        func sendSVL() {
             DispatchQueue.global().async {
                 if let response = Nexilis.writeAndWait(message: CoreMessage_TMessageBank.getChalanger()) {
                     if response.isOk() {
@@ -209,9 +253,13 @@ public class SignUpSignIn: UIViewController {
                         if let publicKey = KeyManagerNexilis.getRSAX509PublicKeyBase64(privateKey: privateKey) {
                             pk = publicKey
                         }
-                        if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSendVerifyChangeDevice(p_email: "", p_vercode: "", number: number, deviceFingerprint: df, publicKey: pk, signature: sign), timeout: 30 * 1000) {
+                        if let response = Nexilis.writeSync(message: CoreMessage_TMessageBank.getSendVerifyChangeDevice(p_email: "", p_vercode: method == 0 ? "" : code, number: number, deviceFingerprint: df, publicKey: pk, signature: sign), timeout: 30 * 1000) {
                             if !response.isOk() {
-                                DispatchQueue.main.async {
+                                if method == 1 {
+                                    DispatchQueue.main.async {
+                                        self.showPageOTP(phone: number, errCode: response.getBody(key: CoreMessage_TMessageKey.ERRCOD, default_value: "99"), method: method)
+                                    }
+                                } else {
                                     DispatchQueue.main.async {
                                         self.showFailedSignUpIn(title: "Failed".localized())
                                     }
@@ -238,12 +286,13 @@ public class SignUpSignIn: UIViewController {
         }
     }
     
-    func showPageOTP(email: String = "", phone: String = "", errCode:String = "") {
+    func showPageOTP(email: String = "", phone: String = "", errCode:String = "", method: Int = 0) {
         let showOTPVC = VerifyEmail()
         showOTPVC.email = email
         showOTPVC.msisdn = phone
         showOTPVC.isMSISDN = !phone.isEmpty
         showOTPVC.showWrongOTP = errCode
+        showOTPVC.method = method
         showOTPVC.isDismiss = { code in
             if !CheckConnection.isConnectedToNetwork() || API.nGetCLXConnState() == 0 {
                 self.showFailedSignUpIn(title: "Check your connection".localized(), withLoader: false)
@@ -269,7 +318,7 @@ public class SignUpSignIn: UIViewController {
             }
             Nexilis.showLoader()
             if !phone.isEmpty {
-                self.verifyOTP(code, number: phone, privateKey: privateKey)
+                self.verifyOTP(code, number: phone, privateKey: privateKey, method: method)
                 return
             }
             DispatchQueue.global().async {

+ 6 - 1
NexilisLite/NexilisLite/Source/View/Control/VerifyEmail.swift

@@ -22,6 +22,7 @@ class VerifyEmail: UIViewController, UITextFieldDelegate, OTPTextFieldDelegate {
     var isDismiss: ((String) -> ())?
     var showWrongOTP = ""
     var isMSISDN = false
+    var method = 0
 
     override func viewDidLoad() {
         super.viewDidLoad()
@@ -47,7 +48,11 @@ class VerifyEmail: UIViewController, UITextFieldDelegate, OTPTextFieldDelegate {
         descVerify.textAlignment = .center
         descVerify.text = "Your verification code has been sent to".localized() + "\n" + email + "\n" + "Please check your email and enter the code sent".localized()
         if isMSISDN {
-            descVerify.text = "Your verification code has been sent to".localized() + "\n" + msisdn + "\n" + "Please check in your message app and enter the code sent".localized()
+            if method == 0 {
+                descVerify.text = "Your verification code has been sent to".localized() + "\n" + msisdn + "\n" + "Please check in your message app and enter the code sent".localized()
+            } else {
+                descVerify.text = "Your verification code has been sent to".localized() + "\n" + msisdn + "\n" + "Please check in your Whatsapp and enter the code sent".localized()
+            }
         }
         view.addSubview(descVerify)
         descVerify.anchor(top: titleVerify.bottomAnchor, paddingTop: 8, centerX: view.centerXAnchor)

+ 6 - 3
NexilisLite/NexilisLite/Source/View/Streaming/SeminarListViewController.swift

@@ -63,7 +63,9 @@ class SeminarListViewController: UIViewController {
 //        searchController.searchBar.setMagnifyingGlassColorTo(color: .white)
         searchController.searchBar.setImage(UIImage(), for: .search, state: .normal)
         searchController.searchBar.setPositionAdjustment(UIOffset(horizontal: 10, vertical: 0), for: .search)
-        searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        if #unavailable(iOS 26.0) {
+            searchController.searchBar.setCustomBackgroundImage(image: UIImage(named: self.traitCollection.userInterfaceStyle == .dark ? "nx_search_bar_dark" : "nx_search_bar", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!)
+        }
         searchController.searchBar.tintColor = .mainColor
         
         tableView.delegate = self
@@ -90,8 +92,9 @@ class SeminarListViewController: UIViewController {
     
     func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
         searchBar.showsCancelButton = true
-        let cBtn = searchBar.value(forKey: "cancelButton") as! UIButton
-        cBtn.setTitle("Cancel".localized(), for: .normal)
+        if let cBtn = searchBar.value(forKey: "cancelButton") as? UIButton {
+            cBtn.setTitle("Cancel".localized(), for: .normal)
+        }
     }
     
     func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {