fix(creator): 커뮤니티 반응 순서를 조정한다
This commit is contained in:
@@ -188,6 +188,19 @@ struct CommunityPostCard: View {
|
||||
|
||||
private var reactionBar: some View {
|
||||
HStack(spacing: 15) {
|
||||
Button(action: onTapComment) {
|
||||
HStack(spacing: SodaSpacing.s4) {
|
||||
Image("ic_feed_community_reply")
|
||||
.resizable()
|
||||
.frame(width: 18, height: 18)
|
||||
|
||||
Text("\(commentCount)")
|
||||
.appFont(.body2)
|
||||
.foregroundColor(Color.gray400)
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
Button {
|
||||
toggleLike()
|
||||
} label: {
|
||||
@@ -202,19 +215,6 @@ struct CommunityPostCard: View {
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
Button(action: onTapComment) {
|
||||
HStack(spacing: SodaSpacing.s4) {
|
||||
Image("ic_feed_community_reply")
|
||||
.resizable()
|
||||
.frame(width: 18, height: 18)
|
||||
|
||||
Text("\(commentCount)")
|
||||
.appFont(.body2)
|
||||
.foregroundColor(Color.gray400)
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
.frame(height: 24)
|
||||
}
|
||||
|
||||
@@ -219,6 +219,18 @@ struct CreatorChannelCommunityListItem: View {
|
||||
|
||||
private var reactionBar: some View {
|
||||
HStack(spacing: 15) {
|
||||
if post.isCommentAvailable && !isPaidLocked {
|
||||
HStack(spacing: SodaSpacing.s4) {
|
||||
Image("ic_feed_community_reply")
|
||||
.resizable()
|
||||
.frame(width: 18, height: 18)
|
||||
|
||||
Text("\(post.commentCount)")
|
||||
.appFont(size: 16, weight: .regular)
|
||||
.foregroundColor(Color.gray400)
|
||||
}
|
||||
}
|
||||
|
||||
if !isPaidLocked {
|
||||
Button {
|
||||
localIsLike.toggle()
|
||||
@@ -238,18 +250,6 @@ struct CreatorChannelCommunityListItem: View {
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
|
||||
if post.isCommentAvailable && !isPaidLocked {
|
||||
HStack(spacing: SodaSpacing.s4) {
|
||||
Image("ic_feed_community_reply")
|
||||
.resizable()
|
||||
.frame(width: 18, height: 18)
|
||||
|
||||
Text("\(post.commentCount)")
|
||||
.appFont(size: 16, weight: .regular)
|
||||
.foregroundColor(Color.gray400)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(height: 24)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,9 @@ struct CreatorChannelCommunityPostDetailCommentListView: View {
|
||||
.foregroundColor(.white)
|
||||
.padding(.horizontal, SodaSpacing.s14)
|
||||
|
||||
LazyVStack(alignment: .leading, spacing: SodaSpacing.s20) {
|
||||
ForEach(comments, id: \.commentId) { comment in
|
||||
LazyVStack(alignment: .leading, spacing: SodaSpacing.s14) {
|
||||
ForEach(Array(comments.enumerated()), id: \.element.commentId) { index, comment in
|
||||
VStack(alignment: .leading, spacing: SodaSpacing.s14) {
|
||||
ZStack(alignment: .topTrailing) {
|
||||
CreatorChannelCommunityPostDetailCommentRow(
|
||||
comment: comment,
|
||||
@@ -41,6 +42,13 @@ struct CreatorChannelCommunityPostDetailCommentListView: View {
|
||||
.padding(.top, 28)
|
||||
}
|
||||
}
|
||||
|
||||
if index < comments.count - 1 {
|
||||
Rectangle()
|
||||
.fill(Color.gray800)
|
||||
.frame(height: 1)
|
||||
}
|
||||
}
|
||||
.onAppear { onAppearComment(comment) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,18 @@ struct CreatorChannelCommunityPostDetailContentView: View {
|
||||
private var reactionBar: some View {
|
||||
HStack(spacing: 15) {
|
||||
if isPaidLocked == false {
|
||||
if detail.isCommentAvailable {
|
||||
HStack(spacing: SodaSpacing.s4) {
|
||||
Image("ic_feed_community_reply")
|
||||
.resizable()
|
||||
.frame(width: 18, height: 18)
|
||||
|
||||
Text("\(detail.commentCount)")
|
||||
.appFont(size: 16, weight: .regular)
|
||||
.foregroundColor(Color.gray500)
|
||||
}
|
||||
}
|
||||
|
||||
Button(action: onTapLike) {
|
||||
HStack(spacing: SodaSpacing.s4) {
|
||||
Image(detail.isLiked ? "ic_feed_community_heart_fill" : "ic_feed_community_heart")
|
||||
@@ -167,18 +179,6 @@ struct CreatorChannelCommunityPostDetailContentView: View {
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
if detail.isCommentAvailable {
|
||||
HStack(spacing: SodaSpacing.s4) {
|
||||
Image("ic_feed_community_reply")
|
||||
.resizable()
|
||||
.frame(width: 18, height: 18)
|
||||
|
||||
Text("\(detail.commentCount)")
|
||||
.appFont(size: 16, weight: .regular)
|
||||
.foregroundColor(Color.gray500)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(height: 24)
|
||||
|
||||
@@ -23,6 +23,10 @@ struct CreatorChannelCommunityPostDetailView: View {
|
||||
)
|
||||
|
||||
if detail.isCommentAvailable {
|
||||
Rectangle()
|
||||
.fill(Color.gray800)
|
||||
.frame(height: 1)
|
||||
|
||||
CreatorChannelCommunityPostDetailCommentListView(
|
||||
creatorId: detail.creatorId,
|
||||
postId: detail.postId,
|
||||
|
||||
@@ -402,6 +402,7 @@
|
||||
- `price <= 0 || existOrdered == true`이면 일반 이미지로 표시한다.
|
||||
- `구매완료` 버튼은 표시하지 않는다.
|
||||
- `creatorProfileImage`, `createdAt`, `likeCount`, `commentCount`를 표시한다.
|
||||
- 반응 정보는 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
|
||||
- `audioUrl`이 있으면 이미지 중앙 재생 UI를 표시한다.
|
||||
- 기존 커뮤니티 구매 API를 재사용해 유료 미구매 포스트 구매를 지원한다.
|
||||
- `createdAt`은 UTC로 파싱해 디바이스 Timezone 기준 상대 날짜로 표시한다.
|
||||
|
||||
@@ -205,6 +205,7 @@ enum class RecommendedActivityType(val code: String) {
|
||||
- 유료 미구매 커뮤니티 포스트는 기존 커뮤니티 구매 API로 구매 가능해야 한다.
|
||||
- `구매완료` 버튼은 표시하지 않는다.
|
||||
- 작성자, 본문, 생성 시간, 좋아요 수, 댓글 수를 표시한다.
|
||||
- 반응 정보는 Figma 기준으로 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
|
||||
- 생성 시간은 UTC 값을 디바이스 Timezone 기준 상대 날짜로 표시한다.
|
||||
- 게시물 카드의 일반 탭 액션과 댓글 아이콘 탭 액션은 커뮤니티 게시물 상세 페이지로 이동한다.
|
||||
|
||||
|
||||
@@ -339,6 +339,7 @@
|
||||
- `COMMUNITY_POST`는 `communityPost` payload가 있을 때만 렌더링한다.
|
||||
- 표시 값은 `postId`, `creatorProfileImage`, `creatorNickname`, `imageUrl`, `content`, `createdAt`, `likeCount`, `commentCount`를 사용한다.
|
||||
- 기존 `CommunityPostCard`를 재사용할 경우 `audioUrl = nil`, `price = 0`, `existOrdered = true`, `isLike = false`로 매핑한다.
|
||||
- 반응 정보는 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
|
||||
- `createdAt`은 기존 `CommunityPostCard`의 `createdAt` 표시 형식에 맞춰 전달한다.
|
||||
- 검증 기준:
|
||||
- 실행 명령: `rg "COMMUNITY_POST|communityPost|CommunityPostCard|postId|creatorProfileImage|likeCount|commentCount|audioUrl: nil|price: 0|existOrdered: true" SodaLive/Sources/V2/Main/Home/Following/Components/MainHomeFollowingNewsSection.swift`
|
||||
|
||||
@@ -417,6 +417,7 @@ Figma 참조:
|
||||
- `CONTENT_RANKING` 탭 시 `contentRanking.contentId`로 콘텐츠 상세로 이동한다.
|
||||
- `COMMUNITY_POST`
|
||||
- 기존 `CommunityPostCard` 또는 기존 커뮤니티 Feed View를 재사용한다.
|
||||
- 반응 정보는 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
|
||||
- `communityPost` payload를 사용한다.
|
||||
- `postId`, `creatorProfileImage`, `creatorNickname`, `imageUrl`, `content`, `createdAt`, `likeCount`, `commentCount`를 표시한다.
|
||||
- 기존 `CommunityPostCard`를 재사용할 경우 `audioUrl = nil`, `price = 0`, `existOrdered = true`로 매핑해 표시 전용으로 사용한다.
|
||||
|
||||
@@ -246,6 +246,7 @@ Figma 참조:
|
||||
- 응답 모델은 `CreatorChannelCommunityPostResponse`를 재사용한다.
|
||||
- 공지 섹션은 일반 커뮤니티 섹션과 시각 구성이 다를 수 있으므로 별도 section component로 분리한다.
|
||||
- `imageUrl`, `audioUrl`, `price`, `existOrdered`, `likeCount`, `commentCount` 처리는 기존 커뮤니티 카드 패턴을 따른다.
|
||||
- 반응 정보는 Figma 기준으로 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
|
||||
- 공지 전체보기 또는 item tap destination은 기존 커뮤니티 상세/목록 흐름이 있으면 연결하고, 없으면 placeholder로 둔다.
|
||||
|
||||
### 7.11 스케줄 섹션
|
||||
@@ -276,9 +277,16 @@ Figma 참조:
|
||||
- `communities`를 사용해 커뮤니티 게시물 목록을 표시한다.
|
||||
- V2 공용 `CommunityPostCard`가 요구사항과 맞으면 재사용한다.
|
||||
- `imageUrl`, `audioUrl`, `price`, `existOrdered`, `likeCount`, `commentCount`를 표시 규칙에 반영한다.
|
||||
- 반응 정보는 Figma 기준으로 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
|
||||
- 유료/잠금 게시물은 기존 커뮤니티 잠금/구매 표시 패턴을 따른다.
|
||||
- 홈에서는 Figma 기준 노출 개수만 표시하고 `전체보기` 버튼으로 커뮤니티 tab placeholder 또는 기존 커뮤니티 목록으로 이동한다.
|
||||
|
||||
### 7.14.1 커뮤니티 게시글 상세
|
||||
|
||||
- 게시글 본문 영역과 댓글 목록 사이에는 Figma 기준 `gray/800` 1pt 하단 border를 표시한다.
|
||||
- 댓글 목록에서는 댓글 row 사이에 `gray/800` 1pt separator를 표시한다.
|
||||
- 상세 본문의 반응 정보도 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
|
||||
|
||||
### 7.15 팬Talk 섹션
|
||||
|
||||
- `fanTalk.totalCount`와 `fanTalk.latestFanTalk`를 사용한다.
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
- 생성: `SodaLive/Sources/V2/CreatorChannel/Community/Components/CreatorChannelCommunityListItem.swift`
|
||||
- 작업 내용:
|
||||
- Figma `290:9061`, `665:19021`, `290:9066`, `665:19024` 기준으로 작성자, 시간, 본문, 이미지/GIF, 오디오 재생 버튼, 가격, 더보기, 좋아요, 댓글 표시를 구성한다.
|
||||
- 반응 정보는 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
|
||||
- `isCommentAvailable == false`이면 댓글 영역을 숨긴다.
|
||||
- 유료 미구매 상태이면 회색 `RoundedRectangle`과 가격 UI를 표시하고 오디오 재생 버튼을 숨긴다.
|
||||
- `imageUrl == nil`이면 유/무료 관계없이 이미지 영역을 표시하지 않는다.
|
||||
|
||||
@@ -104,6 +104,7 @@ data class CreatorChannelCommunityPostResponse(
|
||||
### 5.3 List layout
|
||||
- 리스트형은 Figma `290:9061`과 `665:19021`을 기준으로 표시한다.
|
||||
- 작성자 프로필 이미지, 닉네임, 상대 시간, 본문, 이미지/오디오 영역, 좋아요 수, 댓글 수를 표시한다.
|
||||
- 반응 정보는 Figma 기준으로 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
|
||||
- `isPinned == true`이면 게시글에 고정 표시를 제공한다.
|
||||
- `price > 0 && existOrdered == false && isOwnPost == false`이면 유료 미구매 상태로 표시한다.
|
||||
- 유료 미구매 상태에서는 이미지 URL도 `nil`로 내려올 수 있으므로 이미지 영역에 회색 `RoundedRectangle`을 표시한다.
|
||||
|
||||
@@ -181,6 +181,7 @@
|
||||
- 생성: `SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift`
|
||||
- 작업 내용:
|
||||
- Figma 기준으로 작성자 프로필, 닉네임, 상대 시간, 본문, 이미지/잠금/오디오 영역, 좋아요/댓글 reaction을 표시한다.
|
||||
- 반응 정보는 댓글 icon/count를 먼저, 좋아요 icon/count를 뒤에 표시한다.
|
||||
- 유료 미구매 상태는 `price > 0 && existOrdered == false && isOwnPost == false`로 판정한다.
|
||||
- 유료 미구매 상태에서는 `gray800` 계열 이미지 영역, 잠금 아이콘, 캐시 가격 capsule을 표시한다.
|
||||
- 구매 완료 상태는 `구매완료` capsule tag를 표시한다.
|
||||
@@ -212,6 +213,7 @@
|
||||
- 작업 내용:
|
||||
- section header는 `댓글 {commentCount}`를 표시한다.
|
||||
- 댓글 목록은 `LazyVStack`으로 표시하고 마지막 댓글 `onAppear`에서 다음 페이지 조회를 요청한다.
|
||||
- 댓글 row 사이에는 Figma 기준 `gray800` 1pt separator를 표시한다.
|
||||
- 댓글이 비어 있으면 header만 유지하거나 Figma 기준 빈 목록 영역을 유지한다.
|
||||
- 선택된 댓글의 popup은 기존 `CreatorChannelActionPopup` 또는 `CreatorChannelReplyDetailActionPopup` 기반으로 수정/삭제 action을 표시한다.
|
||||
- 검증 기준:
|
||||
@@ -238,6 +240,7 @@
|
||||
- 생성: `SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift`
|
||||
- 작업 내용:
|
||||
- `CreatorChannelReplyDetailTitleBar`를 재사용해 back-only title bar를 표시한다.
|
||||
- 댓글 가능 상세에서는 게시글 영역과 댓글 목록 사이에 Figma 기준 `gray800` 1pt separator를 표시한다.
|
||||
- `ScrollView` 안에 게시글 콘텐츠와 댓글 목록을 배치한다.
|
||||
- `isCommentAvailable == true`일 때만 하단 입력 바를 `safeAreaInset(edge: .bottom)`으로 고정한다.
|
||||
- loading, toast, 삭제 confirm modal을 연결한다.
|
||||
|
||||
@@ -145,6 +145,7 @@ data class CreatorChannelCommunityRepliesResponse(
|
||||
- 배경은 `Color.black`을 사용한다.
|
||||
- 상단 title bar는 Figma처럼 title text 없이 back chevron만 표시한다.
|
||||
- 게시글 영역은 작성자 프로필, 닉네임, 상대 시간, 본문, 이미지/오디오/잠금 영역, 좋아요/댓글 count를 표시한다.
|
||||
- 댓글 가능 상세에서는 게시글 영역과 댓글 목록 사이에 Figma 기준 `gray800` 1pt separator를 표시한다.
|
||||
- `createdAtUtc`는 기존 `DateParser.relativeTimeText(fromUTC:fallback:now:)` 계열 helper로 상대 시간으로 표시한다.
|
||||
- `price > 0 && existOrdered == false && isOwnPost == false`이면 유료 미구매 잠금 상태로 표시한다.
|
||||
- 유료 미구매 잠금 상태는 Figma처럼 `gray800` 계열 이미지 영역, 잠금 아이콘, 캐시 가격 capsule을 표시한다.
|
||||
@@ -157,6 +158,7 @@ data class CreatorChannelCommunityRepliesResponse(
|
||||
- `isLiked == true`이면 `ic_feed_community_heart_fill`을 표시한다.
|
||||
- `isLiked == false`이면 `ic_feed_community_heart`를 표시한다.
|
||||
- 하트 tap 시 기존 `CreatorCommunityRepository.communityPostLike(postId:)`를 호출한다.
|
||||
- 반응 정보는 Figma 기준으로 댓글 icon/count를 먼저, 좋아요 icon/count를 뒤에 표시한다.
|
||||
- 좋아요 tap 직후 UI는 기존 `CreatorChannelCommunityListItem`처럼 local optimistic state로 반영하고, API 실패 시 toast를 표시한 뒤 tap 직전의 `isLiked`, `likeCount` 값으로 local state를 복구한다.
|
||||
- `isCommentAvailable == true`이면 댓글 icon과 `commentCount`를 표시한다.
|
||||
- `isCommentAvailable == false`이면 댓글 icon/count, 댓글 목록, 하단 입력 바를 모두 숨긴다.
|
||||
@@ -164,6 +166,7 @@ data class CreatorChannelCommunityRepliesResponse(
|
||||
### 7.5 Comments
|
||||
- 상세 API 응답의 `comments.comments`를 초기 댓글 목록으로 표시한다.
|
||||
- 댓글 section header는 Figma처럼 `댓글 {commentCount}` 형식으로 표시한다.
|
||||
- 댓글 row 사이에는 Figma 기준 `gray800` 1pt separator를 표시한다.
|
||||
- 댓글 row는 작성자 프로필, 닉네임, 상대 시간, 본문, 우측 더보기 버튼을 표시한다.
|
||||
- `writerId`로 내 댓글/답글 여부를 판정하고, 게시글의 `creatorId`로 현재 사용자가 해당 커뮤니티 게시글을 쓴 크리에이터인지 판정한다.
|
||||
- 댓글/답글 popup menu는 기존 커뮤니티 댓글과 동일하게 내 댓글/답글이면 `수정하기`, `삭제하기`를 표시하고, 해당 게시글을 쓴 크리에이터이면 내가 쓴 댓글/답글이 아니어도 `삭제하기`를 표시한다.
|
||||
|
||||
Reference in New Issue
Block a user