diff --git a/Data/Data/BrowsingUserRepository.swift b/Data/Data/BrowsingUserRepository.swift index a563f6e4..0721c1dc 100644 --- a/Data/Data/BrowsingUserRepository.swift +++ b/Data/Data/BrowsingUserRepository.swift @@ -7,6 +7,7 @@ import Combine import Entity +import Foundation import Interfaces import P2PSocket @@ -16,6 +17,7 @@ public final class BrowsingUserRepository: BrowsingUserRepositoryInterface { public let updatedBrowsingUser = PassthroughSubject() public let updatedInvitedUser = PassthroughSubject() public let invitationReceived = PassthroughSubject() + public let receivedEvent = PassthroughSubject() public init(socketProvider: SocketProvidable) { self.socketProvider = socketProvider @@ -50,6 +52,12 @@ public extension BrowsingUserRepository { func stopReceiveInvitation() { socketProvider.stopReceiveInvitation() } + + func notice(event: OpeningEvent) { + let event = OpeningEvent.sharedContainer + guard let eventData = try? JSONEncoder().encode(event) else { return } + socketProvider.sendAll(data: eventData) + } } // MARK: - Private Methods @@ -75,6 +83,13 @@ private extension BrowsingUserRepository { } .subscribe(invitationReceived) .store(in: &cancellables) + + socketProvider.dataShared + .compactMap { (data, _) in + try? JSONDecoder().decode(OpeningEvent.self, from: data) + }.sink { [weak self] event in + self?.receivedEvent.send(event) + }.store(in: &cancellables) } func mappingToBrowsingUser(_ peer: SocketPeer) -> BrowsedUser? { diff --git a/Domain/Domain.xcodeproj/project.pbxproj b/Domain/Domain.xcodeproj/project.pbxproj index 5da35bb4..9ca80304 100644 --- a/Domain/Domain.xcodeproj/project.pbxproj +++ b/Domain/Domain.xcodeproj/project.pbxproj @@ -123,7 +123,6 @@ BrowsingUserUseCase.swift, ConnectedUserUseCase.swift, VideoUseCase.swift, - ); target = FE6EF3C62CD8B5CA005DC39D /* UseCase */; }; diff --git a/Domain/Entity/OpeningEvent.swift b/Domain/Entity/OpeningEvent.swift new file mode 100644 index 00000000..cf0a09fc --- /dev/null +++ b/Domain/Entity/OpeningEvent.swift @@ -0,0 +1,10 @@ +// +// Event.swift +// Entity +// +// Created by Yune gim on 12/2/24. +// + +public enum OpeningEvent: Codable { + case sharedContainer +} diff --git a/Domain/Interfaces/RepositoryInterface/BrowsingUserRepositoryInterface.swift b/Domain/Interfaces/RepositoryInterface/BrowsingUserRepositoryInterface.swift index d143de02..691bc458 100644 --- a/Domain/Interfaces/RepositoryInterface/BrowsingUserRepositoryInterface.swift +++ b/Domain/Interfaces/RepositoryInterface/BrowsingUserRepositoryInterface.swift @@ -12,11 +12,13 @@ public protocol BrowsingUserRepositoryInterface { var updatedBrowsingUser: PassthroughSubject { get } var updatedInvitedUser: PassthroughSubject { get } var invitationReceived: PassthroughSubject { get } - + var receivedEvent: PassthroughSubject { get } + func fetchBrowsingUsers() -> [BrowsedUser] func inviteUser(with id: String, timeout: Double) func acceptInvitation() func rejectInvitation() func startReceiveInvitation() func stopReceiveInvitation() + func notice(event: OpeningEvent) } diff --git a/Domain/Interfaces/UseCaseInterface/BrowsingUserUseCaseInterface.swift b/Domain/Interfaces/UseCaseInterface/BrowsingUserUseCaseInterface.swift index 54e05c81..6466b5e2 100644 --- a/Domain/Interfaces/UseCaseInterface/BrowsingUserUseCaseInterface.swift +++ b/Domain/Interfaces/UseCaseInterface/BrowsingUserUseCaseInterface.swift @@ -17,6 +17,8 @@ public protocol BrowsingUserUseCaseInterface { var invitationReceived: PassthroughSubject { get } /// 초대를 받은 유저가, 초대 시간이 만료되었을 때 stream을 통해 이벤트가 방출됩니다. 초대받은 유저만 이벤트를 받습니다. 초대한 유저의 경우 timeout은 reject이벤트로 옵니다. var invitationDidFired: PassthroughSubject { get } + /// 공유 컨테이너로 화면 전환을 알리는 이벤트를 방출합니다. + var openingEvent: PassthroughSubject { get } init(repository: BrowsingUserRepositoryInterface, invitationTimeout: Double) @@ -24,4 +26,5 @@ public protocol BrowsingUserUseCaseInterface { func inviteUser(with id: String) func acceptInvitation() func rejectInvitation() + func noticeOpening() } diff --git a/Domain/UseCase/BrowsingUserUseCase.swift b/Domain/UseCase/BrowsingUserUseCase.swift index 86af938a..7c815b4d 100644 --- a/Domain/UseCase/BrowsingUserUseCase.swift +++ b/Domain/UseCase/BrowsingUserUseCase.swift @@ -24,6 +24,7 @@ public final class BrowsingUserUseCase: BrowsingUserUseCaseInterface { public let invitationResult = PassthroughSubject() public let invitationReceived = PassthroughSubject() public let invitationDidFired = PassthroughSubject() + public var openingEvent = PassthroughSubject() public init(repository: BrowsingUserRepositoryInterface, invitationTimeout: Double = 30.0) { self.repository = repository @@ -57,6 +58,11 @@ public extension BrowsingUserUseCase { repository.startReceiveInvitation() repository.rejectInvitation() } + + func noticeOpening() { + repository.notice(event: OpeningEvent.sharedContainer) + openingEvent.send() + } } // MARK: - Private Methods @@ -79,6 +85,12 @@ private extension BrowsingUserUseCase { self?.invitationDidReceive(from: user) } .store(in: &cancellables) + repository.receivedEvent + .sink { [weak self] event in + guard event == .sharedContainer else { return } + self?.openingEvent.send() + } + .store(in: &cancellables) } func receivedBrowsedUser(_ user: BrowsedUser) { diff --git a/Feature/Feature/ConnectionView/ConnectionViewController.swift b/Feature/Feature/ConnectionView/ConnectionViewController.swift index 714c6bc4..164266d2 100644 --- a/Feature/Feature/ConnectionView/ConnectionViewController.swift +++ b/Feature/Feature/ConnectionView/ConnectionViewController.swift @@ -124,6 +124,8 @@ extension ConnectionViewController { present(UIAlertController( type: .invitationTimeout, actions: [.confirm(), .cancel()]), animated: true) + case .openSharedVideoList: + openVideoList() } } .store(in: &cancellables) @@ -152,10 +154,7 @@ private extension ConnectionViewController { } func nextButtonDidTapped() { - let videoListViewController = VideoListViewController( - viewModel: DIContainer.shared.resolve(type: MultipeerVideoListViewModel.self) - ) - self.navigationController?.pushViewController(videoListViewController, animated: true) + input.send(.nextButtonDidTapped) } } @@ -206,6 +205,14 @@ private extension ConnectionViewController { func resetCurrentUserId() { currentUserId = nil } + + func openVideoList() { + let videoListViewController = VideoListViewController( + viewModel: DIContainer.shared.resolve(type: MultipeerVideoListViewModel.self) + ) + guard navigationController?.viewControllers.last === self else { return } + self.navigationController?.pushViewController(videoListViewController, animated: true) + } } // MARK: - UI Configure diff --git a/Feature/Feature/ConnectionView/ViewModel/ConnectionViewInputOutput.swift b/Feature/Feature/ConnectionView/ViewModel/ConnectionViewInputOutput.swift index 13dfb0d9..531460da 100644 --- a/Feature/Feature/ConnectionView/ViewModel/ConnectionViewInputOutput.swift +++ b/Feature/Feature/ConnectionView/ViewModel/ConnectionViewInputOutput.swift @@ -20,6 +20,7 @@ enum ConnectionViewInput { case acceptInvitation(user: BrowsedUser) case rejectInvitation + case nextButtonDidTapped } // MARK: - Output @@ -36,4 +37,5 @@ enum ConnectionViewOutput { case invitationAcceptedBy(user: BrowsedUser) case invitationRejectedBy(name: String) case invitationTimeout + case openSharedVideoList } diff --git a/Feature/Feature/ConnectionView/ViewModel/ConnectionViewModel.swift b/Feature/Feature/ConnectionView/ViewModel/ConnectionViewModel.swift index 7cf109c1..6046ffe0 100644 --- a/Feature/Feature/ConnectionView/ViewModel/ConnectionViewModel.swift +++ b/Feature/Feature/ConnectionView/ViewModel/ConnectionViewModel.swift @@ -72,6 +72,8 @@ extension ConnectionViewModel { removeCurrentPosition(id: user.id) case .rejectInvitation: usecase.rejectInvitation() + case .nextButtonDidTapped: + usecase.noticeOpening() } } .store(in: &cancellables) @@ -138,6 +140,13 @@ private extension ConnectionViewModel { usecase.rejectInvitation() } .store(in: &cancellables) + + usecase.openingEvent + .sink { [weak self] in + guard let self else { return } + output.send(.openSharedVideoList) + } + .store(in: &cancellables) } }