ソースを参照

update seminar

kevin 2 年 前
コミット
f3477ff08a

+ 21 - 0
appbuilder-ios/NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_od_draw.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_od_draw.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
appbuilder-ios/NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_od_draw.imageset/pb_od_draw.png


+ 21 - 0
appbuilder-ios/NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_raise_hand.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_raise_hand.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
appbuilder-ios/NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_raise_hand.imageset/pb_raise_hand.png


+ 21 - 0
appbuilder-ios/NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_seminar_speaking.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_seminar_speaking.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
appbuilder-ios/NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_seminar_speaking.imageset/pb_seminar_speaking.png


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

@@ -1485,7 +1485,7 @@ class IncomingThread {
         let l_pin = message.getBody(key: CoreMessage_TMessageKey.L_PIN,default_value: "")
         let f_pin = message.getBody(key: CoreMessage_TMessageKey.F_PIN,default_value: "")
         let status = message.getBody(key: CoreMessage_TMessageKey.STATUS,default_value: "")
-        let data = l_pin+","+f_pin+","+status
+        let data = f_pin+","+l_pin+","+status
         print(data)
         if let delegate = Nexilis.shared.seminarDelegate {
             delegate.onJoinSeminar(state: 96, message: data)

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

@@ -26,8 +26,12 @@ class SeminarViewController: UIViewController {
     
     private var frontCamera = true
     
+    private var hasRaiseHand = false
+    
     private var heightTableView: NSLayoutConstraint?
     
+    private var viewers: [SeminarViewer] = []
+    
     private var chats: [SeminarChat] = [] {
         didSet {
             DispatchQueue.main.async {
@@ -138,6 +142,55 @@ class SeminarViewController: UIViewController {
         return button
     }()
     
+    lazy var raiseHandBtn: UIButton = {
+        let button = UIButton()
+        buttonRotate.frame = CGRect(x:0, y:0, width:30, height:30)
+        button.setImage(UIImage(named: "pb_raise_hand", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
+        button.layer.cornerRadius = button.maxCornerRadius()
+        button.backgroundColor = .mainColor
+        button.addTarget(self, action: #selector(raiseHand(sender:)), for: .touchUpInside)
+        return button
+    }()
+    
+    lazy var screenShareBtn: UIButton = {
+        let button = UIButton()
+        buttonRotate.frame = CGRect(x:0, y:0, width:30, height:30)
+        button.setImage(UIImage(named: "pb_screen_share", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
+        button.layer.cornerRadius = button.maxCornerRadius()
+        button.backgroundColor = .mainColor
+        button.addTarget(self, action: #selector(screenShare(sender:)), for: .touchUpInside)
+        return button
+    }()
+    
+    lazy var whiteboardBtn: UIButton = {
+        let button = UIButton()
+        buttonRotate.frame = CGRect(x:0, y:0, width:30, height:30)
+        button.setImage(UIImage(named: "pb_od_draw", in: Bundle.resourceBundle(for: Nexilis.self), with: nil), for: .normal)
+        button.layer.cornerRadius = button.maxCornerRadius()
+        button.backgroundColor = .mainColor
+        button.addTarget(self, action: #selector(whiteboard(sender:)), for: .touchUpInside)
+        return button
+    }()
+    
+    lazy var buttonRotate: UIButton = {
+        let buttonRotate = UIButton()
+        buttonRotate.frame = CGRect(x:0, y:0, width:30, height:30)
+        buttonRotate.setImage(UIImage(systemName: "arrow.triangle.2.circlepath.camera")?.withTintColor(.mainColor, renderingMode: .alwaysOriginal), for: .normal)
+        buttonRotate.backgroundColor = .white.withAlphaComponent(0.2)
+        buttonRotate.layer.cornerRadius = 15.0
+        buttonRotate.addTarget(self, action: #selector(camera(sender:)), for: .touchUpInside)
+        return buttonRotate
+    }()
+    
+    // TODO: badges when raise hand to broadcaster
+    lazy var handNotif: UIView = {
+        let view = UIView()
+        view.frame = CGRect(x:0, y:0, width:10, height:10)
+        view.backgroundColor = hasRaiseHand ? .systemRed : .white.withAlphaComponent(0)
+        view.layer.cornerRadius = view.maxCornerRadius()
+        return view
+    }()
+    
     lazy var stack: UIView = {
         let stack = UIView()
         return stack
@@ -172,37 +225,35 @@ class SeminarViewController: UIViewController {
         buttonBack.addTarget(self, action: #selector(close(sender:)), for: .touchUpInside)
         navigationItem.leftBarButtonItem = UIBarButtonItem(customView: buttonBack)
         
-        let statusView = UIView()
+        
         view.backgroundColor = .clear
         if isLive {
             view.addSubview(tvCameraPreviewB)
             view.addSubview(ivRemoteViewS)
+            addCountViewerView()
+            tvCameraPreviewB.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor)
         }
         else {
             view.addSubview(tvCameraPreviewS)
             view.addSubview(ivRemoteViewM)
             view.addSubview(ivRemoteViewS)
+            ivRemoteViewM.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor)
         }
+        let statusView = UIView()
         view.addSubview(statusView)
-        view.addSubview(stack)
-        view.addLayoutGuide(keyboardLayoutGuide)
-        
-        if isLive {
-            addCountViewerView()
-        }
-        
-        keyboardTopAnchorConstraint = view.layoutMarginsGuide.bottomAnchor.constraint(equalTo: keyboardLayoutGuide.topAnchor, constant: 0)
-        keyboardTopAnchorConstraint.isActive = true
-        keyboardLayoutGuide.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor).isActive = true
-        
-        tvCameraPreviewB.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor)
         statusView.backgroundColor = .white.withAlphaComponent(0.2)
         statusView.layer.cornerRadius = 8.0
         statusView.layer.masksToBounds = true
         statusView.addSubview(status)
         status.anchor(left: statusView.leftAnchor, right: statusView.rightAnchor, paddingLeft: 10, paddingRight: 10, centerX: statusView.centerXAnchor, centerY: statusView.centerYAnchor)
         statusView.anchor(top: view.topAnchor, left: view.leftAnchor, right: view.rightAnchor, paddingTop: 30, paddingLeft: 80, paddingRight: 80, centerX: view.centerXAnchor, height: 30, dynamicLeft: true, dynamicRight: true)
-        stack.anchor(left: view.leftAnchor, bottom: keyboardLayoutGuide.topAnchor, right: view.rightAnchor, paddingLeft: 20, paddingBottom: 30, paddingRight: 20, height: 200)
+        view.addSubview(stack)
+        view.addLayoutGuide(keyboardLayoutGuide)
+        keyboardTopAnchorConstraint = view.layoutMarginsGuide.bottomAnchor.constraint(equalTo: keyboardLayoutGuide.topAnchor, constant: 0)
+        keyboardTopAnchorConstraint.isActive = true
+        keyboardLayoutGuide.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor).isActive = true
+        stack.anchor(left: view.leftAnchor, bottom: keyboardLayoutGuide.topAnchor,
+                     right: view.rightAnchor, paddingLeft: 20, paddingBottom: 30, paddingRight: 20, height: 200)
         
         stack.addSubview(tableView)
         stack.addSubview(textView)
@@ -227,37 +278,16 @@ class SeminarViewController: UIViewController {
         
         Nexilis.shared.seminarDelegate = self
         if isLive {
-            let buttonRotate = UIButton()
-            buttonRotate.frame = CGRect(x:0, y:0, width:30, height:30)
-            buttonRotate.setImage(UIImage(systemName: "arrow.triangle.2.circlepath.camera")?.withTintColor(.mainColor, renderingMode: .alwaysOriginal), for: .normal)
-            buttonRotate.backgroundColor = .white.withAlphaComponent(0.2)
-            buttonRotate.layer.cornerRadius = 15.0
-            buttonRotate.addTarget(self, action: #selector(camera(sender:)), for: .touchUpInside)
             navigationItem.rightBarButtonItem = UIBarButtonItem(customView: buttonRotate)
-            
             API.ibca(sTitle: data, nCamIdx: 1, nResIdx: 2, nVQuality: 4, tvCameraPreview: tvCameraPreviewB, ivRemoteS: ivRemoteViewS)
         } else {
             API.iabc(nCamIdx: 1, nResIdx: 2, nVQuality: 4, tvCameraPreview: tvCameraPreviewS, sBroadcasterID: data, ivRemoteM: ivRemoteViewM, ivRemoteS: ivRemoteViewS)
         }
     }
-    
-//    func addLikeView() {
-//        let viewLiked = UIView()
-//        view.addSubview(viewLiked)
-//        viewLiked.anchor(top: view.safeAreaLayoutGuide.topAnchor, right: view.rightAnchor, paddingRight: 20, height: 40)
-//        viewLiked.backgroundColor = .white.withAlphaComponent(0.2)
-//        viewLiked.layer.cornerRadius = 8.0
-//        viewLiked.layer.masksToBounds = true
-//
-//        let imageLiked = UIImageView()
-//        viewLiked.addSubview(imageLiked)
-//        imageLiked.anchor(left: viewLiked.leftAnchor, paddingLeft: 5.0, centerY: viewLiked.centerYAnchor)
-//        imageLiked.image = UIImage(systemName: "heart.fill")?.withTintColor(.red, renderingMode: .alwaysOriginal)
-//
-//        viewLiked.addSubview(count)
-//        count.anchor(left: imageLiked.rightAnchor, right:viewLiked.rightAnchor, paddingLeft: 5.0, paddingRight: 5.0, centerY: viewLiked.centerYAnchor)
-//
-//    }
+
+    func addToolbarView(){
+        // TODO: add buttons
+    }
     
     func addCountViewerView() {
         let viewCountViewer = UIView()
@@ -274,7 +304,7 @@ class SeminarViewController: UIViewController {
         
         viewCountViewer.addSubview(countViewer)
         countViewer.anchor(left: imageEye.rightAnchor, right:viewCountViewer.rightAnchor, paddingLeft: 5.0, paddingRight: 5.0, centerY: viewCountViewer.centerYAnchor)
-        
+        countViewer.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(showListViewer(selector:))))
     }
     
     override func viewWillDisappear(_ animated: Bool) {
@@ -283,9 +313,9 @@ class SeminarViewController: UIViewController {
     
     @objc func close(sender: Any?) {
         hideKeyboard()
-        var alert = UIAlertController(title: "", message: "Are you sure you want to end Live Streaming?".localized(), preferredStyle: .alert)
+        var alert = UIAlertController(title: "", message: "Are you sure you want to end Seminar?".localized(), preferredStyle: .alert)
         if !isLive {
-            alert = UIAlertController(title: "", message: "Are you sure you want to leave Live Streaming?".localized(), preferredStyle: .alert)
+            alert = UIAlertController(title: "", message: "Are you sure you want to leave Seminar?".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: {[weak self] _ in
@@ -330,6 +360,14 @@ class SeminarViewController: UIViewController {
         textView.text = ""
     }
     
+    @objc func screenShare(sender: Any?) {
+        // TODO: implement screen sharing   
+    }
+    
+    @objc func whiteboard(sender: Any?) {
+        // TODO: implement whiteboard
+    }
+    
     @objc func hideKeyboard() {
         view.endEditing(true)
     }
@@ -398,18 +436,20 @@ class SeminarViewController: UIViewController {
         _ = Nexilis.write(message: CoreMessage_TMessageBank.getSendSeminarChat(l_pin: data, message_text: text))
     }
     
-    private func raiseHand() {
+    @objc func raiseHand(sender: Any?) {
         guard let me = User.getDataCanNil(pin: UserDefaults.standard.string(forKey: "me")) else {
             return
         }
-        _ = Nexilis.write(message: CoreMessage_TMessageBank.getSeminarRaiseHand(p_pin: me.pin, l_pin: data, status: "1"))
+        let status = hasRaiseHand ? "0" : "1"
+        hasRaiseHand = !hasRaiseHand
+        _ = Nexilis.write(message: CoreMessage_TMessageBank.getSeminarRaiseHand(p_pin: me.pin, l_pin: data, status: status))
     }
-    
-    private func cancelRaiseHand() {
-        guard let me = User.getDataCanNil(pin: UserDefaults.standard.string(forKey: "me")) else {
+
+    @objc func showListViewer(sender: Any?){
+        guard hasRaiseHand else {
             return
         }
-        _ = Nexilis.write(message: CoreMessage_TMessageBank.getSeminarRaiseHand(p_pin: me.pin, l_pin: data, status: "0"))
+        / TODO: Show list viewer
     }
     
 }
@@ -533,11 +573,11 @@ extension SeminarViewController: SeminarDelegate {
             let platform = Int(m[3])
             if platform == 1 { // Android
                 DispatchQueue.main.async {
-                    self.tvCameraPreviewB.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 3)/2 : (CGFloat.pi)/2)
+                    self.ivRemoteViewM.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 3)/2 : (CGFloat.pi)/2)
                 }
             } else {
                 DispatchQueue.main.async {
-                    self.tvCameraPreviewB.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 5)/2 : (CGFloat.pi)/2)
+                    self.ivRemoteViewM.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 5)/2 : (CGFloat.pi)/2)
                 }
             }
             sendJoin()
@@ -549,13 +589,29 @@ extension SeminarViewController: SeminarDelegate {
             let platform = Int(m[3])
             if platform == 1 { // Android
                 DispatchQueue.main.async {
-                    self.tvCameraPreviewB.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 3)/2 : (CGFloat.pi)/2)
+                    self.ivRemoteViewM.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 3)/2 : (CGFloat.pi)/2)
                 }
             } else {
                 DispatchQueue.main.async {
-                    self.tvCameraPreviewB.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 5)/2 : (CGFloat.pi)/2)
+                    self.ivRemoteViewM.transform = CGAffineTransform.init(scaleX: 1.9, y: 1.9).rotated(by: camera == 1 ? (CGFloat.pi * 5)/2 : (CGFloat.pi)/2)
                 }
             }
+        } else if state == 32 { // initBCA (3* is from Broadcaster PoV)
+            // TODO
+        } else if state == 33 { // startAudience (3* is from Broadcaster PoV)
+            
+        } else if state == 34 { // endAudience (3* is from Broadcaster PoV)
+            
+        } else if state == 36 || state == 46 { // audience change camera (3* is from Broadcaster PoV)
+            
+        } else if state == 42 { // joinBC (4* is from Audience PoV)
+            
+        } else if state == 43 { // startAudience (4* is from Audience PoV)
+            
+        } else if state == 44 { // endAudience (4* is from Audience PoV)
+            
+        } else if state == 45 { // CCPb Br.ID Br.Title Br.CameraID Br.OS :  (4* is from Audience PoV) broadcaster change camera
+            
         } else if state == 88 {
             DispatchQueue.main.async {
                 self.status.text = "Seminar ended".localized()
@@ -571,14 +627,33 @@ extension SeminarViewController: SeminarDelegate {
             chats.append(SeminarChat(name: name, thumb: thumb, messageText: text))
         } else if state == 96 { // raise hand
             let m = message.split(separator: ",", omittingEmptySubsequences: false)
+            let f_pin = m[0].trimmingCharacters(in: .whitespaces)
+            let broadcaster = m[1].trimmingCharacters(in: .whitespaces)
             let status = m[2].trimmingCharacters(in: .whitespaces)
+            guard broadcaster == data else {
+                return
+            }
+            if(status == "1"){
+                hasRaiseHand = true
+                viewers.first(where: { $0.f_pin == f_pin })?.isRaise = true
+                // TODO: edit badges
+            }
+            else {
+                viewers.first(where: { $0.f_pin == f_pin })?.isRaise = false
+                if viewers.filter({ $0.isRaise }).count == 0 {
+                    hasRaiseHand = false
+                    // TODO: edit badges
+                }
+            }
             // wat to do
             
         } else if state == 97 { // someone left
             let m = message.split(separator: ",", omittingEmptySubsequences: false)
             let name = m[3].trimmingCharacters(in: .whitespaces)
             let thumb = m[2].trimmingCharacters(in: .whitespaces)
+            let f_pin = m[1].trimmingCharacters(in: .whitespaces)
             let text = "Left".localized()
+            viewers.removeAll{ $0.f_pin == f_pin }
             chats.append(SeminarChat(name: name, thumb: thumb, messageText: text, isInfo: true))
             DispatchQueue.main.async {
                 self.countViewer.text = "\(Int(self.countViewer.text!)! - 1)"
@@ -588,6 +663,8 @@ extension SeminarViewController: SeminarDelegate {
             let name = m[3].trimmingCharacters(in: .whitespaces)
             let thumb = m[2].trimmingCharacters(in: .whitespaces)
             let text = "Joined".localized()
+            let f_pin = m[1].trimmingCharacters(in: .whitespaces)
+            viewers.append(SeminarViewer(f_pin: f_pin, thumb: thumb, name: name))
             chats.append(SeminarChat(name: name, thumb: thumb, messageText: text, isInfo: true))
             DispatchQueue.main.async {
                 self.countViewer.text = "\(Int(self.countViewer.text!)! + 1)"
@@ -604,6 +681,13 @@ class SeminarChat: Model {
     let messageText: String
     let isInfo: Bool
     
+    init(viewer: SeminarViewer, messageText: String, isInfo: Bool = false) {
+        self.name = viewer.name
+        self.thumb = viewer.thumb
+        self.messageText = messageText
+        self.isInfo = isInfo
+    }
+    
     init(name: String, thumb: String, messageText: String, isInfo: Bool = false) {
         self.name = name
         self.thumb = thumb
@@ -620,3 +704,30 @@ class SeminarChat: Model {
     }
     
 }
+
+class SeminarViewer : Model {
+    
+    let f_pin: String
+    let thumb: String
+    let name: String
+    var isRaise: Bool
+    var isSpeak: Bool
+    
+    init(f_pin: String, thumb: String, name: String, isRaise: Bool = false, isSpeak: Bool = false){
+        self.f_pin = f_pin
+        self.thumb = thumb
+        self.name = name
+        self.isRaise = isRaise
+        self.isSpeak = isSpeak
+    }
+    
+    var description: String {
+        return ""
+    }
+    
+    static func == (lhs: SeminarViewer, rhs: SeminarViewer) -> Bool {
+        lhs.f_pin == rhs.f_pin
+    }
+    
+    
+}