feat(main): 생성 메뉴를 홈에 추가한다

This commit is contained in:
Yu Sung
2026-07-20 19:14:02 +09:00
parent 9a0e75a391
commit 70af4923c6
6 changed files with 213 additions and 12 deletions

View File

@@ -1880,7 +1880,7 @@
CC01011F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift */; }; CC01011F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift */; };
CC0101272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift */; }; CC0101272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift */; };
CC0101282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift */; }; CC0101282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift */; };
CC0101292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift */; }; CC0101292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift */; };
CC01012A2FF0100000A5BBA3 /* ContentSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002A2FF0100000A5BBA3 /* ContentSort.swift */; }; CC01012A2FF0100000A5BBA3 /* ContentSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002A2FF0100000A5BBA3 /* ContentSort.swift */; };
CC01012B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */; }; CC01012B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */; };
CC01012C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */; }; CC01012C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */; };
@@ -1912,7 +1912,7 @@
CC01021F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift */; }; CC01021F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift */; };
CC0102272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift */; }; CC0102272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift */; };
CC0102282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift */; }; CC0102282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift */; };
CC0102292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift */; }; CC0102292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift */; };
CC01022A2FF0100000A5BBA3 /* ContentSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002A2FF0100000A5BBA3 /* ContentSort.swift */; }; CC01022A2FF0100000A5BBA3 /* ContentSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002A2FF0100000A5BBA3 /* ContentSort.swift */; };
CC01022B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */; }; CC01022B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */; };
CC01022C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */; }; CC01022C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */; };
@@ -1944,7 +1944,7 @@
CC01031F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift */; }; CC01031F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift */; };
CC0103272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift */; }; CC0103272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift */; };
CC0103282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift */; }; CC0103282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift */; };
CC0103292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift */; }; CC0103292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift */; };
CC01032A2FF0100000A5BBA3 /* ContentSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002A2FF0100000A5BBA3 /* ContentSort.swift */; }; CC01032A2FF0100000A5BBA3 /* ContentSort.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002A2FF0100000A5BBA3 /* ContentSort.swift */; };
CC01032B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */; }; CC01032B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */; };
CC01032C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */; }; CC01032C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */; };
@@ -3033,7 +3033,7 @@
CC01001F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelActivitySection.swift; sourceTree = "<group>"; }; CC01001F2FF0100000A5BBA3 /* CreatorChannelActivitySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelActivitySection.swift; sourceTree = "<group>"; };
CC0100272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelSnsSection.swift; sourceTree = "<group>"; }; CC0100272FF0100000A5BBA3 /* CreatorChannelSnsSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelSnsSection.swift; sourceTree = "<group>"; };
CC0100282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelTalkActionSection.swift; sourceTree = "<group>"; }; CC0100282FF0100000A5BBA3 /* CreatorChannelTalkActionSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelTalkActionSection.swift; sourceTree = "<group>"; };
CC0100292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelFloatingActionMenu.swift; sourceTree = "<group>"; }; CC0100292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorContentCreationFloatingActionMenu.swift; sourceTree = "<group>"; };
CC01002A2FF0100000A5BBA3 /* ContentSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentSort.swift; sourceTree = "<group>"; }; CC01002A2FF0100000A5BBA3 /* ContentSort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentSort.swift; sourceTree = "<group>"; };
CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelSortBar.swift; sourceTree = "<group>"; }; CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelSortBar.swift; sourceTree = "<group>"; };
CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelSortContextPopup.swift; sourceTree = "<group>"; }; CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelSortContextPopup.swift; sourceTree = "<group>"; };
@@ -5671,6 +5671,7 @@
B068C16B9D7F3F80901622E8 /* Button */ = { B068C16B9D7F3F80901622E8 /* Button */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CC0100292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift */,
348933CFF7DC1B9DB6E5D1A1 /* FollowAllButton.swift */, 348933CFF7DC1B9DB6E5D1A1 /* FollowAllButton.swift */,
); );
path = Button; path = Button;
@@ -6045,7 +6046,6 @@
CC0100112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift */, CC0100112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift */,
CC0100122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift */, CC0100122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift */,
CC0100132FF0100000A5BBA3 /* CreatorChannelTabBar.swift */, CC0100132FF0100000A5BBA3 /* CreatorChannelTabBar.swift */,
CC0100292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift */,
CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */, CC01002B2FF0100000A5BBA3 /* CreatorChannelSortBar.swift */,
CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */, CC01002C2FF0100000A5BBA3 /* CreatorChannelSortContextPopup.swift */,
C40163E3E9DB325EA984D3C4 /* CreatorChannelFloatingIconButton.swift */, C40163E3E9DB325EA984D3C4 /* CreatorChannelFloatingIconButton.swift */,
@@ -6765,7 +6765,7 @@
CC0101112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift in Sources */, CC0101112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift in Sources */,
CC0101122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift in Sources */, CC0101122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift in Sources */,
CC0101132FF0100000A5BBA3 /* CreatorChannelTabBar.swift in Sources */, CC0101132FF0100000A5BBA3 /* CreatorChannelTabBar.swift in Sources */,
CC0101292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift in Sources */, CC0101292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift in Sources */,
CC0101092FF0100000A5BBA3 /* CreatorChannelViewModel.swift in Sources */, CC0101092FF0100000A5BBA3 /* CreatorChannelViewModel.swift in Sources */,
CC0101102FF0100000A5BBA3 /* CreatorChannelTab.swift in Sources */, CC0101102FF0100000A5BBA3 /* CreatorChannelTab.swift in Sources */,
CC01012A2FF0100000A5BBA3 /* ContentSort.swift in Sources */, CC01012A2FF0100000A5BBA3 /* ContentSort.swift in Sources */,
@@ -7692,7 +7692,7 @@
CC0102112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift in Sources */, CC0102112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift in Sources */,
CC0102122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift in Sources */, CC0102122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift in Sources */,
CC0102132FF0100000A5BBA3 /* CreatorChannelTabBar.swift in Sources */, CC0102132FF0100000A5BBA3 /* CreatorChannelTabBar.swift in Sources */,
CC0102292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift in Sources */, CC0102292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift in Sources */,
CC0102092FF0100000A5BBA3 /* CreatorChannelViewModel.swift in Sources */, CC0102092FF0100000A5BBA3 /* CreatorChannelViewModel.swift in Sources */,
CC0102102FF0100000A5BBA3 /* CreatorChannelTab.swift in Sources */, CC0102102FF0100000A5BBA3 /* CreatorChannelTab.swift in Sources */,
CC01022A2FF0100000A5BBA3 /* ContentSort.swift in Sources */, CC01022A2FF0100000A5BBA3 /* ContentSort.swift in Sources */,
@@ -8637,7 +8637,7 @@
CC0103112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift in Sources */, CC0103112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift in Sources */,
CC0103122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift in Sources */, CC0103122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift in Sources */,
CC0103132FF0100000A5BBA3 /* CreatorChannelTabBar.swift in Sources */, CC0103132FF0100000A5BBA3 /* CreatorChannelTabBar.swift in Sources */,
CC0103292FF0100000A5BBA3 /* CreatorChannelFloatingActionMenu.swift in Sources */, CC0103292FF0100000A5BBA3 /* CreatorContentCreationFloatingActionMenu.swift in Sources */,
CC0103092FF0100000A5BBA3 /* CreatorChannelViewModel.swift in Sources */, CC0103092FF0100000A5BBA3 /* CreatorChannelViewModel.swift in Sources */,
CC0103102FF0100000A5BBA3 /* CreatorChannelTab.swift in Sources */, CC0103102FF0100000A5BBA3 /* CreatorChannelTab.swift in Sources */,
CC01032A2FF0100000A5BBA3 /* ContentSort.swift in Sources */, CC01032A2FF0100000A5BBA3 /* ContentSort.swift in Sources */,

View File

@@ -1,11 +1,26 @@
import SwiftUI import SwiftUI
struct CreatorChannelFloatingActionMenu: View { struct CreatorContentCreationFloatingActionMenu: View {
@Binding var isPresented: Bool @Binding var isPresented: Bool
let bottomPadding: CGFloat
let onTapCommunityPost: () -> Void let onTapCommunityPost: () -> Void
let onTapAudioContent: () -> Void let onTapAudioContent: () -> Void
let onTapCreateLive: () -> Void let onTapCreateLive: () -> Void
init(
isPresented: Binding<Bool>,
bottomPadding: CGFloat = 0,
onTapCommunityPost: @escaping () -> Void,
onTapAudioContent: @escaping () -> Void,
onTapCreateLive: @escaping () -> Void
) {
_isPresented = isPresented
self.bottomPadding = bottomPadding
self.onTapCommunityPost = onTapCommunityPost
self.onTapAudioContent = onTapAudioContent
self.onTapCreateLive = onTapCreateLive
}
private let animation = Animation.interpolatingSpring(mass: 1, stiffness: 256, damping: 24, initialVelocity: 0) private let animation = Animation.interpolatingSpring(mass: 1, stiffness: 256, damping: 24, initialVelocity: 0)
var body: some View { var body: some View {
@@ -66,6 +81,7 @@ struct CreatorChannelFloatingActionMenu: View {
} }
} }
.padding(.trailing, SodaSpacing.s14) .padding(.trailing, SodaSpacing.s14)
.padding(.bottom, bottomPadding)
.animation(animation, value: isPresented) .animation(animation, value: isPresented)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing) .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing)
@@ -73,11 +89,11 @@ struct CreatorChannelFloatingActionMenu: View {
} }
struct CreatorChannelFloatingActionMenu_Previews: PreviewProvider { struct CreatorContentCreationFloatingActionMenu_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
ZStack { ZStack {
Color.black.ignoresSafeArea() Color.black.ignoresSafeArea()
CreatorChannelFloatingActionMenu( CreatorContentCreationFloatingActionMenu(
isPresented: .constant(false), isPresented: .constant(false),
onTapCommunityPost: {}, onTapCommunityPost: {},
onTapAudioContent: {}, onTapAudioContent: {},

View File

@@ -90,7 +90,7 @@ struct CreatorChannelView: View {
} }
if isOwnCreatorChannel && viewModel.selectedTab == .home && !viewModel.isLoading { if isOwnCreatorChannel && viewModel.selectedTab == .home && !viewModel.isLoading {
CreatorChannelFloatingActionMenu( CreatorContentCreationFloatingActionMenu(
isPresented: $isCreatorActionMenuPresented, isPresented: $isCreatorActionMenuPresented,
onTapCommunityPost: showCommunityWrite, onTapCommunityPost: showCommunityWrite,
onTapAudioContent: showAudioContentUpload, onTapAudioContent: showAudioContentUpload,

View File

@@ -24,10 +24,14 @@ struct MainView: View {
@State private var isShowPlayer = false @State private var isShowPlayer = 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()
@State private var hasLoadedMainData = false @State private var hasLoadedMainData = false
private let mainTabBarHeight: CGFloat = 66
private let miniPlayerHeight: CGFloat = 58.1
var body: some View { var body: some View {
GeometryReader { proxy in GeometryReader { proxy in
ZStack(alignment: .bottom) { ZStack(alignment: .bottom) {
@@ -104,6 +108,16 @@ struct MainView: View {
} }
} }
if shouldShowCreatorActionMenu {
CreatorContentCreationFloatingActionMenu(
isPresented: $isCreatorActionMenuPresented,
bottomPadding: creatorActionMenuBottomPadding,
onTapCommunityPost: showMainCommunityWrite,
onTapAudioContent: showMainAudioContentUpload,
onTapCreateLive: showMainCreateLive
)
}
if isShowPlayer { if isShowPlayer {
ContentPlayerView(isShowing: $isShowPlayer, playlist: []) ContentPlayerView(isShowing: $isShowPlayer, playlist: [])
} }
@@ -117,6 +131,11 @@ struct MainView: View {
.valueChanged(value: appState.pushAudioContentId) { handlePushAudioContentId($0) } .valueChanged(value: appState.pushAudioContentId) { handlePushAudioContentId($0) }
.valueChanged(value: appState.pushSeriesId) { handlePushSeriesId($0) } .valueChanged(value: appState.pushSeriesId) { handlePushSeriesId($0) }
.valueChanged(value: appState.pendingMainChatFilter) { handlePendingMainChatFilter($0) } .valueChanged(value: appState.pendingMainChatFilter) { handlePendingMainChatFilter($0) }
.onChange(of: viewModel.currentTab) { currentTab in
if currentTab != .home {
isCreatorActionMenuPresented = false
}
}
.onAppear { .onAppear {
if appState.pushMessageId > 0 { if appState.pushMessageId > 0 {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
@@ -132,6 +151,21 @@ struct MainView: View {
} }
} }
private var shouldShowCreatorActionMenu: Bool {
UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue && viewModel.currentTab == .home
}
private var creatorActionMenuBottomPadding: CGFloat {
var bottomPadding = mainTabBarHeight + SodaSpacing.s14
if contentPlayerPlayManager.isShowingMiniPlayer {
bottomPadding += miniPlayerHeight
}
if contentPlayManager.isShowingMiniPlayer {
bottomPadding += miniPlayerHeight
}
return bottomPadding
}
@ViewBuilder @ViewBuilder
private var contentView: some View { private var contentView: some View {
switch viewModel.currentTab { switch viewModel.currentTab {
@@ -584,6 +618,28 @@ struct MainView: View {
} }
} }
private func showMainCommunityWrite() {
isCreatorActionMenuPresented = false
appState.setAppStep(step: .creatorCommunityWrite(onSuccess: {}))
}
private func showMainAudioContentUpload() {
isCreatorActionMenuPresented = false
appState.setAppStep(step: .createContent(onSuccess: {}))
}
private func showMainCreateLive() {
isCreatorActionMenuPresented = false
appState.setAppStep(step: .createLive(timeSettingMode: .NOW, onSuccess: handleMainCreateLiveSuccess))
}
private func handleMainCreateLiveSuccess(response: CreateLiveRoomResponse) {
liveViewModel.getLiveMain()
if let _ = response.channelName {
liveViewModel.enterRoom(roomId: response.id!)
}
}
private func openRecommendationBannerLink(_ link: String?) { private func openRecommendationBannerLink(_ link: String?) {
guard let link = link?.trimmingCharacters(in: .whitespacesAndNewlines), guard let link = link?.trimmingCharacters(in: .whitespacesAndNewlines),
!link.isEmpty else { !link.isEmpty else {

View File

@@ -621,6 +621,70 @@ Expected: 현재 저장소 상태상 테스트 번들 타깃이 없으면 `Schem
- `채팅`: `ic_nav_chat_selected` / `ic_nav_chat` - `채팅`: `ic_nav_chat_selected` / `ic_nav_chat`
- `마이`: `ic_tabbar_my_selected` / `ic_nav_my` - `마이`: `ic_tabbar_my_selected` / `ic_nav_my`
### Phase 13: 메인 홈 크리에이터 생성 Floating Menu
- [x] **Task 13.1: 내 채널 생성 메뉴를 공용 컴포넌트로 이동**
- 대상 파일:
- 이동/이름 변경: `SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelFloatingActionMenu.swift`
- 생성 위치: `SodaLive/Sources/V2/Component/Button/CreatorContentCreationFloatingActionMenu.swift`
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
- 확인: `SodaLive/Sources/I18n/I18n.swift`
- 작업 내용:
- 내 채널 홈의 `CreatorChannelFloatingActionMenu`를 두 페이지에서 재사용할 수 있는 공용 컴포넌트로 이동하고 이름을 역할 중심으로 변경한다.
- `ic_plus_no_bg`, `ic_new_upload_community_post`, `ic_new_upload_audio`, `ic_new_create_live`, `ic_new_x_black`, dim, 버튼 순서, spring animation을 변경하지 않는다.
- 내 채널 홈도 이동한 공용 컴포넌트를 사용해 기존 UI와 action을 유지한다.
- 검증 기준:
- 실행 명령: `rg "CreatorContentCreationFloatingActionMenu|ic_plus_no_bg|ic_new_upload_community_post|ic_new_upload_audio|ic_new_create_live|ic_new_x_black|interpolatingSpring\\(mass: 1, stiffness: 256, damping: 24" SodaLive/Sources/V2/Component/Button SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
- 기대 결과: 하나의 공용 생성 메뉴 구현을 내 채널 홈에서 사용하고, 기존 아이콘과 animation 값이 유지된다.
- [x] **Task 13.2: 메인 홈에 크리에이터 조건으로 생성 메뉴 표시**
- 대상 파일:
- 수정: `SodaLive/Sources/V2/Main/MainView.swift`
- 확인: `SodaLive/Sources/Extensions/UserDefaultsExtension.swift`
- 확인: `SodaLive/Sources/Settings/Notification/GetMemberInfoResponse.swift`
- 작업 내용:
- `UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue`로 크리에이터 여부를 판별한다.
- 크리에이터이고 `viewModel.currentTab == .home`일 때만 공용 생성 floating menu를 `MainView` 최상위 `ZStack`에 표시한다.
- 메인 홈 내부 `추천`, `랭킹`, `팔로잉` 전환과 관계없이 메뉴를 유지한다.
- `.content`, `.chat`, `.my`로 이동하거나 일반 사용자로 앱을 사용하면 menu/dim을 표시하지 않는다.
- 미니 플레이어와 하단 탭바가 표시될 때 겹치지 않도록 기존 safe area 구조를 따른다.
- 검증 기준:
- 실행 명령: `rg "MemberRole\\.CREATOR|viewModel\\.currentTab == \\.home|CreatorContentCreationFloatingActionMenu" SodaLive/Sources/V2/Main/MainView.swift`
- 기대 결과: 크리에이터와 메인 홈 탭 조건을 모두 만족할 때만 공용 생성 메뉴가 표시된다.
- [x] **Task 13.3: 기존 등록·생성 action 연결**
- 대상 파일:
- 수정: `SodaLive/Sources/V2/Main/MainView.swift`
- 확인: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
- 확인: `SodaLive/Sources/Live/LiveView.swift`
- 확인: `SodaLive/Sources/App/AppStep.swift`
- 작업 내용:
- 커뮤니티 게시글 등록은 기존 `AppStep.creatorCommunityWrite(onSuccess:)`로 이동한다.
- 콘텐츠 등록은 기존 `AppStep.createContent(onSuccess:)`로 이동한다.
- 라이브 생성은 기존 `AppStep.createLive(timeSettingMode: .NOW, onSuccess:)`로 이동한다.
- 라이브 생성 성공 시 내 채널 홈과 `LiveView.onCreateSuccess`의 기존 흐름처럼 라이브 메인 데이터를 갱신하고, `response.channelName`이 있으면 생성된 room에 입장한다.
- 각 action 실행 전에 floating menu를 닫는다.
- 메인 홈 전용 신규 route, 작성/생성 API, 별도 화면을 추가하지 않는다.
- 검증 기준:
- 실행 명령: `rg "creatorCommunityWrite|createContent|createLive\\(timeSettingMode: \\.NOW|getLiveMain|enterRoom|is.*ActionMenuPresented = false" SodaLive/Sources/V2/Main/MainView.swift`
- 기대 결과: 세 버튼이 기존 route에 연결되고 라이브 생성 성공 흐름과 menu 닫힘 처리가 확인된다.
- [x] **Task 13.4: 정적·빌드·수동 검증**
- 대상 파일/화면:
- 확인: `SodaLive/Sources/V2/Main/MainView.swift`
- 확인: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
- 확인: `SodaLive.xcworkspace`
- 수동 확인: 크리에이터/일반 사용자 메인 화면과 내 채널 홈
- 작업 내용:
- 공용 메뉴 사용처와 지정 아이콘/action을 정적 검색한다.
- `SodaLive-dev` Debug 빌드를 실행한다.
- 크리에이터 메인 홈, 일반 사용자 메인 홈, 메인 홈 외 탭, 내 채널 홈에서 표시 조건과 회귀 여부를 확인한다.
- 각 생성 버튼이 기존 등록/생성 화면으로 이동하는지 확인한다.
- 검증 기준:
- 실행 명령: `rg "CreatorContentCreationFloatingActionMenu" SodaLive/Sources/V2/Main SodaLive/Sources/V2/CreatorChannel SodaLive/Sources/V2/Component/Button`
- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build`
- 기대 결과: 메인 홈과 내 채널 홈이 같은 공용 메뉴를 사용하고 빌드가 성공하며, 크리에이터에게만 메인 홈 메뉴가 노출된다.
## 검증 기록 ## 검증 기록
- 계획 문서 작성 단계에서는 코드 구현을 수행하지 않았다. - 계획 문서 작성 단계에서는 코드 구현을 수행하지 않았다.
@@ -651,6 +715,32 @@ Expected: 현재 저장소 상태상 테스트 번들 타깃이 없으면 `Schem
- 2026-07-08 메인 콘텐츠 탭 title bar 요구사항 반영: Figma node `24:6738` 기준으로 콘텐츠 탭 상단은 홈 탭과 같은 좌측 로고/우측 알림 버튼 구성이 아니라, 좌측에 메인 탭명 `콘텐츠`를 고정 표시하고 우측에는 `ic_bar_cash`, `ic_bar_search`, `ic_bar_storage`를 표시하도록 수정했다. - 2026-07-08 메인 콘텐츠 탭 title bar 요구사항 반영: Figma node `24:6738` 기준으로 콘텐츠 탭 상단은 홈 탭과 같은 좌측 로고/우측 알림 버튼 구성이 아니라, 좌측에 메인 탭명 `콘텐츠`를 고정 표시하고 우측에는 `ic_bar_cash`, `ic_bar_search`, `ic_bar_storage`를 표시하도록 수정했다.
- 2026-07-08 메인 콘텐츠 탭 보관함 이동 반영: `ic_bar_storage` 터치 시 기존 보관함 진입 경로인 `AppState.shared.setAppStep(step: .myBox(currentTab: .orderlist))`로 이동하도록 `MainContentView``onTapStorage` 콜백을 추가하고 `MainView`에서 연결했다. 홈 탭의 `HomeTitleBar`/`ic_bar_bell` 동작은 유지한다. - 2026-07-08 메인 콘텐츠 탭 보관함 이동 반영: `ic_bar_storage` 터치 시 기존 보관함 진입 경로인 `AppState.shared.setAppStep(step: .myBox(currentTab: .orderlist))`로 이동하도록 `MainContentView``onTapStorage` 콜백을 추가하고 `MainView`에서 연결했다. 홈 탭의 `HomeTitleBar`/`ic_bar_bell` 동작은 유지한다.
- 2026-07-08 검증: Figma `24:6738` design context와 screenshot을 확인했고, `rg`/`ast-grep`로 콘텐츠 탭은 `DefaultTitleBar(title: MainTab.content.title)``ic_bar_storage`, 홈 탭은 기존 `HomeTitleBar``ic_bar_bell`을 사용하는 것을 확인했다. 구현 직후 `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -destination 'generic/platform=iOS Simulator' -configuration Debug build` 실행 결과 빌드 성공을 확인했다. - 2026-07-08 검증: Figma `24:6738` design context와 screenshot을 확인했고, `rg`/`ast-grep`로 콘텐츠 탭은 `DefaultTitleBar(title: MainTab.content.title)``ic_bar_storage`, 홈 탭은 기존 `HomeTitleBar``ic_bar_bell`을 사용하는 것을 확인했다. 구현 직후 `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -destination 'generic/platform=iOS Simulator' -configuration Debug build` 실행 결과 빌드 성공을 확인했다.
- 2026-07-20 문서 보강: 크리에이터가 메인 홈에서 라이브 생성, 콘텐츠 등록, 커뮤니티 게시글 등록을 실행할 수 있도록 Phase 13을 추가했다. `CreatorChannelFloatingActionMenu`, `CreatorChannelView`의 세 action, `MemberRole.CREATOR` 역할 판별 근거를 확인해 같은 아이콘·animation·기존 `AppStep` route를 공용화하는 범위로 기록했다. 이번 작업은 문서 수정만 수행했으며 구현/빌드는 Phase 13 실행 시 검증한다.
- 2026-07-20 Phase 13 구현: `CreatorChannelFloatingActionMenu``SodaLive/Sources/V2/Component/Button/CreatorContentCreationFloatingActionMenu.swift`로 이동/이름 변경하고, 내 채널 홈과 메인 홈이 같은 공용 메뉴를 사용하도록 반영했다.
- 실행 명령: `rg -n "CreatorContentCreationFloatingActionMenu|ic_plus_no_bg|ic_new_upload_community_post|ic_new_upload_audio|ic_new_create_live|ic_new_x_black|interpolatingSpring\\(mass: 1, stiffness: 256, damping: 24" "SodaLive/Sources/V2/Component/Button" "SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift"`
- 결과: 공용 메뉴 구현과 내 채널 홈 사용처, 기존 plus/커뮤니티/오디오/라이브/닫기 아이콘 및 spring animation 값이 확인됐다.
- 실행 명령: `rg -n "MemberRole\\.CREATOR|viewModel\\.currentTab == \\.home|CreatorContentCreationFloatingActionMenu" "SodaLive/Sources/V2/Main/MainView.swift"`
- 결과: `UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue && viewModel.currentTab == .home` 조건에서만 메인 홈 생성 메뉴를 표시하는 것을 확인했다.
- 실행 명령: `rg -n "creatorCommunityWrite|createContent\\(onSuccess|createLive\\(timeSettingMode: \\.NOW|getLiveMain|enterRoom|isCreatorActionMenuPresented = false" "SodaLive/Sources/V2/Main/MainView.swift"`
- 결과: 커뮤니티 게시글 등록, 콘텐츠 등록, 즉시 라이브 생성 route 연결과 action 실행 전 메뉴 닫힘, 라이브 생성 성공 후 `getLiveMain()``enterRoom(roomId:)` 흐름을 확인했다.
- 실행 명령: `rg -n "CreatorContentCreationFloatingActionMenu" "SodaLive/Sources/V2/Main" "SodaLive/Sources/V2/CreatorChannel" "SodaLive/Sources/V2/Component/Button"`
- 결과: 공용 메뉴 구현 1개와 `MainView`, `CreatorChannelView` 사용처가 확인됐다.
- 실행 명령: `lsp_diagnostics` (`CreatorContentCreationFloatingActionMenu.swift`, `CreatorChannelView.swift`, `MainView.swift`)
- 결과: SourceKit 단독 컨텍스트 한계로 전역 프로젝트 심볼 인식 오류/timeout이 보고되어 실제 컴파일 유효성은 빌드로 판정했다.
- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build`
- 결과: `** BUILD SUCCEEDED **`.
- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test`
- 결과: `Scheme SodaLive is not currently configured for the test action.`
- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug -destination "platform=iOS Simulator,name=iPhone 17,OS=26.0" build`
- 결과: `** BUILD SUCCEEDED **`.
- 실행 명령: `xcrun simctl spawn "iPhone 17" defaults write kr.co.vividnext.sodalive.debug2 role CREATOR`, `token`, `isViewedOnboardingView` 설정 후 앱 launch 및 screenshot 캡처
- 결과: `/var/folders/yh/8xsbvpsj5wg2qnxzxdp11_gm0000gn/T/opencode/sodalive-phase13-creator-main-retry.png`에서 메인 홈 하단 오른쪽 plus floating action button 표시를 확인했다.
- 정리 명령: `xcrun simctl spawn "iPhone 17" defaults delete ...``xcrun simctl shutdown "iPhone 17"`
- 결과: Phase 13 수동 검증용 시뮬레이터 기본값 제거와 시뮬레이터 종료를 완료했다.
- 실행 명령: `git diff --check`
- 결과: 공백 오류 없음.
- 실행 도구: 리뷰어 게이트 `task(category="deep")`
- 결과: 차단 결함 없음. 자동 테스트는 test action 미구성으로 실행할 수 없고, 생성 버튼 실제 탭 이동은 정적 라우팅 검토로 확인했다는 메모만 남았다.
## 커밋 정책 ## 커밋 정책

View File

@@ -29,6 +29,8 @@
- `홈`, `콘텐츠`, `채팅` 탭은 신규 빈 페이지를 만들어 표시한다. - `홈`, `콘텐츠`, `채팅` 탭은 신규 빈 페이지를 만들어 표시한다.
- 하단 내비게이션 아이콘은 요청된 `ic_nav_*` 계열을 사용한다. - 하단 내비게이션 아이콘은 요청된 `ic_nav_*` 계열을 사용한다.
- 현재 없는 `ic_nav_my_selected`는 임시로 `ic_tabbar_my_selected`를 사용한다. - 현재 없는 `ic_nav_my_selected`는 임시로 `ic_tabbar_my_selected`를 사용한다.
- 후속 요구사항(2026-07-20): 크리에이터 계정으로 앱을 사용할 때 메인 `홈` 탭에서 라이브 생성, 콘텐츠 등록, 커뮤니티 게시글 등록으로 진입할 수 있는 plus floating menu를 제공한다.
- 메인 `홈` 탭의 plus 아이콘, 펼침 UI, 생성 액션은 내 채널 홈 탭의 `CreatorChannelFloatingActionMenu`와 동일하게 동작한다.
--- ---
@@ -39,6 +41,8 @@
- 전역 라우팅 구조(`AppState`, `AppStep`, `ContentView`)의 대규모 개편은 하지 않는다. - 전역 라우팅 구조(`AppState`, `AppStep`, `ContentView`)의 대규모 개편은 하지 않는다.
- 미니 플레이어, 팝업, 본인인증, 딥링크 등 기존 메인 주변 기능의 동작 변경은 하지 않는다. - 미니 플레이어, 팝업, 본인인증, 딥링크 등 기존 메인 주변 기능의 동작 변경은 하지 않는다.
- 누락된 실제 이미지 리소스 `ic_nav_my_selected`를 새로 제작하거나 추가하지 않는다. - 누락된 실제 이미지 리소스 `ic_nav_my_selected`를 새로 제작하거나 추가하지 않는다.
- 라이브 생성, 콘텐츠 등록, 커뮤니티 게시글 등록 화면과 API를 새로 구현하지 않는다.
- 일반 사용자 계정에는 생성용 plus floating menu를 표시하지 않는다.
--- ---
@@ -78,6 +82,27 @@
구현 시 탭 버튼별 콘텐츠 높이가 달라도 타이틀 기준선이 흔들리지 않도록 아이콘 영역 높이와 타이틀 영역 높이를 명확히 분리한다. 구현 시 탭 버튼별 콘텐츠 높이가 달라도 타이틀 기준선이 흔들리지 않도록 아이콘 영역 높이와 타이틀 영역 높이를 명확히 분리한다.
### 5.4 크리에이터용 생성 Floating Menu
- 크리에이터 여부는 기존 앱의 역할 판별 기준인 `UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue`를 사용한다.
- 크리에이터이고 메인 하단 탭이 `.home`일 때만 생성용 plus floating menu를 표시한다.
- 메인 홈 내부의 `추천`, `랭킹`, `팔로잉` 선택과 관계없이 메인 하단 탭이 `.home`인 동안 동일한 floating menu를 유지한다.
- 일반 사용자이거나 메인 하단 탭이 `.content`, `.chat`, `.my`이면 floating menu와 dim overlay를 표시하지 않는다.
- 닫힘 상태 plus 버튼, 열림 상태 dim, 버튼 순서, spring animation은 내 채널 홈 탭의 `CreatorChannelFloatingActionMenu`와 동일하게 사용한다.
- 닫힘 상태 아이콘은 `ic_plus_no_bg`를 사용한다.
- 열림 상태의 버튼은 위에서부터 아래 순서로 다음과 같이 표시한다.
1. 커뮤니티 게시글 등록: `ic_new_upload_community_post`
2. 콘텐츠 등록: `ic_new_upload_audio`
3. 라이브 생성: `ic_new_create_live`
4. 닫기: `ic_new_x_black`
- 각 버튼은 내 채널 홈 탭과 동일한 기존 action을 사용한다.
- 커뮤니티 게시글 등록: `AppStep.creatorCommunityWrite(onSuccess:)`
- 콘텐츠 등록: `AppStep.createContent(onSuccess:)`
- 라이브 생성: `AppStep.createLive(timeSettingMode: .NOW, onSuccess:)`
- 라이브 생성 성공 시 기존 내 채널 홈과 `LiveView.onCreateSuccess`가 사용하는 라이브 메인 갱신 및 생성된 room 입장 흐름을 유지한다.
- 액션 선택, 닫기 버튼 탭, dim 영역 탭 시 menu를 닫는 동작은 내 채널 홈과 동일하게 유지한다.
- 메인 미니 플레이어와 하단 탭바가 표시될 때 floating menu가 겹치지 않도록 기존 `MainView`의 overlay와 safe area 구조 안에서 배치한다.
--- ---
## 6. Recommended Approach ## 6. Recommended Approach
@@ -114,6 +139,8 @@ SwiftUI 표준 탭 내비게이션 방식이다. 탭별 독립 상태 관리와
- `I18n.Main.Tab`에는 현재 `home`, `live`, `chat`, `my`만 있으므로 `content` 라벨을 추가해야 한다. - `I18n.Main.Tab`에는 현재 `home`, `live`, `chat`, `my`만 있으므로 `content` 라벨을 추가해야 한다.
- `ic_nav_my_selected`는 현재 에셋에 없으므로 구현 시 `ic_tabbar_my_selected`를 임시 사용한다. - `ic_nav_my_selected`는 현재 에셋에 없으므로 구현 시 `ic_tabbar_my_selected`를 임시 사용한다.
- 신규로 생성되는 메인 페이지 관련 파일은 모두 `SodaLive/Sources/V2/Main/**` 아래에 둔다. - 신규로 생성되는 메인 페이지 관련 파일은 모두 `SodaLive/Sources/V2/Main/**` 아래에 둔다.
- 두 페이지에서 재사용하는 생성 floating menu는 `SodaLive/Sources/V2/Component/Button/**` 아래 공용 컴포넌트로 이동하고, 내 채널 홈과 메인 홈이 같은 구현을 사용한다.
- 기존 `AppStep.creatorCommunityWrite`, `AppStep.createContent`, `AppStep.createLive` case와 각 작성/생성 화면은 변경하지 않는다.
--- ---
@@ -127,6 +154,10 @@ SwiftUI 표준 탭 내비게이션 방식이다. 탭별 독립 상태 관리와
- 탭 아이콘 선택/미선택 매핑이 요구사항과 일치한다. - 탭 아이콘 선택/미선택 매핑이 요구사항과 일치한다.
- `마이` 선택 아이콘은 임시로 `ic_tabbar_my_selected`를 사용한다. - `마이` 선택 아이콘은 임시로 `ic_tabbar_my_selected`를 사용한다.
- 탭 버튼 내부 콘텐츠는 가로/세로 가운데 정렬을 우선하고, 타이틀 하단 라인이 맞는다. - 탭 버튼 내부 콘텐츠는 가로/세로 가운데 정렬을 우선하고, 타이틀 하단 라인이 맞는다.
- 크리에이터 계정의 메인 `홈` 탭에는 내 채널 홈과 동일한 plus floating menu가 표시된다.
- 일반 사용자 계정과 메인 `홈` 이외 탭에는 생성용 plus floating menu가 표시되지 않는다.
- Plus 버튼을 펼치면 커뮤니티 게시글 등록, 콘텐츠 등록, 라이브 생성, 닫기 버튼이 내 채널 홈과 동일한 아이콘과 순서로 표시된다.
- 세 생성 버튼은 각각 기존 커뮤니티 게시글 등록, 콘텐츠 등록, 즉시 라이브 생성 화면으로 이동한다.
--- ---
@@ -135,6 +166,8 @@ SwiftUI 표준 탭 내비게이션 방식이다. 탭별 독립 상태 관리와
- 신규 빈 페이지는 검정 배경을 사용하고 탭명만 표시한다. - 신규 빈 페이지는 검정 배경을 사용하고 탭명만 표시한다.
- 신규로 생성되는 파일은 모두 `SodaLive/Sources/V2/Main/**` 아래에 둔다. - 신규로 생성되는 파일은 모두 `SodaLive/Sources/V2/Main/**` 아래에 둔다.
- 메인 컨테이너는 접근안 B에 따라 신규 구현 후 기존 미니 플레이어, 인증, 팝업 등 필요한 주변 기능을 이관한다. - 메인 컨테이너는 접근안 B에 따라 신규 구현 후 기존 미니 플레이어, 인증, 팝업 등 필요한 주변 기능을 이관한다.
- 크리에이터용 생성 메뉴는 내 채널 홈의 UI와 action을 복제하지 않고 공용 컴포넌트와 기존 `AppStep` route를 재사용한다.
- 메인 홈에서의 크리에이터 판별은 별도 API 없이 저장된 `MemberRole.CREATOR` 값을 사용한다.
--- ---
@@ -145,3 +178,9 @@ SwiftUI 표준 탭 내비게이션 방식이다. 탭별 독립 상태 관리와
- `SodaLive/Sources/App/AppState.swift`, `AppStep.swift`, `ContentView.swift`를 확인해 `.main` 라우팅과 전역 내비게이션 구조를 검증했다. - `SodaLive/Sources/App/AppState.swift`, `AppStep.swift`, `ContentView.swift`를 확인해 `.main` 라우팅과 전역 내비게이션 구조를 검증했다.
- `SodaLive/Resources/Assets.xcassets` 검색으로 `ic_nav_home(_selected)`, `ic_nav_content(_selected)`, `ic_nav_chat(_selected)`, `ic_nav_my`, `ic_tabbar_my_selected` 존재와 `ic_nav_my_selected` 부재를 확인했다. - `SodaLive/Resources/Assets.xcassets` 검색으로 `ic_nav_home(_selected)`, `ic_nav_content(_selected)`, `ic_nav_chat(_selected)`, `ic_nav_my`, `ic_tabbar_my_selected` 존재와 `ic_nav_my_selected` 부재를 확인했다.
- `SodaLive/Sources/I18n/I18n.swift`를 확인해 `I18n.Main.Tab.content`가 아직 없음을 확인했다. - `SodaLive/Sources/I18n/I18n.swift`를 확인해 `I18n.Main.Tab.content`가 아직 없음을 확인했다.
- 2026-07-20: `SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelFloatingActionMenu.swift``CreatorChannelView.swift`를 확인해 내 채널 홈의 plus 아이콘, 4개 메뉴 아이콘, spring animation, 커뮤니티 게시글 등록·콘텐츠 등록·즉시 라이브 생성 route를 확인했다.
- 2026-07-20: `SodaLive/Sources/MyPage/MyPageView.swift``SodaLive/Sources/Extensions/UserDefaultsExtension.swift`를 확인해 기존 크리에이터 역할 판별 기준이 `UserDefaults.string(forKey: .role) == MemberRole.CREATOR.rawValue`임을 확인했다.
## 11. Open Questions
- 해당 없음.