增加换肤功能

This commit is contained in:
启星
2025-08-14 10:07:49 +08:00
parent f6964c1e89
commit 4f9318d98e
8789 changed files with 978530 additions and 2 deletions

View File

@@ -0,0 +1,175 @@
//
// RaiseHandApplicationCell.swift
// TUIRoomKit
//
// Created by janejntang on 2024/5/7.
//
import Foundation
class RaiseHandApplicationCell: UITableViewCell {
let attendeeModel: RequestEntity
let viewModel: RaiseHandApplicationListViewModel
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.font = UIFont.systemFont(ofSize: 16, weight: .regular)
label.numberOfLines = 1
return label
}()
let applyLabel: UILabel = {
let label = UILabel()
label.text = .applyText
label.textColor = UIColor(0x8F9AB2)
label.backgroundColor = UIColor.clear
label.textAlignment = isRTL ? .right : .left
label.font = UIFont.systemFont(ofSize: 12)
return label
}()
let disagreeStageButton: UIButton = {
let button = UIButton(type: .custom)
button.backgroundColor = UIColor(0x6B758A).withAlphaComponent(0.3)
button.setTitle(.disagreeSeatText, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular)
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.setTitleColor(UIColor(0xB2BBD1), for: .normal)
button.layer.cornerRadius = 6
button.clipsToBounds = true
return button
}()
let agreeStageButton: UIButton = {
let button = UIButton(type: .custom)
button.backgroundColor = UIColor(0x1C66E5)
button.setTitle(.agreeSeatText, for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular)
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.layer.cornerRadius = 6
button.clipsToBounds = true
return button
}()
let downLineView : UIView = {
let view = UIView()
view.backgroundColor = UIColor(0x4F586B).withAlphaComponent(0.3)
return view
}()
init(attendeeModel: RequestEntity ,viewModel: RaiseHandApplicationListViewModel) {
self.attendeeModel = attendeeModel
self.viewModel = viewModel
super.init(style: .default, reuseIdentifier: "RaiseHandCell")
}
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(applyLabel)
contentView.addSubview(agreeStageButton)
contentView.addSubview(disagreeStageButton)
contentView.addSubview(downLineView)
}
func activateConstraints() {
avatarImageView.snp.makeConstraints { make in
make.width.height.equalTo(40.scale375())
make.leading.equalToSuperview()
make.top.equalToSuperview().offset(10.scale375Height())
}
agreeStageButton.snp.makeConstraints { make in
make.width.equalTo(48.scale375())
make.height.equalTo(28.scale375Height())
make.trailing.equalToSuperview()
make.centerY.equalToSuperview()
}
disagreeStageButton.snp.makeConstraints { make in
make.trailing.equalTo(agreeStageButton.snp.leading).offset(-10)
make.centerY.equalTo(agreeStageButton)
make.width.height.equalTo(agreeStageButton)
}
userLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(14.scale375Height())
make.leading.equalTo(avatarImageView.snp.trailing).offset(12.scale375())
make.width.equalTo(150.scale375())
make.height.equalTo(22.scale375())
}
applyLabel.snp.makeConstraints { make in
make.top.equalTo(userLabel.snp.bottom).offset(2.scale375Height())
make.leading.equalTo(userLabel)
}
downLineView.snp.makeConstraints { make in
make.leading.equalTo(userLabel)
make.trailing.equalToSuperview()
make.bottom.equalToSuperview()
make.height.equalTo(1.scale375())
}
}
func bindInteraction() {
setupViewState(item: attendeeModel)
agreeStageButton.addTarget(self, action: #selector(agreeStageAction(sender:)), for: .touchUpInside)
disagreeStageButton.addTarget(self, action: #selector(disagreeStageAction(sender:)), for: .touchUpInside)
}
func setupViewState(item: RequestEntity) {
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
backgroundColor = .clear
}
@objc func agreeStageAction(sender: UIButton) {
viewModel.respondRequest(isAgree: true, request: attendeeModel)
}
@objc func disagreeStageAction(sender: UIButton) {
viewModel.respondRequest(isAgree: false, request: attendeeModel)
}
deinit {
debugPrint("deinit \(self)")
}
}
private extension String {
static var applyText: String {
localized("Apply to be on stage")
}
static var disagreeSeatText: String {
localized("Reject")
}
static var agreeSeatText: String {
localized("Agree")
}
}

View File

@@ -0,0 +1,219 @@
//
// RaiseHandApplicationListView.swift
// TUIRoomKit
//
// Created by janejntang on 2023/1/13.
// Copyright © 2023 Tencent. All rights reserved.
//
import Foundation
class RaiseHandApplicationListView: UIView {
let viewModel: RaiseHandApplicationListViewModel
let titleLabel: UILabel = {
let label = UILabel()
label.text = .takeSeatApplyTitle
label.font = UIFont.systemFont(ofSize: 16, weight: .medium)
label.textColor = UIColor(0xD5E0F2)
label.backgroundColor = .clear
return label
}()
let allAgreeButton : UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular)
button.setTitle(.agreeAllText, for: .normal)
button.setTitleColor(UIColor(0xFFFFFF), for: .normal)
button.setBackgroundImage(UIColor(0x1C66E5).withAlphaComponent(0.5).trans2Image(), for: .disabled)
button.setBackgroundImage(UIColor(0x1C66E5).trans2Image(), for: .normal)
button.layer.cornerRadius = 6
button.clipsToBounds = true
button.adjustsImageWhenHighlighted = false
return button
}()
let allRejectButton: UIButton = {
let button = UIButton(type: .custom)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular)
button.setTitle(.rejectAllText, for: .normal)
button.setTitleColor(UIColor(0xB2BBD1), for: .normal)
button.setBackgroundImage(UIColor(0x4F586B).withAlphaComponent(0.5).trans2Image(), for: .disabled)
button.setBackgroundImage(UIColor(0x4F586B).trans2Image(), for: .normal)
button.layer.cornerRadius = 6
button.clipsToBounds = true
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.adjustsImageWhenHighlighted = false
return button
}()
let placeholderUIImageView: UIImageView = {
let image = UIImage(named: "room_apply_placeholder", in: tuiRoomKitBundle(), compatibleWith: nil)
let imageView = UIImageView(image: image)
return imageView
}()
let placeholderLabel: UILabel = {
let label = UILabel()
label.text = .noMemberApplicationText
label.textColor = UIColor(0xB2BBD1)
label.font = UIFont.systemFont(ofSize: 16, weight: .regular)
return label
}()
lazy var applyTableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.separatorStyle = .none
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = .clear
tableView.register(RaiseHandApplicationCell.self, forCellReuseIdentifier: "RaiseHandCell")
return tableView
}()
init(viewModel: RaiseHandApplicationListViewModel) {
self.viewModel = viewModel
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(0x22262E)
guard !isViewReady else { return }
constructViewHierarchy()
activateConstraints()
bindInteraction()
isViewReady = true
}
func constructViewHierarchy() {
addSubview(titleLabel)
addSubview(placeholderUIImageView)
addSubview(placeholderLabel)
addSubview(applyTableView)
addSubview(allRejectButton)
addSubview(allAgreeButton)
}
func activateConstraints() {
titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(10.scale375Height())
make.leading.equalToSuperview().offset(16.scale375())
}
placeholderUIImageView.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.width.height.equalTo(48.scale375())
make.centerY.equalToSuperview().offset(-30.scale375Height())
}
placeholderLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(placeholderUIImageView.snp.bottom).offset(8.scale375Height())
make.height.equalTo(22.scale375Height())
}
applyTableView.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(16.scale375())
make.trailing.equalToSuperview().offset(-16.scale375())
make.top.equalTo(titleLabel.snp.bottom).offset(26.scale375Height())
make.bottom.equalTo(allAgreeButton.snp.top).offset(-10.scale375Height())
}
allRejectButton.snp.remakeConstraints { make in
make.leading.equalTo(applyTableView)
make.bottom.equalToSuperview().offset(-34.scale375Height())
make.height.equalTo(40.scale375Height())
make.width.equalTo(167.scale375())
}
allAgreeButton.snp.makeConstraints { make in
make.trailing.equalTo(applyTableView)
make.bottom.height.width.equalTo(allRejectButton)
}
}
func bindInteraction() {
viewModel.viewResponder = self
allAgreeButton.addTarget(self, action: #selector(allAgreeStageAction(sender:)), for: .touchUpInside)
allRejectButton.addTarget(self, action: #selector(allRejectAction(sender:)), for: .touchUpInside)
setupPlaceholderViewState(isShown: viewModel.isPlaceholderViewShown)
setupApplyButtonState(isEnabled: viewModel.isApplyButtonEnabled)
}
@objc func allAgreeStageAction(sender: UIButton) {
viewModel.respondAllRequest(isAgree: true)
}
@objc func allRejectAction(sender: UIButton) {
viewModel.respondAllRequest(isAgree: false)
}
private func setupPlaceholderViewState(isShown: Bool) {
placeholderLabel.isHidden = !isShown
placeholderUIImageView.isHidden = !isShown
applyTableView.isHidden = isShown
}
private func setupApplyButtonState(isEnabled: Bool) {
allAgreeButton.isEnabled = isEnabled
allRejectButton.isEnabled = isEnabled
}
deinit {
debugPrint("deinit \(self)")
}
}
extension RaiseHandApplicationListView: UITableViewDataSource {
internal func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.inviteSeatList.count
}
}
extension RaiseHandApplicationListView: UITableViewDelegate {
internal func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let attendeeModel = viewModel.inviteSeatList[indexPath.row]
let cell = RaiseHandApplicationCell(attendeeModel: attendeeModel, viewModel: viewModel)
cell.selectionStyle = .none
return cell
}
internal func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60.scale375()
}
}
extension RaiseHandApplicationListView: RaiseHandApplicationListViewResponder {
func updateApplyButtonState(isEnabled: Bool) {
setupApplyButtonState(isEnabled: isEnabled)
}
func updatePlaceholderViewState(isShown: Bool) {
setupPlaceholderViewState(isShown: isShown)
}
func reloadApplyListView() {
applyTableView.reloadData()
}
func makeToast(text: String) {
RoomRouter.makeToastInCenter(toast: text, duration: 1)
}
}
private extension String {
static var takeSeatApplyTitle: String {
localized("Participants apply to come on stage")
}
static var rejectAllText: String {
localized("Reject all")
}
static var noMemberApplicationText: String {
localized("No participants's application yet")
}
static var agreeAllText: String {
localized("Agree to all")
}
}

View File

@@ -0,0 +1,148 @@
//
// RaiseHandApplicationNotificationView.swift
// TUIRoomKit
//
// Created by janejntang on 2024/5/8.
//
import Foundation
protocol RaiseHandApplicationNotificationViewListener: AnyObject {
func onHidden()
func onShown()
}
class RaiseHandApplicationNotificationView: UIView {
let viewModel: RaiseHandApplicationNotificationViewModel
weak var delegate: RaiseHandApplicationNotificationViewListener?
private let imageView: UIImageView = {
let image = UIImage(named: "room_raise_hand_notification", in: tuiRoomKitBundle(), compatibleWith: nil)
return UIImageView(image: image)
}()
private let label: UILabel = {
let label = UILabel()
label.textAlignment = isRTL ? .right : .left
label.font = UIFont.systemFont(ofSize: 14, weight: .regular)
label.textColor = UIColor(0x181820)
label.adjustsFontSizeToFitWidth = false
return label
}()
private let checkButton: UIButton = {
let button = UIButton()
button.backgroundColor = .clear
button.setTitle(.checkText, for: .normal)
button.setTitleColor(UIColor(0x1C66E5), for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
button.titleLabel?.textAlignment = .center
return button
}()
init(viewModel: RaiseHandApplicationNotificationViewModel) {
self.viewModel = viewModel
super.init(frame: .zero)
self.viewModel.responder = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - view layout
private var isViewReady: Bool = false
override func didMoveToWindow() {
super.didMoveToWindow()
guard !isViewReady else { return }
constructViewHierarchy()
activateConstraints()
bindInteraction()
isViewReady = true
}
func constructViewHierarchy() {
addSubview(imageView)
addSubview(label)
addSubview(checkButton)
}
func activateConstraints() {
imageView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.leading.equalToSuperview().offset(8.scale375Height())
make.width.height.equalTo(24.scale375())
}
checkButton.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.trailing.equalToSuperview().offset(-6.scale375())
make.height.equalTo(22.scale375Height())
make.width.equalTo(48.scale375())
}
label.snp.makeConstraints { make in
make.leading.equalTo(imageView.snp.trailing).offset(10.scale375())
make.trailing.equalTo(checkButton.snp.leading).offset(-10.scale375())
make.centerY.equalToSuperview()
make.height.equalTo(22.scale375Height())
}
}
func bindInteraction() {
isHidden = true
backgroundColor = UIColor(0xFFFFFF)
layer.cornerRadius = 6
checkButton.addTarget(self, action: #selector(checkAction(sender:)), for: .touchUpInside)
guard viewModel.isShownRaiseHandApplicationNotificationView else { return }
guard let userId = viewModel.userId, let userName = viewModel.userName, let count = viewModel.applicationCount else { return }
show(userId: userId, userName: userName, count: count)
}
@objc private func checkAction(sender: UIButton) {
hide()
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(hide), object: nil)
viewModel.checkRaiseHandApplicationAction()
}
func show(userId: String, userName: String, count: Int) {
isHidden = false
let nameText = userName ?? userId
let title = count > 1 ?
.multiApplyingOnStageText.replacingOccurrences(of: "xx", with: nameText).replacingOccurrences(of: "yy", with: String(count))
: localizedReplace(.singleApplyingOnStageText, replace: nameText)
label.text = title
delegate?.onShown()
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(hide), object: nil)
guard viewModel.delayDisappearanceTime > 0 else { return }
perform(#selector(hide), with: nil, afterDelay: viewModel.delayDisappearanceTime)
}
@objc func hide() {
isHidden = true
delegate?.onHidden()
}
deinit {
NSObject.cancelPreviousPerformRequests(withTarget: self)
}
}
extension RaiseHandApplicationNotificationView: RaiseHandApplicationNotificationViewModelResponder {
func showRaiseHandApplicationNotificationView(userId: String, userName: String, count: Int) {
show(userId: userId, userName: userName, count: count)
}
func hideRaiseHandApplicationNotificationView() {
hide()
}
}
private extension String {
static var checkText: String {
localized("Check")
}
static var singleApplyingOnStageText: String {
localized("xx is applying to be on stage.")
}
static var multiApplyingOnStageText: String {
localized("Including xx, yy people are applying to be on stage.")
}
}