feat(home): 팔로잉 On Air 섹션을 추가한다
This commit is contained in:
@@ -261,6 +261,9 @@
|
|||||||
401C10412FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */; };
|
401C10412FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */; };
|
||||||
401C10422FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */; };
|
401C10422FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */; };
|
||||||
401C10432FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */; };
|
401C10432FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */; };
|
||||||
|
401C10452FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401C10482FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift */; };
|
||||||
|
401C10462FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401C10482FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift */; };
|
||||||
|
401C10472FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 401C10482FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift */; };
|
||||||
40235DED2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40235DEC2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift */; };
|
40235DED2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40235DEC2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift */; };
|
||||||
40235DEE2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40235DEC2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift */; };
|
40235DEE2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40235DEC2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift */; };
|
||||||
40235DF02E37983D00B09A87 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40235DEF2E37983D00B09A87 /* PersistenceController.swift */; };
|
40235DF02E37983D00B09A87 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40235DEF2E37983D00B09A87 /* PersistenceController.swift */; };
|
||||||
@@ -1800,6 +1803,7 @@
|
|||||||
401C10032FEF300000A5BBA3 /* MainHomeFollowingRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainHomeFollowingRepository.swift; sourceTree = "<group>"; };
|
401C10032FEF300000A5BBA3 /* MainHomeFollowingRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainHomeFollowingRepository.swift; sourceTree = "<group>"; };
|
||||||
401C10042FEF300000A5BBA3 /* MainHomeFollowingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainHomeFollowingViewModel.swift; sourceTree = "<group>"; };
|
401C10042FEF300000A5BBA3 /* MainHomeFollowingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainHomeFollowingViewModel.swift; sourceTree = "<group>"; };
|
||||||
401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainHomeFollowingCreatorSection.swift; sourceTree = "<group>"; };
|
401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainHomeFollowingCreatorSection.swift; sourceTree = "<group>"; };
|
||||||
|
401C10482FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainHomeFollowingLiveSection.swift; sourceTree = "<group>"; };
|
||||||
40235DEC2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RecentContent+CoreDataClass.swift"; sourceTree = "<group>"; };
|
40235DEC2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RecentContent+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||||
40235DEF2E37983D00B09A87 /* PersistenceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = "<group>"; };
|
40235DEF2E37983D00B09A87 /* PersistenceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = "<group>"; };
|
||||||
40235DF22E37987300B09A87 /* RecentContentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentContentService.swift; sourceTree = "<group>"; };
|
40235DF22E37987300B09A87 /* RecentContentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecentContentService.swift; sourceTree = "<group>"; };
|
||||||
@@ -2812,6 +2816,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */,
|
401C10442FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift */,
|
||||||
|
401C10482FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift */,
|
||||||
);
|
);
|
||||||
path = Components;
|
path = Components;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -5481,6 +5486,7 @@
|
|||||||
401C10132FEF300000A5BBA3 /* MainHomeFollowingRepository.swift in Sources */,
|
401C10132FEF300000A5BBA3 /* MainHomeFollowingRepository.swift in Sources */,
|
||||||
401C10142FEF300000A5BBA3 /* MainHomeFollowingViewModel.swift in Sources */,
|
401C10142FEF300000A5BBA3 /* MainHomeFollowingViewModel.swift in Sources */,
|
||||||
401C10412FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */,
|
401C10412FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */,
|
||||||
|
401C10452FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift in Sources */,
|
||||||
409143302A85652F00EEBFB1 /* CanChargeView.swift in Sources */,
|
409143302A85652F00EEBFB1 /* CanChargeView.swift in Sources */,
|
||||||
40975CA32B572298004E2F1B /* LiveRoomOverlayStrokeTextButton.swift in Sources */,
|
40975CA32B572298004E2F1B /* LiveRoomOverlayStrokeTextButton.swift in Sources */,
|
||||||
40235DED2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift in Sources */,
|
40235DED2E3797EB00B09A87 /* RecentContent+CoreDataClass.swift in Sources */,
|
||||||
@@ -6246,6 +6252,7 @@
|
|||||||
401C10232FEF300000A5BBA3 /* MainHomeFollowingRepository.swift in Sources */,
|
401C10232FEF300000A5BBA3 /* MainHomeFollowingRepository.swift in Sources */,
|
||||||
401C10242FEF300000A5BBA3 /* MainHomeFollowingViewModel.swift in Sources */,
|
401C10242FEF300000A5BBA3 /* MainHomeFollowingViewModel.swift in Sources */,
|
||||||
401C10422FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */,
|
401C10422FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */,
|
||||||
|
401C10462FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift in Sources */,
|
||||||
B3AF650899B8FC84E0C0CDA0 /* MainPlaceholderTabView.swift in Sources */,
|
B3AF650899B8FC84E0C0CDA0 /* MainPlaceholderTabView.swift in Sources */,
|
||||||
CA65AD0D677B4A8E9CAC0E15 /* MainTab.swift in Sources */,
|
CA65AD0D677B4A8E9CAC0E15 /* MainTab.swift in Sources */,
|
||||||
A0643C829BE7377DC09112CB /* MainTabBarButton.swift in Sources */,
|
A0643C829BE7377DC09112CB /* MainTabBarButton.swift in Sources */,
|
||||||
@@ -7041,6 +7048,7 @@
|
|||||||
401C10332FEF300000A5BBA3 /* MainHomeFollowingRepository.swift in Sources */,
|
401C10332FEF300000A5BBA3 /* MainHomeFollowingRepository.swift in Sources */,
|
||||||
401C10342FEF300000A5BBA3 /* MainHomeFollowingViewModel.swift in Sources */,
|
401C10342FEF300000A5BBA3 /* MainHomeFollowingViewModel.swift in Sources */,
|
||||||
401C10432FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */,
|
401C10432FEF500000A5BBA3 /* MainHomeFollowingCreatorSection.swift in Sources */,
|
||||||
|
401C10472FEF700000A5BBA3 /* MainHomeFollowingLiveSection.swift in Sources */,
|
||||||
ACD71056E97E13E48941ABBB /* MainPlaceholderTabView.swift in Sources */,
|
ACD71056E97E13E48941ABBB /* MainPlaceholderTabView.swift in Sources */,
|
||||||
33BA3AB731849284E62AE04B /* MainTab.swift in Sources */,
|
33BA3AB731849284E62AE04B /* MainTab.swift in Sources */,
|
||||||
B11681AC02BF51C6E2FA6FF3 /* MainTabBarButton.swift in Sources */,
|
B11681AC02BF51C6E2FA6FF3 /* MainTabBarButton.swift in Sources */,
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct MainHomeFollowingLiveSection: View {
|
||||||
|
let onAirLives: [FollowingLiveResponse]
|
||||||
|
let onTapLive: (Int) -> Void
|
||||||
|
|
||||||
|
init(
|
||||||
|
onAirLives: [FollowingLiveResponse],
|
||||||
|
onTapLive: @escaping (Int) -> Void = { _ in }
|
||||||
|
) {
|
||||||
|
self.onAirLives = onAirLives
|
||||||
|
self.onTapLive = onTapLive
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if !onAirLives.isEmpty {
|
||||||
|
VStack(alignment: .leading, spacing: SodaSpacing.s14) {
|
||||||
|
SectionTitle(title: I18n.HomeFollowing.onAirTitle)
|
||||||
|
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
LazyHStack(alignment: .top, spacing: SodaSpacing.s8) {
|
||||||
|
ForEach(onAirLives) { live in
|
||||||
|
MainHomeFollowingLiveItemView(live: live) {
|
||||||
|
onTapLive(live.liveId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.leading, SodaSpacing.s14)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct MainHomeFollowingLiveItemView: View {
|
||||||
|
let live: FollowingLiveResponse
|
||||||
|
let action: () -> Void
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: action) {
|
||||||
|
HStack(alignment: .center, spacing: SodaSpacing.s8) {
|
||||||
|
DownsampledKFImage(url: URL(string: live.creatorProfileImageUrl), size: CGSize(width: 75, height: 75))
|
||||||
|
.clipShape(Circle())
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: SodaSpacing.s4) {
|
||||||
|
HStack(alignment: .center, spacing: SodaSpacing.s8) {
|
||||||
|
LiveTagView()
|
||||||
|
|
||||||
|
Text(live.relativeStartedAtText())
|
||||||
|
.appFont(size: 14, weight: .regular)
|
||||||
|
.foregroundColor(Color.gray500)
|
||||||
|
.lineLimit(1)
|
||||||
|
.fixedSize(horizontal: true, vertical: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(live.title)
|
||||||
|
.appFont(size: 18, weight: .bold)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.lineLimit(1)
|
||||||
|
.truncationMode(.tail)
|
||||||
|
|
||||||
|
Text(live.creatorNickname)
|
||||||
|
.appFont(size: 14, weight: .regular)
|
||||||
|
.foregroundColor(Color.gray500)
|
||||||
|
.lineLimit(1)
|
||||||
|
.truncationMode(.tail)
|
||||||
|
}
|
||||||
|
.frame(width: 149, alignment: .leading)
|
||||||
|
}
|
||||||
|
.padding(.leading, SodaSpacing.s12)
|
||||||
|
.padding(.trailing, 22)
|
||||||
|
.padding(.vertical, SodaSpacing.s12)
|
||||||
|
.background(Color.gray900)
|
||||||
|
.clipShape(Capsule())
|
||||||
|
.overlay {
|
||||||
|
Capsule()
|
||||||
|
.stroke(Color(hex: "62CFFF"), lineWidth: 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct LiveTagView: View {
|
||||||
|
var body: some View {
|
||||||
|
HStack(alignment: .center, spacing: SodaSpacing.s4) {
|
||||||
|
Circle()
|
||||||
|
.fill(Color.red400)
|
||||||
|
.frame(width: 8, height: 8)
|
||||||
|
|
||||||
|
Text("LIVE")
|
||||||
|
.appFont(size: 12, weight: .regular)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.lineLimit(1)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, SodaSpacing.s4)
|
||||||
|
.padding(.vertical, 2)
|
||||||
|
.frame(height: 18)
|
||||||
|
.background(Color.black)
|
||||||
|
.clipShape(Capsule())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension FollowingLiveResponse {
|
||||||
|
func relativeStartedAtText(now: Date = Date()) -> String {
|
||||||
|
DateParser.relativeTimeText(fromUTC: startedAtUtc, fallback: startedAtUtc, now: now)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MainHomeFollowingLiveSection_Previews: PreviewProvider {
|
||||||
|
private static let previewImageUrl = "https://placehold.co/500"
|
||||||
|
|
||||||
|
static var previews: some View {
|
||||||
|
MainHomeFollowingLiveSection(
|
||||||
|
onAirLives: [
|
||||||
|
FollowingLiveResponse(
|
||||||
|
liveId: 1,
|
||||||
|
creatorProfileImageUrl: previewImageUrl,
|
||||||
|
creatorNickname: "크리에이터",
|
||||||
|
title: "오늘 밤 같이 이야기해요",
|
||||||
|
startedAtUtc: "2026-07-01T00:30:00Z"
|
||||||
|
),
|
||||||
|
FollowingLiveResponse(
|
||||||
|
liveId: 2,
|
||||||
|
creatorProfileImageUrl: previewImageUrl,
|
||||||
|
creatorNickname: "소다",
|
||||||
|
title: "신규 콘텐츠 제작 비하인드",
|
||||||
|
startedAtUtc: "2026-07-01T00:10:00Z"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
.padding(.vertical, SodaSpacing.s20)
|
||||||
|
.background(Color.black)
|
||||||
|
.previewLayout(.sizeThatFits)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct MainHomeFollowingView: View {
|
struct MainHomeFollowingView: View {
|
||||||
|
let onTapLive: (Int) -> Void
|
||||||
let onTapCreator: (Int) -> Void
|
let onTapCreator: (Int) -> Void
|
||||||
let onTapFollowingAll: () -> Void
|
let onTapFollowingAll: () -> Void
|
||||||
|
|
||||||
@StateObject private var viewModel = MainHomeFollowingViewModel()
|
@StateObject private var viewModel = MainHomeFollowingViewModel()
|
||||||
|
|
||||||
init(
|
init(
|
||||||
|
onTapLive: @escaping (Int) -> Void = { _ in },
|
||||||
onTapCreator: @escaping (Int) -> Void = { _ in },
|
onTapCreator: @escaping (Int) -> Void = { _ in },
|
||||||
onTapFollowingAll: @escaping () -> Void = {}
|
onTapFollowingAll: @escaping () -> Void = {}
|
||||||
) {
|
) {
|
||||||
|
self.onTapLive = onTapLive
|
||||||
self.onTapCreator = onTapCreator
|
self.onTapCreator = onTapCreator
|
||||||
self.onTapFollowingAll = onTapFollowingAll
|
self.onTapFollowingAll = onTapFollowingAll
|
||||||
}
|
}
|
||||||
@@ -22,6 +25,11 @@ struct MainHomeFollowingView: View {
|
|||||||
onTapAll: onTapFollowingAll
|
onTapAll: onTapFollowingAll
|
||||||
)
|
)
|
||||||
|
|
||||||
|
MainHomeFollowingLiveSection(
|
||||||
|
onAirLives: viewModel.response?.onAirLives ?? [],
|
||||||
|
onTapLive: onTapLive
|
||||||
|
)
|
||||||
|
|
||||||
MainPlaceholderTabView(title: "팔로잉")
|
MainPlaceholderTabView(title: "팔로잉")
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ struct MainHomeView: View {
|
|||||||
MainHomeRankingView(onTapCreator: onTapCreator)
|
MainHomeRankingView(onTapCreator: onTapCreator)
|
||||||
case .following:
|
case .following:
|
||||||
MainHomeFollowingView(
|
MainHomeFollowingView(
|
||||||
|
onTapLive: onTapLive,
|
||||||
onTapCreator: onTapCreator,
|
onTapCreator: onTapCreator,
|
||||||
onTapFollowingAll: onTapFollowingAll
|
onTapFollowingAll: onTapFollowingAll
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -236,7 +236,7 @@
|
|||||||
|
|
||||||
### Phase 5: On Air 섹션
|
### Phase 5: On Air 섹션
|
||||||
|
|
||||||
- [ ] **Task 5.1: On Air 섹션 생성**
|
- [x] **Task 5.1: On Air 섹션 생성**
|
||||||
- 대상 파일:
|
- 대상 파일:
|
||||||
- 생성: `SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift`
|
- 생성: `SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift`
|
||||||
- 작업 내용:
|
- 작업 내용:
|
||||||
@@ -508,3 +508,14 @@
|
|||||||
- 2026-07-01: `rg "StateObject private var viewModel = MainHomeFollowingViewModel|onAppear|hasLoaded|fetchFollowing|response\?\.followingCreators|isLoading|message|MainPlaceholderTabView" SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingViewModel.swift`로 Phase 4 정적 요구사항을 확인했다.
|
- 2026-07-01: `rg "StateObject private var viewModel = MainHomeFollowingViewModel|onAppear|hasLoaded|fetchFollowing|response\?\.followingCreators|isLoading|message|MainPlaceholderTabView" SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingView.swift SodaLive/Sources/V2/Main/Home/Following/MainHomeFollowingViewModel.swift`로 Phase 4 정적 요구사항을 확인했다.
|
||||||
- 2026-07-01: `rg "onSelectFollowingTab|Binding\(|selectedTab = \.following|setAppStep\(step: \.login\)|TextTabBar" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift`로 비로그인 팔로잉 탭 guard 흐름이 유지됨을 확인했다.
|
- 2026-07-01: `rg "onSelectFollowingTab|Binding\(|selectedTab = \.following|setAppStep\(step: \.login\)|TextTabBar" SodaLive/Sources/V2/Main/Home/MainHomeView.swift SodaLive/Sources/V2/Main/MainView.swift`로 비로그인 팔로잉 탭 guard 흐름이 유지됨을 확인했다.
|
||||||
- 2026-07-01: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`를 실행해 Phase 4 API 호출 연결 후 빌드 성공을 확인했다. 기존 AppIntents metadata extraction warning은 남아 있으나 컴파일 오류는 없었다.
|
- 2026-07-01: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`를 실행해 Phase 4 API 호출 연결 후 빌드 성공을 확인했다. 기존 AppIntents metadata extraction warning은 남아 있으나 컴파일 오류는 없었다.
|
||||||
|
- 2026-07-01: Phase 5 구현을 진행해 `MainHomeFollowingLiveSection`을 추가하고, `FollowingLiveResponse`의 프로필 이미지/닉네임/라이브 제목/`startedAtUtc` 상대 시간 표시와 `onTapLive(liveId)` callback을 연결했다.
|
||||||
|
- 2026-07-01: `rg "struct MainHomeFollowingLiveSection|onAirTitle|FollowingLiveResponse|startedAtUtc|DateParser|onTapLive|DownsampledKFImage|ScrollView\(\.horizontal|!onAirLives\.isEmpty" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift`로 Phase 5 정적 요구사항을 확인했다.
|
||||||
|
- 2026-07-01: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`를 실행해 Phase 5 신규 Swift 파일 컴파일과 빌드 성공을 확인했다. 기존 Crashlytics dSYM/AppIntents metadata extraction warning은 남아 있으나 컴파일 오류는 없었다.
|
||||||
|
- 2026-07-01: 사용자 요청에 따라 Phase 11까지 기다리지 않고 `MainHomeFollowingView`에 `MainHomeFollowingLiveSection`을 조기 조립했다. `viewModel.response?.onAirLives ?? []`를 전달하고, `MainHomeView`의 기존 `onTapLive` callback을 팔로잉 On Air 섹션까지 연결했다.
|
||||||
|
- 2026-07-01: `SodaLive.xcodeproj/project.pbxproj`에 `MainHomeFollowingLiveSection.swift` 파일 참조와 Sources build file을 추가해 Xcode navigator와 target compile sources에서 바로 확인 가능하도록 등록했다.
|
||||||
|
- 2026-07-01: `rg "MainHomeFollowingLiveSection.swift|MainHomeFollowingLiveSection.swift in Sources|MainHomeFollowingLiveSection\(" SodaLive.xcodeproj/project.pbxproj SodaLive/Sources/V2/Main/Home`로 Xcode 프로젝트 등록과 화면 조립을 확인했다.
|
||||||
|
- 2026-07-01: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`를 재실행해 프로젝트 등록 후 빌드 성공을 확인했다. 기존 duplicate build file/run script/Crashlytics dSYM/AppIntents warning은 남아 있으나 컴파일 오류는 없었다.
|
||||||
|
- 2026-07-01: Figma `24:5693`, `24:5696`을 확인해 On Air 섹션을 캡슐형 라이브 아이템으로 수정했다. `75x75` 프로필, 검정 `LIVE` pill, `#62CFFF` 2pt 캡슐 테두리, `14/18/14pt` 텍스트 계층, leading 14/item gap 8 간격을 반영했다.
|
||||||
|
- 2026-07-01: `rg "CGSize\(width: 75, height: 75\)|Color\(hex: \"62CFFF\"\)|Text\(\"LIVE\"\)|frame\(height: 18\)|padding\(\.trailing, 22\)|padding\(\.leading, SodaSpacing\.s14\)|spacing: SodaSpacing\.s8|appFont\(size: 18, weight: \.bold\)|appFont\(size: 14, weight: \.regular\)" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift`로 Figma 핵심 수치 반영을 확인했다.
|
||||||
|
- 2026-07-01: `rg "localhost:3845|img_live|frame\(width: 50, height: 18\)|CGSize\(width: 62, height: 62\)|RoundedRectangle" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingLiveSection.swift` 결과가 없어 Figma localhost asset 미사용과 기존 배지/카드 형태 제거를 확인했다.
|
||||||
|
- 2026-07-01: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`를 실행해 Figma 반영 후 빌드 성공을 확인했다. 기존 Crashlytics dSYM/AppIntents warning은 남아 있으나 컴파일 오류는 없었다.
|
||||||
|
|||||||
Reference in New Issue
Block a user