From b2685959ad632ef7fecc4b4cf278b91f54779c18 Mon Sep 17 00:00:00 2001 From: klaus Date: Thu, 9 Jul 2026 01:28:18 +0900 Subject: [PATCH] =?UTF-8?q?docs(creator-channel):=20=EB=8C=93=EA=B8=80=20?= =?UTF-8?q?=EB=8B=B5=EA=B8=80=20=ED=9B=84=EC=86=8D=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EB=A5=BC=20=EA=B8=B0=EB=A1=9D=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plan-task.md | 38 +++++++++++++++++++ .../prd.md | 14 +++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/docs/20260708_커뮤니티_게시물_상세_댓글_답글/plan-task.md b/docs/20260708_커뮤니티_게시물_상세_댓글_답글/plan-task.md index 02dd2218..5a328269 100644 --- a/docs/20260708_커뮤니티_게시물_상세_댓글_답글/plan-task.md +++ b/docs/20260708_커뮤니티_게시물_상세_댓글_답글/plan-task.md @@ -208,6 +208,41 @@ - 검증: 상대시간 포맷터 회귀 테스트 및 상세/답글 ViewModel 테스트 PASS. - 검증 기록(2026-07-08): 기존 공통 함수 `formatUtcRelativeTimeText`를 보강해 epoch millis 기존 동작을 유지하면서 epoch seconds, ISO offset, 6자리 fraction을 파싱하도록 수정했다. ISO 문자열은 서버/단말 시계 오차를 고려해 10분 이내를 `방금전`으로 보정한다. 댓글/답글 UI model에 원본 `createdAtUtc`를 보존하고 답글 화면 `Intent`에 전달해 부모 댓글도 동일한 `UtcRelativeTimeTextFormatter`로 재포맷하도록 수정했다. `RelativeTimeFormatterTest`, 상세/답글 ViewModel 테스트 PASS로 확인했다. +### Phase 9: 댓글/답글 수정 UX 후속 반영 + +- [x] **Task 9.1: 타이틀/메뉴/모달 계약 정리** + - 수정: `activity_creator_channel_community_detail.xml`, `activity_creator_channel_community_reply.xml`, `content_comment_option_menu.xml`, `content_comment_option_menu2.xml`, 상세/답글 Activity. + - 작업: 상세/답글 titlebar의 `커뮤니티`, `답글` 문구를 제거하고, 댓글/답글 더보기 메뉴 문구를 `수정하기`, `삭제하기`로 바꾼다. v2 패키지 내부 삭제 확인은 `V2ModalDialog`를 사용한다. + - 검증: layout/source 계약 테스트, `./gradlew :app:compileDebugKotlin` + - 검증 기록(2026-07-09): 상세/답글 layout에서 title `TextView`를 제거하고, 댓글 메뉴 리소스는 `creator_channel_fantalk_edit`/`creator_channel_fantalk_delete`를 사용하도록 수정했다. 상세/답글 Activity의 삭제 확인은 `V2ModalDialog`로 교체하고 `AlertDialog` 사용을 제거했다. `CreatorChannelCommunityDetailReplyUiContractTest`에 title id 제거, 메뉴 문구, `V2ModalDialog` source 계약을 추가했으며 targeted community test와 `./gradlew :app:compileDebugKotlin` PASS로 확인했다. + +- [x] **Task 9.2: 하단 입력창 기반 수정 모드 구현** + - 수정: `CreatorChannelCommunityDetailViewModel.kt`, `CreatorChannelCommunityReplyViewModel.kt`, 상세/답글 Activity/layout, 관련 테스트. + - 작업: 수정 선택 시 별도 입력 Dialog 없이 하단 입력창에 기존 내용을 채우고 X 취소 버튼을 표시한다. 수정 모드의 send는 쓰기가 아니라 수정 API를 호출하며, 성공/취소 시 일반 입력 모드로 복귀한다. + - 검증: 상세/답글 ViewModel 회귀 테스트, layout/source 계약 테스트, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"` + - 검증 기록(2026-07-09): 상세 댓글은 `editingCommentId`/`editingOriginalComment`, 답글 화면은 `CreatorChannelCommunityReplyEditTarget`으로 수정 모드를 상태화했다. 수정 선택 시 하단 입력창에 기존 내용을 세팅하고 X 버튼을 표시하며, 수정 모드의 send는 댓글/답글/부모 댓글 수정 API를 호출한다. 성공 또는 X 취소 시 입력과 수정 target을 초기화한다. 변경 없음과 공백 입력은 기존 toast 정책을 유지했다. ViewModel 회귀 테스트와 layout/source 계약 테스트를 추가했고 targeted community test PASS로 확인했다. + +- [x] **Task 9.3: 후속 검증** + - 실행: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`. + - 검증 기록: `Verification Log`에 누적한다. + - 검증 기록(2026-07-09): `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check` 실행 결과 모두 통과했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 남아 있다. + +### Phase 10: 댓글/답글 더보기 메뉴 폰트 후속 반영 + +- [x] **Task 10.1: 더보기 메뉴 regular font 적용** + - 수정/생성: `CreatorChannelCommunityMorePopup.kt`, `view_creator_channel_community_more_popup.xml`, 댓글/답글 adapter, UI 계약 테스트. + - 작업: 기본 `PopupMenu` 대신 `PopupWindow` 기반 커스텀 메뉴를 사용하고, 메뉴 TextView에 `android:fontFamily="@font/regular"`를 명시한다. + - 검증: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`. + - 검증 기록(2026-07-09): 댓글/답글 더보기 메뉴를 `PopupMenu`에서 `CreatorChannelCommunityMorePopup`으로 교체했다. 새 `view_creator_channel_community_more_popup.xml`의 `수정하기`, `삭제하기` TextView에 `@font/regular`를 명시했고, 내 댓글/답글은 수정+삭제, 채널 작성자가 보는 타인 댓글/답글은 삭제만 노출하는 기존 권한 규칙을 유지했다. UI 계약 테스트에 popup layout font와 adapter source 계약을 추가했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 모두 통과했다. + +### Phase 11: 댓글/답글 입력창 키보드 후속 반영 + +- [x] **Task 11.1: 수정 진입/성공 시 키보드 제어** + - 수정: `CreatorChannelCommunityDetailActivity.kt`, `CreatorChannelCommunityReplyActivity.kt`, UI 계약 테스트. + - 작업: `수정하기` 터치 후 하단 입력창 수정 모드로 전환될 때 입력창에 focus를 주고 키보드를 즉시 올린다. 댓글/답글 작성 또는 수정 API 성공 이벤트 수신 시 키보드를 내리고 focus를 해제한다. + - 검증: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`. + - 검증 기록(2026-07-09): 상세/답글 Activity에 `showSoftInput`/`hideSoftInputFromWindow` 기반 키보드 제어를 추가했다. 수정 target이 새로 설정되면 입력창 focus 후 키보드를 올리고, 댓글 작성/수정 및 답글 작성/수정/부모 댓글 수정 성공 이벤트에서 키보드를 내리도록 연결했다. UI 계약 테스트에 IME 제어 source 계약을 추가했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 모두 통과했다. + --- ## Verification Log @@ -227,3 +262,6 @@ - 2026-07-08: 리뷰 결과 3건과 서버 응답 계약 불일치를 반영했다. 상세 응답 내부 `comments`를 최초 댓글 목록으로 사용하도록 바꾸고, 댓글/최신 답글/답글 응답 DTO를 서버 계약의 `writer*`, `content`, `commentId` 필드명에 맞췄다. 상세 댓글/답글 pagination에는 generation guard를 추가해 새로고침 후 stale page 응답이 현재 목록을 덮지 않게 했고, 댓글/답글/부모 댓글 수정 blank 입력은 `screen_creator_community_write_content_hint` toast 후 API를 호출하지 않도록 했다. UI 계약 테스트는 layout 속성/source 문자열 직접 검증을 제거해 필수 view/resource 등록 중심으로 축소했다. 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`가 모두 `BUILD SUCCESSFUL`임을 확인했다. `git diff --check`, `git diff HEAD --check`는 출력 없이 통과했다. `:app:mergeDebugResources`는 최초 sandbox에서 `~/.gradle` lock 파일 권한 문제로 실패했으나, 동일 명령을 권한 상승 재실행해 통과했다. - 2026-07-08: 코드 리뷰에서 발견된 채널 크리에이터 권한 매핑 문제를 반영했다. 상세 응답 embedded `comments`를 최초 UI state로 매핑할 때 아직 `Content` state가 없어 `isCreatorOwner`가 false로 고정되던 문제를, 상세 응답의 `creatorId` 또는 현재 post의 `creatorId`를 기준으로 명시 전달하도록 수정했다. 회귀 테스트는 수정 전 RED 실패 후 수정 후 PASS를 확인했다. 최종 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`가 모두 `BUILD SUCCESSFUL`임을 확인했다. `git diff --check`, `git diff HEAD --check`는 출력 없이 통과했다. `:app:mergeDebugResources`는 최초 sandbox에서 `~/.gradle` lock 파일 권한 문제로 실패했으나, 동일 명령을 권한 상승 재실행해 통과했다. - 2026-07-08: 리뷰 결과 추가 반영을 완료했다. 댓글 불가 화면은 댓글 목록/header/input bar만 숨기고 별도 안내 문구 view를 제거했다. 댓글/답글 item에서 Figma에 없는 reaction row를 제거했다. 유료 미구매 상세는 raw image/audio URL을 UI model에서 계속 제거하면서 `showPaywall`로 중앙 lock+가격 paywall을 표시하도록 수정했다. 상대시간은 기존 공통 `formatUtcRelativeTimeText`를 보강해 epoch seconds, ISO offset, 6자리 fraction, 작성 직후 서버/단말 시계 차이를 처리하고, 답글 화면 부모 댓글에는 원본 `createdAtUtc`를 전달해 동일 포맷터 기준으로 표시되게 했다. 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.common.RelativeTimeFormatterTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`가 모두 `BUILD SUCCESSFUL`임을 확인했다. `git diff --check`, `git diff HEAD --check`는 출력 없이 통과했다. `:app:mergeDebugResources`는 최초 sandbox에서 `~/.gradle` lock 파일 권한 문제로 실패했으나, 동일 명령을 권한 상승 재실행해 통과했다. +- 2026-07-09: 사용자 후속 요청 4건을 반영했다. 상세/답글 titlebar의 `커뮤니티`, `답글` 문구를 제거했고, 댓글/답글 더보기 메뉴 문구를 `수정하기`, `삭제하기`로 변경했다. v2 패키지 내부 삭제 확인은 `V2ModalDialog`로 교체했으며, 수정은 Dialog 없이 하단 입력창 수정 모드로 전환되도록 구현했다. 수정 모드에서는 send 버튼으로 수정 API를 호출하고, send 버튼 오른쪽 X 버튼으로 수정 취소가 가능하다. 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.community.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 모두 통과했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 남아 있다. +- 2026-07-09: 댓글/답글 더보기 메뉴 font 후속 요청을 반영했다. `PopupMenu`는 메뉴 item font를 직접 지정하기 어려워, 댓글/답글 더보기만 `PopupWindow` 기반 `CreatorChannelCommunityMorePopup`으로 교체하고 메뉴 TextView에 `android:fontFamily="@font/regular"`를 명시했다. 검증 명령은 Phase 10.1 기록에 누적한다. +- 2026-07-09: 수정하기 터치 시 키보드가 바로 올라오고, 입력/수정 API success 후 키보드가 내려가야 한다는 후속 요청을 반영했다. 상세/답글 Activity에서 수정 모드 진입 시 입력창 focus와 IME show를 수행하고, 작성/수정 성공 이벤트에서 IME hide와 focus clear를 수행한다. 검증 명령은 Phase 11.1 기록에 누적한다. diff --git a/docs/20260708_커뮤니티_게시물_상세_댓글_답글/prd.md b/docs/20260708_커뮤니티_게시물_상세_댓글_답글/prd.md index 6f4d51f6..2918d909 100644 --- a/docs/20260708_커뮤니티_게시물_상세_댓글_답글/prd.md +++ b/docs/20260708_커뮤니티_게시물_상세_댓글_답글/prd.md @@ -30,7 +30,7 @@ - 최신 답글: `commentId`, `writerId`, `writerProfileImageUrl`, `writerNickname`, `content`, `createdAtUtc` - 댓글/답글 조회 query parameter 기본값은 `page=0`, `size=20`으로 둔다. - 댓글 쓰기, 답글 쓰기, 댓글 수정, 댓글 삭제, 좋아요는 기존 `CreatorCommunityRepository`(`/creator-community/*`) API를 그대로 재사용한다. -- 댓글 팝업 메뉴는 기존 커뮤니티 댓글과 동일한 팝업 메뉴(`content_comment_option_menu`, `content_comment_option_menu2`)를 사용한다. +- 댓글 팝업 메뉴는 기존 커뮤니티 댓글과 동일한 팝업 메뉴(`content_comment_option_menu`, `content_comment_option_menu2`)를 사용하되, 메뉴 문구는 `수정하기`, `삭제하기`로 표시한다. - 하트 터치 시 좋아요 API를 호출하고, `isLiked`에 따라 `ic_feed_community_heart_fill`/`ic_feed_community_heart` icon을 표시한다. - 댓글 작성이 불가능한 게시글(`isCommentAvailable == false`)이면 댓글 목록과 하단 입력 영역을 숨긴다. - 하단 댓글/답글 입력 영역은 화면 하단에 고정하고 키보드 표시 여부에 따라 함께 올라오게 한다. @@ -44,6 +44,7 @@ - 서버 API schema나 endpoint를 새로 정의하지 않는다. - 레거시 커뮤니티/댓글 관련 파일을 직접 수정하지 않는다. - 크리에이터 채널의 다른 탭 UI나 공통 스크롤 구조를 재설계하지 않는다. +- v2 패키지 내부 popup dialog는 `kr.co.vividnext.sodalive.v2.components.modal.V2ModalDialog`를 사용한다. --- @@ -151,11 +152,13 @@ Figma 기준 하단 고정 입력 영역을 제공한다. - 3줄까지는 입력창 높이가 자동 확장된다. - 4줄 이상이면 3줄 높이를 유지하고 vertical scroll로 처리한다. - 입력 영역은 화면 하단에 고정되고 키보드가 올라오면 키보드 위로 함께 올라온다. +- 수정 모드 진입 시 하단 입력창에 focus를 주고 키보드를 즉시 표시한다. - 전송 버튼 비활성 상태: `ic_new_arrow_up_gray` icon, 원형 배경, 배경색 `gray_900`. - 전송 버튼 활성 상태: `ic_new_arrow_up_white` icon, 원형 배경, 배경색 `soda_400`. - 게시물 상세에서 전송 시 댓글 쓰기 API(`registerComment(postId, comment)`)를 호출한다. - 답글 화면에서 전송 시 답글 쓰기 API(`registerComment(postId, comment, parentId = commentId)`)를 호출한다. - 작성 성공 시 입력값을 비우고 목록을 새로고침한다. +- 작성 또는 수정 API 성공 시 키보드를 내린다. #### Edge Cases - 공백/줄바꿈만 입력한 경우 전송 버튼은 비활성 상태다. @@ -166,8 +169,11 @@ Figma 기준 하단 고정 입력 영역을 제공한다. 기존 커뮤니티 댓글 수정/삭제 흐름을 재사용한다. #### Requirements -- 팝업 메뉴 `수정하기` 선택 시 기존 수정 흐름(`modifyComment(commentId, comment = ...)`)을 따른다. -- 팝업 메뉴 `삭제하기` 선택 시 기존 삭제 확인 dialog 후 삭제 흐름(`modifyComment(commentId, isActive = false)`)을 따른다. +- 팝업 메뉴 `수정하기` 선택 시 별도 입력 Dialog를 띄우지 않고 화면 하단 입력창을 수정 모드로 전환한다. +- 수정 모드의 하단 입력창에는 기존 댓글/답글 내용을 채우고, 취소용 X 버튼을 표시한다. +- 수정 모드에서 전송 버튼을 누르면 기존 수정 흐름(`modifyComment(commentId, comment = ...)`)을 따른다. +- X 버튼을 누르면 수정 모드를 취소하고 입력창을 비운 뒤 일반 작성 모드로 돌아간다. +- 팝업 메뉴 `삭제하기` 선택 시 v2 공통 모달(`V2ModalDialog`)로 삭제 확인 후 삭제 흐름(`modifyComment(commentId, isActive = false)`)을 따른다. - 수정/삭제 성공 시 현재 목록(댓글 목록 또는 답글 목록)을 새로고침한다. #### Edge Cases @@ -203,7 +209,7 @@ Figma `290:9266` 기준으로 댓글 불가 상태를 처리한다. - 신규 Activity/Fragment/ViewModel 및 하위 코드는 `kr.co.vividnext.sodalive.v2.creator.channel.community` 하위에 작성한다. - 조회용 신규 v2 endpoint는 v2 API/Repository 계약(`ApiResponse`, RxJava3, Koin)을 따른다. - 댓글 쓰기/답글 쓰기/수정/삭제/좋아요는 기존 `CreatorCommunityRepository`를 호출해 재사용한다(레거시 파일 직접 수정 금지). -- 댓글 팝업 메뉴는 기존 `content_comment_option_menu`, `content_comment_option_menu2` 리소스를 재사용한다. +- 댓글 팝업 메뉴는 기존 `content_comment_option_menu`, `content_comment_option_menu2` 리소스를 재사용하고, 문구는 `수정하기`, `삭제하기`로 표시한다. - 커뮤니티 댓글/답글 신고는 현재 전용 신고 API/레거시 흐름이 없어 이번 구현 범위에서 제외하고, 기존 레거시 메뉴2의 실제 동작인 채널 크리에이터 삭제만 재사용한다. - 신규 문자열은 `values`, `values-en`, `values-ja`에 추가하거나 기존 문자열을 재사용한다. - 오디오 재생은 기존 `CreatorCommunityMediaPlayerManager`를 재사용한다.