alqindiirsyam 2 лет назад
Родитель
Сommit
bc0549853d

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

@@ -533,7 +533,7 @@
 					"@executable_path/Frameworks",
 				);
 				MARKETING_VERSION = 2.2.9;
-				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder1;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilders;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_VERSION = 5.0;
@@ -565,7 +565,7 @@
 					"@executable_path/Frameworks",
 				);
 				MARKETING_VERSION = 2.2.9;
-				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder1;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilders;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
 				SWIFT_VERSION = 5.0;
@@ -592,7 +592,7 @@
 					"@executable_path/../../Frameworks",
 				);
 				MARKETING_VERSION = 1.0;
-				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder1.NotificationService;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilders.NotificationService;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 				SWIFT_EMIT_LOC_STRINGS = YES;
@@ -620,7 +620,7 @@
 					"@executable_path/../../Frameworks",
 				);
 				MARKETING_VERSION = 1.0;
-				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilder1.NotificationService;
+				PRODUCT_BUNDLE_IDENTIFIER = io.newuniverse.AppBuilders.NotificationService;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 				SWIFT_EMIT_LOC_STRINGS = YES;

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

@@ -97,7 +97,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         if PrefsUtil.getCpaasMode() == PrefsUtil.CPAAS_MODE_FLOATING || PrefsUtil.getCpaasMode() == PrefsUtil.CPAAS_MODE_MIX {
             showButton = true
         }
-        Nexilis.connect(apiKey: "***REPLACE***WITH***YOUR***ACCOUNT***", delegate: self, showButton: showButton, fromMAB: true) //AA6164AA13F0A6262677AC7443C37E3F6F0A342E8BEE84B700CB59C876166FE0(AWS) //1C4FA430BC9F44484AFBE99C8974D70B68CE7891DBE83505CBF01205DE51FC18(CBN)
+        Nexilis.connect(apiKey: "1C4FA430BC9F44484AFBE99C8974D70B68CE7891DBE83505CBF01205DE51FC18", delegate: self, showButton: showButton, fromMAB: true) //AA6164AA13F0A6262677AC7443C37E3F6F0A342E8BEE84B700CB59C876166FE0(AWS) //1C4FA430BC9F44484AFBE99C8974D70B68CE7891DBE83505CBF01205DE51FC18(CBN)
         let tabBarAppearance: UITabBarAppearance = UITabBarAppearance()
         tabBarAppearance.configureWithTransparentBackground()
         if Bundle.main.displayName == "DigiNetS" {

+ 2 - 0
appbuilder-ios/AppBuilder/AppBuilder/ViewController.swift

@@ -935,6 +935,8 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
     
     @objc func chatTap() {
         print("chatTap")
+        APIS.openWhiteboard()
+        return
         if(ViewController.checkIsChangePerson()){
             show(b: false)
             ViewController.def?.thirdTab?.webView?.evaluateJavaScript("{if(pauseAll){pauseAll();}}")

+ 17 - 2
appbuilder-ios/NexilisLite/NexilisLite/Source/APIS.swift

@@ -6,8 +6,6 @@
 //
 
 import Foundation
-import AVFoundation
-import AVKit
 import UIKit
 import FMDB
 import NotificationBannerSwift
@@ -326,6 +324,23 @@ public class APIS: NSObject {
             UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
         }
     }
+    
+    public static func openWhiteboard() {
+        let isChangeProfile = Utils.getSetProfile()
+        if !isChangeProfile {
+            APIS.showChangeProfile()
+            return
+        }
+        let callContact = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "contactSID") as! ContactCallViewController
+        callContact.startWhiteBoard = true
+        let navigationController = UINavigationController(rootViewController: callContact)
+        navigationController.defaultStyle()
+        if UIApplication.shared.visibleViewController?.navigationController != nil {
+            UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
+        } else {
+            UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
+        }
+    }
 }
 
 extension UINavigationController {

+ 110 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/CoreMessage_TMessageBank.swift

@@ -2233,4 +2233,114 @@ public class CoreMessage_TMessageBank {
         tmessage.mBodies[CoreMessage_TMessageKey.FILE_ID] = fileid
         return tmessage
     }
+    
+    public static func wbCreate(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "wb"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.WB_INCOMING)"
+        return tmessage;
+    }
+    
+    public static func wbAccept(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "wb"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.WB_ACCEPT_INCOMING)"
+        return tmessage;
+    }
+    
+    public static func wbReject(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "wb"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.WB_REJECT_INCOMING)"
+        return tmessage;
+    }
+    
+    public static func wbOffhook(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "wb"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.WB_OFFHOOK)"
+        return tmessage;
+    }
+    
+    public static func wbEnded(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "wb"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.WB_END)"
+        return tmessage;
+    }
+    
+    public static func ssCreate(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "ss"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.SS_INCOMING)"
+        return tmessage;
+    }
+    
+    public static func ssAccept(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "ss"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.SS_ACCEPT_INCOMING)"
+        return tmessage;
+    }
+    
+    public static func ssReject(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "ss"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.SS_REJECT_INCOMING)"
+        return tmessage;
+    }
+    
+    public static func ssOffhook(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "ss"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.SS_OFFHOOK)"
+        return tmessage;
+    }
+    
+    public static func ssEnded(l_pin: String) -> TMessage {
+        let tmessage = TMessage()
+        tmessage.mCode = CoreMessage_TMessageCode.FORWARD_MESSAGE
+        tmessage.mStatus = CoreMessage_TMessageUtil.getTID()
+        tmessage.mPIN = UserDefaults.standard.string(forKey: "me")!
+        tmessage.mBodies[CoreMessage_TMessageKey.L_PIN] = l_pin
+        tmessage.mBodies[CoreMessage_TMessageKey.TYPE] = "ss"
+        tmessage.mBodies[CoreMessage_TMessageKey.STATUS] = "\(CoreMessage_TMessageCode.SS_END)"
+        return tmessage;
+    }
 }

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

@@ -744,4 +744,19 @@ public class CoreMessage_TMessageCode {
     public static let BACKUP_AVAILABILITY = "BUA2";
     public static let BACKUP_UPLOADED = "BUU2";
     public static let BACKUP_RESTORED = "BUR2";
+    
+    public static let FORWARD_MESSAGE = "C2";
+    public static let WB_INCOMING = 101;
+    public static let WB_OFFHOOK = 102;
+    public static let WB_RINGING = 103;
+    public static let WB_ACCEPT_INCOMING = 104;
+    public static let WB_REJECT_INCOMING = 105;
+    public static let WB_END = 108;
+
+    public static let SS_INCOMING = 121;
+    public static let SS_OFFHOOK = 122;
+    public static let SS_RINGING = 123;
+    public static let SS_ACCEPT_INCOMING = 124;
+    public static let SS_REJECT_INCOMING = 125;
+    public static let SS_END = 128;
 }

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

@@ -159,6 +159,8 @@ class IncomingThread {
             inquiry(message: message)
         } else if message.getCode() == CoreMessage_TMessageCode.BACKUP_AVAILABILITY {
             backupAvailability(message: message)
+        } else if message.getCode() == CoreMessage_TMessageCode.FORWARD_MESSAGE {
+            incomingWBSS(message: message)
         } else {
             print("unprocessed code", message.getCode())
             ack(message: message)
@@ -171,6 +173,37 @@ class IncomingThread {
     /**
      *
      */
+    private func incomingWBSS(message: TMessage) {
+        let type = message.getBody(key: CoreMessage_TMessageKey.TYPE, default_value: "")
+        let status = message.getBody(key: CoreMessage_TMessageKey.STATUS, default_value: "")
+        let f_pin = message.getBody(key: CoreMessage_TMessageKey.F_USER_ID, default_value: "")
+        if type == "wb" {
+            switch (Int(status)) {
+            case CoreMessage_TMessageCode.WB_INCOMING:
+                print("WB_INCOMING")
+                DispatchQueue.main.async {
+                    let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "wbVC") as! WhiteboardViewController
+                    controller.modalPresentationStyle = .overFullScreen
+                    controller.fromContact = 1
+                    controller.user = User.getData(pin: f_pin)
+                    if UIApplication.shared.visibleViewController?.navigationController != nil {
+                        UIApplication.shared.visibleViewController?.navigationController?.present(controller, animated: true, completion: nil)
+                    } else {
+                        UIApplication.shared.visibleViewController?.present(controller, animated: true, completion: nil)
+                    }
+                }
+            default:
+                print("default")
+                var dataMessage: [AnyHashable : Any] = [:]
+                dataMessage["message"] = message
+                NotificationCenter.default.post(name: NSNotification.Name(rawValue: "wbSession"), object: nil, userInfo: dataMessage)
+            }
+        } else if type == "ss"{
+            
+        }
+        ack(message: message)
+    }
+    
     
     private func backupAvailability(message: TMessage) {
         var dataMessage: [AnyHashable : Any] = [:]

+ 226 - 1
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Call/WhiteboardViewController.swift

@@ -29,6 +29,16 @@ class WhiteboardViewController: UIViewController, WhiteboardDelegate {
     var roomId = ""
     var destinations = [String]()
     var incoming = false
+    var fromContact: Int?
+    let myImage = UIImageView()
+    let name = UILabel()
+    let profileImage = UIImageView()
+    let labelIncomingOutgoing = UILabel()
+    var user: User?
+    let buttonDecline = UIButton()
+    let buttonAccept = UIButton()
+    var constraintLeadingButtonDecline = NSLayoutConstraint()
+    var constraintBottomButtonDecline = NSLayoutConstraint()
     
     required init?(coder: NSCoder) {
         super.init(coder: coder)
@@ -37,8 +47,17 @@ class WhiteboardViewController: UIViewController, WhiteboardDelegate {
     
     override func viewDidLoad() {
         super.viewDidLoad()
-        initWhiteboard()
+        if fromContact != nil {
+            addBackgroundIncoming()
+            addProfileNameCalling()
+            Calling()
+            addToolbar()
+        } else {
+            initWhiteboard()
+        }
         self.title = "Whiteboard".localized()
+        let center: NotificationCenter = NotificationCenter.default
+        center.addObserver(self, selector: #selector(wbSession(notification:)), name: NSNotification.Name(rawValue: "wbSession"), object: nil)
 //        navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Close".localized(), style: .plain, target: self, action: #selector(close))
 //        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Clear".localized(), style: .plain,target: self, action: #selector(clear))
         
@@ -46,6 +65,208 @@ class WhiteboardViewController: UIViewController, WhiteboardDelegate {
         // Do any additional setup after loading the view.
     }
     
+    func addBackgroundIncoming() {
+        view.addSubview(myImage)
+        myImage.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            myImage.topAnchor.constraint(equalTo: view.topAnchor),
+            myImage.bottomAnchor.constraint(equalTo: view.bottomAnchor),
+            myImage.leadingAnchor.constraint(equalTo: view.leadingAnchor),
+            myImage.trailingAnchor.constraint(equalTo: view.trailingAnchor),
+        ])
+        myImage.backgroundColor = .lightGray
+        myImage.tintColor = .secondaryColor
+        let image = user!.thumb
+        if image.isEmpty {
+            myImage.image = UIImage(systemName: "person")
+            myImage.contentMode = .scaleAspectFit
+        } else {
+            myImage.setImage(name: image)
+            myImage.contentMode = .scaleAspectFill
+        }
+    }
+    
+    func addProfileNameCalling() {
+        view.addSubview(profileImage)
+        profileImage.translatesAutoresizingMaskIntoConstraints = false
+        profileImage.frame.size = CGSize(width: 60.0, height: 60.0)
+        NSLayoutConstraint.activate([
+            profileImage.topAnchor.constraint(equalTo: view.topAnchor, constant: 40.0),
+            profileImage.centerXAnchor.constraint(equalTo: view.centerXAnchor),
+            profileImage.widthAnchor.constraint(equalToConstant: 60.0),
+            profileImage.heightAnchor.constraint(equalToConstant: 63.0)
+        ])
+        profileImage.backgroundColor = .lightGray
+        profileImage.tintColor = .secondaryColor
+        profileImage.circle()
+        let image = user!.thumb
+        if image.isEmpty {
+            profileImage.image = UIImage(systemName: "person")
+            profileImage.contentMode = .scaleAspectFit
+            profileImage.layer.borderWidth = 1
+            profileImage.layer.borderColor = UIColor.secondaryColor.cgColor
+        } else {
+            profileImage.setImage(name: image)
+            profileImage.contentMode = .scaleAspectFill
+        }
+        
+        view.addSubview(name)
+        name.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            name.topAnchor.constraint(equalTo: profileImage.bottomAnchor, constant: 5.0),
+            name.centerXAnchor.constraint(equalTo: view.centerXAnchor)
+        ])
+        name.font = UIFont.systemFont(ofSize: 12)
+        name.backgroundColor = .black.withAlphaComponent(0.05)
+        name.layer.cornerRadius = 5.0
+        name.clipsToBounds = true
+        name.textColor = .mainColor
+        name.text = user?.fullName.trimmingCharacters(in: .whitespaces)
+    }
+    
+    func Calling() {
+        view.addSubview(labelIncomingOutgoing)
+        labelIncomingOutgoing.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            labelIncomingOutgoing.topAnchor.constraint(equalTo: name.bottomAnchor, constant: 40.0),
+            labelIncomingOutgoing.centerXAnchor.constraint(equalTo: view.centerXAnchor)
+        ])
+        if fromContact == 0 {
+            labelIncomingOutgoing.text = "Waiting for answer".localized() + "..."
+            _ = Nexilis.write(message: CoreMessage_TMessageBank.wbCreate(l_pin: user!.pin))
+        } else {
+            labelIncomingOutgoing.text = "Incoming Whiteboard".localized() + "..."
+        }
+        labelIncomingOutgoing.font = UIFont.systemFont(ofSize: 12)
+        labelIncomingOutgoing.backgroundColor = .black.withAlphaComponent(0.05)
+        labelIncomingOutgoing.layer.cornerRadius = 5.0
+        labelIncomingOutgoing.clipsToBounds = true
+        labelIncomingOutgoing.textColor = .mainColor
+    }
+    
+    func addToolbar() {
+        view.addSubview(buttonDecline)
+        buttonDecline.translatesAutoresizingMaskIntoConstraints = false
+        buttonDecline.frame.size = CGSize(width: 70.0, height: 70.0)
+        if fromContact == 0 {
+            constraintLeadingButtonDecline = buttonDecline.centerXAnchor.constraint(equalTo: view.centerXAnchor)
+        } else {
+            constraintLeadingButtonDecline = buttonDecline.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: view.frame.width * 0.2)
+        }
+        constraintBottomButtonDecline = buttonDecline.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -60.0)
+        NSLayoutConstraint.activate([
+            constraintBottomButtonDecline,
+            constraintLeadingButtonDecline,
+            buttonDecline.widthAnchor.constraint(equalToConstant: 70.0),
+            buttonDecline.heightAnchor.constraint(equalToConstant: 70.0)
+        ])
+        buttonDecline.backgroundColor = .red
+        buttonDecline.circle()
+        buttonDecline.setImage(UIImage(systemName: "xmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
+        buttonDecline.tintColor = .white
+        buttonDecline.addTarget(self, action: #selector(didTapDeclineCallButton(sender:)), for: .touchUpInside)
+        
+        if fromContact == 1 {
+            view.addSubview(buttonAccept)
+            buttonAccept.translatesAutoresizingMaskIntoConstraints = false
+            buttonAccept.frame.size = CGSize(width: 70.0, height: 70.0)
+            NSLayoutConstraint.activate([
+                buttonAccept.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -60.0),
+                buttonAccept.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -(view.frame.width * 0.2)),
+                buttonAccept.widthAnchor.constraint(equalToConstant: 70.0),
+                buttonAccept.heightAnchor.constraint(equalToConstant: 70.0)
+            ])
+            buttonAccept.backgroundColor = .greenColor
+            buttonAccept.circle()
+            buttonAccept.setImage(UIImage(systemName: "checkmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: 30, weight: .medium, scale: .default)), for: .normal)
+            buttonAccept.tintColor = .white
+            buttonAccept.addTarget(self, action: #selector(didTapAcceptCallButton), for: .touchUpInside)
+        }
+    }
+    
+    @objc func didTapDeclineCallButton(sender: Any) {
+        let alert = UIAlertController(title: "End Whiteboard Session".localized(), message: "Are you sure you want to end whiteboard session?".localized(), preferredStyle: .alert)
+        alert.addAction(UIAlertAction(title: "No".localized(), style: UIAlertAction.Style.default, handler: nil))
+        alert.addAction(UIAlertAction(title: "Yes".localized(), style: UIAlertAction.Style.default, handler: {(_) in
+            if self.fromContact == 0 {
+                _ = Nexilis.write(message: CoreMessage_TMessageBank.wbEnded(l_pin: self.user!.pin))
+            } else {
+                _ = Nexilis.write(message: CoreMessage_TMessageBank.wbReject(l_pin: self.user!.pin))
+            }
+            self.dismiss(animated: true, completion: nil)
+        }))
+        self.present(alert, animated: true, completion: nil)
+    }
+    
+    @objc func didTapAcceptCallButton() {
+        _ = Nexilis.write(message: CoreMessage_TMessageBank.wbAccept(l_pin: user!.pin))
+        self.myImage.removeFromSuperview()
+        self.name.removeFromSuperview()
+        self.profileImage.removeFromSuperview()
+        self.labelIncomingOutgoing.removeFromSuperview()
+        self.buttonDecline.removeFromSuperview()
+        self.buttonAccept.removeFromSuperview()
+        NSLayoutConstraint.deactivate([
+            self.constraintLeadingButtonDecline,
+            self.constraintBottomButtonDecline
+        ])
+        self.initWhiteboard()
+        let tid = CoreMessage_TMessageUtil.getTID()
+        self.roomId = "\(user!.pin)WB\(tid)"
+        let idMe = UserDefaults.standard.string(forKey: "me")!
+        UserDefaults.standard.set("\(user!.pin),\(idMe)", forKey: "wb_vc")
+        self.sendJoin()
+    }
+    
+    @objc func wbSession(notification: NSNotification) {
+        DispatchQueue.main.async { [self] in
+            let data:[AnyHashable : Any] = notification.userInfo!
+            if let message = data["message"] as? TMessage {
+                let status = message.getBody(key: CoreMessage_TMessageKey.STATUS, default_value: "")
+                switch (Int(status)) {
+                case CoreMessage_TMessageCode.WB_ACCEPT_INCOMING:
+                    print("WB_ACCEPT_INCOMING")
+                    let f_pin = message.getBody(key: CoreMessage_TMessageKey.F_USER_ID, default_value: "")
+                    _ = Nexilis.write(message: CoreMessage_TMessageBank.wbOffhook(l_pin: f_pin))
+                    DispatchQueue.main.async {
+                        let l_pin = message.getBody(key: CoreMessage_TMessageKey.L_PIN, default_value: "")
+                        self.myImage.removeFromSuperview()
+                        self.name.removeFromSuperview()
+                        self.profileImage.removeFromSuperview()
+                        self.labelIncomingOutgoing.removeFromSuperview()
+                        self.buttonDecline.removeFromSuperview()
+                        NSLayoutConstraint.deactivate([
+                            self.constraintLeadingButtonDecline,
+                            self.constraintBottomButtonDecline
+                        ])
+                        self.initWhiteboard()
+                        let tid = CoreMessage_TMessageUtil.getTID()
+                        self.roomId = "\(f_pin)WB\(tid)"
+                        self.destinations = [l_pin]
+                        self.sendInit()
+                    }
+                case CoreMessage_TMessageCode.WB_REJECT_INCOMING,CoreMessage_TMessageCode.WB_END:
+                    print("WB_REJECT_INCOMING \(status)")
+                    if self.labelIncomingOutgoing.isDescendant(of: self.view) {
+                        self.labelIncomingOutgoing.text = "WhiteBoard session is over".localized()
+                    }
+                    if self.buttonDecline.isDescendant(of: self.view) {
+                        self.buttonDecline.removeFromSuperview()
+                    }
+                    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+                        self.dismiss(animated: true, completion: nil)
+                    }
+                case CoreMessage_TMessageCode.WB_OFFHOOK:
+                    print("WB_OFFHOOK")
+                case CoreMessage_TMessageCode.WB_RINGING:
+                    print("WB_RINGING")
+                default:
+                    print("default")
+                }
+            }
+        }
+    }
+    
     func initWhiteboard(){
         let wbHeight = self.view.frame.width * 20.0 / 9.0
         let rect = CGRect(x: 0.0, y: 0.0, width: self.view.frame.width, height: self.view.frame.height)
@@ -84,6 +305,10 @@ class WhiteboardViewController: UIViewController, WhiteboardDelegate {
     }
     
     @IBAction func didTapClose(_ sender: Any) {
+        if fromContact != nil {
+            didTapDeclineCallButton(sender: 0)
+            return
+        }
         close?()
     }
     

+ 19 - 0
appbuilder-ios/NexilisLite/NexilisLite/Source/View/Contact/ContactCallViewController.swift

@@ -28,6 +28,7 @@ class ContactCallViewController: UIViewController {
     }
     
     var onlyAudioOrVideo = 0
+    var startWhiteBoard = false
     
     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
         if (segue.identifier == "videoVC") {
@@ -56,6 +57,8 @@ class ContactCallViewController: UIViewController {
             title = "Start Audio Call".localized()
         } else if onlyAudioOrVideo == 2 {
             title = "Start Video Call".localized()
+        } else if startWhiteBoard {
+            title = "Start Whiteboard".localized()
         }
         let attributes = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16.0), NSAttributedString.Key.foregroundColor: UIColor.white]
         self.navigationController?.navigationBar.titleTextAttributes = attributes
@@ -175,6 +178,19 @@ extension ContactCallViewController: UITableViewDelegate {
             self.dismiss(animated: true, completion: {
                 self.isDismiss?(self.dataPerson[indexPath.row] as [String: String?])
             })
+        } else if startWhiteBoard {
+            if !CheckConnection.isConnectedToNetwork() {
+                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()
+                return
+            }
+            let controller = AppStoryBoard.Palio.instance.instantiateViewController(identifier: "wbVC") as! WhiteboardViewController
+            controller.modalPresentationStyle = .overFullScreen
+            controller.fromContact = 0
+            controller.user = User.getData(pin: self.dataPerson[indexPath.row]["f_pin"] as! String)
+            present(controller, animated: true, completion: nil)
         }
     }
     
@@ -236,6 +252,9 @@ extension ContactCallViewController: UITableViewDataSource {
                     cell.audioCallButton.removeConstraints(cell.audioCallButton.constraints)
                     cell.audioCallButton.anchor(right: cell.rightAnchor, paddingRight: 20.0, centerY: cell.centerYAnchor)
                 }
+            } else if startWhiteBoard {
+                cell.audioCallButton.isHidden = true
+                cell.videoCallButton.isHidden = true
             } else if onlyAudioOrVideo == 2 {
                 cell.audioCallButton.isHidden = true
             } else if (isAddParticipantVideo) {