BottomView.swift 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. //
  2. // BottomView.swift
  3. // TUIRoomKit
  4. //
  5. // Created by aby on 2022/12/21.
  6. // Copyright © 2022 Tencent. All rights reserved.
  7. //
  8. import UIKit
  9. class BottomView: UIView {
  10. // MARK: - store property
  11. let viewModel: BottomViewModel
  12. private var viewArray: [BottomItemView] = []
  13. var isUnfold: Bool = false
  14. let unfoldHeight = Float(130.scale375Height())
  15. let packUpHeight = Float(68.scale375Height())
  16. let baseButtonMenuView: UIStackView = {
  17. let view = UIStackView()
  18. view.axis = .horizontal
  19. view.alignment = .center
  20. view.distribution = .equalSpacing
  21. view.spacing = 10
  22. return view
  23. }()
  24. let moreButtonMenuView: UIStackView = {
  25. let view = UIStackView()
  26. view.axis = .horizontal
  27. view.alignment = .center
  28. view.distribution = .equalSpacing
  29. view.spacing = 10
  30. return view
  31. }()
  32. let buttonMenuView: UIView = {
  33. let view = UIView()
  34. view.backgroundColor = UIColor(0x0F1014)
  35. view.layer.cornerRadius = 12
  36. return view
  37. }()
  38. let backgroundView: UIView = {
  39. let view = UIView()
  40. view.backgroundColor = UIColor(0x0F1014)
  41. return view
  42. }()
  43. // MARK: - initialized function
  44. init(viewModel: BottomViewModel) {
  45. self.viewModel = viewModel
  46. super.init(frame: .zero)
  47. backgroundColor = .clear
  48. }
  49. required init?(coder: NSCoder) {
  50. fatalError("init(coder:) has not been implemented")
  51. }
  52. // MARK: - view layout
  53. private var isViewReady: Bool = false
  54. override func didMoveToWindow() {
  55. super.didMoveToWindow()
  56. guard !isViewReady else { return }
  57. constructViewHierarchy()
  58. activateConstraints()
  59. bindInteraction()
  60. isViewReady = true
  61. }
  62. func constructViewHierarchy() {
  63. addSubview(backgroundView)
  64. addSubview(buttonMenuView)
  65. buttonMenuView.addSubview(moreButtonMenuView)
  66. buttonMenuView.addSubview(baseButtonMenuView)
  67. moreButtonMenuView.isHidden = true
  68. setupMenuStackView(items: viewModel.viewItems)
  69. layoutMoreButtonMenu()
  70. }
  71. func setupMenuStackView(items: [ButtonItemData]) {
  72. for i in 0...(items.count - 1) {
  73. guard let item = viewModel.viewItems[safe: i] else { continue }
  74. let view = BottomItemView(itemData: item)
  75. let size = item.size ?? CGSize(width: 52.scale375(), height: 52.scale375())
  76. view.snp.makeConstraints { make in
  77. make.height.equalTo(size.height)
  78. make.width.equalTo(size.width)
  79. }
  80. view.backgroundColor = item.backgroundColor ?? UIColor(0x2A2D38)
  81. viewArray.append(view)
  82. if i < 6 {
  83. baseButtonMenuView.addArrangedSubview(view)
  84. } else {
  85. moreButtonMenuView.addArrangedSubview(view)
  86. }
  87. }
  88. }
  89. func layoutMoreButtonMenu() {
  90. let emptyViewCount = baseButtonMenuView.subviews.count - moreButtonMenuView.subviews.count
  91. if emptyViewCount <= 0 {return}
  92. for _ in 1...emptyViewCount {
  93. let emptyView = BottomItemView(itemData: ButtonItemData())
  94. emptyView.snp.makeConstraints { make in
  95. make.height.equalTo(52.scale375())
  96. make.width.equalTo(52.scale375())
  97. moreButtonMenuView.addArrangedSubview(emptyView)
  98. }
  99. viewArray.append(emptyView)
  100. }
  101. }
  102. func activateConstraints() {
  103. backgroundView.snp.makeConstraints { make in
  104. make.bottom.leading.trailing.equalToSuperview()
  105. make.height.equalTo(packUpHeight)
  106. }
  107. let width = min(kScreenWidth, kScreenHeight)
  108. buttonMenuView.snp.makeConstraints { make in
  109. make.width.equalTo(width)
  110. make.bottom.centerX.height.equalToSuperview()
  111. }
  112. baseButtonMenuView.snp.makeConstraints { make in
  113. make.top.equalToSuperview().offset(8.scale375())
  114. make.height.equalTo(52.scale375())
  115. make.leading.equalToSuperview().offset(16.scale375())
  116. make.trailing.equalToSuperview().offset(-16.scale375())
  117. }
  118. moreButtonMenuView.snp.makeConstraints { make in
  119. make.bottom.equalToSuperview()
  120. make.height.equalTo(52.scale375())
  121. make.leading.trailing.equalTo(baseButtonMenuView)
  122. }
  123. }
  124. func bindInteraction() {
  125. viewModel.viewResponder = self
  126. }
  127. deinit {
  128. debugPrint("deinit \(self)")
  129. }
  130. }
  131. extension BottomView: BottomViewModelResponder {
  132. func updateButtonView(item: ButtonItemData) {
  133. guard let view = viewArray.first(where: { $0.itemData.buttonType == item.buttonType }) else { return }
  134. view.setupViewState(item: item)
  135. }
  136. func showAlert(title: String?, message: String?, sureTitle: String?, declineTitle: String?, sureBlock: (() -> ())?, declineBlock: (() -> ())?) {
  137. RoomRouter.presentAlert(title: title, message: message, sureTitle: sureTitle, declineTitle: declineTitle, sureBlock: sureBlock, declineBlock: declineBlock)
  138. }
  139. func updateStackView(items: [ButtonItemData]) {
  140. viewArray.forEach { view in
  141. view.removeFromSuperview()
  142. }
  143. viewArray = []
  144. setupMenuStackView(items: items)
  145. layoutMoreButtonMenu()
  146. }
  147. func makeToast(text: String) {
  148. RoomRouter.makeToastInCenter(toast: text, duration: 1)
  149. }
  150. private func updateBottomViewConstraints(isUnfold: Bool, completion: @escaping () -> Void) {
  151. UIView.animate(withDuration: 0.3) { [weak self] () in
  152. guard let self = self else { return }
  153. self.snp.updateConstraints { make in
  154. make.height.equalTo(isUnfold ? self.unfoldHeight : self.packUpHeight)
  155. }
  156. self.superview?.layoutIfNeeded()
  157. } completion: { _ in
  158. completion()
  159. }
  160. }
  161. func updataBottomView(isUp: Bool) {
  162. buttonMenuView.backgroundColor = isUp ? UIColor(0x2A2D38) : UIColor(0x0F1014)
  163. self.isUnfold = isUp
  164. if isUp {
  165. updateBottomViewConstraints(isUnfold: true) { [weak self] in
  166. guard let self = self else { return }
  167. self.moreButtonMenuView.isHidden = false
  168. }
  169. } else {
  170. moreButtonMenuView.isHidden = true
  171. updateBottomViewConstraints(isUnfold: false) {}
  172. }
  173. }
  174. }
  175. private extension String {
  176. static var leaveRoomTitle: String {
  177. localized("Are you sure you want to leave the conference?")
  178. }
  179. static var destroyRoomTitle: String {
  180. localized("Are you sure you want to end the conference?")
  181. }
  182. static var destroyRoomCancelTitle: String {
  183. localized("Wait")
  184. }
  185. static var logoutOkText: String {
  186. localized("OK")
  187. }
  188. static var dismissMeetingTitle: String {
  189. localized("If you don't want to end the conference")
  190. }
  191. static var appointNewHostText: String {
  192. localized("Please appoint a new host before leaving the conference")
  193. }
  194. static var leaveMeetingText: String {
  195. localized("Leave conference")
  196. }
  197. static var dismissMeetingText: String {
  198. localized("End conference")
  199. }
  200. static var cancelText: String {
  201. localized("Cancel")
  202. }
  203. static var toastTitleText: String {
  204. localized("Share Screen")
  205. }
  206. static var toastMessageText: String {
  207. localized("Stop TUIRoom screen sharing screen live?")
  208. }
  209. static var toastStopText: String {
  210. localized("Stop")
  211. }
  212. }