import SwiftUI struct MainContentRecommendationView: View { let onTapContent: (Int) -> Void let onTapBanner: (AudioBannerResponse) -> Void let onTapSeries: (Int) -> Void let onTapLatestAudioAll: () -> Void let onTapNewAndHotAll: () -> Void let onTapSodaLiveOnlyAll: () -> Void let onTapFreeAudioAll: () -> Void let onTapPointAudioAll: () -> Void @StateObject private var viewModel = MainContentRecommendationViewModel() var body: some View { ZStack { Color.black .ignoresSafeArea() if viewModel.isLoading && !viewModel.hasLoaded { loadingContent } else if viewModel.shouldShowEmptyState { emptyContent } else { LottieRefreshableScrollView(action: { await viewModel.refresh() }) { VStack(alignment: .leading, spacing: SodaSpacing.s24) { if let recommendations = viewModel.recommendations { MainContentAudioBannerSection( items: recommendations.banners, onTapBanner: onTapBanner ) MainContentVoiceOnOnlySection( title: I18n.MainContentRecommendation.sodaLiveOnlySectionTitle, items: recommendations.originalSeries, action: onTapSodaLiveOnlyAll, onTapSeries: onTapSeries ) MainContentAudioListCarouselSection( title: I18n.MainContentRecommendation.newAndHotSectionTitle, items: recommendations.newAndHotAudios, action: onTapNewAndHotAll, onTapContent: onTapContent ) MainContentAudioHorizontalCardSection( title: I18n.MainContentRecommendation.latestAudioSectionTitle, items: recommendations.latestAudios, action: onTapLatestAudioAll, onTapContent: onTapContent ) MainContentAudioHorizontalCardSection( title: I18n.MainContentRecommendation.freeAudioSectionTitle, items: recommendations.freeAudios, action: onTapFreeAudioAll, onTapContent: onTapContent ) MainContentAudioHorizontalCardSection( title: I18n.MainContentRecommendation.pointAudioSectionTitle, items: recommendations.pointAudios, action: onTapPointAudioAll, onTapContent: onTapContent ) MainContentMostCommentedAudioSection( title: I18n.MainContentRecommendation.mostCommentedAudioSectionTitle, items: recommendations.mostCommentedAudios, onTapContent: onTapContent ) MainContentRecommendedAudioGridSection( title: I18n.MainContentRecommendation.recommendedAudioSectionTitle, items: recommendations.recommendedAudios, onTapContent: onTapContent ) } } .padding(.vertical, SodaSpacing.s20) } } } .onAppear { if !viewModel.hasLoaded { viewModel.fetchRecommendations() } } .sodaToast( isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 2 ) } private var loadingContent: some View { GeometryReader { geometry in LottieRefreshableScrollView(action: { await viewModel.refresh() }) { ProgressView() .progressViewStyle(CircularProgressViewStyle(tint: .white)) .frame(maxWidth: .infinity) .frame(minHeight: geometry.size.height) } } } private var emptyContent: some View { GeometryReader { geometry in LottieRefreshableScrollView(action: { await viewModel.refresh() }) { MainContentAudioEmptyStateView(message: viewModel.emptyStateMessage) .frame(minHeight: geometry.size.height) } } } }