UserListManagerView.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. //
  2. // UserListManagerView.swift
  3. // TUIRoomKit
  4. //
  5. // Created by janejntang on 2023/1/5.
  6. // Copyright © 2023 Tencent. All rights reserved.
  7. //
  8. import Foundation
  9. class UserListManagerView: UIView {
  10. var viewModel: UserListManagerViewModel
  11. private var isViewReady: Bool = false
  12. private var viewArray: [ButtonItemView] = []
  13. private var currentLandscape: Bool = isLandscape
  14. let contentView: UIView = {
  15. let view = UIView(frame: .zero)
  16. view.backgroundColor = UIColor(0x22262E)
  17. view.layer.cornerRadius = 12
  18. return view
  19. }()
  20. let dropArrowButton: UIButton = {
  21. let button = UIButton()
  22. button.setImage(UIImage(named: "room_drop_arrow", in: tuiRoomKitBundle(), compatibleWith: nil), for: .normal)
  23. button.contentEdgeInsets = UIEdgeInsets(top: 12.scale375Height(), left: 20.scale375(), bottom: 12.scale375Height(), right: 20.scale375())
  24. return button
  25. }()
  26. let rightArrowButton: UIButton = {
  27. let button = UIButton()
  28. button.setImage(UIImage(named: "room_right_arrow", in: tuiRoomKitBundle(), compatibleWith: nil), for: .normal)
  29. button.contentEdgeInsets = UIEdgeInsets(top: 20.scale375Height(), left: 12.scale375(), bottom: 20.scale375Height(), right: 12.scale375())
  30. return button
  31. }()
  32. let scrollView: UIScrollView = {
  33. let view = UIScrollView()
  34. return view
  35. }()
  36. let avatarImageView: UIImageView = {
  37. let img = UIImageView()
  38. img.layer.cornerRadius = 20
  39. img.layer.masksToBounds = true
  40. return img
  41. }()
  42. let userLabel: UILabel = {
  43. let label = UILabel()
  44. label.textColor = UIColor(0xD5E0F2)
  45. label.textAlignment = isRTL ? .right : .left
  46. label.font = UIFont(name: "PingFangSC-Regular", size: 16)
  47. label.numberOfLines = 1
  48. return label
  49. }()
  50. let headView: UIView = {
  51. let view = UIView()
  52. return view
  53. }()
  54. let stackView: UIStackView = {
  55. let view = UIStackView()
  56. view.axis = .vertical
  57. view.alignment = .center
  58. view.distribution = .equalSpacing
  59. view.spacing = 0
  60. return view
  61. }()
  62. let backBlockView: UIView = {
  63. let view = UIView()
  64. view.backgroundColor = UIColor(0x17181F)
  65. view.alpha = 0.9
  66. return view
  67. }()
  68. lazy var userNameInputView: UserNameInputView = {
  69. let view = UserNameInputView()
  70. view.viewResponder = self.viewModel
  71. return view
  72. }()
  73. init(viewModel: UserListManagerViewModel) {
  74. self.viewModel = viewModel
  75. super.init(frame: .zero)
  76. contentView.transform = CGAffineTransform(translationX: 0, y: kScreenHeight)
  77. alpha = 0
  78. }
  79. required init?(coder: NSCoder) {
  80. fatalError("init(coder:) has not been implemented")
  81. }
  82. override func didMoveToWindow() {
  83. super.didMoveToWindow()
  84. guard !isViewReady else { return }
  85. constructViewHierarchy()
  86. activateConstraints()
  87. bindInteraction()
  88. isViewReady = true
  89. }
  90. override func layoutSubviews() {
  91. super.layoutSubviews()
  92. guard currentLandscape != isLandscape else { return }
  93. setupViewOrientation(isLandscape: isLandscape)
  94. currentLandscape = isLandscape
  95. userNameInputView.hideInputView()
  96. }
  97. private func constructViewHierarchy() {
  98. addSubview(backBlockView)
  99. addSubview(contentView)
  100. contentView.addSubview(dropArrowButton)
  101. contentView.addSubview(rightArrowButton)
  102. contentView.addSubview(scrollView)
  103. scrollView.addSubview(headView)
  104. scrollView.addSubview(stackView)
  105. headView.addSubview(avatarImageView)
  106. headView.addSubview(userLabel)
  107. addSubview(userNameInputView)
  108. setupStackView()
  109. }
  110. private func activateConstraints() {
  111. setupViewOrientation(isLandscape: isLandscape)
  112. headView.snp.makeConstraints { make in
  113. make.top.leading.equalToSuperview()
  114. make.trailing.equalToSuperview().offset(-16.scale375())
  115. make.height.equalTo(40.scale375())
  116. }
  117. avatarImageView.snp.makeConstraints { make in
  118. make.centerY.equalToSuperview()
  119. make.leading.equalToSuperview()
  120. make.width.height.equalTo(40.scale375())
  121. }
  122. userLabel.snp.makeConstraints { make in
  123. make.centerY.equalToSuperview()
  124. make.leading.equalTo(avatarImageView.snp.trailing).offset(10.scale375())
  125. make.trailing.equalToSuperview()
  126. make.height.equalTo(22.scale375())
  127. }
  128. stackView.snp.makeConstraints { make in
  129. make.top.equalTo(headView.snp.bottom).offset(20.scale375())
  130. make.leading.trailing.equalToSuperview()
  131. make.bottom.equalToSuperview()
  132. make.width.equalToSuperview()
  133. }
  134. userNameInputView.snp.makeConstraints { make in
  135. make.edges.equalToSuperview()
  136. }
  137. }
  138. private func setupViewOrientation(isLandscape: Bool) {
  139. backBlockView.snp.remakeConstraints { make in
  140. make.edges.equalToSuperview()
  141. }
  142. contentView.snp.remakeConstraints { make in
  143. if isLandscape {
  144. make.height.equalToSuperview()
  145. } else {
  146. make.height.equalTo(500.scale375())
  147. }
  148. make.bottom.leading.trailing.equalToSuperview()
  149. }
  150. dropArrowButton.snp.remakeConstraints { make in
  151. make.height.equalTo(isLandscape ? 0 : 43.scale375())
  152. make.top.centerX.equalToSuperview()
  153. }
  154. rightArrowButton.snp.remakeConstraints { make in
  155. make.width.equalTo(isLandscape ? 27.scale375() : 0)
  156. make.leading.centerY.equalToSuperview()
  157. }
  158. scrollView.snp.remakeConstraints { make in
  159. make.top.equalTo(dropArrowButton.snp.bottom).offset(10.scale375())
  160. if isLandscape {
  161. make.leading.equalTo(rightArrowButton.snp.trailing).offset(5.scale375())
  162. } else {
  163. make.leading.equalToSuperview().offset(16.scale375())
  164. }
  165. make.bottom.equalToSuperview()
  166. make.trailing.equalToSuperview().offset(-16.scale375())
  167. }
  168. }
  169. func bindInteraction() {
  170. viewModel.viewResponder = self
  171. setupViewState()
  172. let tap = UITapGestureRecognizer(target: self, action: #selector(dismiss))
  173. backBlockView.addGestureRecognizer(tap)
  174. dropArrowButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
  175. rightArrowButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
  176. }
  177. private func setupStackView() {
  178. for item in viewModel.userListManagerItems {
  179. let view = ButtonItemView(itemData: item)
  180. viewArray.append(view)
  181. stackView.addArrangedSubview(view)
  182. view.snp.makeConstraints { make in
  183. make.height.equalTo(53.scale375())
  184. make.width.equalToSuperview()
  185. }
  186. }
  187. }
  188. private func setupViewState() {
  189. let placeholder = UIImage(named: "room_default_user", in: tuiRoomKitBundle(), compatibleWith: nil)
  190. guard let attendeeModel = viewModel.attendeeList.first(where: { $0.userId == viewModel.selectUserId }) else { return }
  191. if let url = URL(string: attendeeModel.avatarUrl) {
  192. avatarImageView.sd_setImage(with: url, placeholderImage: placeholder)
  193. } else {
  194. avatarImageView.image = placeholder
  195. }
  196. if attendeeModel.userId == viewModel.currentUser.userId {
  197. userLabel.text = attendeeModel.userName + "(" + .meText + ")"
  198. } else {
  199. userLabel.text = attendeeModel.userName
  200. }
  201. }
  202. func updateStackView(items:[ButtonItemData]) {
  203. for view in viewArray {
  204. view.removeFromSuperview()
  205. }
  206. viewArray.removeAll()
  207. for item in items {
  208. let view = ButtonItemView(itemData: item)
  209. viewArray.append(view)
  210. stackView.addArrangedSubview(view)
  211. view.snp.makeConstraints { make in
  212. make.height.equalTo(53.scale375())
  213. make.width.equalToSuperview()
  214. }
  215. }
  216. }
  217. func show(rootView: UIView) {
  218. rootView.addSubview(self)
  219. self.snp.makeConstraints { make in
  220. make.edges.equalToSuperview()
  221. }
  222. setupViewOrientation(isLandscape: isLandscape)
  223. UIView.animate(withDuration: 0.3) { [weak self] in
  224. guard let self = self else { return }
  225. self.alpha = 1
  226. self.contentView.transform = .identity
  227. }
  228. }
  229. @objc func dismiss() {
  230. UIView.animate(withDuration: 0.3) { [weak self] in
  231. guard let self = self else { return }
  232. self.alpha = 0
  233. self.contentView.transform = CGAffineTransform(translationX: 0, y: kScreenHeight)
  234. } completion: { [weak self] _ in
  235. guard let self = self else { return }
  236. self.removeFromSuperview()
  237. }
  238. }
  239. @objc func backBlockAction(sender: RoomInfoView) {
  240. viewModel.backBlockAction(sender: self)
  241. }
  242. deinit {
  243. debugPrint("deinit \(self)")
  244. }
  245. }
  246. extension UserListManagerView: UserListManagerViewEventResponder {
  247. func showUserNameInputView(userName: String?) {
  248. userNameInputView.showInputView(userName: userName)
  249. }
  250. func showAlert(title: String?, message: String?, sureTitle: String?, declineTitle: String?, sureBlock: (() -> ())?, declineBlock: (() -> ())?) {
  251. RoomRouter.presentAlert(title: title, message: message, sureTitle: sureTitle, declineTitle: declineTitle, sureBlock: sureBlock, declineBlock: declineBlock)
  252. }
  253. func updateUI(item: ButtonItemData) {
  254. guard let view = viewArray.first(where: { $0.itemData.buttonType == item.buttonType }) else { return }
  255. view.setupViewState(item: item)
  256. }
  257. func addStackView(item: ButtonItemData, index: Int?) {
  258. let view = ButtonItemView(itemData: item)
  259. if let index = index, viewArray.count > index + 1 {
  260. viewArray.insert(view, at: index)
  261. stackView.insertArrangedSubview(view, at: index)
  262. } else {
  263. viewArray.append(view)
  264. stackView.addArrangedSubview(view)
  265. }
  266. view.snp.makeConstraints { make in
  267. make.height.equalTo(53.scale375())
  268. make.width.equalToSuperview()
  269. }
  270. }
  271. func removeStackView(itemType: ButtonItemData.ButtonType) {
  272. let views = viewArray.filter({ view in
  273. view.itemData.buttonType == itemType
  274. })
  275. views.forEach { view in
  276. view.removeFromSuperview()
  277. }
  278. viewArray.removeAll(where: { $0.itemData.buttonType == itemType })
  279. }
  280. func dismissView() {
  281. dismiss()
  282. }
  283. func makeToast(text : String) {
  284. RoomRouter.makeToastInCenter(toast: text, duration: 0.5)
  285. }
  286. func setUserListManagerViewHidden(isHidden: Bool) {
  287. self.isHidden = true
  288. }
  289. }
  290. private extension String {
  291. static var meText: String {
  292. localized("Me")
  293. }
  294. }