From 4214829a20392a580b4e86b1122e9064d27d5b7e Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Fri, 3 Jul 2026 16:49:48 +0900 Subject: [PATCH] =?UTF-8?q?feat(creator):=20=ED=8C=ACTalk=20=EC=84=B9?= =?UTF-8?q?=EC=85=98=EC=9D=84=20=EC=97=B0=EA=B2=B0=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SodaLive.xcodeproj/project.pbxproj | 8 ++ .../CreatorChannelFanTalkSection.swift | 90 +++++++++++++++++++ .../Home/CreatorChannelHomeView.swift | 5 ++ docs/20260701_크리에이터_채널_홈/plan-task.md | 2 +- 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swift diff --git a/SodaLive.xcodeproj/project.pbxproj b/SodaLive.xcodeproj/project.pbxproj index 853913c9..20ca6b2c 100644 --- a/SodaLive.xcodeproj/project.pbxproj +++ b/SodaLive.xcodeproj/project.pbxproj @@ -49,6 +49,9 @@ CC01011C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift */; }; CC01021C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift */; }; CC01031C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift */; }; + CC01011D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift */; }; + CC01021D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift */; }; + CC01031D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC01001D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift */; }; CC0101082FF0100000A5BBA3 /* CreatorChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100082FF0100000A5BBA3 /* CreatorChannelView.swift */; }; CC0102082FF0100000A5BBA3 /* CreatorChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100082FF0100000A5BBA3 /* CreatorChannelView.swift */; }; CC0103082FF0100000A5BBA3 /* CreatorChannelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC0100082FF0100000A5BBA3 /* CreatorChannelView.swift */; }; @@ -1782,6 +1785,7 @@ CC01001A2FF0100000A5BBA3 /* CreatorChannelAudioSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelAudioSection.swift; sourceTree = ""; }; CC01001B2FF0100000A5BBA3 /* CreatorChannelSeriesSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelSeriesSection.swift; sourceTree = ""; }; CC01001C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelCommunitySection.swift; sourceTree = ""; }; + CC01001D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatorChannelFanTalkSection.swift; sourceTree = ""; }; 0BBDC3ECBBE049EAA4057D3A /* PostChannelDonationRequest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PostChannelDonationRequest.swift; sourceTree = ""; }; 0EC05859619BDC03056911E7 /* MainTab.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainTab.swift; sourceTree = ""; }; 189350EA101CF12EEBA6EC1D /* MainTabBarView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainTabBarView.swift; sourceTree = ""; }; @@ -2710,6 +2714,7 @@ CC01001A2FF0100000A5BBA3 /* CreatorChannelAudioSection.swift */, CC01001B2FF0100000A5BBA3 /* CreatorChannelSeriesSection.swift */, CC01001C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift */, + CC01001D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift */, ); path = Components; sourceTree = ""; @@ -5653,6 +5658,7 @@ CC01011A2FF0100000A5BBA3 /* CreatorChannelAudioSection.swift in Sources */, CC01011B2FF0100000A5BBA3 /* CreatorChannelSeriesSection.swift in Sources */, CC01011C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift in Sources */, + CC01011D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift in Sources */, CC0101082FF0100000A5BBA3 /* CreatorChannelView.swift in Sources */, CC0101112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift in Sources */, CC0101122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift in Sources */, @@ -6459,6 +6465,7 @@ CC01021A2FF0100000A5BBA3 /* CreatorChannelAudioSection.swift in Sources */, CC01021B2FF0100000A5BBA3 /* CreatorChannelSeriesSection.swift in Sources */, CC01021C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift in Sources */, + CC01021D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift in Sources */, CC0102082FF0100000A5BBA3 /* CreatorChannelView.swift in Sources */, CC0102112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift in Sources */, CC0102122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift in Sources */, @@ -7281,6 +7288,7 @@ CC01031A2FF0100000A5BBA3 /* CreatorChannelAudioSection.swift in Sources */, CC01031B2FF0100000A5BBA3 /* CreatorChannelSeriesSection.swift in Sources */, CC01031C2FF0100000A5BBA3 /* CreatorChannelCommunitySection.swift in Sources */, + CC01031D2FF0100000A5BBA3 /* CreatorChannelFanTalkSection.swift in Sources */, CC0103082FF0100000A5BBA3 /* CreatorChannelView.swift in Sources */, CC0103112FF0100000A5BBA3 /* CreatorChannelTitleBar.swift in Sources */, CC0103122FF0100000A5BBA3 /* CreatorChannelHeaderSection.swift in Sources */, diff --git a/SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swift b/SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swift new file mode 100644 index 00000000..6121154c --- /dev/null +++ b/SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swift @@ -0,0 +1,90 @@ +import SwiftUI + +struct CreatorChannelFanTalkSection: View { + let fanTalk: CreatorChannelFanTalkSummaryResponse + let onSelectTab: (CreatorChannelTab) -> Void + + var body: some View { + if let latestFanTalk = fanTalk.latestFanTalk { + VStack(alignment: .leading, spacing: SodaSpacing.s14) { + SectionTitle(title: I18n.CreatorChannelHome.fanTalk) { + onSelectTab(.fanTalk) + } + + CreatorChannelFanTalkCard( + totalCount: fanTalk.totalCount, + latestFanTalk: latestFanTalk + ) + .padding(.horizontal, SodaSpacing.s14) + } + .padding(.top, SodaSpacing.s20) + } + } +} + +private struct CreatorChannelFanTalkCard: View { + let totalCount: Int + let latestFanTalk: CreatorChannelFanTalkResponse + + var body: some View { + VStack(alignment: .leading, spacing: SodaSpacing.s8) { + HStack(spacing: SodaSpacing.s4) { + Text("전체") + .appFont(size: 16, weight: .medium) + .foregroundColor(.white) + + Text("\(totalCount)") + .appFont(size: 16, weight: .medium) + .foregroundColor(Color.gray500) + } + + HStack(alignment: .center, spacing: SodaSpacing.s14) { + DownsampledKFImage( + url: URL(string: latestFanTalk.profileImageUrl), + size: CGSize(width: 28, height: 28) + ) + .background(Color.white.opacity(0.9)) + .clipShape(Circle()) + + Text(latestFanTalk.content) + .appFont(size: 14, weight: .regular) + .foregroundColor(.white) + .lineLimit(2) + .truncationMode(.tail) + .frame(maxWidth: .infinity, minHeight: 40, alignment: .leading) + .frame(maxWidth: .infinity, alignment: .leading) + + Image(systemName: "chevron.down") + .font(.system(size: 12, weight: .medium)) + .foregroundColor(.white) + .frame(width: 18, height: 18) + } + } + .padding(SodaSpacing.s14) + .frame(maxWidth: .infinity, alignment: .leading) + .background(Color.gray900) + .clipShape(RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous)) + } +} + +struct CreatorChannelFanTalkSection_Previews: PreviewProvider { + static var previews: some View { + CreatorChannelFanTalkSection( + fanTalk: CreatorChannelFanTalkSummaryResponse( + totalCount: 23, + latestFanTalk: CreatorChannelFanTalkResponse( + fanTalkId: 1, + memberId: 10, + nickname: "팬 닉네임", + profileImageUrl: "https://picsum.photos/120/120", + content: "팬이 쓴 응원이 보이는 부분입니다. 두 줄까지만 보여주고 초과 시 말줄임 처리합니다.", + languageCode: "ko", + createdAtUtc: "2026-07-03T03:44:00Z" + ) + ), + onSelectTab: { _ in } + ) + .background(Color.black) + .previewLayout(.sizeThatFits) + } +} diff --git a/SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift b/SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift index c0365571..364c6785 100644 --- a/SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift +++ b/SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift @@ -72,6 +72,11 @@ struct CreatorChannelHomeView: View { onSelectTab: onSelectTab, onTapLike: onTapCommunityLike ) + + CreatorChannelFanTalkSection( + fanTalk: response.fanTalk, + onSelectTab: onSelectTab + ) } .frame(maxWidth: .infinity, alignment: .leading) .background(Color.black) diff --git a/docs/20260701_크리에이터_채널_홈/plan-task.md b/docs/20260701_크리에이터_채널_홈/plan-task.md index 65d1f105..1183af66 100644 --- a/docs/20260701_크리에이터_채널_홈/plan-task.md +++ b/docs/20260701_크리에이터_채널_홈/plan-task.md @@ -482,7 +482,7 @@ ### Phase 13: 팬Talk 섹션 -- [ ] **Task 13.1: 팬Talk 섹션 구현** +- [x] **Task 13.1: 팬Talk 섹션 구현** - 대상 파일: - 생성: `SodaLive/Sources/V2/CreatorChannel/Home/Components/CreatorChannelFanTalkSection.swift` - 수정: `SodaLive/Sources/V2/CreatorChannel/Home/CreatorChannelHomeView.swift`