Files
featherVoice/TUIKit/TUIRoomKit/Source/View/ConferenceOptions/MemberSelect/Example/SelectedMembersViewController.swift

323 lines
10 KiB
Swift
Raw Normal View History

2025-08-08 10:49:36 +08:00
//
// SelectedMembersViewController.swift
// TUIRoomKit
//
// Created by CY zhao on 2024/6/24.
//
import Foundation
import RTCRoomEngine
protocol SelectedMemberCellProtocol: AnyObject {
func didDeleteButtonClicked(in memberCell: SelectedMemberCell)
}
class SelectedMembersViewController: UIViewController {
private(set) var showDeleteButton: Bool = true
var selectedMember: [UserInfo] = []
var didDeselectMember: ((UserInfo) -> Void)?
private let arrowViewHeight: CGFloat = 35.0
init(showDeleteButton: Bool = true, selectedMembers: [UserInfo] = []) {
self.showDeleteButton = showDeleteButton
self.selectedMember = selectedMembers
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .custom
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.backgroundColor = .clear
tableView.register(SelectedMemberCell.self, forCellReuseIdentifier: SelectedMemberCell.reuseIdentifier)
if #available(iOS 15.0, *) {
tableView.sectionHeaderTopPadding = 0
}
return tableView
}()
private let dropArrowView : UIView = {
let view = UIView()
view.backgroundColor = .white
return view
}()
private let dropArrowImageView: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "room_drop_arrow", in:tuiRoomKitBundle(), compatibleWith: nil)
return view
}()
let contentView: UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = .white
view.layer.cornerRadius = 8
view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
view.clipsToBounds = true
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.tui_color(withHex: "0F1014", alpha: 0.6)
constructViewHierarchy()
activateConstraints()
bindInteraction()
}
private func constructViewHierarchy() {
view.addSubview(contentView)
dropArrowView.addSubview(dropArrowImageView)
contentView.addSubview(dropArrowView)
contentView.addSubview(tableView)
}
private func activateConstraints() {
contentView.snp.makeConstraints { make in
make.height.equalTo(610)
make.leading.bottom.trailing.equalToSuperview()
}
dropArrowView.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
make.height.equalTo(arrowViewHeight)
}
dropArrowImageView.snp.makeConstraints { make in
make.centerX.centerY.equalToSuperview()
make.width.equalTo(24.scale375())
make.height.equalTo(3.scale375())
}
tableView.snp.makeConstraints { make in
make.top.equalTo(dropArrowView.snp.bottom)
make.leading.bottom.trailing.equalToSuperview()
}
}
private func bindInteraction() {
tableView.delegate = self
tableView.dataSource = self
let dropArrowTap = UITapGestureRecognizer(target: self, action: #selector(dropDownPopUpViewAction(sender:)))
dropArrowView.addGestureRecognizer(dropArrowTap)
dropArrowView.isUserInteractionEnabled = true
}
@objc func dropDownPopUpViewAction(sender: UIView) {
self.dismiss(animated: true)
}
}
extension SelectedMembersViewController: SelectedMemberCellProtocol{
func didDeleteButtonClicked(in memberCell: SelectedMemberCell) {
guard let indexPath = self.tableView.indexPath(for: memberCell) else {
return
}
let member = selectedMember[indexPath.row]
self.didDeselectMember?(member)
selectedMember.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .none)
guard let headerView = tableView.headerView(forSection: 0) as? SelectedMemberHeaderView else {
return
}
headerView.updateLabel(with: selectedMember.count)
}
}
extension SelectedMembersViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 52
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = SelectedMemberHeaderView(reuseIdentifier: "CustomHeaderView")
headerView.updateLabel(with: selectedMember.count)
return headerView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 38
}
}
extension SelectedMembersViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return selectedMember.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: SelectedMemberCell.reuseIdentifier, for: indexPath)
as? SelectedMemberCell else {
return UITableViewCell()
}
let member = selectedMember[indexPath.row]
cell.updateView(with: member)
cell.delegate = self
if showDeleteButton {
cell.showDeleteButton()
} else {
cell.hideDeleteButton()
}
return cell
}
}
class SelectedMemberCell: UITableViewCell {
static let reuseIdentifier = "SelectedMemberCell"
weak var delegate: SelectedMemberCellProtocol?
private let avatarImageView: UIImageView = {
let imgView = UIImageView()
imgView.layer.cornerRadius = 2
imgView.layer.masksToBounds = true
return imgView
}()
private let nameLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor.tui_color(withHex: "22262E")
label.textAlignment = isRTL ? .right : .left
label.font = UIFont(name: "PingFangSC-Regular", size: 14)
label.numberOfLines = 1
return label
}()
let deleteButton: UIButton = {
let button = LargerHitAreaButton()
let image = UIImage(named: "room_delete", in: tuiRoomKitBundle(), compatibleWith: nil)
button.setImage(image, for: .normal)
return button
}()
private var isViewReady = false
override func didMoveToWindow() {
super.didMoveToWindow()
guard !isViewReady else {
return
}
isViewReady = true
selectionStyle = .none
constructViewHierarchy()
activateConstraints()
bindInteraction()
contentView.backgroundColor = .clear
}
private func constructViewHierarchy() {
contentView.addSubview(avatarImageView)
contentView.addSubview(nameLabel)
contentView.addSubview(deleteButton)
}
private func activateConstraints() {
avatarImageView.snp.makeConstraints { make in
make.width.height.equalTo(32)
make.leading.equalToSuperview().offset(20)
make.centerY.equalToSuperview()
}
nameLabel.snp.makeConstraints { make in
make.leading.equalTo(self.avatarImageView.snp.trailing).offset(5)
make.centerY.equalToSuperview()
}
deleteButton.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-20)
make.centerY.equalToSuperview()
make.width.height.equalTo(16)
}
}
func updateView(with info: UserInfo) {
let placeholder = UIImage(named: "room_default_avatar_rect", in: tuiRoomKitBundle(), compatibleWith: nil)
if let url = URL(string: info.avatarUrl) {
avatarImageView.sd_setImage(with: url, placeholderImage: placeholder)
} else {
avatarImageView.image = placeholder
}
if !info.userName.isEmpty {
nameLabel.text = info.userName
} else {
nameLabel.text = info.userId
}
}
func hideDeleteButton() {
self.deleteButton.isHidden = true
}
func showDeleteButton() {
self.deleteButton.isHidden = false
}
private func bindInteraction() {
deleteButton.addTarget(self, action: #selector(deleteButtonTapped(sender:)), for: .touchUpInside)
}
@objc func deleteButtonTapped(sender: UIButton) {
self.delegate?.didDeleteButtonClicked(in: self)
}
}
class SelectedMemberHeaderView: UITableViewHeaderFooterView {
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
backgroundView = UIView()
backgroundView?.backgroundColor = .white
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let label: UILabel = {
let label = UILabel()
label.textColor = UIColor.tui_color(withHex: "4F586B")
label.font = UIFont(name: "PingFangSC-Medium", size: 18)
label.text = .selectedText
label.sizeToFit()
return label
}()
private var isViewReady = false
override func didMoveToWindow() {
super.didMoveToWindow()
guard !isViewReady else {
return
}
isViewReady = true
constructViewHierarchy()
activateConstraints()
}
private func constructViewHierarchy() {
addSubview(label)
}
private func activateConstraints() {
label.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(20)
make.top.equalToSuperview()
}
}
func updateLabel(with count: Int) {
let text = .selectedText + " (" + "\(count)" + ")"
self.label.text = text
}
}
class LargerHitAreaButton: UIButton {
var hitAreaEdgeInsets = UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10)
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let largerFrame = bounds.inset(by: hitAreaEdgeInsets)
return largerFrame.contains(point)
}
}
private extension String {
static var selectedText: String {
localized("Selected")
}
}