feat(home): 팔로잉 탭 화면을 조립한다
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import SwiftUI
|
||||
|
||||
struct MainHomeFollowingEmptyStateView: View {
|
||||
let message: String
|
||||
let loginAction: (() -> Void)?
|
||||
|
||||
init(message: String, loginAction: (() -> Void)? = nil) {
|
||||
self.message = message
|
||||
self.loginAction = loginAction
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: SodaSpacing.s16) {
|
||||
Spacer()
|
||||
|
||||
Text(message)
|
||||
.appFont(.body5)
|
||||
.foregroundColor(Color.gray500)
|
||||
.multilineTextAlignment(.center)
|
||||
|
||||
if let loginAction {
|
||||
Button(action: loginAction) {
|
||||
Text(I18n.HomeFollowing.loginButtonTitle)
|
||||
.appFont(size: 14, weight: .bold)
|
||||
.foregroundColor(.black)
|
||||
.padding(.horizontal, SodaSpacing.s16)
|
||||
.frame(height: 40)
|
||||
.background(Color.soda400)
|
||||
.clipShape(RoundedRectangle(cornerRadius: SodaRadius.r14, style: .continuous))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color.black)
|
||||
}
|
||||
}
|
||||
|
||||
struct MainHomeFollowingEmptyStateView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MainHomeFollowingEmptyStateView(message: I18n.HomeFollowing.emptyStateMessage)
|
||||
.frame(width: 390, height: 320)
|
||||
.previewLayout(.sizeThatFits)
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,12 @@ struct MainHomeFollowingNewsSection: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if !recentNews.isEmpty {
|
||||
if !renderableNews.isEmpty {
|
||||
VStack(alignment: .leading, spacing: SodaSpacing.s14) {
|
||||
SectionTitle(title: I18n.HomeFollowing.recentNewsTitle)
|
||||
|
||||
VStack(alignment: .leading, spacing: SodaSpacing.s8) {
|
||||
ForEach(recentNews) { news in
|
||||
ForEach(renderableNews) { news in
|
||||
newsItemView(news)
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,25 @@ struct MainHomeFollowingNewsSection: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var renderableNews: [FollowingNewsResponse] {
|
||||
recentNews.filter { news in
|
||||
switch news.type {
|
||||
case .creatorRanking:
|
||||
return news.creatorRanking != nil
|
||||
case .contentRanking:
|
||||
return news.contentRanking != nil
|
||||
case .communityPost:
|
||||
return news.communityPost != nil
|
||||
case .audioContent:
|
||||
return news.audioContent != nil
|
||||
case .photoContent:
|
||||
return news.photoContent != nil
|
||||
case .unknown:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func newsItemView(_ news: FollowingNewsResponse) -> some View {
|
||||
switch news.type {
|
||||
|
||||
@@ -3,6 +3,8 @@ import SwiftUI
|
||||
struct MainHomeFollowingView: View {
|
||||
let onTapLive: (Int) -> Void
|
||||
let onTapCreator: (Int) -> Void
|
||||
let onTapContent: (Int) -> Void
|
||||
let onTapLogin: () -> Void
|
||||
let onTapFollowingAll: () -> Void
|
||||
let onTapChatTab: () -> Void
|
||||
let onTapChatRoom: (Int) -> Void
|
||||
@@ -13,6 +15,8 @@ struct MainHomeFollowingView: View {
|
||||
init(
|
||||
onTapLive: @escaping (Int) -> Void = { _ in },
|
||||
onTapCreator: @escaping (Int) -> Void = { _ in },
|
||||
onTapContent: @escaping (Int) -> Void = { _ in },
|
||||
onTapLogin: @escaping () -> Void = {},
|
||||
onTapFollowingAll: @escaping () -> Void = {},
|
||||
onTapChatTab: @escaping () -> Void = {},
|
||||
onTapChatRoom: @escaping (Int) -> Void = { _ in },
|
||||
@@ -20,6 +24,8 @@ struct MainHomeFollowingView: View {
|
||||
) {
|
||||
self.onTapLive = onTapLive
|
||||
self.onTapCreator = onTapCreator
|
||||
self.onTapContent = onTapContent
|
||||
self.onTapLogin = onTapLogin
|
||||
self.onTapFollowingAll = onTapFollowingAll
|
||||
self.onTapChatTab = onTapChatTab
|
||||
self.onTapChatRoom = onTapChatRoom
|
||||
@@ -27,41 +33,78 @@ struct MainHomeFollowingView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
MainHomeFollowingCreatorSection(
|
||||
followingCreators: viewModel.response?.followingCreators ?? [],
|
||||
onTapCreator: onTapCreator,
|
||||
onTapAll: onTapFollowingAll
|
||||
)
|
||||
|
||||
MainHomeFollowingLiveSection(
|
||||
onAirLives: viewModel.response?.onAirLives ?? [],
|
||||
onTapLive: onTapLive
|
||||
)
|
||||
|
||||
if let recentChats = viewModel.response?.recentChats, !recentChats.isEmpty {
|
||||
MainHomeFollowingChatSection(
|
||||
recentChats: recentChats,
|
||||
onTapTitle: onTapChatTab,
|
||||
onTapChatRoom: onTapChatRoom
|
||||
)
|
||||
}
|
||||
|
||||
if let monthlySchedules = viewModel.response?.monthlySchedules, !monthlySchedules.isEmpty {
|
||||
MainHomeFollowingScheduleSection(
|
||||
monthlySchedules: monthlySchedules,
|
||||
onTapSchedule: onTapSchedule
|
||||
)
|
||||
}
|
||||
|
||||
MainPlaceholderTabView(title: I18n.HomeFollowing.tabTitle)
|
||||
}
|
||||
content
|
||||
.onAppear {
|
||||
if viewModel.hasLoaded == false {
|
||||
viewModel.fetchFollowing()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var content: some View {
|
||||
if viewModel.isLoading {
|
||||
ProgressView()
|
||||
.tint(.white)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background(Color.black)
|
||||
} else if viewModel.isLoginRequired {
|
||||
MainHomeFollowingEmptyStateView(
|
||||
message: I18n.HomeFollowing.loginRequiredMessage,
|
||||
loginAction: onTapLogin
|
||||
)
|
||||
} else if !viewModel.message.isEmpty {
|
||||
MainHomeFollowingEmptyStateView(message: viewModel.message)
|
||||
} else if let response = viewModel.response {
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
VStack(spacing: 0) {
|
||||
MainHomeFollowingCreatorSection(
|
||||
followingCreators: response.followingCreators,
|
||||
onTapCreator: onTapCreator,
|
||||
onTapAll: onTapFollowingAll
|
||||
)
|
||||
|
||||
if !response.onAirLives.isEmpty {
|
||||
MainHomeFollowingLiveSection(
|
||||
onAirLives: response.onAirLives,
|
||||
onTapLive: onTapLive
|
||||
)
|
||||
.padding(.top, 28)
|
||||
}
|
||||
|
||||
if !response.recentChats.isEmpty {
|
||||
MainHomeFollowingChatSection(
|
||||
recentChats: response.recentChats,
|
||||
onTapTitle: onTapChatTab,
|
||||
onTapChatRoom: onTapChatRoom
|
||||
)
|
||||
.padding(.top, 48)
|
||||
}
|
||||
|
||||
if !response.monthlySchedules.isEmpty {
|
||||
MainHomeFollowingScheduleSection(
|
||||
monthlySchedules: response.monthlySchedules,
|
||||
onTapSchedule: onTapSchedule
|
||||
)
|
||||
.padding(.top, 48)
|
||||
}
|
||||
|
||||
if !response.recentNews.isEmpty {
|
||||
MainHomeFollowingNewsSection(
|
||||
recentNews: response.recentNews,
|
||||
onTapCreator: onTapCreator,
|
||||
onTapContent: onTapContent
|
||||
)
|
||||
.padding(.top, 48)
|
||||
}
|
||||
}
|
||||
.padding(.bottom, SodaSpacing.s20)
|
||||
}
|
||||
.background(Color.black)
|
||||
} else {
|
||||
MainHomeFollowingEmptyStateView(message: I18n.HomeFollowing.emptyStateMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MainHomeFollowingView_Previews: PreviewProvider {
|
||||
|
||||
@@ -12,6 +12,7 @@ struct MainHomeView: View {
|
||||
let onTapBanner: (RecommendationBannerResponse) -> Void
|
||||
let onTapFollowAll: (@escaping () -> Void) -> Void
|
||||
let onSelectFollowingTab: () -> Bool
|
||||
let onTapFollowingLogin: () -> Void
|
||||
let onTapFollowingAll: () -> Void
|
||||
let onTapChatTab: () -> Void
|
||||
let onTapChatRoom: (Int) -> Void
|
||||
@@ -78,6 +79,8 @@ struct MainHomeView: View {
|
||||
MainHomeFollowingView(
|
||||
onTapLive: onTapLive,
|
||||
onTapCreator: onTapCreator,
|
||||
onTapContent: onTapContent,
|
||||
onTapLogin: onTapFollowingLogin,
|
||||
onTapFollowingAll: onTapFollowingAll,
|
||||
onTapChatTab: onTapChatTab,
|
||||
onTapChatRoom: onTapChatRoom,
|
||||
@@ -118,6 +121,7 @@ struct MainHomeView_Previews: PreviewProvider {
|
||||
onTapBanner: { _ in },
|
||||
onTapFollowAll: { action in action() },
|
||||
onSelectFollowingTab: { true },
|
||||
onTapFollowingLogin: {},
|
||||
onTapFollowingAll: {},
|
||||
onTapChatTab: {},
|
||||
onTapChatRoom: { _ in },
|
||||
|
||||
Reference in New Issue
Block a user