feat(creator): 플로팅 액션 진입을 연결한다
This commit is contained in:
@@ -62,7 +62,7 @@ enum AppStep {
|
|||||||
|
|
||||||
case serviceCenter
|
case serviceCenter
|
||||||
|
|
||||||
case createContent
|
case createContent(onSuccess: (() -> Void)? = nil)
|
||||||
|
|
||||||
case modifyContent(contentId: Int)
|
case modifyContent(contentId: Int)
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ struct ContentListView: View {
|
|||||||
.cornerRadius(5.3)
|
.cornerRadius(5.3)
|
||||||
.padding(.top, 13.3)
|
.padding(.top, 13.3)
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
.onTapGesture { AppState.shared.setAppStep(step: .createContent) }
|
.onTapGesture { AppState.shared.setAppStep(step: .createContent()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
HStack(spacing: 13.3) {
|
HStack(spacing: 13.3) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import Kingfisher
|
|||||||
|
|
||||||
struct ContentCreateView: View {
|
struct ContentCreateView: View {
|
||||||
@Environment(\.locale) private var locale
|
@Environment(\.locale) private var locale
|
||||||
|
let onSuccess: (() -> Void)?
|
||||||
|
|
||||||
@StateObject var keyboardHandler = KeyboardHandler()
|
@StateObject var keyboardHandler = KeyboardHandler()
|
||||||
@StateObject private var viewModel = ContentCreateViewModel()
|
@StateObject private var viewModel = ContentCreateViewModel()
|
||||||
@@ -24,6 +25,10 @@ struct ContentCreateView: View {
|
|||||||
@State private var isShowSelectDateView = false
|
@State private var isShowSelectDateView = false
|
||||||
@State private var isShowSelectTimeView = false
|
@State private var isShowSelectTimeView = false
|
||||||
|
|
||||||
|
init(onSuccess: (() -> Void)? = nil) {
|
||||||
|
self.onSuccess = onSuccess
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let normalizedCountryCode = UserDefaults
|
let normalizedCountryCode = UserDefaults
|
||||||
.string(forKey: .countryCode)
|
.string(forKey: .countryCode)
|
||||||
@@ -655,7 +660,10 @@ struct ContentCreateView: View {
|
|||||||
title: I18n.CreateContent.uploadTitle,
|
title: I18n.CreateContent.uploadTitle,
|
||||||
desc: I18n.CreateContent.uploadDescription,
|
desc: I18n.CreateContent.uploadDescription,
|
||||||
confirmButtonTitle: I18n.Common.confirm,
|
confirmButtonTitle: I18n.Common.confirm,
|
||||||
confirmButtonAction: { AppState.shared.back() },
|
confirmButtonAction: {
|
||||||
|
onSuccess?()
|
||||||
|
AppState.shared.back()
|
||||||
|
},
|
||||||
cancelButtonTitle: "",
|
cancelButtonTitle: "",
|
||||||
cancelButtonAction: {}
|
cancelButtonAction: {}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -162,8 +162,8 @@ struct AppStepLayerView: View {
|
|||||||
case .serviceCenter:
|
case .serviceCenter:
|
||||||
ServiceCenterView()
|
ServiceCenterView()
|
||||||
|
|
||||||
case .createContent:
|
case .createContent(let onSuccess):
|
||||||
ContentCreateView()
|
ContentCreateView(onSuccess: onSuccess)
|
||||||
|
|
||||||
case .liveReservationComplete(let response):
|
case .liveReservationComplete(let response):
|
||||||
LiveReservationCompleteView(reservationCompleteData: response)
|
LiveReservationCompleteView(reservationCompleteData: response)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ struct UserProfileContentView: View {
|
|||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.background(Color.button)
|
.background(Color.button)
|
||||||
.cornerRadius(12)
|
.cornerRadius(12)
|
||||||
.onTapGesture { AppState.shared.setAppStep(step: .createContent) }
|
.onTapGesture { AppState.shared.setAppStep(step: .createContent()) }
|
||||||
} else {
|
} else {
|
||||||
collectionInfoView()
|
collectionInfoView()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ struct HomeTabView: View {
|
|||||||
.padding(.trailing, 16.7)
|
.padding(.trailing, 16.7)
|
||||||
.padding(.bottom, 16.7)
|
.padding(.bottom, 16.7)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
AppState.shared.setAppStep(step: .createContent)
|
AppState.shared.setAppStep(step: .createContent())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ struct CreatorChannelFloatingActionMenu: View {
|
|||||||
.padding(.bottom, SodaSpacing.s32)
|
.padding(.bottom, SodaSpacing.s32)
|
||||||
.animation(animation, value: isPresented)
|
.animation(animation, value: isPresented)
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func floatingButton(
|
private func floatingButton(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ struct CreatorChannelView: View {
|
|||||||
|
|
||||||
@StateObject private var viewModel = CreatorChannelViewModel()
|
@StateObject private var viewModel = CreatorChannelViewModel()
|
||||||
@StateObject private var channelDonationViewModel = ChannelDonationViewModel()
|
@StateObject private var channelDonationViewModel = ChannelDonationViewModel()
|
||||||
|
@StateObject private var liveViewModel = LiveViewModel()
|
||||||
@StateObject private var mypageViewModel = MyPageViewModel()
|
@StateObject private var mypageViewModel = MyPageViewModel()
|
||||||
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
|
@AppStorage("token") private var token: String = UserDefaults.string(forKey: UserDefaultsKey.token)
|
||||||
@AppStorage("auth") private var auth: Bool = UserDefaults.bool(forKey: UserDefaultsKey.auth)
|
@AppStorage("auth") private var auth: Bool = UserDefaults.bool(forKey: UserDefaultsKey.auth)
|
||||||
@@ -15,6 +16,7 @@ struct CreatorChannelView: View {
|
|||||||
@State private var isShowChannelDonationDialog = false
|
@State private var isShowChannelDonationDialog = false
|
||||||
@State private var isShowAuthView = false
|
@State private var isShowAuthView = false
|
||||||
@State private var isShowAuthConfirmView = false
|
@State private var isShowAuthConfirmView = false
|
||||||
|
@State private var isCreatorActionMenuPresented = false
|
||||||
@State private var pendingAction: (() -> Void)? = nil
|
@State private var pendingAction: (() -> Void)? = nil
|
||||||
@State private var payload = Payload()
|
@State private var payload = Payload()
|
||||||
|
|
||||||
@@ -84,6 +86,15 @@ struct CreatorChannelView: View {
|
|||||||
LoadingView()
|
LoadingView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isOwnCreatorChannel && viewModel.selectedTab == .home && !viewModel.isLoading {
|
||||||
|
CreatorChannelFloatingActionMenu(
|
||||||
|
isPresented: $isCreatorActionMenuPresented,
|
||||||
|
onTapCommunityPost: showCommunityWrite,
|
||||||
|
onTapAudioContent: showAudioContentUpload,
|
||||||
|
onTapCreateLive: showCreateLive
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if isShowAuthConfirmView {
|
if isShowAuthConfirmView {
|
||||||
authConfirmDialog
|
authConfirmDialog
|
||||||
}
|
}
|
||||||
@@ -123,6 +134,11 @@ struct CreatorChannelView: View {
|
|||||||
}
|
}
|
||||||
.sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 1)
|
.sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 1)
|
||||||
.sodaToast(isPresented: $channelDonationViewModel.isShowPopup, message: channelDonationViewModel.errorMessage, autohideIn: 2)
|
.sodaToast(isPresented: $channelDonationViewModel.isShowPopup, message: channelDonationViewModel.errorMessage, autohideIn: 2)
|
||||||
|
.onChange(of: viewModel.selectedTab) { selectedTab in
|
||||||
|
if selectedTab != .home {
|
||||||
|
isCreatorActionMenuPresented = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func titleBar(backgroundProgress: CGFloat) -> some View {
|
private func titleBar(backgroundProgress: CGFloat) -> some View {
|
||||||
@@ -289,6 +305,37 @@ struct CreatorChannelView: View {
|
|||||||
AppState.shared.setAppStep(step: .creatorCommunityAll(creatorId: creatorId))
|
AppState.shared.setAppStep(step: .creatorCommunityAll(creatorId: creatorId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func showCommunityWrite() {
|
||||||
|
isCreatorActionMenuPresented = false
|
||||||
|
AppState.shared.setAppStep(
|
||||||
|
step: .creatorCommunityWrite(onSuccess: {
|
||||||
|
viewModel.fetchHome(creatorId: creatorId)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showAudioContentUpload() {
|
||||||
|
isCreatorActionMenuPresented = false
|
||||||
|
AppState.shared.setAppStep(
|
||||||
|
step: .createContent(onSuccess: {
|
||||||
|
viewModel.fetchHome(creatorId: creatorId)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showCreateLive() {
|
||||||
|
isCreatorActionMenuPresented = false
|
||||||
|
AppState.shared.setAppStep(step: .createLive(timeSettingMode: .NOW, onSuccess: handleCreateLiveSuccess))
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleCreateLiveSuccess(response: CreateLiveRoomResponse) {
|
||||||
|
liveViewModel.getLiveMain()
|
||||||
|
if let _ = response.channelName {
|
||||||
|
liveViewModel.enterRoom(roomId: response.id!)
|
||||||
|
}
|
||||||
|
viewModel.fetchHome(creatorId: creatorId)
|
||||||
|
}
|
||||||
|
|
||||||
private func handleScheduleTap(type: CreatorActivityType, targetId: Int) {
|
private func handleScheduleTap(type: CreatorActivityType, targetId: Int) {
|
||||||
guard targetId > 0 else { return }
|
guard targetId > 0 else { return }
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@
|
|||||||
|
|
||||||
### Phase 3: CreatorChannelView overlay 연결과 액션 라우팅
|
### Phase 3: CreatorChannelView overlay 연결과 액션 라우팅
|
||||||
|
|
||||||
- [ ] **Task 3.1: floating menu 표시 상태 연결**
|
- [x] **Task 3.1: floating menu 표시 상태 연결**
|
||||||
- 대상 파일:
|
- 대상 파일:
|
||||||
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
||||||
- 작업 내용:
|
- 작업 내용:
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
- 실행 명령: `rg "isCreatorActionMenuPresented|CreatorChannelFloatingActionMenu|isOwnCreatorChannel && viewModel\\.selectedTab == \\.home" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
- 실행 명령: `rg "isCreatorActionMenuPresented|CreatorChannelFloatingActionMenu|isOwnCreatorChannel && viewModel\\.selectedTab == \\.home" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
||||||
- 기대 결과: 본인 채널 홈 탭에서만 floating menu가 연결된다.
|
- 기대 결과: 본인 채널 홈 탭에서만 floating menu가 연결된다.
|
||||||
|
|
||||||
- [ ] **Task 3.2: 오디오 콘텐츠 업로드 성공 callback 확장**
|
- [x] **Task 3.2: 오디오 콘텐츠 업로드 성공 callback 확장**
|
||||||
- 대상 파일:
|
- 대상 파일:
|
||||||
- 수정: `SodaLive/Sources/App/AppStep.swift`
|
- 수정: `SodaLive/Sources/App/AppStep.swift`
|
||||||
- 수정: `SodaLive/Sources/ContentView.swift`
|
- 수정: `SodaLive/Sources/ContentView.swift`
|
||||||
@@ -157,7 +157,7 @@
|
|||||||
- 실행 명령: `rg "createContent|ContentCreateView\\(|onSuccess|isShowCompletePopup|AppState\\.shared\\.back\\(\\)" SodaLive/Sources/App/AppStep.swift SodaLive/Sources/ContentView.swift SodaLive/Sources/Content/Create/ContentCreateView.swift`
|
- 실행 명령: `rg "createContent|ContentCreateView\\(|onSuccess|isShowCompletePopup|AppState\\.shared\\.back\\(\\)" SodaLive/Sources/App/AppStep.swift SodaLive/Sources/ContentView.swift SodaLive/Sources/Content/Create/ContentCreateView.swift`
|
||||||
- 기대 결과: 기존 create content 진입은 유지되고, 업로드 성공 callback 전달과 호출 지점이 확인된다.
|
- 기대 결과: 기존 create content 진입은 유지되고, 업로드 성공 callback 전달과 호출 지점이 확인된다.
|
||||||
|
|
||||||
- [ ] **Task 3.3: 커뮤니티 글 올리기 액션 연결**
|
- [x] **Task 3.3: 커뮤니티 글 올리기 액션 연결**
|
||||||
- 대상 파일:
|
- 대상 파일:
|
||||||
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
||||||
- 확인: `SodaLive/Sources/App/AppStep.swift`
|
- 확인: `SodaLive/Sources/App/AppStep.swift`
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
- 실행 명령: `rg "showCommunityWrite|creatorCommunityWrite\\(onSuccess:|fetchHome\\(creatorId: creatorId\\)" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
- 실행 명령: `rg "showCommunityWrite|creatorCommunityWrite\\(onSuccess:|fetchHome\\(creatorId: creatorId\\)" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
||||||
- 기대 결과: 커뮤니티 글 작성 진입과 작성 성공 후 홈 갱신이 확인된다.
|
- 기대 결과: 커뮤니티 글 작성 진입과 작성 성공 후 홈 갱신이 확인된다.
|
||||||
|
|
||||||
- [ ] **Task 3.4: 오디오 콘텐츠 올리기 액션 연결**
|
- [x] **Task 3.4: 오디오 콘텐츠 올리기 액션 연결**
|
||||||
- 대상 파일:
|
- 대상 파일:
|
||||||
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
||||||
- 확인: `SodaLive/Sources/App/AppStep.swift`
|
- 확인: `SodaLive/Sources/App/AppStep.swift`
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
- 실행 명령: `rg "showAudioContentUpload|createContent\\(onSuccess:|fetchHome\\(creatorId: creatorId\\)" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
- 실행 명령: `rg "showAudioContentUpload|createContent\\(onSuccess:|fetchHome\\(creatorId: creatorId\\)" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
||||||
- 기대 결과: 오디오 콘텐츠 업로드 진입과 업로드 성공 후 홈 갱신 연결이 확인된다.
|
- 기대 결과: 오디오 콘텐츠 업로드 진입과 업로드 성공 후 홈 갱신 연결이 확인된다.
|
||||||
|
|
||||||
- [ ] **Task 3.5: 라이브 만들기 액션 연결**
|
- [x] **Task 3.5: 라이브 만들기 액션 연결**
|
||||||
- 대상 파일:
|
- 대상 파일:
|
||||||
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
|
||||||
- 확인: `SodaLive/Sources/Live/LiveView.swift`
|
- 확인: `SodaLive/Sources/Live/LiveView.swift`
|
||||||
@@ -242,3 +242,4 @@
|
|||||||
- 2026-07-03: 문서 작성 단계. 구현/빌드 검증은 아직 수행하지 않음.
|
- 2026-07-03: 문서 작성 단계. 구현/빌드 검증은 아직 수행하지 않음.
|
||||||
- 2026-07-03: Open Questions 결정 사항을 반영함. `ic_plus_no_bg`, 기존 `AppStep.createContent`, 기존 `LiveView.onCreateSuccess` 동일 처리, 커뮤니티/오디오 성공 후 홈 갱신 기준을 문서화함.
|
- 2026-07-03: Open Questions 결정 사항을 반영함. `ic_plus_no_bg`, 기존 `AppStep.createContent`, 기존 `LiveView.onCreateSuccess` 동일 처리, 커뮤니티/오디오 성공 후 홈 갱신 기준을 문서화함.
|
||||||
- 2026-07-03: Phase 1, 2 구현 완료. 계획서의 Task 1.1~2.3 `rg` 검증을 수행했고, `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 성공을 확인함. 자동화 테스트 타깃은 `rg "Tests|XCTest|testTarget|PBXNativeTarget.*Tests|\.xctest|unit test|swift test" "SodaLive.xcodeproj" "SodaLive"` 검색 결과 확인되지 않아 별도 RED/GREEN 테스트는 추가하지 않음.
|
- 2026-07-03: Phase 1, 2 구현 완료. 계획서의 Task 1.1~2.3 `rg` 검증을 수행했고, `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 성공을 확인함. 자동화 테스트 타깃은 `rg "Tests|XCTest|testTarget|PBXNativeTarget.*Tests|\.xctest|unit test|swift test" "SodaLive.xcodeproj" "SodaLive"` 검색 결과 확인되지 않아 별도 RED/GREEN 테스트는 추가하지 않음.
|
||||||
|
- 2026-07-03: Phase 3 구현 완료. Task 3.1~3.5 `rg` 검증을 수행했고, `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 성공을 확인함. 자동화 테스트 타깃 부재로 별도 RED/GREEN 테스트는 추가하지 않았으며, 실제 화면 수동 검증은 Phase 4.3에 남김.
|
||||||
|
|||||||
Reference in New Issue
Block a user