| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814 |
- //
- // BottomViewModel.swift
- //
- // 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(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 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 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
- }
- guard !(currentUser.userRole == .generalUser && roomInfo.isScreenShareDisableForAllUser) else {
- viewResponder?.makeToast(text: .failedShareOnlyHostOrAdminCanShare)
- 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)
- var contactViewController: (ContactViewProtocol & UIViewController)?
- if ConferenceSession.sharedInstance.implementation.hasCustomContacts {
- contactViewController = Container.shared.contactViewController.resolve(participants) as? (ContactViewProtocol & UIViewController)
- } else {
- contactViewController = SelectMemberViewController(participants: participants)
- }
- guard let contactViewController = contactViewController else { return }
- contactViewController.delegate = self
- RoomRouter.shared.push(viewController: contactViewController)
- }
-
- @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("Close")
- }
- 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("Another user is sharing the screen.")
- }
- 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")
- }
- static let failedShareOnlyHostOrAdminCanShare = localized("Failed to initiate share, currently only host/admin can share")
- }
|