import SwiftUI struct CreatorChannelLiveTabView: View { let creatorId: Int let isOwnCreatorChannel: Bool let onTapLive: (Int) -> Void let onTapContent: (Int) -> Void @StateObject private var viewModel = CreatorChannelLiveViewModel() @State private var isSortPopupPresented = false var body: some View { content .background(Color.black) .onAppear { if viewModel.hasLoaded == false { viewModel.fetchFirstPage(creatorId: creatorId) } } .sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 1) } private var content: some View { VStack(spacing: 0) { if isEmptyState { emptyStateView } else { ZStack(alignment: .topTrailing) { VStack(spacing: 0) { CreatorChannelSortBar( selectedSort: viewModel.selectedSort, totalCount: viewModel.response?.liveReplayContentCount, onTapSort: { isSortPopupPresented.toggle() } ) LazyVStack(spacing: 0) { CreatorChannelCurrentLiveSection( currentLive: viewModel.response?.currentLive, onTapLive: onTapLive ) .padding(.top, SodaSpacing.s14) .padding(.bottom, SodaSpacing.s12) ForEach(viewModel.liveReplayContents) { audioContent in AudioContentListRow( item: AudioContentListRowItem( audioContent: audioContent, subtitle: audioContent.duration ), style: .purchaseState ) { onTapContent(audioContent.audioContentId) } .onAppear { viewModel.fetchNextPageIfNeeded(creatorId: creatorId, currentItem: audioContent) } } if viewModel.isLoadingNextPage { ProgressView() .padding(.vertical, SodaSpacing.s20) } } .padding(.bottom, isOwnCreatorChannel ? 70 : SodaSpacing.s20) } if isSortPopupPresented { Color.black .opacity(0.001) .frame(maxWidth: .infinity, maxHeight: .infinity) .onTapGesture { isSortPopupPresented = false } CreatorChannelSortContextPopup(selectedSort: viewModel.selectedSort) { sort in viewModel.selectSort(sort, creatorId: creatorId) isSortPopupPresented = false } .padding(.top, 52) .padding(.trailing, SodaSpacing.s14) .zIndex(1) } } .frame(maxWidth: .infinity, alignment: .topTrailing) .onChange(of: viewModel.selectedSort) { _ in isSortPopupPresented = false } .onDisappear { isSortPopupPresented = false } } } } private var isEmptyState: Bool { guard viewModel.hasLoaded, let response = viewModel.response else { return false } return response.currentLive == nil && response.liveReplayContentCount == 0 } private var emptyStateView: some View { Text(I18n.CreatorChannelLive.emptyMessage) .appFont(.body3) .foregroundColor(Color.gray500) .multilineTextAlignment(.center) .frame(maxWidth: .infinity) .padding(.top, 20) .padding(.bottom, 48) } } struct CreatorChannelLiveTabView_Previews: PreviewProvider { static var previews: some View { CreatorChannelLiveTabView( creatorId: 1, isOwnCreatorChannel: true, onTapLive: { _ in }, onTapContent: { _ in } ) .background(Color.black) .previewLayout(.sizeThatFits) } }