From 298c02b83f80b121695e240aba5fcf5279373e17 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Fri, 6 Mar 2026 17:46:26 +0900 Subject: [PATCH] =?UTF-8?q?feat(live):=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=EB=A5=BC=20=EC=A0=84=EC=97=AD=20=EB=B0=94?= =?UTF-8?q?=ED=85=80=EC=8B=9C=ED=8A=B8=EB=A1=9C=20=ED=91=9C=EC=8B=9C?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SodaLive/Sources/App/AppState.swift | 33 +++++++++++++++++++ SodaLive/Sources/ContentView.swift | 15 +++++++++ .../Live/Room/Detail/LiveDetailView.swift | 2 +- docs/20260306_라이브상세바텀시트표시.md | 30 +++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 docs/20260306_라이브상세바텀시트표시.md diff --git a/SodaLive/Sources/App/AppState.swift b/SodaLive/Sources/App/AppState.swift index 1b1979f..35ee724 100644 --- a/SodaLive/Sources/App/AppState.swift +++ b/SodaLive/Sources/App/AppState.swift @@ -11,6 +11,14 @@ 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() @@ -62,6 +70,7 @@ class AppState: ObservableObject { @Published var isShowErrorPopup = false @Published var errorMessage = "" + @Published var liveDetailSheet: LiveDetailSheetState? = nil private func syncStepWithNavigationPath() { let validRoutes = Set(navigationPath) @@ -83,10 +92,21 @@ class AppState: ObservableObject { 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() @@ -99,6 +119,12 @@ class AppState: ObservableObject { 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 @@ -108,6 +134,13 @@ class AppState: ObservableObject { _ = self.navigationPath.popLast() } } + + func hideLiveDetailSheet() { + DispatchQueue.main.async { + self.liveDetailSheet = nil + self.syncStepWithNavigationPath() + } + } // 언어 적용 직후 앱을 소프트 재시작(스플래시 -> 메인)하여 전역 UI를 새로고침 func softRestart() { diff --git a/SodaLive/Sources/ContentView.swift b/SodaLive/Sources/ContentView.swift index c4b1efa..a952cab 100644 --- a/SodaLive/Sources/ContentView.swift +++ b/SodaLive/Sources/ContentView.swift @@ -30,6 +30,21 @@ struct ContentView: View { .navigationBarBackButtonHidden(true) } + if let liveDetailSheet = appState.liveDetailSheet { + LiveDetailView( + roomId: liveDetailSheet.roomId, + onClickParticipant: liveDetailSheet.onClickParticipant, + onClickReservation: liveDetailSheet.onClickReservation, + onClickStart: liveDetailSheet.onClickStart, + onClickCancel: liveDetailSheet.onClickCancel, + onClickClose: { + withAnimation { + appState.hideLiveDetailSheet() + } + } + ) + } + if isShowDialog { SodaDialog( title: I18n.Common.pointGrantTitle, diff --git a/SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift b/SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift index b938ac8..6236754 100644 --- a/SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift +++ b/SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift @@ -33,7 +33,7 @@ struct LiveDetailView: View { var onClickClose: (() -> Void)? = nil var body: some View { - BaseView(isLoading: $viewModel.isLoading) { + ZStack { Color.black.opacity(0.7) .onTapGesture { viewModel.onBack { diff --git a/docs/20260306_라이브상세바텀시트표시.md b/docs/20260306_라이브상세바텀시트표시.md new file mode 100644 index 0000000..db0e54a --- /dev/null +++ b/docs/20260306_라이브상세바텀시트표시.md @@ -0,0 +1,30 @@ +# 20260306 라이브 상세 바텀시트 표시 전환 + +## 작업 체크리스트 +- [x] LiveDetailView 진입 경로(현재 페이지 이동 방식) 확인 +- [x] LiveDetailView를 BottomSheet로 표시하도록 화면 전환 로직 수정 +- [x] 영향 범위 컴파일/진단 확인 + +## 검증 기록 +- 2026-03-06 / LiveDetailView 표시 방식 전환 검증 + - 무엇: `AppState`의 `.liveDetail` 처리에서 네비게이션 푸시 대신 전역 BottomSheet 상태(`liveDetailSheet`)를 사용하도록 변경하고, `ContentView`에서 해당 상태를 감지해 `LiveDetailView`를 오버레이 표시하도록 반영. + - 왜: `LiveDetailView` 진입 시 페이지 이동(push) 없이 동일 화면 맥락에서 바텀시트로 표시하기 위함. + - 어떻게: + - `lsp_diagnostics` 실행: `SodaLive/Sources/App/AppState.swift`, `SodaLive/Sources/ContentView.swift` + - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build` + - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test` + - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` + - 결과: + - `xcodebuild` 빌드: `SodaLive`, `SodaLive-dev` 모두 `** BUILD SUCCEEDED **` + - `xcodebuild test`: `Scheme SodaLive is not currently configured for the test action.`로 테스트 실행 불가 + - `lsp_diagnostics`: 현재 SourceKit 컨텍스트에서 프로젝트 타입 해석 실패로 다수 심볼 미해결 오류가 표시되어, 최종 검증은 실제 `xcodebuild` 결과 기준으로 확인 + +- 2026-03-06 / LiveDetailView 배경 dim 표시 보정 + - 무엇: `LiveDetailView`의 루트 컨테이너를 `BaseView`에서 `ZStack`으로 변경하여 전체 검정 배경 고정 레이어를 제거. + - 왜: 오버레이 표시 시 현재 화면이 완전히 검정으로 가려지는 문제를 제거하고, 현재 화면 위에 dim 레이어가 덮이는 형태로 보이게 하기 위함. + - 어떻게: + - `lsp_diagnostics` 실행: `SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift` + - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build` + - 결과: + - `xcodebuild` 빌드: `SodaLive` `** BUILD SUCCEEDED **` + - `lsp_diagnostics`: 현재 SourceKit 컨텍스트에서 `Kingfisher` 모듈 인식 실패(`No such module 'Kingfisher'`)가 표시되나, 실제 빌드는 정상 통과