fix(main): 추천 커뮤니티 상세로 이동한다
This commit is contained in:
@@ -14,6 +14,7 @@ struct CommunityPostCard: View {
|
|||||||
let isLike: Bool
|
let isLike: Bool
|
||||||
let likeCount: Int
|
let likeCount: Int
|
||||||
let commentCount: Int
|
let commentCount: Int
|
||||||
|
let onTapPost: () -> Void
|
||||||
let onTapLike: () -> Void
|
let onTapLike: () -> Void
|
||||||
let onTapComment: () -> Void
|
let onTapComment: () -> Void
|
||||||
let onTapPurchase: () -> Void
|
let onTapPurchase: () -> Void
|
||||||
@@ -36,6 +37,7 @@ struct CommunityPostCard: View {
|
|||||||
isLike: Bool,
|
isLike: Bool,
|
||||||
likeCount: Int,
|
likeCount: Int,
|
||||||
commentCount: Int,
|
commentCount: Int,
|
||||||
|
onTapPost: @escaping () -> Void = {},
|
||||||
onTapLike: @escaping () -> Void = {},
|
onTapLike: @escaping () -> Void = {},
|
||||||
onTapComment: @escaping () -> Void = {},
|
onTapComment: @escaping () -> Void = {},
|
||||||
onTapPurchase: @escaping () -> Void = {}
|
onTapPurchase: @escaping () -> Void = {}
|
||||||
@@ -52,6 +54,7 @@ struct CommunityPostCard: View {
|
|||||||
self.isLike = isLike
|
self.isLike = isLike
|
||||||
self.likeCount = likeCount
|
self.likeCount = likeCount
|
||||||
self.commentCount = commentCount
|
self.commentCount = commentCount
|
||||||
|
self.onTapPost = onTapPost
|
||||||
self.onTapLike = onTapLike
|
self.onTapLike = onTapLike
|
||||||
self.onTapComment = onTapComment
|
self.onTapComment = onTapComment
|
||||||
self.onTapPurchase = onTapPurchase
|
self.onTapPurchase = onTapPurchase
|
||||||
@@ -76,6 +79,8 @@ struct CommunityPostCard: View {
|
|||||||
.padding(SodaSpacing.s14)
|
.padding(SodaSpacing.s14)
|
||||||
.background(Color.gray900)
|
.background(Color.gray900)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous))
|
.clipShape(RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous))
|
||||||
|
.contentShape(RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous))
|
||||||
|
.onTapGesture(perform: onTapPost)
|
||||||
.onChange(of: isLike) { newValue in
|
.onChange(of: isLike) { newValue in
|
||||||
localIsLike = newValue
|
localIsLike = newValue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ struct MainHomeView: View {
|
|||||||
let onTapCreator: (Int) -> Void
|
let onTapCreator: (Int) -> Void
|
||||||
let onTapContent: (Int) -> Void
|
let onTapContent: (Int) -> Void
|
||||||
let onTapCharacter: (Int) -> Void
|
let onTapCharacter: (Int) -> Void
|
||||||
let onTapCommunity: (Int) -> Void
|
let onTapCommunityPost: (Int) -> Void
|
||||||
let onTapBanner: (RecommendationBannerResponse) -> Void
|
let onTapBanner: (RecommendationBannerResponse) -> Void
|
||||||
let onTapFollowAll: (@escaping () -> Void) -> Void
|
let onTapFollowAll: (@escaping () -> Void) -> Void
|
||||||
let onSelectFollowingTab: () -> Bool
|
let onSelectFollowingTab: () -> Bool
|
||||||
@@ -69,7 +69,7 @@ struct MainHomeView: View {
|
|||||||
onTapCreator: onTapCreator,
|
onTapCreator: onTapCreator,
|
||||||
onTapContent: onTapContent,
|
onTapContent: onTapContent,
|
||||||
onTapCharacter: onTapCharacter,
|
onTapCharacter: onTapCharacter,
|
||||||
onTapCommunity: onTapCommunity,
|
onTapCommunityPost: onTapCommunityPost,
|
||||||
onTapBanner: onTapBanner,
|
onTapBanner: onTapBanner,
|
||||||
onTapFollowAll: onTapFollowAll
|
onTapFollowAll: onTapFollowAll
|
||||||
)
|
)
|
||||||
@@ -117,7 +117,7 @@ struct MainHomeView_Previews: PreviewProvider {
|
|||||||
onTapCreator: { _ in },
|
onTapCreator: { _ in },
|
||||||
onTapContent: { _ in },
|
onTapContent: { _ in },
|
||||||
onTapCharacter: { _ in },
|
onTapCharacter: { _ in },
|
||||||
onTapCommunity: { _ in },
|
onTapCommunityPost: { _ in },
|
||||||
onTapBanner: { _ in },
|
onTapBanner: { _ in },
|
||||||
onTapFollowAll: { action in action() },
|
onTapFollowAll: { action in action() },
|
||||||
onSelectFollowingTab: { true },
|
onSelectFollowingTab: { true },
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ struct MainHomeActiveCreatorSection: View {
|
|||||||
let items: [HomeActiveCreatorItem]
|
let items: [HomeActiveCreatorItem]
|
||||||
let onTapLive: (Int) -> Void
|
let onTapLive: (Int) -> Void
|
||||||
let onTapContent: (Int) -> Void
|
let onTapContent: (Int) -> Void
|
||||||
let onTapCommunity: (Int) -> Void
|
let onTapCommunityPost: (Int) -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
items: [HomeActiveCreatorItem],
|
items: [HomeActiveCreatorItem],
|
||||||
onTapLive: @escaping (Int) -> Void = { _ in },
|
onTapLive: @escaping (Int) -> Void = { _ in },
|
||||||
onTapContent: @escaping (Int) -> Void = { _ in },
|
onTapContent: @escaping (Int) -> Void = { _ in },
|
||||||
onTapCommunity: @escaping (Int) -> Void = { _ in }
|
onTapCommunityPost: @escaping (Int) -> Void = { _ in }
|
||||||
) {
|
) {
|
||||||
self.items = items
|
self.items = items
|
||||||
self.onTapLive = onTapLive
|
self.onTapLive = onTapLive
|
||||||
self.onTapContent = onTapContent
|
self.onTapContent = onTapContent
|
||||||
self.onTapCommunity = onTapCommunity
|
self.onTapCommunityPost = onTapCommunityPost
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@@ -46,7 +46,7 @@ struct MainHomeActiveCreatorSection: View {
|
|||||||
case .audio:
|
case .audio:
|
||||||
onTapContent(targetId)
|
onTapContent(targetId)
|
||||||
case .community:
|
case .community:
|
||||||
onTapCommunity(targetId)
|
onTapCommunityPost(targetId)
|
||||||
case .unknown:
|
case .unknown:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,18 @@ import SwiftUI
|
|||||||
|
|
||||||
struct MainHomePopularCommunitySection: View {
|
struct MainHomePopularCommunitySection: View {
|
||||||
let items: [HomePopularCommunityPostItem]
|
let items: [HomePopularCommunityPostItem]
|
||||||
let onTapCommunity: (Int) -> Void
|
let onTapCommunityPost: (Int) -> Void
|
||||||
let onTapLike: (Int) -> Void
|
let onTapLike: (Int) -> Void
|
||||||
let onTapPurchase: (HomePopularCommunityPostItem) -> Void
|
let onTapPurchase: (HomePopularCommunityPostItem) -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
items: [HomePopularCommunityPostItem],
|
items: [HomePopularCommunityPostItem],
|
||||||
onTapCommunity: @escaping (Int) -> Void = { _ in },
|
onTapCommunityPost: @escaping (Int) -> Void = { _ in },
|
||||||
onTapLike: @escaping (Int) -> Void = { _ in },
|
onTapLike: @escaping (Int) -> Void = { _ in },
|
||||||
onTapPurchase: @escaping (HomePopularCommunityPostItem) -> Void = { _ in }
|
onTapPurchase: @escaping (HomePopularCommunityPostItem) -> Void = { _ in }
|
||||||
) {
|
) {
|
||||||
self.items = items
|
self.items = items
|
||||||
self.onTapCommunity = onTapCommunity
|
self.onTapCommunityPost = onTapCommunityPost
|
||||||
self.onTapLike = onTapLike
|
self.onTapLike = onTapLike
|
||||||
self.onTapPurchase = onTapPurchase
|
self.onTapPurchase = onTapPurchase
|
||||||
}
|
}
|
||||||
@@ -38,11 +38,14 @@ struct MainHomePopularCommunitySection: View {
|
|||||||
isLike: item.isLiked,
|
isLike: item.isLiked,
|
||||||
likeCount: item.likeCount,
|
likeCount: item.likeCount,
|
||||||
commentCount: item.commentCount,
|
commentCount: item.commentCount,
|
||||||
|
onTapPost: {
|
||||||
|
onTapCommunityPost(item.postId)
|
||||||
|
},
|
||||||
onTapLike: {
|
onTapLike: {
|
||||||
onTapLike(item.postId)
|
onTapLike(item.postId)
|
||||||
},
|
},
|
||||||
onTapComment: {
|
onTapComment: {
|
||||||
onTapCommunity(item.creatorId)
|
onTapCommunityPost(item.postId)
|
||||||
},
|
},
|
||||||
onTapPurchase: {
|
onTapPurchase: {
|
||||||
onTapPurchase(item)
|
onTapPurchase(item)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ struct MainHomeRecommendationView: View {
|
|||||||
let onTapCreator: (Int) -> Void
|
let onTapCreator: (Int) -> Void
|
||||||
let onTapContent: (Int) -> Void
|
let onTapContent: (Int) -> Void
|
||||||
let onTapCharacter: (Int) -> Void
|
let onTapCharacter: (Int) -> Void
|
||||||
let onTapCommunity: (Int) -> Void
|
let onTapCommunityPost: (Int) -> Void
|
||||||
let onTapBanner: (RecommendationBannerResponse) -> Void
|
let onTapBanner: (RecommendationBannerResponse) -> Void
|
||||||
let onTapFollowAll: (@escaping () -> Void) -> Void
|
let onTapFollowAll: (@escaping () -> Void) -> Void
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ struct MainHomeRecommendationView: View {
|
|||||||
items: viewModel.recommendations?.recentlyActiveCreators ?? [],
|
items: viewModel.recommendations?.recentlyActiveCreators ?? [],
|
||||||
onTapLive: onTapLive,
|
onTapLive: onTapLive,
|
||||||
onTapContent: onTapContent,
|
onTapContent: onTapContent,
|
||||||
onTapCommunity: onTapCommunity
|
onTapCommunityPost: onTapCommunityPost
|
||||||
)
|
)
|
||||||
|
|
||||||
MainHomeRecentDebutCreatorSection(
|
MainHomeRecentDebutCreatorSection(
|
||||||
@@ -79,7 +79,7 @@ struct MainHomeRecommendationView: View {
|
|||||||
|
|
||||||
MainHomePopularCommunitySection(
|
MainHomePopularCommunitySection(
|
||||||
items: viewModel.recommendations?.popularCommunityPosts ?? [],
|
items: viewModel.recommendations?.popularCommunityPosts ?? [],
|
||||||
onTapCommunity: onTapCommunity,
|
onTapCommunityPost: onTapCommunityPost,
|
||||||
onTapLike: { postId in
|
onTapLike: { postId in
|
||||||
viewModel.likeCommunityPost(postId: postId)
|
viewModel.likeCommunityPost(postId: postId)
|
||||||
},
|
},
|
||||||
@@ -132,7 +132,7 @@ struct MainHomeRecommendationView_Previews: PreviewProvider {
|
|||||||
onTapCreator: { _ in },
|
onTapCreator: { _ in },
|
||||||
onTapContent: { _ in },
|
onTapContent: { _ in },
|
||||||
onTapCharacter: { _ in },
|
onTapCharacter: { _ in },
|
||||||
onTapCommunity: { _ in },
|
onTapCommunityPost: { _ in },
|
||||||
onTapBanner: { _ in },
|
onTapBanner: { _ in },
|
||||||
onTapFollowAll: { action in action() }
|
onTapFollowAll: { action in action() }
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ struct MainView: View {
|
|||||||
onTapCreator: handleRecommendationCreatorTap,
|
onTapCreator: handleRecommendationCreatorTap,
|
||||||
onTapContent: handleRecommendationContentTap,
|
onTapContent: handleRecommendationContentTap,
|
||||||
onTapCharacter: handleRecommendationCreatorTap,
|
onTapCharacter: handleRecommendationCreatorTap,
|
||||||
onTapCommunity: handleRecommendationCommunityTap,
|
onTapCommunityPost: handleRecommendationCommunityPostTap,
|
||||||
onTapBanner: handleRecommendationBannerTap,
|
onTapBanner: handleRecommendationBannerTap,
|
||||||
onTapFollowAll: handleRecommendationFollowAllTap,
|
onTapFollowAll: handleRecommendationFollowAllTap,
|
||||||
onSelectFollowingTab: handleFollowingTabSelection,
|
onSelectFollowingTab: handleFollowingTabSelection,
|
||||||
@@ -494,10 +494,10 @@ struct MainView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleRecommendationCommunityTap(creatorId: Int) {
|
private func handleRecommendationCommunityPostTap(postId: Int) {
|
||||||
guard creatorId > 0 else { return }
|
guard postId > 0 else { return }
|
||||||
performRecommendationDetailAction {
|
performRecommendationDetailAction {
|
||||||
appState.setAppStep(step: .creatorCommunityAll(creatorId: creatorId))
|
appState.setAppStep(step: .creatorChannelCommunityPostDetail(postId: postId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +527,9 @@ struct MainView: View {
|
|||||||
case .audio:
|
case .audio:
|
||||||
handleRecommendationContentTap(contentId: targetId)
|
handleRecommendationContentTap(contentId: targetId)
|
||||||
case .community:
|
case .community:
|
||||||
handleRecommendationCommunityTap(creatorId: targetId)
|
performRecommendationDetailAction {
|
||||||
|
appState.setAppStep(step: .creatorCommunityAll(creatorId: targetId))
|
||||||
|
}
|
||||||
case .unknown:
|
case .unknown:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -477,8 +477,76 @@
|
|||||||
- 실행 명령: `rg "### Phase [0-9]+:|- \\[[ x]\\] \\*\\*Task [0-9]+\\.[0-9]+:" docs/20260602_메인_홈_추천_UI_API_연동/plan-task.md`
|
- 실행 명령: `rg "### Phase [0-9]+:|- \\[[ x]\\] \\*\\*Task [0-9]+\\.[0-9]+:" docs/20260602_메인_홈_추천_UI_API_연동/plan-task.md`
|
||||||
- 기대 결과: phase heading과 `Task N.N` 형식 체크박스가 검색된다.
|
- 기대 결과: phase heading과 `Task N.N` 형식 체크박스가 검색된다.
|
||||||
|
|
||||||
|
### Phase 20: 추천 커뮤니티 게시물 상세 진입 보정
|
||||||
|
|
||||||
|
- [x] **Task 20.1: PRD/계획 문서에 커뮤니티 게시물 상세 이동 요구사항 추가**
|
||||||
|
- 대상 파일:
|
||||||
|
- 수정: `docs/20260602_메인_홈_추천_UI_API_연동/prd.md`
|
||||||
|
- 수정: `docs/20260602_메인_홈_추천_UI_API_연동/plan-task.md`
|
||||||
|
- 작업 내용:
|
||||||
|
- 최근 활동 크리에이터의 `activityType == COMMUNITY` 탭 액션을 커뮤니티 게시물 상세 이동으로 명시한다.
|
||||||
|
- 인기 커뮤니티 섹션의 게시물 탭 액션을 커뮤니티 게시물 상세 이동으로 명시한다.
|
||||||
|
- `targetId`는 최근 활동 `COMMUNITY`일 때 커뮤니티 게시물 `postId`로 취급한다.
|
||||||
|
- 검증 기준:
|
||||||
|
- 실행 명령: `rg "activityType == COMMUNITY|커뮤니티 게시물 상세|targetId.*postId|인기 커뮤니티" docs/20260602_메인_홈_추천_UI_API_연동`
|
||||||
|
- 기대 결과: PRD와 계획 문서에서 이번 상세 이동 요구사항이 검색된다.
|
||||||
|
|
||||||
|
- [x] **Task 20.2: 추천 탭 커뮤니티 게시물 상세 라우팅 연결**
|
||||||
|
- 대상 파일:
|
||||||
|
- 수정: `SodaLive/Sources/V2/Main/MainView.swift`
|
||||||
|
- 수정: `SodaLive/Sources/V2/Main/Home/MainHomeView.swift`
|
||||||
|
- 수정: `SodaLive/Sources/V2/Main/Home/Recommendation/MainHomeRecommendationView.swift`
|
||||||
|
- 수정: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeActiveCreatorSection.swift`
|
||||||
|
- 수정: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomePopularCommunitySection.swift`
|
||||||
|
- 수정: `SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift`
|
||||||
|
- 작업 내용:
|
||||||
|
- 추천 탭 커뮤니티 callback을 `postId` 기준으로 명확히 연결한다.
|
||||||
|
- 최근 활동 크리에이터의 `COMMUNITY` 타입은 `targetId`를 `postId`로 전달한다.
|
||||||
|
- 인기 커뮤니티 카드 일반 탭과 댓글 아이콘 탭은 `postId`로 커뮤니티 게시물 상세에 진입한다.
|
||||||
|
- 좋아요, 구매, 오디오 재생 액션은 기존 동작을 유지한다.
|
||||||
|
- 팔로잉 탭 스케줄의 기존 `.community` 라우팅은 이번 추천 탭 범위 밖이므로 변경하지 않는다.
|
||||||
|
- 검증 기준:
|
||||||
|
- 실행 명령: `rg "onTapCommunityPost|handleRecommendationCommunityPostTap|creatorChannelCommunityPostDetail|onTapPost|onTapComment|handleFollowingScheduleTap" SodaLive/Sources/V2/Main SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift`
|
||||||
|
- 기대 결과: 추천 탭 커뮤니티 액션은 `postId` 기반 상세 이동을 사용하고, 팔로잉 스케줄 community 라우팅은 기존 분기를 유지한다.
|
||||||
|
|
||||||
|
- [x] **Task 20.3: 정적 검증과 빌드 검증**
|
||||||
|
- 대상 파일:
|
||||||
|
- 확인: `SodaLive/Sources/V2/Main/**`
|
||||||
|
- 확인: `SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift`
|
||||||
|
- 확인: `SodaLive.xcodeproj/project.pbxproj`
|
||||||
|
- 작업 내용:
|
||||||
|
- 변경 파일의 공백 오류와 프로젝트 파일 유효성을 확인한다.
|
||||||
|
- 가능한 빌드를 실행한다.
|
||||||
|
- 실행 결과를 검증 기록에 누적한다.
|
||||||
|
- 검증 기준:
|
||||||
|
- 실행 명령: `git diff --check`
|
||||||
|
- 기대 결과: 출력 없이 성공한다.
|
||||||
|
- 실행 명령: `plutil -lint SodaLive.xcodeproj/project.pbxproj`
|
||||||
|
- 기대 결과: `OK`
|
||||||
|
- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build`
|
||||||
|
- 기대 결과: `BUILD SUCCEEDED`
|
||||||
|
|
||||||
## 검증 기록
|
## 검증 기록
|
||||||
|
|
||||||
|
### 2026-07-10 Phase 20 추천 커뮤니티 게시물 상세 진입 보정 완료
|
||||||
|
|
||||||
|
- 목적: 메인 홈 추천 탭의 최근 활동 `COMMUNITY`와 인기 커뮤니티 게시물 탭 액션을 커뮤니티 게시물 상세 페이지로 연결
|
||||||
|
- 수행 내용:
|
||||||
|
- PRD에 최근 활동 `activityType == COMMUNITY`의 `targetId`를 커뮤니티 게시물 `postId`로 취급한다는 기준을 추가
|
||||||
|
- PRD에 인기 커뮤니티 게시물 일반 탭/댓글 아이콘 탭이 커뮤니티 게시물 상세 페이지로 이동한다는 기준을 추가
|
||||||
|
- `MainHomeView`, `MainHomeRecommendationView`, `MainHomeActiveCreatorSection`, `MainHomePopularCommunitySection`의 추천 커뮤니티 callback 이름을 `onTapCommunityPost`로 정리
|
||||||
|
- `MainView.handleRecommendationCommunityPostTap(postId:)`를 추가해 추천 탭 커뮤니티 액션을 `AppStep.creatorChannelCommunityPostDetail(postId:onCommunityRefresh:)`로 연결
|
||||||
|
- `CommunityPostCard`에 기본 no-op `onTapPost`를 추가하고, 인기 커뮤니티 섹션에서 일반 탭과 댓글 아이콘 탭 모두 `postId` 기반 상세 이동으로 연결
|
||||||
|
- 팔로잉 스케줄의 기존 `.community` 라우팅은 `creatorCommunityAll(creatorId:)`로 유지하고 로그인 guard 흐름도 유지
|
||||||
|
- 검증:
|
||||||
|
- `rg "activityType == COMMUNITY|커뮤니티 게시물 상세|targetId.*postId|인기 커뮤니티" docs/20260602_메인_홈_추천_UI_API_연동` 실행, PRD/계획 문서에 요구사항 반영 확인
|
||||||
|
- `rg -n "onTapCommunityPost|handleRecommendationCommunityPostTap|creatorChannelCommunityPostDetail|onTapPost|onTapComment|handleFollowingScheduleTap|creatorCommunityAll" SodaLive/Sources/V2/Main SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift` 실행, 추천 탭 `postId` 상세 이동과 팔로잉 스케줄 기존 분기 확인
|
||||||
|
- `rg -n "onTapCommunity:|handleRecommendationCommunityTap" SodaLive/Sources/V2/Main SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift` 실행, 기존 모호한 추천 커뮤니티 callback 이름 제거 확인
|
||||||
|
- `git diff --check` 실행, 출력 없이 성공 확인
|
||||||
|
- `plutil -lint SodaLive.xcodeproj/project.pbxproj` 실행, `OK` 확인
|
||||||
|
- 샌드박스 내 `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 실행, CoreSimulator/로그 접근 제한으로 실패 확인
|
||||||
|
- 승인 후 동일 `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 재실행, `BUILD SUCCEEDED` 확인
|
||||||
|
|
||||||
### 2026-06-30 Phase 17~19 최종 조립/검증/문서 갱신 완료
|
### 2026-06-30 Phase 17~19 최종 조립/검증/문서 갱신 완료
|
||||||
|
|
||||||
- 목적: V2 Main Home 추천 탭 섹션 조립 순서와 빈 섹션 숨김 조건을 최종 확인하고, 프로젝트 포함/정적 점검/빌드 검증 결과를 계획 문서에 반영
|
- 목적: V2 Main Home 추천 탭 섹션 조립 순서와 빈 섹션 숨김 조건을 최종 확인하고, 프로젝트 포함/정적 점검/빌드 검증 결과를 계획 문서에 반영
|
||||||
|
|||||||
@@ -179,6 +179,8 @@ enum class RecommendedActivityType(val code: String) {
|
|||||||
- 민감 콘텐츠 보기 설정이 꺼져 있으면 `AppState.shared.setPendingContentSettingsGuideMessage(I18n.Settings.adultContentEnableGuide)`로 안내 문구를 예약하고 `AppState.shared.setAppStep(step: .contentViewSettings)`로 이동한다.
|
- 민감 콘텐츠 보기 설정이 꺼져 있으면 `AppState.shared.setPendingContentSettingsGuideMessage(I18n.Settings.adultContentEnableGuide)`로 안내 문구를 예약하고 `AppState.shared.setAppStep(step: .contentViewSettings)`로 이동한다.
|
||||||
- 위 조건을 통과한 경우에만 `liveDetail`, `creatorDetail`, `contentDetail`, `characterDetail` 등 실제 상세 이동을 실행한다.
|
- 위 조건을 통과한 경우에만 `liveDetail`, `creatorDetail`, `contentDetail`, `characterDetail` 등 실제 상세 이동을 실행한다.
|
||||||
- 추천 탭 현재 라이브 아이템은 `roomId`가 항상 존재하는 값으로 취급하고, 아이템 탭 시 상세 화면을 거치지 않고 기존 `LiveViewModel.enterLiveRoom(roomId:)` 흐름을 호출해 방 상세 조회, 입장 전 결제 확인, 비밀방 비밀번호 dialog, `LiveRoomViewV2` 입장을 재사용한다.
|
- 추천 탭 현재 라이브 아이템은 `roomId`가 항상 존재하는 값으로 취급하고, 아이템 탭 시 상세 화면을 거치지 않고 기존 `LiveViewModel.enterLiveRoom(roomId:)` 흐름을 호출해 방 상세 조회, 입장 전 결제 확인, 비밀방 비밀번호 dialog, `LiveRoomViewV2` 입장을 재사용한다.
|
||||||
|
- 최근 활동 크리에이터에서 `activityType == COMMUNITY`인 아이템은 `targetId`를 커뮤니티 게시물 `postId`로 취급하고, 탭 시 커뮤니티 게시물 상세 페이지로 이동한다.
|
||||||
|
- 인기 커뮤니티 섹션의 커뮤니티 게시물은 `postId` 기준으로 커뮤니티 게시물 상세 페이지로 이동한다. 좋아요, 구매, 오디오 재생 액션은 기존 개별 액션을 유지한다.
|
||||||
|
|
||||||
라이브 항목 주의사항:
|
라이브 항목 주의사항:
|
||||||
- 기존 홈의 라이브 guard는 `roomId`와 `isAdult`를 함께 받아 성인 여부를 판단한다.
|
- 기존 홈의 라이브 guard는 `roomId`와 `isAdult`를 함께 받아 성인 여부를 판단한다.
|
||||||
@@ -204,6 +206,7 @@ enum class RecommendedActivityType(val code: String) {
|
|||||||
- `구매완료` 버튼은 표시하지 않는다.
|
- `구매완료` 버튼은 표시하지 않는다.
|
||||||
- 작성자, 본문, 생성 시간, 좋아요 수, 댓글 수를 표시한다.
|
- 작성자, 본문, 생성 시간, 좋아요 수, 댓글 수를 표시한다.
|
||||||
- 생성 시간은 UTC 값을 디바이스 Timezone 기준 상대 날짜로 표시한다.
|
- 생성 시간은 UTC 값을 디바이스 Timezone 기준 상대 날짜로 표시한다.
|
||||||
|
- 게시물 카드의 일반 탭 액션과 댓글 아이콘 탭 액션은 커뮤니티 게시물 상세 페이지로 이동한다.
|
||||||
|
|
||||||
### 7.5 사업자 정보 더보기/접기
|
### 7.5 사업자 정보 더보기/접기
|
||||||
|
|
||||||
@@ -298,6 +301,7 @@ MainHomeView
|
|||||||
- `FeedCommunityView`에 `구매완료` 버튼이 표시되지 않는다.
|
- `FeedCommunityView`에 `구매완료` 버튼이 표시되지 않는다.
|
||||||
- 사업자 정보는 마지막 섹션에서 화면 width를 채우고, 기본 3줄 말줄임표, 더보기, 전체 표시, 접기 전환이 동작한다.
|
- 사업자 정보는 마지막 섹션에서 화면 width를 채우고, 기본 3줄 말줄임표, 더보기, 전체 표시, 접기 전환이 동작한다.
|
||||||
- 상세 진입 탭 액션은 기존 홈과 같은 로그인, 한국 사용자 본인인증, 민감 콘텐츠 보기 설정 guard를 통과한 뒤에만 실행된다.
|
- 상세 진입 탭 액션은 기존 홈과 같은 로그인, 한국 사용자 본인인증, 민감 콘텐츠 보기 설정 guard를 통과한 뒤에만 실행된다.
|
||||||
|
- 최근 활동 크리에이터의 `COMMUNITY` 활동과 인기 커뮤니티 섹션의 게시물은 커뮤니티 게시물 상세 페이지로 이동한다.
|
||||||
- `MainHomeView`는 추천/랭킹/팔로잉 탭 shell 역할만 하고, 추천 탭 섹션 조립은 `MainHomeRecommendationView`에 분리되어 있다.
|
- `MainHomeView`는 추천/랭킹/팔로잉 탭 shell 역할만 하고, 추천 탭 섹션 조립은 `MainHomeRecommendationView`에 분리되어 있다.
|
||||||
- 반복 UI는 기존 widget 또는 공용 컴포넌트를 재사용하고 불필요하게 중복 구현하지 않는다.
|
- 반복 UI는 기존 widget 또는 공용 컴포넌트를 재사용하고 불필요하게 중복 구현하지 않는다.
|
||||||
- 빌드가 성공하고, 가능하면 ViewModel 디코딩/상태 전환 검증을 수행한다.
|
- 빌드가 성공하고, 가능하면 ViewModel 디코딩/상태 전환 검증을 수행한다.
|
||||||
@@ -307,7 +311,7 @@ MainHomeView
|
|||||||
- 각 섹션별 최대 표시 개수와 가로/세로 스크롤 정책이 Figma 기준 그대로인지, 서버 응답 전체를 모두 표시해야 하는지 확인이 필요하다.
|
- 각 섹션별 최대 표시 개수와 가로/세로 스크롤 정책이 Figma 기준 그대로인지, 서버 응답 전체를 모두 표시해야 하는지 확인이 필요하다.
|
||||||
- `HomeLiveItem`에 민감/성인 라이브 여부를 판단할 `isAdult` 또는 동등한 필드가 추가되는지, 아니면 서버에서 추천 라이브를 사전 필터링하는지 확인이 필요하다.
|
- `HomeLiveItem`에 민감/성인 라이브 여부를 판단할 `isAdult` 또는 동등한 필드가 추가되는지, 아니면 서버에서 추천 라이브를 사전 필터링하는지 확인이 필요하다.
|
||||||
- 커뮤니티 `audioUrl`을 추천 탭 카드에서 표시/재생해야 하는지 확인이 필요하다.
|
- 커뮤니티 `audioUrl`을 추천 탭 카드에서 표시/재생해야 하는지 확인이 필요하다.
|
||||||
- 각 카드 터치 시 상세 이동 대상이 모두 정의되어 있는지 확인이 필요하다.
|
- 각 카드 터치 시 상세 이동 대상이 모두 정의되어 있는지 확인이 필요하다. 단, 최근 활동 `COMMUNITY`와 인기 커뮤니티 게시물은 커뮤니티 게시물 상세 페이지로 확정한다.
|
||||||
|
|
||||||
## 12. Verification Plan
|
## 12. Verification Plan
|
||||||
- 문서 검증: API URL, 응답 모델, 제외 섹션, FeedCommunityView, 사업자 정보 요구가 PRD와 계획 문서에 반영되었는지 확인한다.
|
- 문서 검증: API URL, 응답 모델, 제외 섹션, FeedCommunityView, 사업자 정보 요구가 PRD와 계획 문서에 반영되었는지 확인한다.
|
||||||
|
|||||||
Reference in New Issue
Block a user