|
@@ -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
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|