807 lines
34 KiB
Swift
807 lines
34 KiB
Swift
//
|
|
// BottomViewModel.swift
|
|
// Alamofire
|
|
//
|
|
// Created by aby on 2022/12/22.
|
|
// Copyright © 2022 Tencent. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import RTCRoomEngine
|
|
import TUICore
|
|
import Factory
|
|
import Combine
|
|
|
|
protocol BottomViewModelResponder: AnyObject {
|
|
func updateButtonView(item: ButtonItemData)
|
|
func makeToast(text: String)
|
|
func updataBottomView(isUp:Bool)
|
|
func updateStackView(items: [ButtonItemData])
|
|
func showAlert(title: String?, message: String?, sureTitle:String?, declineTitle: String?, sureBlock: (() -> ())?, declineBlock: (() -> ())?)
|
|
}
|
|
|
|
class BottomViewModel: NSObject {
|
|
private(set) var viewItems: [ButtonItemData] = []
|
|
weak var viewResponder: BottomViewModelResponder?
|
|
|
|
var engineManager: EngineManager {
|
|
EngineManager.shared
|
|
}
|
|
var engineEventCenter: EngineEventCenter {
|
|
EngineEventCenter.shared
|
|
}
|
|
var roomInfo: TUIRoomInfo {
|
|
engineManager.store.roomInfo
|
|
}
|
|
var currentUser: UserEntity {
|
|
engineManager.store.currentUser
|
|
}
|
|
var attendeeList: [UserEntity] {
|
|
engineManager.store.attendeeList
|
|
}
|
|
var inviteSeatList: [RequestEntity] {
|
|
engineManager.store.inviteSeatList
|
|
}
|
|
var isCalledFromShareScreen = false
|
|
var cancellableSet = Set<AnyCancellable>()
|
|
|
|
private lazy var memberItem: ButtonItemData = {
|
|
let memberItem = ButtonItemData()
|
|
memberItem.normalTitle = String(format: .memberText, attendeeList.count)
|
|
memberItem.normalIcon = "room_member"
|
|
memberItem.resourceBundle = tuiRoomKitBundle()
|
|
memberItem.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.memberAction(sender: button)
|
|
}
|
|
return memberItem
|
|
}()
|
|
private lazy var muteAudioItem: ButtonItemData = {
|
|
let muteAudioItem = ButtonItemData()
|
|
muteAudioItem.normalTitle = .muteAudioText
|
|
muteAudioItem.selectedTitle = .unMuteAudioText
|
|
muteAudioItem.normalIcon = "room_unMute_audio"
|
|
muteAudioItem.selectedIcon = "room_mic_off"
|
|
muteAudioItem.resourceBundle = tuiRoomKitBundle()
|
|
muteAudioItem.buttonType = .muteAudioItemType
|
|
muteAudioItem.isSelect = !currentUser.hasAudioStream
|
|
muteAudioItem.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.muteAudioAction(sender: button)
|
|
}
|
|
return muteAudioItem
|
|
}()
|
|
private lazy var muteVideoItem: ButtonItemData = {
|
|
let muteVideoItem = ButtonItemData()
|
|
muteVideoItem.normalTitle = .muteVideoText
|
|
muteVideoItem.selectedTitle = .unMuteVideoText
|
|
muteVideoItem.normalIcon = "room_camera_on"
|
|
muteVideoItem.selectedIcon = "room_camera_off"
|
|
muteVideoItem.resourceBundle = tuiRoomKitBundle()
|
|
muteVideoItem.buttonType = .muteVideoItemType
|
|
muteVideoItem.isSelect = !currentUser.hasVideoStream
|
|
muteVideoItem.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.muteVideoAction(sender: button)
|
|
}
|
|
return muteVideoItem
|
|
}()
|
|
private lazy var shareScreenItem: ButtonItemData = {
|
|
let shareScreenItem = ButtonItemData()
|
|
shareScreenItem.normalTitle = .shareScreenOnText
|
|
shareScreenItem.selectedTitle = .shareScreenOffText
|
|
shareScreenItem.normalIcon = "room_shareScreen_on"
|
|
shareScreenItem.selectedIcon = "room_shareScreen_off"
|
|
shareScreenItem.resourceBundle = tuiRoomKitBundle()
|
|
shareScreenItem.buttonType = .shareScreenItemType
|
|
shareScreenItem.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.shareScreenAction(sender: button)
|
|
}
|
|
return shareScreenItem
|
|
}()
|
|
private lazy var chatItem: ButtonItemData = {
|
|
let chatItem = ButtonItemData()
|
|
chatItem.normalIcon = "room_chat"
|
|
chatItem.normalTitle = .chatText
|
|
chatItem.resourceBundle = tuiRoomKitBundle()
|
|
chatItem.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.chatAction(sender: button)
|
|
}
|
|
return chatItem
|
|
}()
|
|
private lazy var moreItem: ButtonItemData = {
|
|
let moreItem = ButtonItemData()
|
|
moreItem.normalTitle = .unfoldText
|
|
moreItem.normalIcon = "room_more"
|
|
moreItem.selectedTitle = .dropText
|
|
moreItem.selectedIcon = "room_drop"
|
|
moreItem.resourceBundle = tuiRoomKitBundle()
|
|
moreItem.buttonType = .moreItemType
|
|
moreItem.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.moreAction(sender: button)
|
|
}
|
|
return moreItem
|
|
}()
|
|
|
|
private lazy var floatItem: ButtonItemData = {
|
|
let floatItem = ButtonItemData()
|
|
floatItem.normalTitle = .floatText
|
|
floatItem.normalIcon = "room_float"
|
|
floatItem.resourceBundle = tuiRoomKitBundle()
|
|
floatItem.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.floatAction(sender: button)
|
|
}
|
|
return floatItem
|
|
}()
|
|
private lazy var setupItem: ButtonItemData = {
|
|
let setupItem = ButtonItemData()
|
|
setupItem.normalTitle = .setupText
|
|
setupItem.normalIcon = "room_setting"
|
|
setupItem.resourceBundle = tuiRoomKitBundle()
|
|
setupItem.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.setupAction(sender: button)
|
|
}
|
|
return setupItem
|
|
}()
|
|
private lazy var inviteItem: ButtonItemData = {
|
|
let inviteItem = ButtonItemData()
|
|
inviteItem.normalTitle = .inviteText
|
|
inviteItem.normalIcon = "room_invite"
|
|
inviteItem.resourceBundle = tuiRoomKitBundle()
|
|
inviteItem.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.inviteAction(sender: button)
|
|
}
|
|
return inviteItem
|
|
}()
|
|
|
|
private lazy var raiseHandApplyItem: ButtonItemData = {
|
|
let item = ButtonItemData()
|
|
item.normalTitle = .stageManagementText
|
|
item.normalIcon = "room_hand_raise_list"
|
|
item.resourceBundle = tuiRoomKitBundle()
|
|
item.buttonType = .raiseHandApplyItemType
|
|
item.noticeText = String(inviteSeatList.count)
|
|
item.hasNotice = inviteSeatList.count > 0
|
|
item.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.raiseHandApplyAction(sender: button)
|
|
}
|
|
return item
|
|
}()
|
|
|
|
private lazy var raiseHandItem: ButtonItemData = {
|
|
let item = ButtonItemData()
|
|
item.normalTitle = currentUser.userRole == .generalUser ? .applyJoinStageText : .joinStageText
|
|
item.normalIcon = "room_apply_join_stage"
|
|
item.selectedIcon = "room_cancel_request"
|
|
item.selectedTitle = .cancelStageText
|
|
item.resourceBundle = tuiRoomKitBundle()
|
|
item.buttonType = .raiseHandItemType
|
|
item.isSelect = engineManager.store.selfTakeSeatRequestId != nil
|
|
item.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.raiseHandAction(sender: button)
|
|
}
|
|
return item
|
|
}()
|
|
|
|
private lazy var leaveSeatHandItem: ButtonItemData = {
|
|
let item = ButtonItemData()
|
|
item.normalIcon = "room_leave_seat"
|
|
item.selectedIcon = "room_apply_join_stage"
|
|
item.normalTitle = .leaveSeatText
|
|
item.selectedTitle = .applyJoinStageText
|
|
item.buttonType = .leaveSeatItemType
|
|
item.resourceBundle = tuiRoomKitBundle()
|
|
item.action = { [weak self] sender in
|
|
guard let self = self, let button = sender as? UIButton else { return }
|
|
self.leaveSeatAction(sender: button)
|
|
}
|
|
return item
|
|
}()
|
|
|
|
private lazy var invitationPopupPublisher = {
|
|
conferenceStore.select(ViewSelectors.getShowinvitationPopupView)
|
|
}()
|
|
|
|
override init() {
|
|
super.init()
|
|
createBottomData()
|
|
EngineEventCenter.shared.subscribeUIEvent(key: .TUIRoomKitService_UserOnSeatChanged, responder: self)
|
|
EngineEventCenter.shared.subscribeUIEvent(key: .TUIRoomKitService_CurrentUserRoleChanged, responder: self)
|
|
EngineEventCenter.shared.subscribeUIEvent(key: .TUIRoomKitService_CurrentUserHasAudioStream, responder: self)
|
|
EngineEventCenter.shared.subscribeUIEvent(key: .TUIRoomKitService_CurrentUserHasVideoStream, responder: self)
|
|
EngineEventCenter.shared.subscribeUIEvent(key: .TUIRoomKitService_SomeoneSharing, responder: self)
|
|
EngineEventCenter.shared.subscribeUIEvent(key: .TUIRoomKitService_RenewUserList, responder: self)
|
|
EngineEventCenter.shared.subscribeUIEvent(key: .TUIRoomKitService_RenewSeatList, responder: self)
|
|
EngineEventCenter.shared.subscribeEngine(event: .onAllUserCameraDisableChanged, observer: self)
|
|
EngineEventCenter.shared.subscribeEngine(event: .onAllUserMicrophoneDisableChanged, observer: self)
|
|
EngineEventCenter.shared.subscribeEngine(event: .onInitialSelfUserInfo, observer: self)
|
|
EngineEventCenter.shared.subscribeEngine(event: .onRemoteUserEnterRoom, observer: self)
|
|
NotificationCenter.default.addObserver(self,
|
|
selector: #selector(onUserScreenCaptureStarted),
|
|
name: UIScreen.capturedDidChangeNotification, object: nil)
|
|
invitationPopupPublisher
|
|
.receive(on: DispatchQueue.mainQueue)
|
|
.sink { [weak self] showInvitationPopupView in
|
|
guard let self = self else { return }
|
|
if showInvitationPopupView {
|
|
showMemberSelectViewAction()
|
|
}
|
|
}
|
|
.store(in: &cancellableSet)
|
|
}
|
|
|
|
func createBottomData() {
|
|
creatBaseBottomData()
|
|
createMoreBottomData()
|
|
}
|
|
|
|
func creatBaseBottomData(){
|
|
viewItems.append(memberItem)
|
|
viewItems.append(muteAudioItem)
|
|
viewItems.append(muteVideoItem)
|
|
if roomInfo.isSeatEnabled {
|
|
if currentUser.userRole == .roomOwner {
|
|
viewItems.append(raiseHandApplyItem)
|
|
} else {
|
|
if currentUser.isOnSeat {
|
|
viewItems.append(leaveSeatHandItem)
|
|
} else {
|
|
viewItems.append(raiseHandItem)
|
|
}
|
|
}
|
|
if currentUser.userRole == .administrator {
|
|
viewItems.append(raiseHandApplyItem)
|
|
}
|
|
}
|
|
viewItems.append(shareScreenItem)
|
|
if hasTUIChatItem() {
|
|
viewItems.append(chatItem)
|
|
}
|
|
viewItems.append(moreItem)
|
|
updateAudioItem()
|
|
updateVideoItem()
|
|
}
|
|
|
|
func createMoreBottomData(){
|
|
viewItems.append(inviteItem)
|
|
viewItems.append(floatItem)
|
|
viewItems.append(setupItem)
|
|
reorderTheMoreItem()
|
|
}
|
|
|
|
func memberAction(sender: UIButton) {
|
|
RoomRouter.shared.presentPopUpViewController(viewType: .userListViewType, height: 720.scale375Height(), backgroundColor: UIColor(0x17181F))
|
|
}
|
|
|
|
func muteAudioAction(sender: UIButton) {
|
|
engineEventCenter.notifyUIEvent(key: .TUIRoomKitService_SetToolBarDelayHidden, param: ["isDelay": true])
|
|
if currentUser.hasAudioStream {
|
|
engineManager.muteLocalAudio()
|
|
return
|
|
}
|
|
//If all hosts are muted, ordinary members of the room cannot turn on their microphones.
|
|
if self.roomInfo.isMicrophoneDisableForAllUser && currentUser.userRole == .generalUser {
|
|
viewResponder?.makeToast(text: .muteAudioRoomReasonText)
|
|
return
|
|
}
|
|
//If you are speaking in a room with your hand raised and you are not on the microphone, you cannot turn on the microphone.
|
|
if roomInfo.isSeatEnabled, !currentUser.isOnSeat {
|
|
viewResponder?.makeToast(text: .muteSeatReasonText)
|
|
return
|
|
}
|
|
engineManager.unmuteLocalAudio()
|
|
guard !engineManager.store.audioSetting.isMicOpened else { return }
|
|
engineManager.openLocalMicrophone()
|
|
}
|
|
|
|
func muteVideoAction(sender: UIButton) {
|
|
engineEventCenter.notifyUIEvent(key: .TUIRoomKitService_SetToolBarDelayHidden, param: ["isDelay": true])
|
|
if currentUser.hasVideoStream {
|
|
engineManager.closeLocalCamera()
|
|
return
|
|
}
|
|
//If the entire host bans paintings, ordinary members of the room cannot turn on the camera.
|
|
if self.roomInfo.isCameraDisableForAllUser && self.currentUser.userRole == .generalUser {
|
|
viewResponder?.makeToast(text: .muteVideoRoomReasonText)
|
|
return
|
|
}
|
|
//If you are speaking in a room with your hands raised and you are not on the mic, you cannot turn on the camera.
|
|
if roomInfo.isSeatEnabled, !currentUser.isOnSeat {
|
|
viewResponder?.makeToast(text: .muteSeatReasonText)
|
|
return
|
|
}
|
|
engineManager.setLocalVideoView(streamType: .cameraStream, view: nil)
|
|
engineManager.openLocalCamera()
|
|
}
|
|
|
|
func raiseHandApplyAction(sender: UIButton) {
|
|
RoomRouter.shared.presentPopUpViewController(viewType: .raiseHandApplicationListViewType, height: 720.scale375Height(), backgroundColor: UIColor(0x22262E))
|
|
}
|
|
|
|
func raiseHandAction(sender: UIButton) {
|
|
sender.isSelected = !sender.isSelected
|
|
engineEventCenter.notifyUIEvent(key: .TUIRoomKitService_SetToolBarDelayHidden, param: ["isDelay": true])
|
|
if sender.isSelected {
|
|
handleRaiseHandAction()
|
|
} else {
|
|
handleCancelRaiseHandAction()
|
|
}
|
|
}
|
|
|
|
func handleRaiseHandAction() {
|
|
_ = engineManager.takeSeat() { [weak self] _,_ in
|
|
guard let self = self else { return }
|
|
self.viewResponder?.makeToast(text: .takenSeatText)
|
|
} onRejected: { [weak self] _, _, _ in
|
|
guard let self = self else { return }
|
|
self.viewResponder?.makeToast(text: .rejectedTakeSeatText)
|
|
self.changeItemSelectState(type: .raiseHandItemType, isSelected: false)
|
|
} onTimeout: { [weak self] requestId, userId in
|
|
guard let self = self else { return }
|
|
self.viewResponder?.makeToast(text: .joinStageApplicationTimedOutText)
|
|
self.changeItemSelectState(type: .raiseHandItemType, isSelected: false)
|
|
} onError: { [weak self] _, _, code, message in
|
|
guard let self = self else { return }
|
|
self.changeItemSelectState(type: .raiseHandItemType, isSelected: false)
|
|
}
|
|
changeItemSelectState(type: .raiseHandItemType)
|
|
guard currentUser.userRole == .generalUser else { return }
|
|
viewResponder?.makeToast(text: .applicationHasSentText)
|
|
}
|
|
|
|
func handleCancelRaiseHandAction() {
|
|
engineManager.cancelTakeSeatRequest()
|
|
changeItemSelectState(type: .raiseHandItemType)
|
|
viewResponder?.makeToast(text: .joinStageApplicationCancelledText)
|
|
}
|
|
|
|
func leaveSeatAction(sender: UIButton) {
|
|
engineEventCenter.notifyUIEvent(key: .TUIRoomKitService_SetToolBarDelayHidden, param: ["isDelay": true])
|
|
if currentUser.userRole == .administrator {
|
|
engineManager.leaveSeat()
|
|
} else {
|
|
viewResponder?.showAlert(title: .leaveSeatTitle, message: .leaveSeatMessage, sureTitle: .leaveSeatText, declineTitle: .toastCancelText, sureBlock: { [weak self] in
|
|
guard let self = self else { return }
|
|
self.engineManager.leaveSeat()
|
|
}, declineBlock: nil)
|
|
}
|
|
}
|
|
|
|
func shareScreenAction(sender: UIButton) {
|
|
if #available(iOS 12.0, *) {
|
|
guard let item = viewItems.first(where: { $0.buttonType == .shareScreenItemType })
|
|
else { return }
|
|
if !item.isSelect {
|
|
//If someone else is screen sharing, you can no longer screen share yourself
|
|
guard engineManager.store.attendeeList.first(where: {$0.hasScreenStream}) == nil else {
|
|
viewResponder?.makeToast(text: .othersScreenSharingText)
|
|
return
|
|
}
|
|
//If you are in a room where you are raising your hand to speak, and you are not on the mic, you cannot share your screen.
|
|
guard !(roomInfo.isSeatEnabled && !currentUser.isOnSeat) else {
|
|
viewResponder?.makeToast(text: .muteSeatReasonText)
|
|
return
|
|
}
|
|
if TUICore.callService(TUICore_PrivacyService,
|
|
method: TUICore_PrivacyService_ScreenShareAntifraudReminderMethod,
|
|
param: nil, resultCallback: { [weak self] code, message, param in
|
|
guard let self = self else { return }
|
|
if code == TUICore_PrivacyService_EnableScreenShareAntifraudReminderMethod_Continue {
|
|
self.isCalledFromShareScreen = true
|
|
BroadcastLauncher.launch()
|
|
}
|
|
}) == nil {
|
|
isCalledFromShareScreen = true
|
|
BroadcastLauncher.launch()
|
|
}
|
|
} else {
|
|
viewResponder?.showAlert(title: .toastTitleText, message: .toastMessageText, sureTitle: .toastStopText, declineTitle: .toastCancelText, sureBlock: { [weak self] in
|
|
guard let self = self else { return }
|
|
self.engineManager.stopScreenCapture()
|
|
}, declineBlock: nil)
|
|
}
|
|
} else {
|
|
viewResponder?.makeToast(text: .versionLowToastText)
|
|
}
|
|
}
|
|
|
|
func chatAction(sender: UIButton) {
|
|
let user = engineManager.store.currentUser
|
|
let roomInfo = engineManager.store.roomInfo
|
|
RoomRouter.shared.pushToChatController(user: user, roomInfo: roomInfo)
|
|
}
|
|
|
|
func moreAction(sender: UIButton) {
|
|
sender.isSelected = !sender.isSelected
|
|
engineEventCenter.notifyUIEvent(key: .TUIRoomKitService_SetToolBarDelayHidden, param: ["isDelay": !sender.isSelected])
|
|
viewResponder?.updataBottomView(isUp: sender.isSelected)
|
|
changeItemSelectState(type: .moreItemType)
|
|
}
|
|
|
|
func inviteAction(sender: UIButton) {
|
|
RoomRouter.shared.presentPopUpViewController(viewType: .inviteViewType, height: 158.scale375Height())
|
|
}
|
|
|
|
func floatAction(sender: UIButton) {
|
|
EngineEventCenter.shared.notifyUIEvent(key: .TUIRoomKitService_ShowRoomVideoFloatView, param: [:])
|
|
}
|
|
|
|
func setupAction(sender: UIButton) {
|
|
RoomRouter.shared.presentPopUpViewController(viewType: .mediaSettingViewType, height: 709.scale375Height())
|
|
}
|
|
|
|
func showMemberSelectViewAction() {
|
|
conferenceStore.dispatch(action: InvitationViewActions.resetPopupViewFlag())
|
|
let inRoomUsers = attendeeList.map{ UserInfo(userEntity: $0).convertToUser() }
|
|
// TODO: @jeremiawang Use ConferenceRouter to push ContactVC
|
|
let participants = ConferenceParticipants(unSelectableList: inRoomUsers)
|
|
guard let vc = Container.shared.contactViewController(participants) as? (ContactViewProtocol & UIViewController) else {
|
|
return
|
|
}
|
|
vc.delegate = self
|
|
RoomRouter.shared.push(viewController: vc)
|
|
}
|
|
|
|
@objc func onUserScreenCaptureStarted(notification:Notification)
|
|
{
|
|
guard let screen = notification.object as? UIScreen else {return}
|
|
if screen.isCaptured,isCalledFromShareScreen {
|
|
engineManager.startScreenCapture()
|
|
}
|
|
}
|
|
|
|
deinit {
|
|
EngineEventCenter.shared.unsubscribeUIEvent(key: .TUIRoomKitService_UserOnSeatChanged, responder: self)
|
|
EngineEventCenter.shared.unsubscribeUIEvent(key: .TUIRoomKitService_CurrentUserRoleChanged, responder: self)
|
|
EngineEventCenter.shared.unsubscribeUIEvent(key: .TUIRoomKitService_CurrentUserHasAudioStream, responder: self)
|
|
EngineEventCenter.shared.unsubscribeUIEvent(key: .TUIRoomKitService_CurrentUserHasVideoStream, responder: self)
|
|
EngineEventCenter.shared.unsubscribeUIEvent(key: .TUIRoomKitService_SomeoneSharing, responder: self)
|
|
EngineEventCenter.shared.unsubscribeUIEvent(key: .TUIRoomKitService_RenewUserList, responder: self)
|
|
EngineEventCenter.shared.unsubscribeUIEvent(key: .TUIRoomKitService_RenewSeatList, responder: self)
|
|
EngineEventCenter.shared.unsubscribeEngine(event: .onAllUserCameraDisableChanged, observer: self)
|
|
EngineEventCenter.shared.unsubscribeEngine(event: .onAllUserMicrophoneDisableChanged, observer: self)
|
|
EngineEventCenter.shared.unsubscribeEngine(event: .onInitialSelfUserInfo, observer: self)
|
|
EngineEventCenter.shared.unsubscribeEngine(event: .onRemoteUserEnterRoom, observer: self)
|
|
NotificationCenter.default.removeObserver(self, name: UIScreen.capturedDidChangeNotification, object: nil)
|
|
debugPrint("deinit \(self)")
|
|
}
|
|
|
|
@Injected(\.conferenceStore) private var conferenceStore: ConferenceStore
|
|
}
|
|
|
|
// MARK: - Private
|
|
extension BottomViewModel {
|
|
private func hasTUIChatItem() -> Bool {
|
|
return TUICore.getService(TUICore_TUIChatService) != nil
|
|
}
|
|
|
|
private func changeItemSelectState(type: ButtonItemData.ButtonType, isSelected: Bool? = nil) {
|
|
guard let item = viewItems.first(where: { $0.buttonType == type })
|
|
else { return }
|
|
if let isSelected = isSelected {
|
|
item.isSelect = isSelected
|
|
} else {
|
|
item.isSelect = !item.isSelect
|
|
}
|
|
viewResponder?.updateButtonView(item: item)
|
|
}
|
|
|
|
private func updateRaiseHandItem() {
|
|
guard roomInfo.isSeatEnabled else { return }
|
|
raiseHandItem.normalTitle = currentUser.userRole == .generalUser ? .applyJoinStageText : .joinStageText
|
|
leaveSeatHandItem.isSelect = false
|
|
raiseHandItem.isSelect = false
|
|
if currentUser.userRole == .roomOwner {
|
|
guard let index = viewItems.firstIndex(where:{ $0.buttonType == .leaveSeatItemType || $0.buttonType == .raiseHandItemType }) else { return }
|
|
viewItems.remove(at: index)
|
|
} else if let index = viewItems.firstIndex(where:{ $0.buttonType == .leaveSeatItemType || $0.buttonType == .raiseHandItemType }) {
|
|
if currentUser.isOnSeat {
|
|
viewItems[index] = leaveSeatHandItem
|
|
} else {
|
|
viewItems[index] = raiseHandItem
|
|
}
|
|
} else {
|
|
if currentUser.isOnSeat {
|
|
addViewItem(buttonItem: leaveSeatHandItem, index: 3)
|
|
} else {
|
|
addViewItem(buttonItem: raiseHandItem, index: 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func reorderTheMoreItem() {
|
|
guard viewItems.count > 6 else { return }
|
|
guard let index = viewItems.firstIndex(where: { $0.buttonType == .moreItemType }), index != 5 else { return }
|
|
viewItems.remove(at: index)
|
|
viewItems.insert(moreItem, at: 5)
|
|
}
|
|
|
|
private func removeViewItem(buttonType: ButtonItemData.ButtonType) {
|
|
viewItems.removeAll(where: { $0.buttonType == buttonType })
|
|
}
|
|
|
|
private func addViewItem(buttonItem: ButtonItemData, index: Int) {
|
|
guard !isContainedViewItem(buttonType: buttonItem.buttonType) else { return }
|
|
if viewItems.count > index + 1 {
|
|
viewItems.insert(buttonItem, at: index)
|
|
} else {
|
|
viewItems.append(buttonItem)
|
|
}
|
|
}
|
|
|
|
private func isContainedViewItem(buttonType: ButtonItemData.ButtonType) -> Bool {
|
|
return viewItems.contains(where: { $0.buttonType == buttonType })
|
|
}
|
|
|
|
private func updateAudioItem() {
|
|
if roomInfo.isSeatEnabled, currentUser.userRole == .generalUser, !currentUser.isOnSeat {
|
|
//If the audience in the room who raises their hand to speak is not on the microphone, the microphone button will not be displayed.
|
|
removeViewItem(buttonType: .muteAudioItemType)
|
|
} else if !isContainedViewItem(buttonType: .muteAudioItemType) {
|
|
addViewItem(buttonItem: muteAudioItem, index: 1)
|
|
}
|
|
muteAudioItem.isSelect = !currentUser.hasAudioStream
|
|
muteAudioItem.alpha = checkMicAuthority() || currentUser.hasAudioStream ? 1 : 0.5
|
|
}
|
|
|
|
private func updateVideoItem() {
|
|
if roomInfo.isSeatEnabled, currentUser.userRole == .generalUser, !currentUser.isOnSeat {
|
|
removeViewItem(buttonType: .muteVideoItemType)
|
|
} else if !isContainedViewItem(buttonType: .muteVideoItemType) {
|
|
addViewItem(buttonItem: muteVideoItem, index: 2)
|
|
}
|
|
muteVideoItem.isSelect = !currentUser.hasVideoStream
|
|
muteVideoItem.alpha = checkCameraAuthority() || currentUser.hasVideoStream ? 1 : 0.5
|
|
}
|
|
|
|
private func checkMicAuthority() -> Bool {
|
|
if self.roomInfo.isMicrophoneDisableForAllUser && currentUser.userRole == .generalUser {
|
|
return false
|
|
}
|
|
if roomInfo.isSeatEnabled, !currentUser.isOnSeat {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
private func checkCameraAuthority() -> Bool {
|
|
if self.roomInfo.isCameraDisableForAllUser && currentUser.userRole == .generalUser {
|
|
return false
|
|
}
|
|
if roomInfo.isSeatEnabled, !currentUser.isOnSeat {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
private func updateRaiseHandApplyItem() {
|
|
guard roomInfo.isSeatEnabled else { return }
|
|
raiseHandItem.normalTitle = currentUser.userRole == .generalUser ? .applyJoinStageText : .joinStageText
|
|
if currentUser.userRole == .roomOwner {
|
|
addViewItem(buttonItem: raiseHandApplyItem, index: 3)
|
|
} else if currentUser.userRole == .administrator {
|
|
addViewItem(buttonItem: raiseHandApplyItem, index: 4)
|
|
} else {
|
|
removeViewItem(buttonType: .raiseHandApplyItemType)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension BottomViewModel: RoomKitUIEventResponder {
|
|
func onNotifyUIEvent(key: EngineEventCenter.RoomUIEvent, Object: Any?, info: [AnyHashable : Any]?) {
|
|
switch key {
|
|
case .TUIRoomKitService_UserOnSeatChanged:
|
|
guard roomInfo.isSeatEnabled else { return }
|
|
updateRaiseHandItem()
|
|
updateAudioItem()
|
|
updateVideoItem()
|
|
reorderTheMoreItem()
|
|
viewResponder?.updateStackView(items: viewItems)
|
|
case .TUIRoomKitService_CurrentUserRoleChanged:
|
|
updateAudioItem()
|
|
updateVideoItem()
|
|
updateRaiseHandApplyItem()
|
|
updateRaiseHandItem()
|
|
reorderTheMoreItem()
|
|
viewResponder?.updateStackView(items: viewItems)
|
|
case .TUIRoomKitService_CurrentUserHasAudioStream:
|
|
guard let hasAudio = info?["hasAudio"] as? Bool else { return }
|
|
guard let reason = info?["reason"] as? TUIChangeReason else { return }
|
|
if !hasAudio, reason == .byAdmin, !roomInfo.isMicrophoneDisableForAllUser {
|
|
if !roomInfo.isSeatEnabled {
|
|
viewResponder?.makeToast(text: .noticeMicrophoneOffTitleText)
|
|
} else if currentUser.isOnSeat {
|
|
viewResponder?.makeToast(text: .noticeMicrophoneOffTitleText)
|
|
}
|
|
}
|
|
updateAudioItem()
|
|
viewResponder?.updateButtonView(item: muteAudioItem)
|
|
case .TUIRoomKitService_CurrentUserHasVideoStream:
|
|
guard let hasVideo = info?["hasVideo"] as? Bool else { return }
|
|
guard let reason = info?["reason"] as? TUIChangeReason else { return }
|
|
if !hasVideo, reason == .byAdmin, !roomInfo.isCameraDisableForAllUser {
|
|
if !roomInfo.isSeatEnabled {
|
|
viewResponder?.makeToast(text: .noticeCameraOffTitleText)
|
|
} else if currentUser.isOnSeat {
|
|
viewResponder?.makeToast(text: .noticeCameraOffTitleText)
|
|
}
|
|
}
|
|
updateVideoItem()
|
|
viewResponder?.updateButtonView(item: muteVideoItem)
|
|
case .TUIRoomKitService_SomeoneSharing:
|
|
guard let userId = info?["userId"] as? String else { return }
|
|
guard let hasVideo = info?["hasVideo"] as? Bool else { return }
|
|
guard userId == currentUser.userId else { return }
|
|
changeItemSelectState(type: .shareScreenItemType, isSelected: hasVideo)
|
|
if !hasVideo {
|
|
isCalledFromShareScreen = false
|
|
}
|
|
case .TUIRoomKitService_RenewUserList:
|
|
memberItem.normalTitle = String(format: .memberText, attendeeList.count)
|
|
viewResponder?.updateButtonView(item: memberItem)
|
|
case .TUIRoomKitService_RenewSeatList:
|
|
raiseHandApplyItem.noticeText = String(inviteSeatList.count)
|
|
raiseHandApplyItem.hasNotice = inviteSeatList.count > 0
|
|
viewResponder?.updateButtonView(item: raiseHandApplyItem)
|
|
default: break
|
|
}
|
|
}
|
|
}
|
|
|
|
extension BottomViewModel: RoomEngineEventResponder {
|
|
func onEngineEvent(name: EngineEventCenter.RoomEngineEvent, param: [String : Any]?) {
|
|
switch name {
|
|
case .onAllUserCameraDisableChanged:
|
|
updateVideoItem()
|
|
viewResponder?.updateButtonView(item: muteVideoItem)
|
|
case .onAllUserMicrophoneDisableChanged:
|
|
updateAudioItem()
|
|
viewResponder?.updateButtonView(item: muteAudioItem)
|
|
case .onInitialSelfUserInfo:
|
|
updateAudioItem()
|
|
updateVideoItem()
|
|
updateRaiseHandApplyItem()
|
|
updateRaiseHandItem()
|
|
reorderTheMoreItem()
|
|
viewResponder?.updateStackView(items: viewItems)
|
|
case .onRemoteUserEnterRoom:
|
|
guard let userInfo = param?["userInfo"] as? TUIUserInfo else { return }
|
|
conferenceStore.dispatch(action: ConferenceInvitationActions.removeInvitation(payload: userInfo.userId))
|
|
default: break
|
|
}
|
|
}
|
|
}
|
|
|
|
extension BottomViewModel: ContactViewSelectDelegate {
|
|
func onMemberSelected(_ viewController: any ContactViewProtocol, invitees: [User]) {
|
|
let userIdList = invitees.map{ $0.userId }
|
|
self.conferenceStore.dispatch(action: ConferenceInvitationActions.inviteUsers(payload: (roomInfo.roomId, userIdList)))
|
|
RoomRouter.shared.pop()
|
|
if !invitees.isEmpty{
|
|
viewResponder?.makeToast(text: .inviteEnterRoomSuccesstext)
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension String {
|
|
static var memberText: String {
|
|
localized("Users(%lld)")
|
|
}
|
|
static var muteAudioText: String {
|
|
localized("Mute")
|
|
}
|
|
static var unMuteAudioText: String {
|
|
localized("Unmute")
|
|
}
|
|
static var muteVideoText: String {
|
|
localized("Stop video")
|
|
}
|
|
static var unMuteVideoText: String {
|
|
localized("Start video")
|
|
}
|
|
static var stageManagementText: String {
|
|
localized("Applies")
|
|
}
|
|
static var cancelStageText: String {
|
|
localized("Cancel")
|
|
}
|
|
static var applyJoinStageText: String {
|
|
localized("Join stage")
|
|
}
|
|
static var leaveSeatText: String {
|
|
localized("Step down")
|
|
}
|
|
static var muteSeatReasonText: String {
|
|
localized("Can be turned on after taking the stage")
|
|
}
|
|
static var muteAudioRoomReasonText: String {
|
|
localized("All on mute audio, unable to turn on microphone")
|
|
}
|
|
static var muteVideoRoomReasonText: String {
|
|
localized("All on mute video, unable to turn on camera")
|
|
}
|
|
static var noticeCameraOffTitleText: String {
|
|
localized("The conference owner disabled your video.")
|
|
}
|
|
static var noticeMicrophoneOffTitleText: String {
|
|
localized("You were muted by the host.")
|
|
}
|
|
static var shareScreenOnText: String {
|
|
localized("Share")
|
|
}
|
|
static var shareScreenOffText: String {
|
|
localized("Stop")
|
|
}
|
|
static var versionLowToastText: String {
|
|
localized("Your system version is below 12.0. Please update.")
|
|
}
|
|
static var chatText: String {
|
|
localized("Chat")
|
|
}
|
|
static var unfoldText: String {
|
|
localized("More")
|
|
}
|
|
static var inviteText: String {
|
|
localized("Invite")
|
|
}
|
|
static var floatText: String {
|
|
localized("Floating")
|
|
}
|
|
static var setupText: String {
|
|
localized("Settings")
|
|
}
|
|
static var dropText: String {
|
|
localized("Drop")
|
|
}
|
|
static var rejectedTakeSeatText: String {
|
|
localized("Application to go on stage was rejected")
|
|
}
|
|
static var takenSeatText: String {
|
|
localized("Succeed on stage")
|
|
}
|
|
static var othersScreenSharingText: String {
|
|
localized("An existing member is sharing. Please try again later")
|
|
}
|
|
static var toastTitleText: String {
|
|
localized("Share Screen")
|
|
}
|
|
static var toastMessageText: String {
|
|
localized("Stop TUIRoom screen sharing screen live?")
|
|
}
|
|
static var toastCancelText: String {
|
|
localized("Cancel")
|
|
}
|
|
static var toastStopText: String {
|
|
localized("Stop")
|
|
}
|
|
static var applicationHasSentText: String {
|
|
localized("Application has been sent, please wait for the owner/administrator to approve")
|
|
}
|
|
static var joinStageText: String {
|
|
localized("Join stage")
|
|
}
|
|
static var leaveSeatTitle: String {
|
|
localized("Are you sure you want to step down?")
|
|
}
|
|
static var leaveSeatMessage: String {
|
|
localized("To get on stage again, you need to resend the application and wait for the owner/administrator to approve it.")
|
|
}
|
|
static var joinStageApplicationCancelledText: String {
|
|
localized("Application for stage has been cancelled")
|
|
}
|
|
static var joinStageApplicationTimedOutText: String {
|
|
localized("The request to go on stage has timed out")
|
|
}
|
|
static var inviteEnterRoomSuccesstext: String {
|
|
localized("Invitation has been sent, waiting for users to join")
|
|
}
|
|
}
|