提交
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// ConferenceInvitationService.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by jeremiawang on 2024/8/8.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RTCRoomEngine
|
||||
import Combine
|
||||
import Factory
|
||||
|
||||
class ConferenceInvitationService: NSObject {
|
||||
@WeakLazyInjected(\.conferenceStore) var store: ConferenceStore?
|
||||
|
||||
typealias InviteUsersResult = ([String: NSNumber])
|
||||
typealias InvitationfetchResult = ([TUIInvitation], String)
|
||||
private let timeout: Double = 60
|
||||
private let invitationManager = TUIRoomEngine.sharedInstance().getExtension(extensionType: .conferenceInvitationManager) as? TUIConferenceInvitationManager
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
invitationManager?.addObserver(self)
|
||||
}
|
||||
|
||||
deinit {
|
||||
invitationManager?.removeObserver(self)
|
||||
}
|
||||
|
||||
func inviteUsers(roomId: String, userIdList: [String]) -> AnyPublisher<InviteUsersResult, RoomError> {
|
||||
return Future<InviteUsersResult, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.invitationManager?.inviteUsers(roomId, userIdList: userIdList, timeout: timeout, extensionInfo: "") {dic in
|
||||
promise(.success((dic)))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error, message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func accept(roomId: String) -> AnyPublisher<String, RoomError> {
|
||||
return Future<String, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.invitationManager?.accept(roomId) {
|
||||
promise(.success(roomId))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error, message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func reject(roomId: String, reason: TUIInvitationRejectedReason) -> AnyPublisher<String, RoomError> {
|
||||
return Future<String, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.invitationManager?.reject(roomId, reason: reason) {
|
||||
promise(.success(roomId))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error, message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func getInvitationList(roomId: String, cursor: String, count: Int = 20) -> AnyPublisher<InvitationfetchResult, RoomError> {
|
||||
return Future<InvitationfetchResult, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.invitationManager?.getInvitationList(roomId, cursor: cursor, count: count) {invitations, cursor in
|
||||
promise(.success((invitations, cursor)))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error, message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
extension ConferenceInvitationService: TUIConferenceInvitationObserver {
|
||||
func onReceiveInvitation(roomInfo: TUIRoomInfo, invitation: TUIInvitation, extensionInfo: String) {
|
||||
|
||||
}
|
||||
|
||||
func onInvitationHandledByOtherDevice(roomInfo: TUIRoomInfo, accepted: Bool) {
|
||||
guard let store = self.store else { return }
|
||||
store.dispatch(action: InvitationViewActions.dismissInvitationView())
|
||||
}
|
||||
|
||||
func onInvitationCancelled(roomInfo: TUIRoomInfo, invitation: TUIInvitation) {
|
||||
|
||||
}
|
||||
|
||||
func onInvitationAccepted(roomInfo: TUIRoomInfo, invitation: TUIInvitation) {
|
||||
|
||||
}
|
||||
|
||||
func onInvitationRejected(roomInfo: TUIRoomInfo, invitation: TUIInvitation, reason: TUIInvitationRejectedReason) {
|
||||
|
||||
}
|
||||
|
||||
func onInvitationTimeout(roomInfo: TUIRoomInfo, invitation: TUIInvitation) {
|
||||
guard let store = self.store else { return }
|
||||
store.dispatch(action: InvitationViewActions.dismissInvitationView())
|
||||
}
|
||||
|
||||
func onInvitationRevokedByAdmin(roomInfo: TUIRoomInfo, invitation: TUIInvitation, admin: TUIUserInfo) {
|
||||
|
||||
}
|
||||
|
||||
func onInvitationAdded(roomId: String, invitation: TUIInvitation) {
|
||||
guard let store = self.store else { return }
|
||||
let currentRoomId = store.selectCurrent(RoomSelectors.getRoomId)
|
||||
guard currentRoomId == roomId else { return }
|
||||
store.dispatch(action: ConferenceInvitationActions.addInvitation(payload: invitation))
|
||||
}
|
||||
|
||||
func onInvitationRemoved(roomId: String, invitation: TUIInvitation) {
|
||||
guard let store = self.store else { return }
|
||||
let currentRoomId = store.selectCurrent(RoomSelectors.getRoomId)
|
||||
guard currentRoomId == roomId else { return }
|
||||
store.dispatch(action: ConferenceInvitationActions.removeInvitation(payload: invitation.invitee.userId))
|
||||
}
|
||||
|
||||
func onInvitationStatusChanged(roomId: String, invitation: TUIInvitation) {
|
||||
guard let store = self.store else { return }
|
||||
let currentRoomId = store.selectCurrent(RoomSelectors.getRoomId)
|
||||
guard currentRoomId == roomId else { return }
|
||||
store.dispatch(action: ConferenceInvitationActions.changeInvitationStatus(payload: invitation))
|
||||
}
|
||||
|
||||
}
|
||||
191
TUIKit/TUIRoomKit/Source/Service/ConferenceListService.swift
Normal file
191
TUIKit/TUIRoomKit/Source/Service/ConferenceListService.swift
Normal file
@@ -0,0 +1,191 @@
|
||||
//
|
||||
// ConferenceListService.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by CY zhao on 2024/6/27.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RTCRoomEngine
|
||||
import Combine
|
||||
import Factory
|
||||
|
||||
class ConferenceListService: NSObject {
|
||||
@WeakLazyInjected(\.conferenceStore) var store: ConferenceStore?
|
||||
|
||||
private let listManager = TUIRoomEngine.sharedInstance().getExtension(extensionType: .conferenceListManager) as? TUIConferenceListManager
|
||||
typealias ConferencesFetchResult = ([ConferenceInfo], String)
|
||||
typealias AttendeesFetchResult = ([UserInfo], String, UInt)
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
listManager?.addObserver(self)
|
||||
}
|
||||
|
||||
deinit {
|
||||
listManager?.removeObserver(self)
|
||||
}
|
||||
|
||||
func scheduleConference(conferenceInfo: TUIConferenceInfo) -> AnyPublisher<TUIConferenceInfo, RoomError> {
|
||||
return Future<TUIConferenceInfo, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.listManager?.scheduleConference(conferenceInfo) {
|
||||
promise(.success(conferenceInfo))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error, message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
|
||||
func cancelConference(conferenceId: String) -> AnyPublisher<Void, RoomError> {
|
||||
return Future<Void, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.listManager?.cancelConference(conferenceId) {
|
||||
promise(.success(()))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error , message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func updateConferenceInfo(conferenceInfo: TUIConferenceInfo, modifyFlag: TUIConferenceModifyFlag) -> AnyPublisher<Void, RoomError> {
|
||||
return Future<Void, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.listManager?.updateConferenceInfo(conferenceInfo: conferenceInfo, modifyFlag: modifyFlag) {
|
||||
promise(.success(()))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error , message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func fetchConferenceList(status: TUIConferenceStatus, cursor: String, count: Int = 20) -> AnyPublisher<ConferencesFetchResult, RoomError> {
|
||||
return Future<ConferencesFetchResult, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.listManager?.fetchScheduledConferenceList(status: status,
|
||||
cursor: cursor,
|
||||
count: count) { conferenceList, cursor in
|
||||
let list = conferenceList.map { ConferenceInfo(with: $0) }
|
||||
promise(.success((list, cursor)))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error, message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func fetchAttendeeList(conferenceId: String, cursor: String, count: Int = 20) -> AnyPublisher<AttendeesFetchResult, RoomError> {
|
||||
return Future<AttendeesFetchResult, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.listManager?.fetchAttendeeList(roomId: conferenceId, cursor: cursor, count: count) { attendeeList, cursor, totalCount in
|
||||
|
||||
let userInfoList = attendeeList.map { UserInfo(userInfo: $0) }
|
||||
promise(.success((userInfoList, cursor, totalCount)))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error, message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func addAttendeesByAdmin(conferenceId: String, userIdList: [String]) -> AnyPublisher<Void, RoomError> {
|
||||
return Future<Void, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.listManager?.addAttendeesByAdmin(roomId: conferenceId, userIdList: userIdList) {
|
||||
promise(.success(()))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error , message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func removeAttendeesByAdmin(conferenceId: String, userIdList: [String]) -> AnyPublisher<Void, RoomError> {
|
||||
return Future<Void, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.listManager?.removeAttendeesByAdmin(roomId: conferenceId, userIdList: userIdList) {
|
||||
promise(.success(()))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error , message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func fetchConferenceInfo(roomId: String) -> AnyPublisher<ConferenceInfo, RoomError> {
|
||||
return Future<ConferenceInfo, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
EngineManager.shared.fetchRoomInfo(roomId: roomId) { [weak self] roomInfo in
|
||||
guard let self = self, let roomInfo = roomInfo else { return }
|
||||
let currentList = self.store?.selectCurrent(ConferenceListSelectors.getConferenceList)
|
||||
guard var updateConference = currentList?.first(where: { $0.basicInfo.roomId == roomInfo.roomId }) else { return }
|
||||
updateConference.basicInfo = RoomInfo(with: roomInfo)
|
||||
promise(.success(updateConference))
|
||||
} onError: { error, message in
|
||||
promise(.failure(RoomError(error: error , message: message)))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
extension ConferenceListService: TUIConferenceListManagerObserver {
|
||||
func onConferenceScheduled(conferenceInfo: TUIConferenceInfo) {
|
||||
guard let store = self.store else { return }
|
||||
let conference = ConferenceInfo(with: conferenceInfo)
|
||||
let currentList = store.selectCurrent(ConferenceListSelectors.getConferenceList)
|
||||
let contain = currentList.contains { $0.basicInfo.roomId == conference.basicInfo.roomId }
|
||||
if !contain {
|
||||
store.dispatch(action: ConferenceListActions.insertConference(payload: conference))
|
||||
}
|
||||
}
|
||||
|
||||
func onConferenceCancelled(roomId: String, reason: TUIConferenceCancelReason, operateUser: TUIUserInfo) {
|
||||
guard let store = self.store else { return }
|
||||
let currentList = store.selectCurrent(ConferenceListSelectors.getConferenceList).map { $0.basicInfo.roomId }
|
||||
if currentList.contains(roomId) {
|
||||
store.dispatch(action: ConferenceListActions.removeConference(payload: roomId))
|
||||
}
|
||||
}
|
||||
|
||||
func onConferenceInfoChanged(conferenceInfo: TUIConferenceInfo, modifyFlag: TUIConferenceModifyFlag) {
|
||||
guard let store = self.store else { return }
|
||||
let currentList = store.selectCurrent(ConferenceListSelectors.getConferenceList)
|
||||
if let index = currentList.firstIndex(where: { $0.basicInfo.roomId == conferenceInfo.basicRoomInfo.roomId }) {
|
||||
var updateConference = currentList[index]
|
||||
if modifyFlag.contains(.roomName) {
|
||||
updateConference.basicInfo.name = conferenceInfo.basicRoomInfo.name
|
||||
}
|
||||
if modifyFlag.contains(.scheduleStartTime) || modifyFlag.contains(.scheduleEndTime) {
|
||||
updateConference.scheduleStartTime = conferenceInfo.scheduleStartTime
|
||||
updateConference.scheduleEndTime = conferenceInfo.scheduleEndTime
|
||||
updateConference.durationTime = conferenceInfo.scheduleEndTime - conferenceInfo.scheduleStartTime
|
||||
}
|
||||
store.dispatch(action: ConferenceListActions.onConferenceUpdated(payload: updateConference))
|
||||
}
|
||||
}
|
||||
|
||||
func onConferenceStatusChanged(roomId: String, status: TUIConferenceStatus) {
|
||||
guard let store = self.store else { return }
|
||||
let currentList = store.selectCurrent(ConferenceListSelectors.getConferenceList)
|
||||
if let index = currentList.firstIndex(where: { $0.basicInfo.roomId == roomId }) {
|
||||
var updateConference = currentList[index]
|
||||
updateConference.status = status
|
||||
store.dispatch(action: ConferenceListActions.onConferenceUpdated(payload: updateConference))
|
||||
}
|
||||
}
|
||||
|
||||
func onConferenceWillStart(conferenceInfo: TUIConferenceInfo) {
|
||||
|
||||
}
|
||||
|
||||
func onScheduleAttendeesChanged(roomId: String, leftUsers: [TUIUserInfo], joinedUsers: [TUIUserInfo]) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
23
TUIKit/TUIRoomKit/Source/Service/ErrorService.swift
Normal file
23
TUIKit/TUIRoomKit/Source/Service/ErrorService.swift
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// ErrorService.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by CY zhao on 2024/6/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RTCRoomEngine
|
||||
|
||||
struct RoomError: Error {
|
||||
let error: TUIError
|
||||
let message: String
|
||||
var actions: [Action] = []
|
||||
|
||||
init(error: TUIError, message: String = "", showToast: Bool = true) {
|
||||
self.error = error
|
||||
self.message = message
|
||||
if showToast {
|
||||
actions.append(ViewActions.showToast(payload: ToastInfo(message: message)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// InvitationObserverService.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by jeremiawang on 2024/8/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RTCRoomEngine
|
||||
import Factory
|
||||
|
||||
class InvitationObserverService: NSObject {
|
||||
static let shared = InvitationObserverService()
|
||||
private var invitationWindow: UIWindow?
|
||||
|
||||
private override init() {
|
||||
}
|
||||
|
||||
func showInvitationWindow(roomInfo: TUIRoomInfo, invitation: TUIInvitation) {
|
||||
DispatchQueue.main.async {
|
||||
let invitationViewController = ConferenceInvitationViewController(roomInfo: roomInfo, invitation: invitation)
|
||||
self.invitationWindow = UIWindow()
|
||||
self.invitationWindow?.windowLevel = .alert + 1
|
||||
self.invitationWindow?.rootViewController = invitationViewController
|
||||
self.invitationWindow?.isHidden = false
|
||||
self.invitationWindow?.t_makeKeyAndVisible()
|
||||
}
|
||||
}
|
||||
|
||||
func dismissInvitationWindow() {
|
||||
DispatchQueue.main.async {
|
||||
self.invitationWindow?.isHidden = true
|
||||
self.invitationWindow = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension InvitationObserverService: TUIConferenceInvitationObserver {
|
||||
func onReceiveInvitation(roomInfo: TUIRoomInfo, invitation: TUIInvitation, extensionInfo: String) {
|
||||
let store = Container.shared.conferenceStore()
|
||||
store.dispatch(action: ConferenceInvitationActions.onReceiveInvitation(payload: (roomInfo, invitation)))
|
||||
}
|
||||
|
||||
func onInvitationHandledByOtherDevice(roomInfo: TUIRoomInfo, accepted: Bool) {
|
||||
}
|
||||
|
||||
func onInvitationCancelled(roomInfo: TUIRoomInfo, invitation: TUIInvitation) {
|
||||
}
|
||||
|
||||
func onInvitationAccepted(roomInfo: TUIRoomInfo, invitation: TUIInvitation) {
|
||||
}
|
||||
|
||||
func onInvitationRejected(roomInfo: TUIRoomInfo, invitation: TUIInvitation, reason: TUIInvitationRejectedReason) {
|
||||
}
|
||||
|
||||
func onInvitationTimeout(roomInfo: TUIRoomInfo, invitation: TUIInvitation) {
|
||||
}
|
||||
|
||||
func onInvitationRevokedByAdmin(roomInfo: TUIRoomInfo, invitation: TUIInvitation, admin: TUIUserInfo) {
|
||||
}
|
||||
|
||||
func onInvitationAdded(roomId: String, invitation: TUIInvitation) {
|
||||
}
|
||||
|
||||
func onInvitationRemoved(roomId: String, invitation: TUIInvitation) {
|
||||
}
|
||||
|
||||
func onInvitationStatusChanged(roomId: String, invitation: TUIInvitation) {
|
||||
}
|
||||
}
|
||||
|
||||
extension UIWindow {
|
||||
public func t_makeKeyAndVisible() {
|
||||
if #available(iOS 13.0, *) {
|
||||
for windowScene in UIApplication.shared.connectedScenes {
|
||||
if windowScene.activationState == UIScene.ActivationState.foregroundActive ||
|
||||
windowScene.activationState == UIScene.ActivationState.background {
|
||||
self.windowScene = windowScene as? UIWindowScene
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
self.makeKeyAndVisible()
|
||||
}
|
||||
}
|
||||
37
TUIKit/TUIRoomKit/Source/Service/RoomService.swift
Normal file
37
TUIKit/TUIRoomKit/Source/Service/RoomService.swift
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// RoomService.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by CY zhao on 2024/7/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RTCRoomEngine
|
||||
import ImSDK_Plus
|
||||
import Combine
|
||||
|
||||
class RoomService {
|
||||
private let engineManager = EngineManager.shared
|
||||
|
||||
func enterRoom(roomId: String,
|
||||
options: TUIEnterRoomOptions? = nil,
|
||||
enableAudio: Bool,
|
||||
enableVideo: Bool,
|
||||
isSoundOnSpeaker: Bool) -> AnyPublisher<Void, RoomError> {
|
||||
return Future<Void, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
//TODO: use RTCRoomEngine directly
|
||||
self.engineManager.enterRoom(roomId: roomId,
|
||||
options: options,
|
||||
enableAudio: enableAudio,
|
||||
enableVideo: enableVideo,
|
||||
isSoundOnSpeaker: isSoundOnSpeaker) { roomInfo in
|
||||
promise(.success(()))
|
||||
} onError: { error, message in
|
||||
let error = RoomError(error: error, message: message)
|
||||
promise(.failure(error))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
22
TUIKit/TUIRoomKit/Source/Service/ServiceCenter.swift
Normal file
22
TUIKit/TUIRoomKit/Source/Service/ServiceCenter.swift
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// ServiceCenter.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by CY zhao on 2024/6/12.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Factory
|
||||
import RTCRoomEngine
|
||||
import Combine
|
||||
|
||||
class ServiceCenter: NSObject {
|
||||
@WeakLazyInjected(\.conferenceStore) var store: ConferenceStore?
|
||||
@WeakLazyInjected(\.navigation) var navigator: Route?
|
||||
|
||||
let userService = UserService()
|
||||
let conferenceListService = ConferenceListService()
|
||||
let roomService = RoomService()
|
||||
let conferenceInvitationService = ConferenceInvitationService()
|
||||
}
|
||||
|
||||
34
TUIKit/TUIRoomKit/Source/Service/UserService.swift
Normal file
34
TUIKit/TUIRoomKit/Source/Service/UserService.swift
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// UserService.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by CY zhao on 2024/6/13.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RTCRoomEngine
|
||||
import ImSDK_Plus
|
||||
import Combine
|
||||
|
||||
class UserService {
|
||||
private let engine = TUIRoomEngine.sharedInstance()
|
||||
private let imManager = V2TIMManager.sharedInstance()
|
||||
|
||||
func fetchUserInfo(_ userId: String) -> AnyPublisher<UserInfo, RoomError> {
|
||||
return Future<UserInfo, RoomError> { [weak self] promise in
|
||||
guard let self = self else { return }
|
||||
self.engine.getUserInfo(userId) { userInfo in
|
||||
if let user = userInfo {
|
||||
promise(.success(UserInfo(userInfo: user)))
|
||||
} else {
|
||||
let error = RoomError(error: TUIError.userNotExist)
|
||||
promise(.failure(error))
|
||||
}
|
||||
} onError: { err, message in
|
||||
let error = RoomError(error: err, message: message, showToast: false)
|
||||
promise(.failure(error))
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user