RoomVideoFloatView.swift 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. //
  2. // RoomVideoFloatView.swift
  3. // TUIRoomKit
  4. //
  5. // Created by janejntang on 2023/7/11.
  6. //
  7. import Foundation
  8. import Factory
  9. class RoomVideoFloatView: UIView {
  10. @Injected(\.floatChatService) private var store: FloatChatStoreProvider
  11. @Injected(\.conferenceStore) private var conferenceStore: ConferenceStore
  12. private var isDraging: Bool = false
  13. private let viewModel: RoomVideoFloatViewModel
  14. private let space: CGFloat = 10
  15. private let renderView: UIView = {
  16. let view = UIView()
  17. view.backgroundColor = UIColor(0x5C5C5C)
  18. return view
  19. }()
  20. private let shutterView: UIView = {
  21. let view = UIView()
  22. view.backgroundColor = UIColor(0x17181F)
  23. view.isHidden = true
  24. return view
  25. }()
  26. private let avatarImageView: UIImageView = {
  27. let imageView = UIImageView(frame: .zero)
  28. imageView.layer.masksToBounds = true
  29. imageView.isHidden = true
  30. return imageView
  31. }()
  32. private let userStatusView: RoomUserStatusView = {
  33. let view = RoomUserStatusView(frame: .zero)
  34. return view
  35. }()
  36. override init(frame: CGRect) {
  37. viewModel = RoomVideoFloatViewModel()
  38. super.init(frame: frame)
  39. }
  40. required init?(coder: NSCoder) {
  41. fatalError("init(coder:) has not been implemented")
  42. }
  43. deinit {
  44. debugPrint("deinit:\(self)")
  45. }
  46. // MARK: - view layout
  47. private var isViewReady: Bool = false
  48. override func didMoveToWindow() {
  49. super.didMoveToWindow()
  50. guard !isViewReady else { return }
  51. backgroundColor = .clear
  52. constructViewHierarchy()
  53. activateConstraints()
  54. bindInteraction()
  55. reportViewShow()
  56. isViewReady = true
  57. }
  58. override func draw(_ rect: CGRect) {
  59. super.draw(rect)
  60. roundedRect(rect: bounds,
  61. byRoundingCorners: .allCorners,
  62. cornerRadii: CGSize(width: 10, height: 10))
  63. avatarImageView.roundedCircle(rect: avatarImageView.bounds)
  64. }
  65. override func layoutSubviews() {
  66. super.layoutSubviews()
  67. if !isDraging {
  68. self.center = adsorption(centerPoint: self.center)
  69. }
  70. }
  71. func constructViewHierarchy() {
  72. addSubview(renderView)
  73. addSubview(shutterView)
  74. addSubview(avatarImageView)
  75. addSubview(userStatusView)
  76. }
  77. func activateConstraints() {
  78. renderView.snp.makeConstraints { make in
  79. make.edges.equalToSuperview()
  80. }
  81. shutterView.snp.makeConstraints { make in
  82. make.edges.equalToSuperview()
  83. }
  84. avatarImageView.snp.makeConstraints { make in
  85. make.center.equalToSuperview()
  86. make.height.width.equalTo(50)
  87. }
  88. userStatusView.snp.makeConstraints { make in
  89. make.leading.equalToSuperview().offset(5)
  90. make.bottom.equalToSuperview().offset(-5)
  91. make.width.lessThanOrEqualTo(self).multipliedBy(0.9)
  92. }
  93. }
  94. func bindInteraction() {
  95. let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didPan(panGesture:)))
  96. addGestureRecognizer(panGesture)
  97. let tap = UITapGestureRecognizer(target: self, action: #selector(didTap(sender:)))
  98. addGestureRecognizer(tap)
  99. viewModel.viewResponder = self
  100. viewModel.showFloatWindowViewVideo()
  101. }
  102. private func reportViewShow() {
  103. viewModel.reportFloatWindowShow()
  104. }
  105. @objc func didTap(sender: UIView) {
  106. viewModel.showRoomMainView()
  107. }
  108. @objc func didPan(panGesture: UIPanGestureRecognizer) {
  109. guard let viewSuperview = superview else { return }
  110. let moveState = panGesture.state
  111. let viewCenter = center
  112. switch moveState {
  113. case .changed:
  114. isDraging = true
  115. let point = panGesture.translation(in: viewSuperview)
  116. center = CGPoint(x: viewCenter.x + point.x, y: viewCenter.y + point.y)
  117. break
  118. case .ended:
  119. let point = panGesture.translation(in: viewSuperview)
  120. let newPoint = CGPoint(x: viewCenter.x + point.x, y: viewCenter.y + point.y)
  121. UIView.animate(withDuration: 0.2) {
  122. self.center = self.adsorption(centerPoint: newPoint)
  123. }
  124. isDraging = false
  125. break
  126. default: break
  127. }
  128. panGesture.setTranslation(.zero, in: viewSuperview)
  129. }
  130. class func show(width: CGFloat = 100, height: CGFloat = 180) {
  131. DispatchQueue.main.async {
  132. guard let currentWindow = RoomRouter.getCurrentWindow() else { return }
  133. let roomFloatView = RoomVideoFloatView()
  134. currentWindow.addSubview(roomFloatView)
  135. roomFloatView.snp.makeConstraints { make in
  136. make.trailing.equalToSuperview().offset(-5)
  137. make.bottom.equalToSuperview().offset(-100)
  138. make.width.equalTo(width)
  139. make.height.equalTo(height)
  140. }
  141. }
  142. }
  143. class func dismiss() {
  144. DispatchQueue.main.async {
  145. guard let currentWindow = RoomRouter.getCurrentWindow() else { return }
  146. let videoFloatViewArray = currentWindow.subviews.filter({ $0 is RoomVideoFloatView })
  147. for view in videoFloatViewArray {
  148. view.removeFromSuperview()
  149. }
  150. }
  151. }
  152. private func adsorption(centerPoint: CGPoint) -> CGPoint {
  153. guard let viewSuperview = superview else { return centerPoint }
  154. let limitMargin = 5.0
  155. let frame = self.frame
  156. let point = CGPoint(x: centerPoint.x - frame.width / 2, y: centerPoint.y - frame.height / 2)
  157. var newPoint = point
  158. if centerPoint.x < (viewSuperview.frame.width / 2) {
  159. newPoint.x = limitMargin
  160. } else {
  161. newPoint.x = viewSuperview.frame.width - frame.width - limitMargin
  162. }
  163. if point.y <= limitMargin {
  164. newPoint.y = limitMargin
  165. } else if (point.y + frame.height) > (viewSuperview.frame.height - limitMargin) {
  166. newPoint.y = viewSuperview.frame.height - frame.height - limitMargin
  167. }
  168. return CGPoint(x: newPoint.x + frame.width / 2, y: newPoint.y + frame.height / 2)
  169. }
  170. }
  171. extension RoomVideoFloatView: RoomVideoFloatViewResponder {
  172. func getRenderView() -> UIView {
  173. return renderView
  174. }
  175. func makeToast(text: String) {
  176. RoomRouter.makeToastInCenter(toast: text, duration: 0.5)
  177. }
  178. func updateUserStatus(user: UserEntity) {
  179. let placeholder = UIImage(named: "room_default_user", in: tuiRoomKitBundle(), compatibleWith: nil)
  180. avatarImageView.sd_setImage(with: URL(string: user.avatarUrl), placeholderImage: placeholder)
  181. userStatusView.updateUserStatus(userModel: user)
  182. }
  183. func updateUserVolume(volume: Int) {
  184. userStatusView.updateUserVolume(volume: volume)
  185. }
  186. func updateUserAudio(hasAudio: Bool) {
  187. userStatusView.updateUserAudio(hasAudio)
  188. }
  189. func showAvatarImageView(isShow: Bool) {
  190. shutterView.isHidden = !isShow
  191. avatarImageView.isHidden = !isShow
  192. }
  193. }