Files
midi_ios/TUIKit/TUIRoomKit/Source/View/Page/Widget/TransferOwnerControlPanel/TransferMasterView.swift
2025-08-14 10:07:49 +08:00

357 lines
12 KiB
Swift

//
// TransferMasterView.swift
// TUIRoomKit
//
// Created by janejntang on 2023/2/20.
//
import Foundation
class TransferMasterView: UIView {
let viewModel: TransferMasterViewModel
var attendeeList: [UserEntity]
var searchArray: [UserEntity] = []
private var isSearching: Bool = false
let topLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor(0xD5E0F2)
label.font = UIFont(name: "PingFangSC-Regular", size: 16)
label.text = .transferMasterText
return label
}()
let searchBar: UISearchBar = {
let searchBar = UISearchBar()
searchBar.placeholder = .searchMemberText
searchBar.setBackgroundImage(UIColor(0x1B1E26).trans2Image(), for: .top, barMetrics: .default)
if #available(iOS 13, *) {
searchBar.searchTextField.textColor = UIColor(0xB2BBD1)
searchBar.searchTextField.tintColor = UIColor(0xB2BBD1).withAlphaComponent(0.3)
searchBar.searchTextField.layer.cornerRadius = 6
searchBar.searchTextField.font = UIFont.systemFont(ofSize: 14, weight: .medium)
} else {
if let textField = searchBar.value(forKey: "searchField") as? UITextField {
textField.textColor = UIColor(0xB2BBD1)
textField.tintColor = UIColor(0xB2BBD1).withAlphaComponent(0.3)
textField.layer.cornerRadius = 6
textField.font = UIFont.systemFont(ofSize: 14, weight: .medium)
}
}
return searchBar
}()
let searchControl: UIControl = {
let view = UIControl()
view.backgroundColor = .clear
view.isHidden = true
return view
}()
let appointMasterButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14)
button.setTitle(.appointAndLeaveRoomText, for: .normal)
button.setTitleColor(UIColor(0xFFFFFF), for: .normal)
button.setBackgroundImage(UIColor(0x006EFF).withAlphaComponent(0.2).trans2Image(), for: .disabled)
button.setBackgroundImage(UIColor(0x006EFF).trans2Image(), for: .normal)
button.layer.cornerRadius = 12
button.clipsToBounds = true
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.adjustsImageWhenHighlighted = false
return button
}()
lazy var transferMasterTableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.separatorStyle = .none
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = UIColor(0x1B1E26)
tableView.register(TransferMasterTableCell.self, forCellReuseIdentifier: "RaiseHandCell")
return tableView
}()
init(viewModel: TransferMasterViewModel) {
self.viewModel = viewModel
self.attendeeList = viewModel.attendeeList
super.init(frame: .zero)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private var isViewReady: Bool = false
override func didMoveToWindow() {
super.didMoveToWindow()
backgroundColor = UIColor(0x1B1E26)
guard !isViewReady else { return }
constructViewHierarchy()
activateConstraints()
bindInteraction()
isViewReady = true
}
func constructViewHierarchy() {
addSubview(topLabel)
addSubview(searchBar)
addSubview(transferMasterTableView)
addSubview(appointMasterButton)
addSubview(searchControl)
}
func activateConstraints() {
topLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(10.scale375Height())
make.leading.equalToSuperview().offset(16.scale375())
make.trailing.equalToSuperview().offset(-16.scale375())
make.height.equalTo(24.scale375Height())
}
searchBar.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(16.scale375())
make.trailing.equalToSuperview().offset(-16.scale375())
make.height.equalTo(34.scale375Height())
make.top.equalTo(topLabel.snp.bottom).offset(23.scale375Height())
}
transferMasterTableView.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(16.scale375())
make.trailing.equalToSuperview().offset(-16.scale375())
make.top.equalTo(searchBar.snp.bottom).offset(10.scale375Height())
make.bottom.equalToSuperview()
}
appointMasterButton.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-20)
make.bottom.equalToSuperview().offset(-40 - kDeviceSafeBottomHeight)
make.height.equalTo(50)
make.leading.equalToSuperview().offset(20)
}
searchControl.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
func bindInteraction() {
searchBar.delegate = self
viewModel.viewResponder = self
appointMasterButton.addTarget(self, action: #selector(appointMasterAction(sender:)), for: .touchUpInside)
let tap = UITapGestureRecognizer(target: self, action: #selector(hideSearchControl(sender:)))
searchControl.addGestureRecognizer(tap)
appointMasterButton.isEnabled = viewModel.userId.count > 0
}
@objc func appointMasterAction(sender: UIButton) {
viewModel.appointMasterAction(sender: sender)
}
@objc func hideSearchControl(sender: UIView) {
if #available(iOS 13, *) {
searchBar.searchTextField.resignFirstResponder()
} else {
searchBar.resignFirstResponder()
}
searchControl.isHidden = true
}
deinit {
debugPrint("deinit \(self)")
}
}
extension TransferMasterView: UISearchBarDelegate {
func searchBar(_ searchBar:UISearchBar,textDidChange searchText:String){
let searchContentText = searchText.trimmingCharacters(in: .whitespaces)
if searchContentText.count == 0 {
attendeeList = viewModel.attendeeList
transferMasterTableView.reloadData()
isSearching = false
} else {
searchArray = viewModel.attendeeList.filter({ model -> Bool in
return model.userName.contains(searchContentText)
})
attendeeList = searchArray
transferMasterTableView.reloadData()
isSearching = true
}
}
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
searchControl.isHidden = false
return true
}
}
extension TransferMasterView: UITableViewDataSource {
internal func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return attendeeList.count
}
}
extension TransferMasterView: UITableViewDelegate {
internal func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let attendeeModel = attendeeList[indexPath.row]
let cell = TransferMasterTableCell(attendeeModel: attendeeModel, viewModel: viewModel)
cell.selectionStyle = .none
return cell
}
internal func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
searchBar.endEditing(true)
if #available(iOS 13, *) {
searchBar.searchTextField.resignFirstResponder()
} else {
searchBar.resignFirstResponder()
}
viewModel.userId = attendeeList[indexPath.row].userId
appointMasterButton.isEnabled = true
transferMasterTableView.reloadData()
}
internal func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60.scale375Height()
}
}
extension TransferMasterView: TransferMasterViewResponder {
func makeToast(message: String) {
makeToast(message)
}
func reloadTransferMasterTableView() {
guard !isSearching else { return }
attendeeList = viewModel.attendeeList
transferMasterTableView.reloadData()
}
func searchControllerChangeActive(isActive: Bool) {
searchBar.endEditing(!isActive)
if #available(iOS 13, *) {
searchBar.searchTextField.resignFirstResponder()
} else {
searchBar.resignFirstResponder()
}
}
}
class TransferMasterTableCell: UITableViewCell {
let attendeeModel: UserEntity
let viewModel: TransferMasterViewModel
let avatarImageView: UIImageView = {
let img = UIImageView()
img.layer.cornerRadius = 20
img.layer.masksToBounds = true
return img
}()
let userLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor(0xD5E0F2)
label.backgroundColor = UIColor.clear
label.textAlignment = isRTL ? .right : .left
label.textAlignment = .left
label.font = UIFont(name: "PingFangSC-Regular", size: 16)
label.numberOfLines = 1
return label
}()
let checkMarkButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "room_check_mark", in: tuiRoomKitBundle(), compatibleWith: nil), for: .normal)
button.isHidden = true
return button
}()
let downLineView : UIView = {
let view = UIView()
view.backgroundColor = UIColor(0x2A2D38)
return view
}()
init(attendeeModel: UserEntity ,viewModel: TransferMasterViewModel) {
self.attendeeModel = attendeeModel
self.viewModel = viewModel
super.init(style: .default, reuseIdentifier: "TransferMasterTableCell")
}
private var isViewReady: Bool = false
override func didMoveToWindow() {
super.didMoveToWindow()
guard !isViewReady else { return }
constructViewHierarchy()
activateConstraints()
bindInteraction()
isViewReady = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func constructViewHierarchy() {
contentView.addSubview(avatarImageView)
contentView.addSubview(userLabel)
contentView.addSubview(checkMarkButton)
contentView.addSubview(downLineView)
}
func activateConstraints() {
avatarImageView.snp.makeConstraints { make in
make.width.height.equalTo(40.scale375Height())
make.leading.equalToSuperview()
make.centerY.equalToSuperview()
}
checkMarkButton.snp.makeConstraints { make in
make.width.height.equalTo(22.scale375())
make.trailing.equalToSuperview()
make.centerY.equalTo(self.avatarImageView)
}
userLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.leading.equalTo(avatarImageView.snp.trailing).offset(10.scale375())
make.width.equalTo(150.scale375())
make.height.equalTo(22.scale375Height())
}
downLineView.snp.makeConstraints { make in
make.leading.equalTo(userLabel)
make.trailing.equalToSuperview()
make.bottom.equalToSuperview()
make.height.equalTo(1.scale375Height())
}
}
func bindInteraction() {
backgroundColor = UIColor(0x1B1E26)
setupViewState(item: attendeeModel)
}
func setupViewState(item: UserEntity) {
let placeholder = UIImage(named: "room_default_user", in: tuiRoomKitBundle(), compatibleWith: nil)
if let url = URL(string: item.avatarUrl) {
avatarImageView.sd_setImage(with: url, placeholderImage: placeholder)
} else {
avatarImageView.image = placeholder
}
userLabel.text = item.userName
if viewModel.userId == attendeeModel.userId {
checkMarkButton.isHidden = false
}
}
deinit {
debugPrint("deinit \(self)")
}
}
private extension String {
static var transferMasterText: String {
localized("Appoint a new master")
}
static var searchMemberText: String {
localized("Search for participants")
}
static var appointAndLeaveRoomText: String {
localized("Appoint and leave")
}
}