feat(main): 라이브 전체 진입을 추가한다

This commit is contained in:
Yu Sung
2026-07-22 15:47:52 +09:00
parent 70af4923c6
commit a0db58e53f
6 changed files with 44 additions and 4 deletions

View File

@@ -8946,7 +8946,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.55.1; MARKETING_VERSION = 1.55.2;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.vividnext.sodalive; PRODUCT_BUNDLE_IDENTIFIER = kr.co.vividnext.sodalive;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@@ -8987,7 +8987,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.55.1; MARKETING_VERSION = 1.55.2;
PRODUCT_BUNDLE_IDENTIFIER = kr.co.vividnext.sodalive; PRODUCT_BUNDLE_IDENTIFIER = kr.co.vividnext.sodalive;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

View File

@@ -3546,6 +3546,10 @@ If you block this user, the following features will be restricted.
pick(ko: "현재 라이브", en: "Live now", ja: "現在ライブ") pick(ko: "현재 라이브", en: "Live now", ja: "現在ライブ")
} }
static var liveAll: String {
pick(ko: "전체", en: "All", ja: "すべて")
}
static var activeCreatorSectionTitle: String { static var activeCreatorSectionTitle: String {
pick(ko: "방금 활동한 크리에이터", en: "Recently active creators", ja: "最近活動したクリエイター") pick(ko: "방금 활동한 크리에이터", en: "Recently active creators", ja: "最近活動したクリエイター")
} }

View File

@@ -10,6 +10,7 @@ struct MainHomeView: View {
let onTapCharacter: (Int) -> Void let onTapCharacter: (Int) -> Void
let onTapCommunityPost: (Int) -> Void let onTapCommunityPost: (Int) -> Void
let onTapBanner: (RecommendationBannerResponse) -> Void let onTapBanner: (RecommendationBannerResponse) -> Void
let onTapLiveAll: () -> Void
let onTapFollowAll: (@escaping () -> Void) -> Void let onTapFollowAll: (@escaping () -> Void) -> Void
let onSelectFollowingTab: () -> Bool let onSelectFollowingTab: () -> Bool
let onTapFollowingLogin: () -> Void let onTapFollowingLogin: () -> Void
@@ -71,6 +72,7 @@ struct MainHomeView: View {
onTapCharacter: onTapCharacter, onTapCharacter: onTapCharacter,
onTapCommunityPost: onTapCommunityPost, onTapCommunityPost: onTapCommunityPost,
onTapBanner: onTapBanner, onTapBanner: onTapBanner,
onTapLiveAll: onTapLiveAll,
onTapFollowAll: onTapFollowAll onTapFollowAll: onTapFollowAll
) )
case .ranking: case .ranking:
@@ -120,6 +122,7 @@ struct MainHomeView_Previews: PreviewProvider {
onTapCharacter: { _ in }, onTapCharacter: { _ in },
onTapCommunityPost: { _ in }, onTapCommunityPost: { _ in },
onTapBanner: { _ in }, onTapBanner: { _ in },
onTapLiveAll: {},
onTapFollowAll: { action in action() }, onTapFollowAll: { action in action() },
onSelectFollowingTab: { true }, onSelectFollowingTab: { true },
onTapFollowingLogin: {}, onTapFollowingLogin: {},

View File

@@ -3,6 +3,7 @@ import SwiftUI
struct MainHomeLiveSection: View { struct MainHomeLiveSection: View {
let items: [HomeLiveItem] let items: [HomeLiveItem]
let onTapLive: (Int) -> Void let onTapLive: (Int) -> Void
let onTapAll: () -> Void
var body: some View { var body: some View {
if !items.isEmpty { if !items.isEmpty {
@@ -11,6 +12,8 @@ struct MainHomeLiveSection: View {
ForEach(items, id: \.self) { item in ForEach(items, id: \.self) { item in
MainHomeLiveItemView(item: item, onTapLive: onTapLive) MainHomeLiveItemView(item: item, onTapLive: onTapLive)
} }
MainHomeLiveAllItemView(onTapAll: onTapAll)
} }
.padding(.horizontal, SodaSpacing.s20) .padding(.horizontal, SodaSpacing.s20)
} }
@@ -54,6 +57,27 @@ private struct MainHomeLiveItemView: View {
} }
} }
private struct MainHomeLiveAllItemView: View {
let onTapAll: () -> Void
var body: some View {
Button(action: onTapAll) {
VStack(alignment: .center, spacing: SodaSpacing.s6) {
Circle()
.fill(Color.gray800)
.frame(width: 70, height: 70)
.overlay {
Text(I18n.HomeRecommendation.liveAll)
.appFont(.body4)
.foregroundColor(.white)
}
}
.frame(width: 70, height: 102, alignment: .top)
}
.buttonStyle(.plain)
}
}
struct MainHomeLiveSection_Previews: PreviewProvider { struct MainHomeLiveSection_Previews: PreviewProvider {
private static let previewImageUrl = "https://picsum.photos/500/500" private static let previewImageUrl = "https://picsum.photos/500/500"
@@ -72,7 +96,8 @@ struct MainHomeLiveSection_Previews: PreviewProvider {
HomeLiveItem(roomId: 1, creatorNickname: "설린", creatorProfileImage: previewImageUrl), HomeLiveItem(roomId: 1, creatorNickname: "설린", creatorProfileImage: previewImageUrl),
HomeLiveItem(roomId: 2, creatorNickname: "크리에이터", creatorProfileImage: previewImageUrl) HomeLiveItem(roomId: 2, creatorNickname: "크리에이터", creatorProfileImage: previewImageUrl)
], ],
onTapLive: { _ in } onTapLive: { _ in },
onTapAll: {}
) )
.padding(.vertical, SodaSpacing.s20) .padding(.vertical, SodaSpacing.s20)
.background(Color.black) .background(Color.black)

View File

@@ -7,6 +7,7 @@ struct MainHomeRecommendationView: View {
let onTapCharacter: (Int) -> Void let onTapCharacter: (Int) -> Void
let onTapCommunityPost: (Int) -> Void let onTapCommunityPost: (Int) -> Void
let onTapBanner: (RecommendationBannerResponse) -> Void let onTapBanner: (RecommendationBannerResponse) -> Void
let onTapLiveAll: () -> Void
let onTapFollowAll: (@escaping () -> Void) -> Void let onTapFollowAll: (@escaping () -> Void) -> Void
@StateObject private var viewModel = MainHomeRecommendationViewModel() @StateObject private var viewModel = MainHomeRecommendationViewModel()
@@ -25,7 +26,8 @@ struct MainHomeRecommendationView: View {
VStack(alignment: .leading, spacing: SodaSpacing.s24) { VStack(alignment: .leading, spacing: SodaSpacing.s24) {
MainHomeLiveSection( MainHomeLiveSection(
items: viewModel.recommendations?.lives ?? [], items: viewModel.recommendations?.lives ?? [],
onTapLive: onTapLive onTapLive: onTapLive,
onTapAll: onTapLiveAll
) )
MainHomeBannerSection( MainHomeBannerSection(
@@ -122,6 +124,7 @@ struct MainHomeRecommendationView_Previews: PreviewProvider {
onTapCharacter: { _ in }, onTapCharacter: { _ in },
onTapCommunityPost: { _ in }, onTapCommunityPost: { _ in },
onTapBanner: { _ in }, onTapBanner: { _ in },
onTapLiveAll: {},
onTapFollowAll: { action in action() } onTapFollowAll: { action in action() }
) )
} }

View File

@@ -180,6 +180,7 @@ struct MainView: View {
onTapCharacter: handleRecommendationCreatorTap, onTapCharacter: handleRecommendationCreatorTap,
onTapCommunityPost: handleRecommendationCommunityPostTap, onTapCommunityPost: handleRecommendationCommunityPostTap,
onTapBanner: handleRecommendationBannerTap, onTapBanner: handleRecommendationBannerTap,
onTapLiveAll: handleRecommendationLiveAllTap,
onTapFollowAll: handleRecommendationFollowAllTap, onTapFollowAll: handleRecommendationFollowAllTap,
onSelectFollowingTab: handleFollowingTabSelection, onSelectFollowingTab: handleFollowingTabSelection,
onTapFollowingLogin: handleFollowingLoginTap, onTapFollowingLogin: handleFollowingLoginTap,
@@ -483,6 +484,10 @@ struct MainView: View {
} }
} }
private func handleRecommendationLiveAllTap() {
appState.setAppStep(step: .liveNowAll(onClickParticipant: handleRecommendationLiveTap))
}
private func handleRecommendationCreatorTap(creatorId: Int) { private func handleRecommendationCreatorTap(creatorId: Int) {
guard creatorId > 0 else { return } guard creatorId > 0 else { return }
performRecommendationDetailAction { performRecommendationDetailAction {