// // AppState.swift // SodaLive // // Created by klaus on 2023/08/09. // import Foundation struct AppRoute: Hashable { let id = UUID() } struct LiveDetailSheetState { let roomId: Int let onClickParticipant: () -> Void let onClickReservation: () -> Void let onClickStart: () -> Void let onClickCancel: () -> Void } class AppState: ObservableObject { static let shared = AppState() private var routeStepMap: [AppRoute: AppStep] = [:] @Published var alreadyUpdatedMarketingInfo = false @Published private(set) var appStep: AppStep = .splash @Published private(set) var rootStep: AppStep = .splash @Published var navigationPath: [AppRoute] = [] { didSet { syncStepWithNavigationPath() } } @Published var isShowPlayer = false { didSet { if isShowPlayer { ContentPlayManager.shared.stopAudio() ContentPlayerPlayManager.shared.resetPlayer() } } } @Published var isShowNotificationSettingsDialog = false @Published var pushRoomId = 0 @Published var pushChannelId = 0 @Published var pushMessageId = 0 @Published var pushAudioContentId = 0 @Published var pushSeriesId = 0 @Published var pendingDeepLinkAction: AppDeepLinkAction? = nil @Published var pendingCommunityCommentCreatorId = 0 @Published var pendingCommunityCommentPostId = 0 @Published var isPushRoomFromDeepLink = false @Published var roomId = 0 { didSet { if roomId <= 0 { isShowPlayer = false } } } @Published var eventPopup: EventItem? = nil @Published var purchasedContentId = 0 @Published var purchasedContentOrderType = OrderType.KEEP @Published var isRestartApp = false @Published var startTab: HomeViewModel.CurrentTab = .home @Published var marketingUtmSource = "" @Published var marketingUtmMedium = "" @Published var marketingUtmCampaign = "" @Published var isShowErrorPopup = false @Published var errorMessage = "" @Published var liveDetailSheet: LiveDetailSheetState? = nil private func syncStepWithNavigationPath() { let validRoutes = Set(navigationPath) routeStepMap = routeStepMap.filter { validRoutes.contains($0.key) } if let route = navigationPath.last, let step = routeStepMap[route] { appStep = step } else { appStep = rootStep } } func appStep(for route: AppRoute) -> AppStep? { routeStepMap[route] } func setAppStep(step: AppStep) { DispatchQueue.main.async { switch step { case .splash, .main: self.liveDetailSheet = nil self.rootStep = step self.routeStepMap.removeAll() self.navigationPath.removeAll() self.appStep = step case .liveDetail(let roomId, let onClickParticipant, let onClickReservation, let onClickStart, let onClickCancel): self.liveDetailSheet = LiveDetailSheetState( roomId: roomId, onClickParticipant: onClickParticipant, onClickReservation: onClickReservation, onClickStart: onClickStart, onClickCancel: onClickCancel ) self.appStep = step default: let route = AppRoute() self.routeStepMap[route] = step self.navigationPath.append(route) self.appStep = step } } } func back() { DispatchQueue.main.async { if self.liveDetailSheet != nil { self.liveDetailSheet = nil self.syncStepWithNavigationPath() return } if self.navigationPath.isEmpty { self.rootStep = .main self.appStep = .main return } _ = self.navigationPath.popLast() } } func hideLiveDetailSheet() { DispatchQueue.main.async { self.liveDetailSheet = nil self.syncStepWithNavigationPath() } } func consumePendingDeepLinkAction() -> AppDeepLinkAction? { let action = pendingDeepLinkAction pendingDeepLinkAction = nil return action } func setPendingCommunityCommentDeepLink(creatorId: Int, postId: Int) { guard creatorId > 0, postId > 0 else { return } pendingCommunityCommentCreatorId = creatorId pendingCommunityCommentPostId = postId } func consumePendingCommunityCommentPostId(creatorId: Int) -> Int? { guard creatorId > 0 else { return nil } guard pendingCommunityCommentCreatorId == creatorId, pendingCommunityCommentPostId > 0 else { return nil } let postId = pendingCommunityCommentPostId clearPendingCommunityCommentDeepLink() return postId } func clearPendingCommunityCommentDeepLink() { pendingCommunityCommentCreatorId = 0 pendingCommunityCommentPostId = 0 } // 언어 적용 직후 앱을 소프트 재시작(스플래시 -> 메인)하여 전역 UI를 새로고침 func softRestart() { isRestartApp = true setAppStep(step: .splash) DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.setAppStep(step: .main) } } }