935 lines
96 KiB
Markdown
935 lines
96 KiB
Markdown
# 크리에이터 채널 홈 탭 구현 계획/TASK
|
|
|
|
> **For agentic workers:** 구현 시 `superpowers:subagent-driven-development` 또는 `superpowers:executing-plans`를 사용해 task 단위로 진행한다. 각 단계는 체크박스(`- [ ]`)로 추적하고, 완료 즉시 `- [x]`로 갱신한다.
|
|
|
|
**Goal:** `GET /api/v2/creator-channels/{creatorId}/home` 응답을 기반으로 크리에이터 채널 신규 페이지의 상단 구성과 `홈` 탭 컨텐츠를 표시한다.
|
|
|
|
**Architecture:** 신규 화면은 `kr.co.vividnext.sodalive.v2.creator.channel` 하위에 Activity, ViewModel, data/model/ui 패키지를 두고 기존 Retrofit + RxJava3 + `ApiResponse<T>` + Koin 패턴을 따른다. `RecommendedActivityType`은 홈 추천 전용 이름을 제거해 공용 `CreatorActivityType`으로 이동하고, 홈 추천과 크리에이터 채널 홈이 같은 타입을 참조하게 한다. UI는 Android XML Views/ViewBinding 기반으로 구성하고, 홈 탭 외 다른 탭 상세 화면은 이번 범위에서 연결하지 않는다.
|
|
|
|
**Tech Stack:** Kotlin, Android XML Views, ViewBinding, RecyclerView/NestedScroll, Retrofit, Gson, RxJava3, Koin, JUnit4/Robolectric local unit test.
|
|
|
|
---
|
|
|
|
## 전제와 성공 기준
|
|
- PRD: `docs/20260611_크리에이터_채널_홈_탭/prd.md`
|
|
- Figma 전체 페이지: `296:14890`
|
|
- 크리에이터 이미지 영역: `296:14892`
|
|
- title-bar 상태별 Figma:
|
|
- 팔로우 상태가 아님: `296:14287`
|
|
- 팔로우 중 + 알림 받기 중: `296:14288`
|
|
- 팔로우 중 + 알림 받기 중이 아님: `296:14289`
|
|
- 이번 범위는 크리에이터 채널 전체 구성과 `홈` 탭에 한정한다.
|
|
- tab-bar 목록은 `홈`, `라이브`, `오디오`, `시리즈`, `커뮤니티`, `팬Talk`, `후원` 순서를 따른다.
|
|
- `라이브`, `오디오`, `시리즈`, `커뮤니티`, `팬Talk`, `후원` 탭의 상세 컨텐츠와 pagination은 구현하지 않는다.
|
|
- 홈 API는 `GET /api/v2/creator-channels/{creatorId}/home`을 사용한다.
|
|
- 팔로우/알림 변경은 기존 `UserRepository.creatorFollow()` 및 `CreatorFollowNotifyFragment` 사용 패턴을 재사용한다.
|
|
- `대화하기`는 `TalkApi.createChatRoom` 호출 후 반환된 `chatRoomId`로 `ChatRoomActivity`, `DM 보내기`는 `DmChatRoomActivity.newIntentByCreatorId()`로 이동한다.
|
|
- title-bar black 전환 기준은 title-bar와 tab-bar의 실제 거리 및 프로필 이미지가 절반 이상 사라졌는지를 함께 사용한다.
|
|
- 구현 완료 후 최소 다음 명령을 실행한다.
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.common.*"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"`
|
|
- `./gradlew :app:mergeDebugResources`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- `./gradlew :app:ktlintCheck`
|
|
|
|
---
|
|
|
|
## Figma 참조 필요 Phase
|
|
- Phase 1: 부분 참조
|
|
- 구현 범위 확인 시 PRD의 Figma 노드 기준만 확인한다.
|
|
- 실제 치수/레이어 구현 판단은 하지 않는다.
|
|
- Phase 2: Figma 참조 불필요
|
|
- `CreatorActivityType` 공용화는 서버 타입/기존 홈 추천 타입 정리 작업이다.
|
|
- Phase 3: Figma 참조 불필요
|
|
- API/DTO/Repository는 서버 계약과 기존 네트워크 패턴만 따른다.
|
|
- Phase 4: 부분 참조
|
|
- `CreatorChannelHomeSection` 순서와 section 표시 여부를 Figma `296:14890` 홈 구성 기준으로 맞출 때 참조한다.
|
|
- title-bar 아이콘 상태 자체는 PRD와 리소스명으로 검증 가능하지만, 우측 액션 배치 우선순위는 Figma 상태별 노드 `296:14287`, `296:14288`, `296:14289`를 확인한다.
|
|
- Phase 5: 필수 참조
|
|
- `activity_creator_channel_home.xml`, title-bar overlay, 크리에이터 이미지 영역, 버튼 영역 보존/중앙 정렬, tab-bar 배치, 홈 section item layout은 Figma `296:14890`, `296:14892`, `296:14287`, `296:14288`, `296:14289`를 기준으로 구현한다.
|
|
- Phase 6: 필수 참조
|
|
- sticky tab-bar 위치, title-bar와 tab-bar가 가까워지는 시점, 프로필 이미지가 절반 이상 사라지는 기준을 실제 화면 배치와 비교해야 하므로 Figma `296:14890`과 `296:14892`를 참조한다.
|
|
- Phase 7: 부분 참조
|
|
- 팔로우/알림 API 연결은 Figma가 필요 없지만, tab-bar 7개 항목의 시각 표시와 title-bar 아이콘 click target 배치는 Figma 기준을 확인한다.
|
|
- Phase 8: 필수 참조
|
|
- 수동 화면 검증은 Figma와 실제 구현 화면을 비교해 PRD Metrics를 확인한다.
|
|
|
|
---
|
|
|
|
## 파일 구조
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/common/CreatorActivityType.kt`
|
|
- 기존 `RecommendedActivityType`을 대체하는 공용 활동 타입을 정의한다.
|
|
- 수정/삭제 후보: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/RecommendedActivityType.kt`
|
|
- 공용 타입 이동 후 기존 파일은 제거하거나 호환 alias가 반드시 필요한 경우 최소 범위로 남긴다.
|
|
- 수정: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/HomeRecommendationMappers.kt`
|
|
- `RecommendedActivityType` 참조를 `CreatorActivityType`으로 변경한다.
|
|
- 수정: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/HomeRecommendationUiModels.kt`
|
|
- 최근 활동 크리에이터 UI 모델의 타입을 공용 `CreatorActivityType`으로 변경한다.
|
|
- 수정: `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/RecommendedActivityTypeTest.kt`
|
|
- 테스트명을 유지하거나 `CreatorActivityTypeTest`로 이동해 공용 타입 검증으로 변경한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- 크리에이터 채널 홈 화면, intent 진입, edge-to-edge/inset, title/tab scroll, click 연결을 담당한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModel.kt`
|
|
- 홈 API 호출, 팔로우/알림 변경, loading/error/content 상태를 관리한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeApi.kt`
|
|
- `GET /api/v2/creator-channels/{creatorId}/home` endpoint를 정의한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.kt`
|
|
- PRD의 서버 DTO를 Android DTO로 정의한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeRepository.kt`
|
|
- 홈 API, 기존 크리에이터 팔로우 API, 기존 `TalkApi.createChatRoom` 호출을 ViewModel에 제공한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeUiModels.kt`
|
|
- 화면 상태, tab 항목, header/action/home section UI model을 정의한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeMappers.kt`
|
|
- API 응답을 UI model로 변환한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelTitleBarState.kt`
|
|
- 팔로우/알림 조합별 title-bar 아이콘 상태와 버튼 표시 상태를 순수 모델로 정의한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelScrollState.kt`
|
|
- title-bar black 전환과 tab-bar sticky 기준을 순수 함수로 계산한다.
|
|
- 생성: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt`
|
|
- 홈 탭 section 목록을 RecyclerView로 표시한다.
|
|
- 생성 후보: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelTabAdapter.kt`
|
|
- 기존 `TextTabBarView`로 7개 탭 표시가 어렵거나 Figma tab-bar와 맞지 않을 때만 추가한다.
|
|
- 생성: `app/src/main/res/layout/activity_creator_channel_home.xml`
|
|
- 크리에이터 이미지 영역, title-bar, tab-bar, 홈 컨텐츠 RecyclerView를 포함한 화면 레이아웃이다.
|
|
- 생성: `app/src/main/res/layout/item_creator_channel_home_*.xml`
|
|
- 홈 탭 섹션별 item layout을 필요한 만큼 추가한다.
|
|
- 수정: `app/src/main/AndroidManifest.xml`
|
|
- `CreatorChannelHomeActivity`를 등록한다.
|
|
- 수정: `app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt`
|
|
- 신규 API, Repository, ViewModel을 Koin에 등록한다.
|
|
- 테스트 생성/수정:
|
|
- 생성: `app/src/test/java/kr/co/vividnext/sodalive/v2/common/CreatorActivityTypeTest.kt`
|
|
- 생성: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeMapperTest.kt`
|
|
- 생성: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelTitleBarStateTest.kt`
|
|
- 생성: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelScrollStateTest.kt`
|
|
- 생성: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModelTest.kt`
|
|
- 생성: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivitySourceTest.kt`
|
|
|
|
---
|
|
|
|
### Phase 1: 기존 구조 확인과 작업 경계 고정
|
|
|
|
- [x] **Task 1.1: 기존 v2 홈/채팅/팔로우 구조 확인**
|
|
- 확인:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/data/HomeRecommendationApi.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeRecommendationViewModel.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/user/UserRepository.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/explorer/profile/CreatorFollowNotifyFragment.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/chat/talk/TalkApi.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/CreateChatRoomRequest.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/CreateChatRoomResponse.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailViewModel.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/dm/DmChatRoomActivity.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt`
|
|
- 검증:
|
|
- REST는 Retrofit + RxJava3 + `ApiResponse<T>` 패턴을 따른다.
|
|
- AI 채팅 이동은 `TalkApi.createChatRoom(CreateChatRoomRequest(characterId))` 호출 후 `CreateChatRoomResponse.chatRoomId`를 받아 `ChatRoomActivity.newIntent(context, roomId)`로 이동하는 패턴을 따른다.
|
|
- DM 이동은 `DmChatRoomActivity.newIntentByCreatorId(context, creatorId)`를 사용할 수 있음을 확인한다.
|
|
- 팔로우/알림 변경은 `UserRepository.creatorFollow(creatorId, follow, notify, token)`를 재사용할 수 있음을 확인한다.
|
|
|
|
- [x] **Task 1.2: 구현 제외 범위 재확인**
|
|
- 확인:
|
|
- `docs/20260611_크리에이터_채널_홈_탭/prd.md`
|
|
- 제외:
|
|
- `라이브`, `오디오`, `시리즈`, `커뮤니티`, `팬Talk`, `후원` 탭 상세 화면
|
|
- 홈 탭 pagination
|
|
- 신규 팔로우/알림 API
|
|
- `ChatRoomActivity`, `DmChatRoomActivity` 내부 동작 변경
|
|
- 별도 analytics/logging
|
|
- 검증:
|
|
- 이후 Phase의 모든 Task가 위 제외 범위를 침범하지 않는지 확인한다.
|
|
|
|
---
|
|
|
|
### Phase 2: `CreatorActivityType` 공용화
|
|
|
|
- [x] **Task 2.1: 공용 활동 타입 RED 테스트 작성**
|
|
- 생성:
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/common/CreatorActivityTypeTest.kt`
|
|
- 수정:
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/RecommendedActivityTypeTest.kt`
|
|
- 작업:
|
|
- `LIVE`, `LIVE_REPLAY`, `AUDIO`, `COMMUNITY`가 대소문자 무시로 파싱되는지 검증한다.
|
|
- 각 타입의 label resource가 기존 `RecommendedActivityType`과 동일한지 검증한다.
|
|
- 알 수 없는 code는 `null`을 반환하는지 검증한다.
|
|
- 대소문자 무시 파싱은 홈 추천 등 클라이언트 helper 호환성 검증이며, 크리에이터 채널 홈 API의 서버 enum 계약은 대문자 code만 내려오는 것으로 본다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.common.CreatorActivityTypeTest"`
|
|
- 기대 결과:
|
|
- 공용 타입 미구현으로 RED 실패한다.
|
|
|
|
- [x] **Task 2.2: `CreatorActivityType` 생성 및 홈 추천 참조 변경**
|
|
- 생성:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/common/CreatorActivityType.kt`
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/HomeRecommendationMappers.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/HomeRecommendationUiModels.kt`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragmentLayoutTest.kt`
|
|
- 삭제 후보:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/model/RecommendedActivityType.kt`
|
|
- 작업:
|
|
- 기존 enum 값과 `code`, `labelResId`를 그대로 유지해 `CreatorActivityType`을 생성한다.
|
|
- `HomeRecommendationRecentlyActiveCreatorUiModel.activityType` 타입을 `CreatorActivityType?`으로 변경한다.
|
|
- `HomeRecommendationMappers.kt`의 parser helper 이름은 `toCreatorActivityTypeLabelRes()`로 변경하거나, 기존 테스트 호환을 위해 같은 파일 안에서 최소 alias만 유지한다.
|
|
- 홈 추천 테스트의 import와 enum 참조를 `CreatorActivityType`으로 변경한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.common.CreatorActivityTypeTest"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"`
|
|
- 기대 결과:
|
|
- 공용 타입 테스트와 기존 홈 추천 테스트가 PASS한다.
|
|
|
|
---
|
|
|
|
### Phase 3: 크리에이터 채널 홈 API/DTO/Repository 추가
|
|
|
|
- [x] **Task 3.1: API DTO와 endpoint 정의**
|
|
- 생성:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeApi.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.kt`
|
|
- 작업:
|
|
- PRD의 `CreatorChannelHomeResponse`와 하위 DTO를 모두 `@Keep`, `@SerializedName` 기반 data class로 추가한다.
|
|
- `CreatorChannelCreatorResponse`에는 `creatorId: Long`과 `characterId: Long?`를 모두 추가한다.
|
|
- `CreatorChannelScheduleResponse.type`은 공용 `CreatorActivityType`을 사용한다.
|
|
- 백엔드 `CreatorActivityType` 원본 enum은 `LIVE`, `AUDIO`, `COMMUNITY`, `LIVE_REPLAY` 대문자 code를 내려주므로 DTO에서 공용 enum을 직접 사용하는 것을 정상 계약으로 본다.
|
|
- 이후 코드리뷰에서는 별도 서버 계약 변경 근거가 없는 한 `type` 대소문자 불일치 대응 또는 Gson enum TypeAdapter 부재를 문제로 보지 않는다.
|
|
- Retrofit endpoint는 `@GET("/api/v2/creator-channels/{creatorId}/home")`로 정의한다.
|
|
- 반환 타입은 `Single<ApiResponse<CreatorChannelHomeResponse>>`를 사용한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 기대 결과:
|
|
- 신규 DTO와 API가 컴파일된다.
|
|
|
|
- [x] **Task 3.2: Repository 추가**
|
|
- 생성:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeRepository.kt`
|
|
- 작업:
|
|
- `getHome(creatorId: Long, token: String)`에서 홈 API를 호출한다.
|
|
- 기존 `UserRepository`를 생성자 인자로 받아 `followCreator(creatorId, follow, notify, token)`를 얇게 위임한다.
|
|
- 기존 `TalkApi`를 생성자 인자로 받아 `createChatRoom(characterId, token)`에서 `CreateChatRoomRequest(characterId)`로 `TalkApi.createChatRoom`을 호출한다.
|
|
- token 문자열은 기존 ViewModel 패턴과 맞춰 ViewModel에서 `"Bearer ${SharedPreferenceManager.token}"`로 만든다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 기대 결과:
|
|
- Repository가 기존 DI 패턴과 충돌 없이 컴파일된다.
|
|
|
|
- [x] **Task 3.3: Koin DI 등록**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt`
|
|
- 작업:
|
|
- `CreatorChannelHomeApi`, `CreatorChannelHomeRepository`, `CreatorChannelHomeViewModel` import를 추가한다.
|
|
- `networkModule`에 `single { ApiBuilder().build(get(), CreatorChannelHomeApi::class.java) }`를 추가한다.
|
|
- 기존 `networkModule`의 `TalkApi` 등록을 재사용한다.
|
|
- `repositoryModule`에 `factory { CreatorChannelHomeRepository(api = get(), userRepository = get(), talkApi = get()) }`를 추가한다.
|
|
- `viewModelModule`에 `viewModel { CreatorChannelHomeViewModel(get()) }`를 추가한다.
|
|
- 참고: Phase 3 현재 구현에서는 `CreatorChannelHomeViewModel` 클래스가 Phase 4 산출물이므로 컴파일을 깨지 않기 위해 ViewModel DI 등록은 Phase 4로 보류하고, API/Repository 등록만 완료했다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 기대 결과:
|
|
- Koin 등록과 import가 컴파일된다.
|
|
|
|
---
|
|
|
|
### Phase 4: UI 모델/매퍼/ViewModel 구현
|
|
|
|
- [x] **Task 4.1: 홈 응답 매퍼 RED 테스트 작성**
|
|
- 생성:
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeMapperTest.kt`
|
|
- 작업:
|
|
- `creator.characterId`, `creator.isFollow`, `creator.isNotify`, `creator.isAiChatAvailable`, `creator.isDmAvailable`가 UI model에 그대로 반영되는지 검증한다.
|
|
- tab 목록이 `홈`, `라이브`, `오디오`, `시리즈`, `커뮤니티`, `팬Talk`, `후원` 순서인지 검증한다.
|
|
- `currentLive`, `latestAudioContent`가 null이면 해당 홈 section이 생성되지 않는지 검증한다.
|
|
- 빈 list는 crash 없이 빈 section 또는 hidden section 정책으로 매핑되는지 검증한다.
|
|
- SNS URL이 빈 문자열이면 해당 SNS item이 숨김 또는 disabled 상태로 매핑되는지 검증한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest"`
|
|
- 기대 결과:
|
|
- UI model/mapper 미구현으로 RED 실패한다.
|
|
|
|
- [x] **Task 4.2: UI model과 mapper 구현**
|
|
- 생성:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeUiModels.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeMappers.kt`
|
|
- 작업:
|
|
- `CreatorChannelHomeUiState.Loading`, `Content`, `Empty`, `Error`를 정의한다.
|
|
- `CreatorChannelTab.Home`, `Live`, `Audio`, `Series`, `Community`, `FanTalk`, `Donation`을 정의한다.
|
|
- `CreatorChannelHeaderUiModel`에 `creatorId`, `characterId`, `nickname`, `profileImageUrl`, `followerCount`, `isFollow`, `isNotify`, `isAiChatAvailable`, `isDmAvailable`을 둔다.
|
|
- 홈 section은 Figma 순서에 맞춰 `sealed interface CreatorChannelHomeSection`으로 정의한다.
|
|
- `CreatorChannelHomeResponse.toUiContent()` 매퍼를 구현한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest"`
|
|
- 기대 결과:
|
|
- 매퍼 테스트가 PASS한다.
|
|
|
|
- [x] **Task 4.3: title-bar 상태 순수 모델 테스트와 구현**
|
|
- 생성:
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelTitleBarStateTest.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelTitleBarState.kt`
|
|
- 작업:
|
|
- `isFollow=false`이면 follow icon은 `ic_new_follow`, bell icon은 없음으로 계산한다.
|
|
- `isFollow=true && isNotify=true`이면 follow icon은 `ic_new_following`, bell icon은 `ic_bar_bell_colored`로 계산한다.
|
|
- `isFollow=true && isNotify=false`이면 follow icon은 `ic_new_following`, bell icon은 `ic_bar_bell`로 계산한다.
|
|
- 상태 변경 중에는 중복 클릭 방지를 위한 `isActionEnabled=false` 상태를 표현한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelTitleBarStateTest"`
|
|
- 기대 결과:
|
|
- title-bar 상태 테스트가 PASS한다.
|
|
|
|
- [x] **Task 4.4: ViewModel RED 테스트와 구현**
|
|
- 생성:
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModelTest.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModel.kt`
|
|
- 작업:
|
|
- `loadHome(creatorId)`는 `creatorId > 0`일 때만 홈 API를 호출한다.
|
|
- API 성공 시 `CreatorChannelHomeUiState.Content`를 발행한다.
|
|
- API 실패 또는 exception 시 `Error`와 unknown error toast를 발행한다.
|
|
- `follow(follow, notify)`는 기존 팔로우 API를 호출하고 성공 시 로컬 header의 `isFollow`, `isNotify`를 갱신한다.
|
|
- `createChatRoom(characterId)`는 `characterId > 0`일 때만 `TalkApi.createChatRoom` 위임 API를 호출하고, 성공 시 `ChatRoomActivity` 이동에 사용할 `chatRoomId` 이벤트를 발행한다.
|
|
- 팔로우/알림 변경 중에는 중복 요청을 막는다.
|
|
- 채팅방 생성 중에는 중복 요청을 막는다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"`
|
|
- 기대 결과:
|
|
- ViewModel 테스트가 PASS한다.
|
|
|
|
---
|
|
|
|
### Phase 5: 레이아웃과 홈 탭 UI 연결
|
|
|
|
- [x] **Task 5.1: 화면 layout 생성**
|
|
- 생성:
|
|
- `app/src/main/res/layout/activity_creator_channel_home.xml`
|
|
- 작업:
|
|
- root는 `CoordinatorLayout`, `ConstraintLayout`, `NestedScrollView`/`RecyclerView` 중 기존 sticky 구현에 가장 적합한 구조를 선택한다.
|
|
- 크리에이터 이미지 영역은 status bar 영역까지 확장 가능하게 상단에 배치한다.
|
|
- title-bar는 이미지 위 overlay로 배치하고 `ic_new_bar_back`, `ic_new_more`를 사용한다.
|
|
- follow, following, bell icon view를 title-bar 우측에 배치한다.
|
|
- `대화하기`, `DM 보내기` 버튼 영역은 버튼이 없어도 높이를 보존할 수 있는 container로 만든다.
|
|
- tab-bar는 7개 긴 라벨이 가로 폭을 초과해도 표시되도록 `HorizontalScrollView` + 동적 `TextView` container로 만든다.
|
|
- 각 tab 이름은 하드코딩 문자열이 아니라 `CreatorChannelTab.labelResId`와 `values`, `values-en`, `values-ja` string resource를 사용한다.
|
|
- 홈 컨텐츠는 `RecyclerView` 또는 기존 섹션 패턴에 맞는 container로 둔다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:mergeDebugResources`
|
|
- 기대 결과:
|
|
- 신규 layout과 drawable 참조가 resource merge를 통과한다.
|
|
|
|
- [x] **Task 5.2: 홈 섹션 Adapter와 item layout 추가**
|
|
- 생성:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt`
|
|
- `app/src/main/res/layout/item_creator_channel_home_live.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_latest_audio.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_donation.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_notice.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_schedule.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_audio.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_series.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_community.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_fantalk.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_introduce.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_activity.xml`
|
|
- `app/src/main/res/layout/item_creator_channel_home_sns.xml`
|
|
- 작업:
|
|
- 모든 section을 한 번에 과하게 완성하지 말고, API 필드를 화면에 표시할 최소 텍스트/이미지 영역부터 연결한다.
|
|
- 기존 `AudioContentCardView`, `SeriesContentCardView`, `FeedAdapter`, `LiveThumbnail*` 위젯을 재사용할 수 있는 section은 우선 재사용한다.
|
|
- 빈 list 또는 null section은 adapter item으로 추가하지 않는다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:mergeDebugResources`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 기대 결과:
|
|
- section adapter와 item layout이 컴파일된다.
|
|
|
|
- [x] **Task 5.3: Activity 생성 및 ViewModel observe 연결**
|
|
- 생성:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivitySourceTest.kt`
|
|
- 수정:
|
|
- `app/src/main/AndroidManifest.xml`
|
|
- 작업:
|
|
- `EXTRA_CREATOR_ID`와 `newIntent(context, creatorId)`를 추가한다.
|
|
- 7개 tab은 `content.tabs`를 순회하며 `getString(tab.labelResId)`로 생성한다.
|
|
- `creatorId <= 0`이면 API 호출 없이 finish한다.
|
|
- `onCreate`에서 ViewModel observe, adapter, tab-bar, title-bar click listener를 연결한다.
|
|
- `onCreate` 또는 `onStart`에서 `viewModel.loadHome(creatorId)`를 호출한다.
|
|
- Manifest에 Activity를 등록한다.
|
|
- Source test에서 `HorizontalScrollView` 탭 구조, string resource 기반 탭명, 채팅/DM 이동 계약, Manifest 등록, `CreatorFollowNotifyFragment` 미참조를 검증한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 기대 결과:
|
|
- intent extra, invalid creatorId 처리, Manifest 등록 검증이 PASS한다.
|
|
|
|
- [x] **Task 5.4: title-bar와 이미지 영역 bind 구현**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- 작업:
|
|
- `creator.profileImageUrl`, `nickname`, `followerCount`를 이미지 영역에 표시한다.
|
|
- `CreatorChannelTitleBarState`에 따라 `ic_new_follow`, `ic_new_following`, `ic_bar_bell_colored`, `ic_bar_bell`을 표시한다.
|
|
- title-bar 초기 배경은 투명 overlay로 시작한다.
|
|
- 뒤로가기는 `finish()`로 처리한다.
|
|
- 더보기는 기존 프로필/크리에이터 더보기 메뉴 패턴을 확인해 최소 연결하거나, 기존 패턴이 명확하지 않으면 click handler만 분리하고 후속 구현 대상으로 남긴다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 기대 결과:
|
|
- header/title bind가 컴파일된다.
|
|
|
|
- [x] **Task 5.5: 대화하기/DM 버튼 표시와 이동 연결**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- 작업:
|
|
- `isAiChatAvailable=false`이거나 `characterId == null`이면 `대화하기` 버튼을 숨긴다.
|
|
- `isDmAvailable=false`이면 `DM 보내기` 버튼을 숨긴다.
|
|
- 두 버튼 중 하나만 보일 때는 버튼 container 안에서 가운데 정렬한다.
|
|
- 두 버튼이 모두 숨김이어도 버튼 영역 container 높이는 유지한다.
|
|
- `대화하기`는 ViewModel의 `createChatRoom(characterId)`를 호출한다.
|
|
- 채팅방 생성 성공 이벤트의 `chatRoomId`를 받아 `ChatRoomActivity.newIntent(context, roomId)`로 이동한다.
|
|
- 채팅방 생성 실패 시 기존 unknown error toast 패턴을 따른다.
|
|
- `DM 보내기`는 `DmChatRoomActivity.newIntentByCreatorId(context, creatorId)`로 이동한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 기대 결과:
|
|
- 버튼 표시 조건과 AI 채팅/DM 이동이 컴파일된다.
|
|
|
|
- [x] **Task 5.6: Phase 5 코드 리뷰 지적 title-bar capsule 구조 수정**
|
|
- 수정:
|
|
- `app/src/main/res/layout/activity_creator_channel_home.xml`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivitySourceTest.kt`
|
|
- 생성:
|
|
- `app/src/main/res/drawable/bg_creator_channel_follow_capsule.xml`
|
|
- `app/src/main/res/drawable/bg_creator_channel_following_capsule.xml`
|
|
- 작업:
|
|
- Figma `296:14287`의 미팔로우 상태는 follow icon + `팔로우` 텍스트가 하나의 capsule 안에 표시되도록 구성한다.
|
|
- Figma `296:14288`, `296:14289`의 팔로우 상태는 흰색 원형 capsule 안 follow icon, 별도 bell icon, 별도 more icon 구조로 표시되도록 구성한다.
|
|
- 기존 `tv_follow`와 `iv_follow`가 배경 없이 나란히 놓인 구조를 제거한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`
|
|
- `./gradlew :app:mergeDebugResources`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 기대 결과:
|
|
- title-bar 상태별 capsule 구조 source 계약과 리소스/컴파일이 PASS한다.
|
|
|
|
- [x] **Task 5.7: Phase 5 코드 리뷰 지적 홈 섹션 데이터 보존 수정**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt`
|
|
- `app/src/main/res/values/strings.xml`
|
|
- `app/src/main/res/values-en/strings.xml`
|
|
- `app/src/main/res/values-ja/strings.xml`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivitySourceTest.kt`
|
|
- 작업:
|
|
- 모든 section을 `tv_section_title`/`tv_primary`/`tv_secondary`/`iv_thumbnail` 공통 카드 하나로 동일 처리하던 바인딩을 section별 `bind*` 함수로 분리한다.
|
|
- 오디오/시리즈/커뮤니티/SNS 등 list section은 `firstOrNull()` 또는 단일 `joinToString()` 축약으로 주요 데이터를 버리지 않고 여러 항목 텍스트를 줄 단위로 보존한다.
|
|
- 활동 section은 `debutDateUtc`, `liveCount`, `liveDurationHours`, `liveContributorCount`, `audioContentCount`, `seriesCount`를 모두 resource format으로 표시한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`
|
|
- `./gradlew :app:ktlintCheck`
|
|
- 기대 결과:
|
|
- section별 데이터 보존 source 계약, creator channel 테스트, ktlint가 PASS한다.
|
|
|
|
- [x] **Task 5.8: Phase 5 코드 리뷰 Findings 반영**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivitySourceTest.kt`
|
|
- 작업:
|
|
- 시리즈 가로 타일 row는 화면 밖으로 잘리지 않도록 가로 스크롤 가능한 컨테이너에 넣는다.
|
|
- SNS 버튼은 `CreatorChannelSnsUiItem.url`을 사용해 외부 링크 intent를 실행할 수 있게 한다.
|
|
- 일정 타입은 서버 code가 아니라 `CreatorActivityType.labelResId` 기반 다국어 label로 표시한다.
|
|
- 크리에이터 채널 홈 화면은 어두운 헤더 위 status bar icon 가독성을 위해 light status bar를 끈다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`
|
|
- `./gradlew :app:mergeDebugResources`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- `./gradlew :app:ktlintCheck`
|
|
- `git diff --check`
|
|
- 기대 결과:
|
|
- Phase 5 코드 리뷰 Findings 4건이 모두 source 계약과 빌드/테스트에서 PASS한다.
|
|
|
|
- [x] **Task 5.9: Phase 5 추가 리뷰 반영**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModel.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivitySourceTest.kt`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModelTest.kt`
|
|
- 작업:
|
|
- SNS 버튼은 고정 52dp가 아니라 52dp를 최대값으로 두고, 디바이스 width가 402dp보다 작으면 `52 * width / 402` 비율로 축소한다.
|
|
- toast 이벤트는 화면 재생성 시 중복 표시되지 않도록 `CreatorChannelEvent`로 한 번만 소비되게 한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- `./gradlew :app:ktlintCheck`
|
|
- 기대 결과:
|
|
- SNS 버튼 크기 비율 계산과 toast 단발 이벤트 계약이 PASS한다.
|
|
|
|
- [x] **Task 5.10: Phase 5 코드 리뷰 Finding 1/2와 SNS 아이콘 정책 반영**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeUiModels.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeMappers.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt`
|
|
- `app/src/main/res/values/strings.xml`
|
|
- `app/src/main/res/values-en/strings.xml`
|
|
- `app/src/main/res/values-ja/strings.xml`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivitySourceTest.kt`
|
|
- 작업:
|
|
- 활동 섹션의 데뷔 row는 `데뷔` label과 `debutDateUtc(dDay)` 형식 value를 resource format으로 표시한다.
|
|
- 활동 섹션의 count/hour/person/content/series 값은 단위가 포함된 resource format으로 표시한다.
|
|
- 오디오 콘텐츠 섹션은 각 항목을 세로로 쌓지 않고 단일 가로 스크롤 row로 표시한다.
|
|
- SNS는 텍스트 버튼이 아니라 `ic_sns_`로 시작하는 drawable icon을 사용하는 원형 아이콘 버튼으로 표시한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`
|
|
- `./gradlew :app:mergeDebugResources`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- `./gradlew :app:ktlintCheck`
|
|
- `git diff --check`
|
|
- 기대 결과:
|
|
- 활동 섹션 단위 표시, 오디오 가로 스크롤, SNS 아이콘 source 계약과 빌드/테스트가 PASS한다.
|
|
|
|
- [x] **Task 5.11: Phase 5 SNS 순서/URL 안전성/마지막 여백 리뷰 반영**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelHomeMappers.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeMapperTest.kt`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivitySourceTest.kt`
|
|
- 작업:
|
|
- SNS 매핑 순서를 Figma `296:14890` 기준 `Instagram`, `YouTube`, `X`, `Kakao Open Chat`, `Fancimm` 순서로 맞춘다.
|
|
- blank가 아니더라도 유효하지 않은 SNS URL은 UI item에서 제외한다.
|
|
- SNS 링크 클릭 시 `resolveActivity()`로 열 수 있는 intent만 실행한다.
|
|
- 작은 화면 SNS 버튼 비율 축소 정책은 유지하되, 마지막 아이콘 뒤 trailing `marginEnd`만 제거한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- `./gradlew :app:ktlintCheck`
|
|
- `git diff --check`
|
|
- 기대 결과:
|
|
- SNS 순서, URL 안전성, 마지막 margin source 계약과 빌드/테스트가 PASS한다.
|
|
|
|
---
|
|
|
|
### Phase 5R: 탭 바 아래 홈 컨텐츠 Figma Component 기준 재구성
|
|
|
|
> 2026-06-15 사용자 요청으로 추가된 후속 재구성 Phase다. 기존 Task 5.2에서 만든 탭 바 아래 홈 섹션 UI는 삭제 대상으로 보고, Figma `296:14895`에 있는 component 성격의 구조를 섹션별 Task로 다시 구성한다. 이번 문서 수정 단계에서는 구현하지 않는다.
|
|
|
|
- [x] **Task 5R.0: 기존 홈 섹션 동적 조립 UI 제거 계획 확정**
|
|
- 수정 예정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt`
|
|
- `app/src/main/res/layout/item_creator_channel_home_*.xml`
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivitySourceTest.kt`
|
|
- 작업:
|
|
- 확인 결과 `CreatorChannelHomeSectionAdapter`는 `bind*` 함수에서 `addHeroCard`, `addAudioCard`, `createContentTile`, `addFeedCard`, `addScheduleRow`, `addDonationCard`, `addCommentCard`, `addTextCard`, `addActivityRow`, `createSnsButton` 등으로 view를 코드에서 직접 생성하고 있으므로 Phase 5R 섹션별 Task에서 삭제 대상으로 확정한다.
|
|
- 확인 결과 12개 `item_creator_channel_home_*.xml`은 동일한 `tv_section_title`/`ll_section_items` 컨테이너만 갖는 구조를 공유하므로 Phase 5R 재구성에서는 이 공통 컨테이너 구조를 재사용하지 않는다.
|
|
- adapter는 `getItemViewType()`, `onCreateViewHolder()`, `ViewHolder.bind()`에서 섹션 타입을 선택하고 해당 XML/ViewBinding 또는 재사용 가능한 Android View에 데이터를 전달하는 역할로 축소한다.
|
|
- 실제 UI 구성은 섹션별 XML/ViewBinding 또는 재사용 가능한 Android View로 옮기며, adapter 내부에서 `LinearLayout`, `TextView`, `ImageView`, `HorizontalScrollView`를 조합해 화면 구조를 만드는 패턴은 제거한다.
|
|
- 재사용 후보로 `AudioContentCardView`, `SeriesContentCardView`, `FeedAdapter`, `FeedCommunityView`, `LiveThumbnailSimpleView`, `LiveThumbnailDetailView`, `view_section_title.xml`을 확인했으며, 각 섹션 Task에서 Figma 요구와 맞는지 먼저 판정한다.
|
|
- Figma `296:14895`에는 `화보` 섹션이 있으나 현재 홈 API 응답에는 화보 데이터가 없으므로 이번 재구성 범위에서 제외한다.
|
|
- 검증 명령:
|
|
- 문서 단계에서는 실행하지 않는다.
|
|
- 기대 결과:
|
|
- 기존 구현을 어떤 기준으로 제거하고 어떤 단위로 재구성할지 문서에 명확히 남는다.
|
|
- 확인 근거:
|
|
- `CreatorChannelHomeSectionAdapter.kt`는 현재 섹션별 `bind*`에서 코드 생성 helper를 호출해 실제 UI를 조립한다.
|
|
- `item_creator_channel_home_live.xml`을 포함한 섹션 layout은 `tv_section_title`과 `ll_section_items` 중심의 동일 컨테이너 구조다.
|
|
- `view_section_title.xml`과 v2 widget/feed/live thumbnail 계열 컴포넌트는 재사용 후보로 확인했다.
|
|
- 검증 기록:
|
|
- 2026-06-15: 문서 확정 Task라 빌드/테스트는 실행하지 않았다. `rg`와 파일 확인으로 삭제 대상 helper, 공통 컨테이너 layout, 재사용 후보 컴포넌트를 확인했다.
|
|
|
|
- [x] **Task 5R.1: 현재 라이브 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_live.xml`
|
|
- 필요 시 현재 라이브 전용 View/layout
|
|
- Figma 기준:
|
|
- `296:14897`의 현재 라이브 섹션
|
|
- 최상단 현재 라이브는 `SectionTitle` 없이 374dp x 78dp cyan gradient pill card로 표시한다.
|
|
- 작업:
|
|
- `currentLive`가 null이면 섹션을 표시하지 않는다.
|
|
- `item_creator_channel_home_live.xml`은 기존 `tv_section_title`/`ll_section_items` 공통 컨테이너를 제거하고 현재 라이브 전용 layout id로 구성한다.
|
|
- 라이브 제목, 시작 시간, 유료 가격 capsule, 성인 상태가 있으면 Figma 라이브 카드 구조에 맞춰 표시한다.
|
|
- 기존 `LiveThumbnail*` 계열 위젯은 원형 프로필/썸네일 기반 구조라 `296:14897`의 pill card와 맞지 않아 재사용하지 않는다.
|
|
- 검증 기준:
|
|
- adapter가 `addHeroCard` 동적 helper로 라이브 카드를 만들지 않고 `item_creator_channel_home_live.xml`의 전용 view id를 bind한다.
|
|
- 검증 기록:
|
|
- 2026-06-15: Figma `296:14897`을 확인해 현재 라이브가 `SectionTitle`/썸네일 없는 374dp x 78dp cyan gradient pill card임을 반영했다. RED로 `CreatorChannelHomeActivitySourceTest`에 live 전용 layout/bind 계약을 추가해 기존 구현 실패를 확인했고, 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 PASS했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고와 Kotlin deprecation warning은 기존 경고로 이번 변경과 무관하다.
|
|
|
|
- [x] **Task 5R.2: 최신 오디오 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_latest_audio.xml`
|
|
- 필요 시 오디오 list row 전용 View/layout
|
|
- Figma 기준:
|
|
- `296:14898`의 최신 오디오 `Contents` 변형 card
|
|
- 최상단 최신 오디오는 `SectionTitle` 없이 gray 900 card 안에 88dp 썸네일, Point 태그, `New` label, 제목, duration을 표시한다.
|
|
- 작업:
|
|
- `latestAudioContent`가 null이면 섹션을 표시하지 않는다.
|
|
- Figma card 구조에 맞춰 이미지, Point 태그, `New` label, 제목, duration을 표시한다.
|
|
- 기존 `AudioContentCardView`는 Point 태그 구성은 유사하지만 세로 카드 구조라 `296:14898`과 맞지 않아 재사용하지 않고 전용 layout을 만든다.
|
|
- 검증 기준:
|
|
- 최신 오디오는 `addAudioCard` 같은 코드 생성 helper 없이 `item_creator_channel_home_latest_audio.xml`의 전용 view id를 bind한다.
|
|
- 검증 기록:
|
|
- 2026-06-15: Figma `296:14898`을 확인해 최신 오디오가 `SectionTitle` 없는 `Contents` 변형 card이며 기존 `AudioContentCardView`와 UI 구성이 다름을 반영했다. RED로 `CreatorChannelHomeActivitySourceTest`에 최신 오디오 전용 layout/bind 계약을 추가해 기존 구현 실패를 확인했고, 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 PASS했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고와 Kotlin deprecation warning은 기존 경고로 이번 변경과 무관하다.
|
|
- 2026-06-15: `docs/agent-guides/code-style.md`의 radius clipping 규칙에 따라 `item_creator_channel_home_latest_audio.xml`의 `android:clipToOutline` 속성을 제거하고, `CreatorChannelLatestAudioThumbnailView`에서 `clipToOutline = true`와 `ViewOutlineProvider.setRoundRect(...)`를 함께 설정하도록 수정했다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 PASS했다.
|
|
|
|
- [x] **Task 5R.3: 후원 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_donation.xml`
|
|
- 필요 시 후원 row 전용 View/layout
|
|
- Figma 기준:
|
|
- `296:14895`의 list/comment 계열 스타일
|
|
- 공통 제목은 `SectionTitle`
|
|
- 작업:
|
|
- `channelDonations`가 empty이면 섹션을 표시하지 않는다.
|
|
- 후원자 프로필, 닉네임, 후원 메시지, can 수량을 표시한다.
|
|
- 비밀 후원은 기존 채널 후원 UI 정책을 확인해 닉네임/프로필 노출 방식을 맞춘다.
|
|
- 검증 기준:
|
|
- 후원 항목은 섹션 전용 row layout 또는 기존 후원 item layout 재사용으로 렌더링된다.
|
|
- 검증 기록:
|
|
- 2026-06-15: Figma `296:14908`을 확인해 후원 섹션이 `SectionTitle`, 가로 스크롤 후원 카드 row, `ic_new_donation` 후원하기 버튼 구조임을 반영했다. `CreatorChannelHomeActivitySourceTest`에 후원 전용 layout/row bind, can 수량별 헤더 배경색, 402dp 기준 최대 374dp/작은 화면 비율 축소, 최대 8개 표시, 빈 메시지 fallback 다국어 계약을 RED로 추가한 뒤 구현했다. 후원 메시지가 blank이면 `%1$d캔을 후원하였습니다.` 형식의 다국어 string을 표시하고, can 배경색은 1~50 `#E2E2E2`, 51~100 `#73FF01`, 101~499 `#00EAFF`, 500 이상 `#FF4C3C`로 매핑했다. 비밀 후원은 기존 채널 후원 UI 정책 확인 결과 닉네임/프로필을 숨기지 않으므로 동일하게 노출한다. `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 PASS했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고와 Kotlin/Java deprecation warning은 기존 경고로 이번 변경과 무관하다.
|
|
- 2026-06-15: 후속 수정으로 `item_creator_channel_home_donation_row.xml`의 XML `android:clipToOutline`을 제거하고 `CreatorChannelDonationCardView` custom view에서 `clipToOutline = true`와 `ViewOutlineProvider.setRoundRect(..., R.dimen.radius_14)`를 설정하도록 변경했다. 또한 Figma 구조에 맞춰 후원하기 버튼 참조 기준을 child `tv_donation_button`이 아니라 parent `layout_donation_button`으로 고정하고 관련 source test 계약을 갱신했다.
|
|
|
|
- [x] **Task 5R.4: 공지 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_notice.xml`
|
|
- 필요 시 공지 row/feed 전용 View/layout
|
|
- Figma 기준:
|
|
- `296:14915`의 공지 섹션 구조
|
|
- 공통 제목은 `SectionTitle`
|
|
- 공지는 `ic_pin` + `Notice` label, 프로필 42dp, 작성자/날짜, 본문, 선택 이미지 썸네일을 가진 feed card로 표시한다.
|
|
- 공지 item UI width는 디바이스 width 402dp 기준 최대 346dp이며, 402dp 미만에서는 같은 비율로 축소한다.
|
|
- 작업:
|
|
- `notices`가 empty이면 섹션을 표시하지 않는다.
|
|
- 공지는 1개 고정이 아니라 최대 3개까지 가로 row에 나열한다.
|
|
- 공지 item width는 `346 * deviceWidth / 402` 비율로 계산하되 402dp 이상에서는 346dp로 고정한다.
|
|
- 공지 본문, 날짜, 이미지가 있으면 이미지 영역을 표시한다.
|
|
- 유료/잠금 상태 표현이 필요한 경우 Figma `Lock` 구조와 API `price` 값을 연결한다.
|
|
- 검증 기준:
|
|
- 공지 섹션은 공통 텍스트 카드가 아니라 공지 전용 layout으로 렌더링된다.
|
|
- 검증 기록:
|
|
- 2026-06-15: Figma `296:14915`를 확인해 공지 섹션이 `SectionTitle`, `ic_pin` Notice label, 프로필/작성자/날짜, 본문, 선택 썸네일을 가진 가로 feed card 구조임을 반영했다. 사용자 피드백에 따라 공지는 1개가 아니라 최대 3개까지 `HorizontalScrollView` row에 나열하고, 공지 item width는 디바이스 width 402dp 기준 최대 346dp이며 402dp 미만에서는 `346 * deviceWidth / 402` 비율로 축소하도록 구현했다. RED로 `CreatorChannelHomeActivitySourceTest`에 공지 전용 layout/row bind, 최대 3개 제한, 마지막 카드 trailing margin 제거, 이미지 null/blank 시 썸네일 숨김, radius clipping custom view, 346dp width 계산 계약을 추가했고 기존 구현이 row layout/custom thumbnail view 부재 및 374dp width 계산으로 실패함을 확인했다. 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest.공지 섹션은 최대 3개 Figma feed card를 가로 row로 렌더링한다"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest.공지 컴포넌트 width는 402dp 기준 최대 346dp이고 작은 화면에서는 비율 축소한다"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 PASS했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고와 Kotlin/Gradle deprecation warning은 기존 경고로 이번 변경과 무관하다.
|
|
|
|
- [x] **Task 5R.5: 일정 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_schedule.xml`
|
|
- 필요 시 일정 row 전용 View/layout
|
|
- Figma 기준:
|
|
- `296:14895`의 list row 구조
|
|
- 공통 제목은 `SectionTitle`
|
|
- 작업:
|
|
- `schedules`가 empty이면 섹션을 표시하지 않는다.
|
|
- 일정 타입은 `CreatorActivityType.labelResId`로 표시한다.
|
|
- 일정 제목과 일시를 Figma row 구조에 맞춘다.
|
|
- 검증 기준:
|
|
- 일정은 `addScheduleRow` 동적 생성 없이 전용 row bind로 렌더링된다.
|
|
- 검증 기록:
|
|
- 2026-06-15: Figma `296:14947`을 확인해 일정 섹션이 `SectionTitle`, 351dp feed card, 53dp calendar 영역, 타입 tag, 로컬 시간 텍스트를 가진 세로 3개 row 구조임을 반영했다. 사용자 추가 요구에 따라 `scheduledAtUtc`는 UTC로 파싱한 뒤 디바이스 Timezone 기준 날짜/요일/시간으로 표시한다. 스케줄은 `scheduledAtUtc`가 가장 가까운 순으로 정렬해 최대 3개만 매핑한다. 스케줄 item 클릭은 콘텐츠(`AUDIO`, `LIVE_REPLAY`)는 `AudioContentDetailActivity`로, 라이브(`LIVE`)는 예약 라이브를 고려해 `LiveRoomActivity` 직접 진입이 아니라 `LiveRoomDetailFragment` 표시로 연결했다. RED로 `CreatorChannelHomeMapperTest`와 `CreatorChannelHomeActivitySourceTest`에 정렬/최대 3개, 전용 layout/row bind, Timezone 변환, 상세 이동 계약을 추가했고, 기존 구현이 `formatCreatorChannelSchedule*` 미구현으로 실패함을 확인했다. 구현 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest.스케줄은 scheduledAtUtc가 가까운 순으로 최대 3개만 매핑한다"`와 일정 source/timezone/navigation 테스트 3건이 PASS했다. 최종 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`가 PASS했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고와 Kotlin/Gradle deprecation warning은 기존 경고로 이번 변경과 무관하다.
|
|
- 2026-06-15: 후속 확인에서 Figma `296:14953`의 왼쪽 timeline indicator가 누락되어 있음을 확인하고 추가 구현했다. `item_creator_channel_home_schedule.xml`에 `ll_schedule_timeline` column을 추가하고, `CreatorChannelHomeSectionAdapter`에서 실제 표시 스케줄 수만큼 dot을 만들며 dot 사이 line 개수는 `scheduleCount - 1`개로 계산한다. 첫 dot은 Figma처럼 `soda_400`, 나머지 dot과 line은 `gray_700`으로 표시한다. RED로 `CreatorChannelHomeActivitySourceTest`에 timeline dot/line 동적 생성 계약을 추가해 `calculateCreatorChannelScheduleTimelineLineCount` 미구현 실패를 확인했고, 구현 후 해당 테스트와 `./gradlew :app:mergeDebugResources`가 PASS했다.
|
|
|
|
- [ ] **Task 5R.6: 오디오 컨텐츠 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_audio.xml`
|
|
- 필요 시 `Contents` audio variant 대응 View/layout
|
|
- Figma 기준:
|
|
- `296:14895`의 오디오 컨텐츠 섹션
|
|
- Figma `Contents(type=audio, size=s)` 또는 해당 섹션의 88dp list row 구조
|
|
- 작업:
|
|
- `audioContents`가 empty이면 섹션을 표시하지 않는다.
|
|
- 각 오디오 항목은 이미지, 제목, 시리즈명/시간, 유료/무료/포인트/first/original 상태를 Figma tag 정책에 맞춰 표시한다.
|
|
- 기존 `AudioContentCardView` 재사용 여부를 먼저 판정하고, 요구와 다르면 전용 Android View를 만든다.
|
|
- 검증 기준:
|
|
- 오디오 컨텐츠는 adapter 내부 `createContentTile`이 아니라 component/layout bind로 표시된다.
|
|
|
|
- [ ] **Task 5R.7: 시리즈 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_series.xml`
|
|
- 필요 시 `Contents` series variant 대응 View/layout
|
|
- Figma 기준:
|
|
- `296:14895`의 시리즈 섹션
|
|
- Figma `Contents(type=series, size=m)`
|
|
- 작업:
|
|
- `series`가 empty이면 섹션을 표시하지 않는다.
|
|
- 시리즈 썸네일은 163dp x 230dp 비율과 radius 14dp를 따른다.
|
|
- `isOriginal`, `isNew`, `isPopular`, `isComplete`, `numberOfContent`, `publishedDaysOfWeek`를 Figma tag/label 정책에 맞춰 표시한다.
|
|
- 기존 `SeriesContentCardView` 또는 시리즈 카드 layout을 재사용할 수 있는지 먼저 확인한다.
|
|
- 검증 기준:
|
|
- 시리즈 섹션은 Figma `Contents` 구조에 대응하는 View/layout으로 렌더링된다.
|
|
|
|
- [ ] **Task 5R.8: 커뮤니티 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_community.xml`
|
|
- 필요 시 커뮤니티 feed 전용 View/layout
|
|
- Figma 기준:
|
|
- `296:14895`의 `Feed` 구조
|
|
- 작업:
|
|
- `communities`가 empty이면 섹션을 표시하지 않는다.
|
|
- 프로필 42dp 원형 이미지, 작성자, 작성 시간, 본문, 이미지, 잠금 overlay, 좋아요/댓글 reaction을 표시한다.
|
|
- 기존 `FeedCommunityView` 또는 `FeedAdapter` 재사용 여부를 먼저 확인한다.
|
|
- Figma의 `전체보기` capsule 버튼을 표시하되, 이동 대상이 없는 경우 click listener는 후속 범위로 분리한다.
|
|
- 검증 기준:
|
|
- 커뮤니티는 단순 `addFeedCard`가 아니라 Figma `Feed` 구조를 가진 View/layout으로 렌더링된다.
|
|
|
|
- [ ] **Task 5R.9: 팬Talk 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_fantalk.xml`
|
|
- 필요 시 `ListComment` 대응 View/layout
|
|
- Figma 기준:
|
|
- `296:14895`의 `ListComment`
|
|
- 작업:
|
|
- `fanTalk.latestFanTalk`가 null이고 `totalCount`도 0이면 섹션을 표시하지 않는다.
|
|
- `전체` label과 total count를 표시한다.
|
|
- 최신 팬Talk의 프로필 28dp 원형 이미지, 댓글 본문 2줄 말줄임, chevron-down 아이콘을 표시한다.
|
|
- 검증 기준:
|
|
- 팬Talk는 `addCommentCard`가 아니라 `ListComment` 대응 View/layout으로 렌더링된다.
|
|
|
|
- [ ] **Task 5R.10: 소개 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_introduce.xml`
|
|
- Figma 기준:
|
|
- `296:14895`의 소개 본문 텍스트 영역
|
|
- `SectionTitle(hasRightIcon=false)`
|
|
- 작업:
|
|
- `introduce`가 blank이면 섹션을 표시하지 않는다.
|
|
- 소개 본문은 카드 배경 없이 16sp regular, white, 362dp 폭 기준으로 표시한다.
|
|
- 검증 기준:
|
|
- 소개 섹션은 `addTextCard` 같은 어두운 카드 배경을 사용하지 않는다.
|
|
|
|
- [ ] **Task 5R.11: 활동 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_activity.xml`
|
|
- Figma 기준:
|
|
- `296:14895`의 활동 label/value row 목록
|
|
- `SectionTitle(hasRightIcon=false)`
|
|
- 작업:
|
|
- 배경 카드 없이 label/value row를 세로로 나열한다.
|
|
- 데뷔, 라이브 총 진행 수, 라이브 누적 진행 시간, 라이브 누적 참여자, 오디오, 시리즈를 표시한다.
|
|
- Figma에는 화보 row가 있으나 현재 API 응답에 화보 count가 없으므로 이번 범위에서는 표시하지 않는다.
|
|
- 검증 기준:
|
|
- 활동 row는 `bg_round_corner_16_7_222222` 같은 row 배경을 사용하지 않는다.
|
|
|
|
- [ ] **Task 5R.12: SNS 섹션 재구성**
|
|
- 수정 예정:
|
|
- `CreatorChannelHomeSectionAdapter.kt`
|
|
- `item_creator_channel_home_sns.xml`
|
|
- 필요 시 `SNS` 대응 View/layout
|
|
- Figma 기준:
|
|
- `296:14895`의 `SNS`
|
|
- 작업:
|
|
- `sns` 매핑 결과가 empty이면 섹션을 표시하지 않는다.
|
|
- SNS 제목은 Figma처럼 18sp bold title 영역을 사용한다.
|
|
- 아이콘 순서는 Instagram, YouTube, X, Kakao Open Chat, Fancimm을 유지한다.
|
|
- 각 아이콘은 52dp 원형 이미지, 16dp gap을 기준으로 표시한다.
|
|
- URL은 기존 안전성 정책처럼 유효한 http/https URL만 사용하고, 열 수 있는 intent만 실행한다.
|
|
- 검증 기준:
|
|
- SNS는 adapter 내부 계산/조립이 아니라 `SNS` 대응 View/layout으로 렌더링된다. 단, 작은 화면 52dp 축소 정책은 기존 요구를 유지할 수 있다.
|
|
|
|
---
|
|
|
|
### Phase 6: sticky tab-bar와 scroll 상태 구현
|
|
|
|
- [ ] **Task 6.1: scroll 상태 계산 RED 테스트 작성**
|
|
- 생성:
|
|
- `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelScrollStateTest.kt`
|
|
- 작업:
|
|
- title-bar와 tab-bar의 실제 거리가 기준 이하이고 프로필 이미지가 절반 이상 사라졌을 때 black 전환이 `true`인지 검증한다.
|
|
- 둘 중 하나라도 만족하지 않으면 black 전환이 `false`인지 검증한다.
|
|
- tab-bar sticky top은 status bar 높이와 title-bar 높이를 합산해 계산되는지 검증한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelScrollStateTest"`
|
|
- 기대 결과:
|
|
- scroll 상태 모델 미구현으로 RED 실패한다.
|
|
|
|
- [ ] **Task 6.2: scroll 상태 계산 모델 구현**
|
|
- 생성:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/model/CreatorChannelScrollState.kt`
|
|
- 작업:
|
|
- `shouldUseBlackTitleBar(titleBarBottom: Int, tabBarTop: Int, profileImageVisibleHeight: Int, profileImageTotalHeight: Int): Boolean`을 추가한다.
|
|
- 실제 거리 조건은 `tabBarTop <= titleBarBottom` 또는 기존 layout에서 측정 가능한 최소 gap 기준으로 구현한다.
|
|
- 프로필 이미지 절반 이상 사라짐은 `profileImageVisibleHeight <= profileImageTotalHeight / 2`로 계산한다.
|
|
- sticky top 계산 helper는 `statusBarHeight + titleBarHeight`를 반환한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelScrollStateTest"`
|
|
- 기대 결과:
|
|
- scroll 상태 테스트가 PASS한다.
|
|
|
|
- [ ] **Task 6.3: Activity scroll listener 연결**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- 작업:
|
|
- system bar inset을 읽어 이미지 영역이 status bar 뒤까지 확장되도록 적용한다.
|
|
- title-bar content에는 status bar inset만큼 top padding 또는 margin을 적용해 터치 영역을 보존한다.
|
|
- scroll listener에서 tab-bar sticky 위치와 title-bar black 배경을 갱신한다.
|
|
- tab-bar가 sticky 된 이후에는 홈 컨텐츠만 계속 스크롤되도록 header/tab translate 또는 parent scroll range를 조정한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 수동 확인:
|
|
- 상단에서 이미지가 status bar 영역까지 표시된다.
|
|
- 스크롤 시 tab-bar가 title-bar 아래에 고정된다.
|
|
- 프로필 이미지가 절반 이상 사라지고 tab-bar가 title-bar에 가까워지면 title-bar가 black으로 전환된다.
|
|
|
|
---
|
|
|
|
### Phase 7: 팔로우/알림 변경과 탭 동작 연결
|
|
|
|
- [ ] **Task 7.1: 팔로우/알림 click 흐름 연결**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModel.kt`
|
|
- 작업:
|
|
- 미팔로우 상태에서 follow icon 클릭 시 `viewModel.follow(follow = true, notify = true)`를 호출한다.
|
|
- 팔로우 중 상태에서 follow/following icon 클릭 시 `CreatorFollowNotifyFragment`를 띄운다.
|
|
- `알림 모두 받기`, `알림 받지 않기`, `언팔로우` 선택은 각각 기존 `follow=true/notify=true`, `follow=true/notify=false`, `follow=false/notify=false` 조합으로 호출한다.
|
|
- 요청 중에는 title-bar follow/bell click을 막는다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 기대 결과:
|
|
- 팔로우/알림 상태 변경 테스트와 컴파일이 PASS한다.
|
|
|
|
- [ ] **Task 7.2: tab-bar 7개 항목 표시와 홈 외 탭 클릭 정책 적용**
|
|
- 수정:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt`
|
|
- `app/src/main/res/layout/activity_creator_channel_home.xml`
|
|
- 생성 후보:
|
|
- `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelTabAdapter.kt`
|
|
- 작업:
|
|
- tab-bar에 `홈`, `라이브`, `오디오`, `시리즈`, `커뮤니티`, `팬Talk`, `후원`을 표시한다.
|
|
- 기본 선택은 `홈`이다.
|
|
- 홈 외 탭 클릭 시 상세 화면을 로드하지 않는다.
|
|
- 홈 외 탭 클릭 정책은 구현 시점에 최소 동작으로 둔다.
|
|
- 선택 상태만 바꾸지 않고 유지하거나,
|
|
- 선택은 가능하되 컨텐츠 전환은 하지 않는 방식 중 기존 tab 컴포넌트 동작과 가장 충돌이 적은 방식을 선택한다.
|
|
- 검증 명령:
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- 수동 확인:
|
|
- 7개 탭이 가로 폭을 초과해도 표시/스크롤이 가능하다.
|
|
- 홈 외 탭을 눌러도 crash가 발생하지 않는다.
|
|
|
|
---
|
|
|
|
### Phase 8: 최종 검증과 문서 기록
|
|
|
|
- [ ] **Task 8.1: 단위 테스트 실행**
|
|
- 실행:
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.common.*"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`
|
|
- `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"`
|
|
- 기대 결과:
|
|
- 신규 공용 타입, 크리에이터 채널 홈, 기존 홈 추천 관련 테스트가 모두 `BUILD SUCCESSFUL`로 통과한다.
|
|
|
|
- [ ] **Task 8.2: 리소스/컴파일/린트 검증**
|
|
- 실행:
|
|
- `./gradlew :app:mergeDebugResources`
|
|
- `./gradlew :app:compileDebugKotlin`
|
|
- `./gradlew :app:ktlintCheck`
|
|
- 기대 결과:
|
|
- 모든 명령이 `BUILD SUCCESSFUL`로 통과한다.
|
|
|
|
- [ ] **Task 8.3: 수동 화면 검증**
|
|
- 확인:
|
|
- 크리에이터 이미지가 OS status bar 영역까지 표시된다.
|
|
- title-bar 좌측 `ic_new_bar_back`, 우측 `ic_new_more`가 표시된다.
|
|
- 팔로우/알림 상태별 아이콘 조합이 PRD와 일치한다.
|
|
- `대화하기`, `DM 보내기` 버튼 표시 조합별 레이아웃이 유지된다.
|
|
- tab-bar가 title-bar 아래에 sticky 되고 title-bar black 전환 기준이 동작한다.
|
|
- 홈 API 응답의 각 section이 홈 탭에 표시된다.
|
|
- 기대 결과:
|
|
- PRD Metrics 항목을 모두 만족한다.
|
|
|
|
- [ ] **Task 8.4: 검증 기록 누적**
|
|
- 수정:
|
|
- `docs/20260611_크리에이터_채널_홈_탭/plan-task.md`
|
|
- `docs/20260611_크리에이터_채널_홈_탭/prd.md`
|
|
- 작업:
|
|
- 실행한 테스트/빌드/린트 명령과 결과를 검증 기록에 누적한다.
|
|
- 실패 후 수정한 명령이 있다면 실패 기록을 삭제하지 않고 후속 성공 기록을 추가한다.
|
|
- 기대 결과:
|
|
- 문서 하단에 구현 후 검증 이력이 남는다.
|
|
|
|
---
|
|
|
|
## Verification Log
|
|
- 2026-06-12: `docs/20260611_크리에이터_채널_홈_탭/prd.md`, `docs/agent-guides/work-plan-docs.md`, `docs/agent-guides/build-test-style.md`, `docs/agent-guides/code-style.md`를 확인해 계획 문서 작성 규칙과 검증 명령 규칙을 확인했다.
|
|
- 2026-06-12: 기존 `HomeRecommendationApi`, `HomeRecommendationModels`, `HomeRecommendationRepository`, `HomeRecommendationViewModel`, `RecommendedActivityType`, `HomeRecommendationMappers`, `HomeRecommendationUiModels`, `AppDI`, `ChatRoomActivity`, `DmChatRoomActivity`를 확인해 신규 크리에이터 채널 홈 구현 계획의 파일 경계와 재사용 지점을 정리했다.
|
|
- 2026-06-12: 이번 단계는 구현 계획/TASK 문서 작성만 수행했으며 구현/빌드/테스트는 실행하지 않았다.
|
|
- 2026-06-12: Figma Design 참조가 필요한 Phase를 점검해 Phase 5, Phase 6, Phase 8은 필수 참조, Phase 1, Phase 4, Phase 7은 부분 참조, Phase 2, Phase 3은 참조 불필요로 계획 문서에 명시했다.
|
|
- 2026-06-12: Phase 1 진행으로 `HomeRecommendationApi`, `HomeRecommendationRepository`, `HomeRecommendationViewModel`을 확인해 기존 v2 홈 네트워크가 Retrofit + RxJava3 `Single<ApiResponse<T>>`와 `Bearer ${SharedPreferenceManager.token}` 패턴을 사용함을 재확인했다.
|
|
- 2026-06-12: `UserRepository.creatorFollow(creatorId, follow, notify, token)`와 `CreatorFollowNotifyFragment`의 알림 전체/없음/언팔로우 callback 구조를 확인해 크리에이터 채널 홈의 팔로우/알림 변경에 기존 API와 bottom sheet를 재사용할 수 있음을 확인했다.
|
|
- 2026-06-12: `ChatRoomActivity`는 `newIntent(context, roomId)` 계약으로 `roomId`가 필요하고, `DmChatRoomActivity.newIntentByCreatorId(context, creatorId)`가 존재함을 확인해 계획서의 AI 채팅/DM 이동 경계를 재확인했다.
|
|
- 2026-06-12: `TalkApi.createChatRoom`, `CreateChatRoomRequest(characterId)`, `CreateChatRoomResponse.chatRoomId`, `CharacterDetailViewModel.createChatRoom(characterId)`를 확인해 `대화하기`는 `characterId` 기반 채팅방 생성 후 `chatRoomId`로 `ChatRoomActivity`에 진입해야 함을 확인했다.
|
|
- 2026-06-12: `AppDI`의 `networkModule`, `repositoryModule`, `viewModelModule` 등록 패턴을 확인해 Phase 3 이후 신규 API/Repository/ViewModel 등록 위치와 형태를 확인했다.
|
|
- 2026-06-12: `prd.md`의 Non-Goals와 Technical Constraints를 확인해 `라이브`, `오디오`, `시리즈`, `커뮤니티`, `팬Talk`, `후원` 탭 상세, 홈 pagination, 신규 팔로우/알림 API, 채팅 내부 동작 변경, 별도 analytics/logging을 Phase 1 기준 제외 범위로 유지했다. Phase 1은 문서 확인/체크 갱신만 수행했으며 구현/빌드/테스트는 실행하지 않았다.
|
|
- 2026-06-12: 사용자 추가 요구사항에 따라 `CreatorChannelCreatorResponse.characterId: Long?`를 PRD/계획에 반영하고, `CharacterDetailViewModel.createChatRoom`과 동일하게 `TalkApi.createChatRoom(CreateChatRoomRequest(characterId))` 호출 후 반환된 `chatRoomId`로 `ChatRoomActivity`에 이동하도록 Phase 3/4/5 작업을 갱신했다. 이번 단계는 문서 수정만 수행했으며 구현/빌드/테스트는 실행하지 않았다.
|
|
|
|
- 2026-06-13: Phase 2 RED 테스트로 `CreatorActivityTypeTest`를 먼저 추가하고 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.common.CreatorActivityTypeTest"`를 실행해 `CreatorActivityType` 미구현으로 실패함을 확인했다.
|
|
- 2026-06-13: `RecommendedActivityType`을 `v2/common/CreatorActivityType`으로 공용화하고 홈 추천 mapper/model/test 참조를 갱신했다. `RecommendedActivityType.kt`는 제거했으며 `rg -n "RecommendedActivityType|toRecommendedActivityTypeLabelRes" app/src/main app/src/test` 결과 남은 참조가 없음을 확인했다.
|
|
- 2026-06-13: Phase 3 RED 테스트로 `CreatorChannelHomeModelsTest`를 추가해 Gson이 `CreatorChannelScheduleResponse.type`을 `CreatorActivityType`으로 파싱하고 nullable 필드를 보존하는지 검증하도록 했다. 초기 실행은 `CreatorChannelHomeResponse`와 `CreatorActivityType` 미구현으로 실패했다.
|
|
- 2026-06-13: `CreatorChannelHomeApi`, `CreatorChannelHomeModels`, `CreatorChannelHomeRepository`를 추가하고 `AppDI`에 `CreatorChannelHomeApi`와 `CreatorChannelHomeRepository`를 등록했다. `CreatorChannelHomeViewModel` 등록은 Phase 4 클래스가 아직 없으므로 컴파일 유지를 위해 보류했다.
|
|
- 2026-06-13: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.common.*"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creatorchannel.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:ktlintCheck`를 실행해 모두 `BUILD SUCCESSFUL`을 확인했다.
|
|
- 2026-06-13: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"`는 88개 중 8개가 `HomeMainFragmentLayoutTest.kt:1410`의 `FileNotFoundException`으로 실패했다. 별도 focused 실행인 `HomeCreatorActivityTypeLabelResTest`와 recent activity route 관련 2개 테스트는 `BUILD SUCCESSFUL`로 통과해 이번 타입 공용화 변경과 직접 관련된 회귀는 없음을 확인했다.
|
|
- 2026-06-13: reviewer gate를 실행해 Phase 2/3 구현 범위, PRD DTO 일치, stale 참조 제거, DI 등록 범위, 검증 증거에 대해 무조건 승인을 받았다.
|
|
- 2026-06-13: `HomeMainFragmentLayoutTest.kt`의 source-path helper가 실제 파일 위치와 다른 `v2/main/HomeMainFragment.kt`를 읽고 있어 `FileNotFoundException`이 발생함을 확인하고, 실제 위치인 `v2/main/home/HomeMainFragment.kt`로 수정했다.
|
|
- 2026-06-13: 백엔드 `CreatorActivityType` 원본 enum이 `LIVE`, `AUDIO`, `COMMUNITY`, `LIVE_REPLAY` 대문자 상수와 동일한 `code`를 사용함을 확인해 Android Gson enum 파싱용 별도 TypeAdapter는 추가하지 않기로 판단했다.
|
|
- 2026-06-13: 사용자 추가 요청에 따라 신규 크리에이터 채널 홈 패키지를 `kr.co.vividnext.sodalive.v2.creatorchannel`에서 `kr.co.vividnext.sodalive.v2.creator.channel`로 변경하고, 계획 본문의 신규 파일 경로와 테스트 필터를 새 패키지명 기준으로 갱신했다.
|
|
- 2026-06-13: `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.common.*" --tests "kr.co.vividnext.sodalive.v2.creator.channel.*" --tests "kr.co.vividnext.sodalive.v2.main.home.*" :app:compileDebugKotlin`를 실행해 `BUILD SUCCESSFUL`을 확인했다.
|
|
- 2026-06-13: 패키지 이동 후 `./gradlew :app:ktlintCheck`를 실행해 `BUILD SUCCESSFUL`을 확인했다.
|
|
- 2026-06-13: 사용자 확인에 따라 백엔드 `CreatorActivityType` 원본 enum이 `LIVE`, `AUDIO`, `COMMUNITY`, `LIVE_REPLAY` 대문자 code를 내려주는 계약임을 Phase 2/3 작업 항목에 명시했다. 이후 코드리뷰에서는 별도 서버 계약 변경 근거가 없는 한 크리에이터 채널 홈 DTO의 `CreatorActivityType` 직접 사용과 Gson enum TypeAdapter 부재를 대소문자 대응 문제로 제기하지 않는다. 이번 단계는 문서 수정만 수행했으며 빌드/테스트는 실행하지 않았다.
|
|
- 2026-06-13: Phase 4 TDD RED로 `CreatorChannelHomeMapperTest`, `CreatorChannelTitleBarStateTest`, `CreatorChannelHomeViewModelTest`를 먼저 추가했다. 각 focused 명령은 `CreatorChannelHomeUiModels`, `CreatorChannelHomeMappers`, `CreatorChannelTitleBarState`, `CreatorChannelHomeViewModel` 미구현 참조로 `compileDebugUnitTestKotlin` 실패함을 확인했다.
|
|
- 2026-06-13: Phase 4 GREEN으로 UI state/tab/header/section/SNS 모델, `CreatorChannelHomeResponse.toUiContent()`, title-bar 상태 모델, `CreatorChannelHomeViewModel`, `AppDI` ViewModel 등록을 최소 구현했다. `ic_bar_bell_colored`는 기존 `drawable-mdpi/ic_bar_bell_colored.png`가 있어 신규 리소스를 추가하지 않았다.
|
|
- 2026-06-13: Phase 4 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelTitleBarStateTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:compileDebugKotlin` 모두 `BUILD SUCCESSFUL`을 확인했다. 병렬 Gradle 실행 중 KSP 캐시 `StreamCorruptedException`이 한 차례 발생해 `./gradlew --stop` 후 순차 재실행했다.
|
|
- 2026-06-13: Phase 4 자체 검증 중 `CreatorChannelHomeViewModelTest`의 `null data` 케이스 assertion이 실제로는 API failure만 검증하고 있음을 확인해 별도 `홈 API null data는 Error와 unknown toast를 emit한다` 테스트를 추가했다. 이후 `./gradlew :app:ktlintCheck`는 unused import와 긴 `whenever(...)` 라인으로 실패했으며, 테스트 파일 import/line wrapping을 수정했다.
|
|
- 2026-06-13: Phase 4 보강 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`를 재실행해 모두 `BUILD SUCCESSFUL`을 확인했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|
|
- 2026-06-13: Phase 4 review-work gate에서 code quality 리뷰어가 `chatRoomIdLiveData`를 일반 `MutableLiveData<Long>`로 두면 화면 재생성/재구독 시 채팅방 이동이 반복될 수 있다고 지적해 FAIL했다. 기존 `DmChatEvent<T>.consume()` 패턴을 참고해 `CreatorChannelEvent<T>` 소비형 이벤트로 변경하고, `chatRoomIdLiveData` 테스트에서 첫 번째 `consume()`은 `chatRoomId`, 두 번째 `consume()`은 `null`임을 검증하도록 보강했다.
|
|
- 2026-06-13: 소비형 이벤트 수정 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`를 재실행해 모두 `BUILD SUCCESSFUL`을 확인했다.
|
|
- 2026-06-13: 추가 코드리뷰에서 팔로우/채팅방 생성 액션 실패도 `showUnknownError()`를 통해 홈 상태를 `Error`로 덮어 기존 Content가 사라질 수 있다는 P1 지적을 받았다. `팔로우 실패는 현재 content를 유지하고 unknown toast만 emit한다`, `채팅방 생성 실패는 현재 content를 유지하고 unknown toast만 emit한다` 테스트를 먼저 추가했고, 기존 구현에서 `ClassCastException`으로 실패하는 RED를 확인했다.
|
|
- 2026-06-13: 홈 로드 실패는 기존처럼 `CreatorChannelHomeUiState.Error`를 유지하되, 팔로우/채팅방 생성 액션 실패는 `showUnknownErrorToast()`만 호출하도록 분리했다. 수정 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"`를 실행해 `BUILD SUCCESSFUL`을 확인했다.
|
|
|
|
- 2026-06-13: Phase 5 사용자 추가 요구사항에 맞춰 `CreatorChannelTab`을 문자열 label 대신 `labelResId: Int`로 변경하고 `values`, `values-en`, `values-ja`에 7개 탭 및 Phase 5 버튼/섹션 문자열을 추가했다. Production 변경 전 RED로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest"`를 실행해 `creator_channel_tab_*`/`labelResId` 미구현 컴파일 실패를 확인했다.
|
|
- 2026-06-13: Phase 5 구현으로 `activity_creator_channel_home.xml`, `CreatorChannelHomeActivity`, `CreatorChannelHomeSectionAdapter`, 12개 `item_creator_channel_home_*` layout, header gradient/button drawable, Manifest 등록, `CreatorChannelHomeActivitySourceTest`를 추가했다. `TextTabBarView`는 사용하지 않고 `HorizontalScrollView` + 동적 `TextView`로 7개 긴 탭을 가로 스크롤 가능하게 구성했다. Phase 6 sticky scroll/title black 전환과 Phase 7 `CreatorFollowNotifyFragment` bottom sheet는 구현하지 않았다.
|
|
- 2026-06-13: Phase 5 검증 중 병렬 Gradle 실행에서 KSP incremental cache 충돌(`kspCaches/debug/...`)이 발생했으나 순차 실행으로 전환해 `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"` 모두 `BUILD SUCCESSFUL`을 확인했다. 이후 `./gradlew :app:ktlintCheck`는 `CreatorChannelHomeSectionAdapter.kt`의 130자 초과 한 줄로 실패했고, 줄바꿈 수정 후 `./gradlew :app:ktlintCheck`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest" --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`가 모두 `BUILD SUCCESSFUL`로 통과했다. `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|
|
- 2026-06-13: Phase 5 수동 표면 검증으로 `./gradlew :app:assembleDebug` 후 연결 기기(`adb devices`)에 debug APK를 설치했다. `adb shell run-as kr.co.vividnext.sodalive.debug am start --user 0 -n kr.co.vividnext.sodalive.debug/kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivity --el extra_creator_id 0` 및 `--el extra_creator_id 100` 실행을 시도했고 `AndroidRuntime:E` crash 로그는 없었다. 다만 Activity가 `exported=false`이고 shell/background start 제한이 있어 실제 전면 화면 상호작용은 제한적으로만 확인했다.
|
|
- 2026-06-13: Phase 5 자체 검토 중 `대화하기`가 숨겨지고 `DM 보내기`만 표시될 때 XML의 `layout_marginStart`가 남아 단독 버튼 중앙 정렬이 틀어질 수 있음을 확인했다. `CreatorChannelHomeActivitySourceTest`에 `updateActionButtonLayout`과 `marginStart = if (isChatVisible && isDmVisible)` 계약을 먼저 추가했고, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`가 해당 assertion에서 실패하는 RED를 확인했다. 이후 Activity에서 버튼 표시 조합별 margin을 조정하도록 수정하고 같은 명령을 재실행해 `BUILD SUCCESSFUL`을 확인했다.
|
|
- 2026-06-13: Phase 5 보강 후 `./gradlew :app:mergeDebugResources`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`를 실행해 모두 `BUILD SUCCESSFUL`을 확인했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|
|
- 2026-06-13: Phase 5 review-work gate에서 code quality 리뷰어가 `CreatorChannelHomeSectionAdapter`의 활동 요약 문자열(`Live`, `Audio`, `Series`) 하드코딩으로 다국어 일관성이 깨진다고 FAIL했고, context mining 리뷰어가 PRD/Figma에 명시된 `대화하기`/`DM 보내기` 버튼 아이콘(`ic_new_talk`, `ic_new_dm`) 누락으로 FAIL했다.
|
|
- 2026-06-13: 차단 이슈 수정 전 RED로 `CreatorChannelHomeActivitySourceTest`에 `android:drawableStart="@drawable/ic_new_talk"`, `android:drawableStart="@drawable/ic_new_dm"`, `creator_channel_activity_summary` resource format 사용, `"Live `, `"Audio `, `"Series ` 하드코딩 부재 assertion을 추가했고, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`가 2개 assertion 실패로 `BUILD FAILED`임을 확인했다.
|
|
- 2026-06-13: `ic_new_talk`, `ic_new_dm` vector drawable을 추가하고 버튼 XML에 `drawableStart`를 연결했다. 활동 요약은 `creator_channel_activity_summary`를 `values`, `values-en`, `values-ja`에 추가하고 `CreatorChannelHomeSectionAdapter`에서 `context.getString(...)`으로 표시하도록 수정했다. 이후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.home.*"`, `git diff --check`를 실행해 모두 성공 또는 출력 없음(`git diff --check`)을 확인했다.
|
|
- 2026-06-13: Phase 5 코드 리뷰에서 확인된 `화보` 탭은 사용자 결정에 따라 이번 범위 제외로 확정했으므로 결함으로 보지 않았다. 나머지 3개 Finding에 대해 RED로 `CreatorChannelHomeActivitySourceTest`에 홈 API Error 상태의 Activity toast 중복 호출 금지, status bar 뒤 header 렌더링을 위한 `BaseActivity.shouldApplySystemBarTopInset` hook 및 화면 자체 title inset 처리, Figma 기준 tab selected indicator/16sp/110dp 폭 계약 assertion을 추가했다. 기존 구현에서 해당 테스트가 3개 assertion 실패로 `BUILD FAILED`임을 확인했다.
|
|
- 2026-06-13: `BaseActivity`에 `shouldApplySystemBarTopInset` hook을 추가하고 `CreatorChannelHomeActivity`에서 false로 override해 header는 status bar 뒤까지 그리고 title-bar만 system bar top inset을 반영하도록 수정했다. 홈 로드 Error 상태는 ViewModel의 unknown toast만 사용하도록 Activity의 `showToast(state.message.orEmpty())` 호출을 제거했다. tab은 110dp 폭 `LinearLayout` 안에 16sp `TextView`와 `soda_400` 3dp selected indicator를 구성하도록 변경했다.
|
|
- 2026-06-13: Phase 5 코드 리뷰 수정 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`를 실행했다. 모두 `BUILD SUCCESSFUL` 또는 출력 없음(`git diff --check`)을 확인했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|
|
- 2026-06-13: Phase 5 추가 코드 리뷰 지적 3건(title-bar follow 상태 capsule 불일치, 홈 section item UI 공통 카드 축약, 활동 DTO 주요 필드 미노출)에 대해 Figma `296:14287`, `296:14288`, `296:14289`, `296:14890`을 재확인했다. RED로 `CreatorChannelHomeActivitySourceTest`에 title-bar capsule 구조와 section별 데이터 보존 assertion을 추가했고, 기존 구현에서 `title bar source는 Figma 상태별 capsule 구조를 사용한다`, `section adapter source는 Figma 섹션별 데이터를 공통 카드 하나로 축약하지 않는다` 2개 테스트가 실패해 `BUILD FAILED`임을 확인했다.
|
|
- 2026-06-13: title-bar는 `layout_follow_capsule` 안에 follow icon/text를 넣고, 팔로우 상태에서는 흰색 원형 capsule 배경과 icon-only 형태로 전환하도록 `bg_creator_channel_follow_capsule`, `bg_creator_channel_following_capsule`, `CreatorChannelHomeActivity.bindTitleBar()`를 수정했다. 홈 section adapter는 section별 `bind*` 함수로 분리하고 오디오/시리즈/커뮤니티/팬Talk/SNS list 데이터를 줄 단위로 보존했으며, 활동 section은 `debutDateUtc`, `liveCount`, `liveDurationHours`, `liveContributorCount`, `audioContentCount`, `seriesCount`를 모두 다국어 resource format으로 표시하도록 수정했다.
|
|
- 2026-06-13: Phase 5 추가 코드 리뷰 수정 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`를 재실행해 `BUILD SUCCESSFUL`을 확인했다. 첫 GREEN 시도는 120초 timeout으로 중단됐으나 컴파일 오류 없이 진행 중이었고, timeout을 300초로 늘린 재실행이 성공했다. 이어서 `./gradlew :app:mergeDebugResources`, `git diff --check`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`를 실행해 모두 `BUILD SUCCESSFUL` 또는 출력 없음(`git diff --check`)을 확인했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|
|
- 2026-06-13: 추가 reviewer gate에서 security/QA/code quality는 PASS했으나 goal/context 리뷰가 홈 section layout이 여전히 `72dp thumbnail + tv_primary/tv_secondary` 공통 카드에 가깝고, list 데이터를 한 `TextView`에 줄바꿈으로 합쳐 Figma `296:14890`의 반복 카드/활동 행/SNS 아이콘 구조를 충분히 만족하지 못한다고 FAIL했다.
|
|
- 2026-06-13: reviewer FAIL 수정으로 12개 `item_creator_channel_home_*` layout에 `ll_section_items` 동적 컨테이너를 추가하고, `CreatorChannelHomeSectionAdapter`가 기존 단일 공통 카드 영역을 숨긴 뒤 section별로 여러 child card/row를 생성하도록 변경했다. 오디오/시리즈/커뮤니티/후원/공지/일정/팬Talk는 항목마다 개별 card를 추가하고, SNS는 52dp 버튼 row를 추가하며, 활동은 `dDay`/데뷔일 및 라이브 총 진행 수/누적 시간/누적 참여자/오디오 수/시리즈 수를 행 단위로 표시한다.
|
|
- 2026-06-13: 동적 section row 보강 검증으로 `CreatorChannelHomeActivitySourceTest`에 `ll_section_items`, `sectionItems.addView`, `addActivityRow`, `createSnsButton`, 줄바꿈 `joinToString(separator = "\\n")` 금지 assertion을 추가했다. 첫 실행은 기존 활동 요약 source assertion이 새 행 단위 구조와 충돌해 `BUILD FAILED`였고, 테스트를 활동 지표 label resource 계약으로 갱신한 뒤 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:mergeDebugResources`, `git diff --check`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:assembleDebug`, `./gradlew :app:ktlintCheck`가 모두 `BUILD SUCCESSFUL` 또는 출력 없음(`git diff --check`)임을 확인했다. `ktlintCheck`는 줄바꿈/indentation 2차례 실패 후 해당 라인만 수정해 최종 통과했다.
|
|
- 2026-06-13: 후속 reviewer gate에서 context/code quality는 PASS했으나 goal 리뷰가 `addCard()`가 대부분 섹션을 동일한 72dp 썸네일 가로 카드로 렌더링해 Figma `296:14890`의 섹션별 카드/피드/콘텐츠 그리드 구조와 아직 다르다고 FAIL했다.
|
|
- 2026-06-13: 두 번째 reviewer FAIL 수정으로 `CreatorChannelHomeSectionAdapter`의 공통 `addCard()`를 제거하고 섹션별 helper로 분리했다. 현재 라이브는 `addHeroCard`, 오디오/시리즈는 `createContentTile` 기반 가로 콘텐츠 타일, 커뮤니티는 `addFeedCard`, 일정은 `addScheduleRow`, 후원은 `addDonationCard`, 팬Talk는 `addCommentCard`, SNS는 `createSnsButton`, 활동은 `addActivityRow`를 사용해 섹션별 구조가 같은 72dp 카드 하나로 수렴하지 않도록 했다. `CreatorChannelHomeActivitySourceTest`도 `addHeroCard`, `createContentTile`, `addFeedCard`, `addScheduleRow`, `addDonationCard`, `addCommentCard` 존재와 `private fun addCard` 부재를 검증하도록 보강했다.
|
|
- 2026-06-13: 섹션별 helper 분리 후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:mergeDebugResources`, `git diff --check`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:assembleDebug`, `./gradlew :app:ktlintCheck`를 재실행했다. 모두 `BUILD SUCCESSFUL` 또는 출력 없음(`git diff --check`)을 확인했으며, `ktlintCheck`는 series tile 인자 indentation 실패를 수정한 뒤 최종 통과했다.
|
|
- 2026-06-13: 섹션별 helper 분리 후 code quality reviewer가 legacy 공통 카드 잔재(`tv_primary`, `tv_secondary`, `iv_thumbnail`, `legacyCard`, `getChildAt(2)`, `CreatorChannelHomeSection.imageUrl()`)를 차단 이슈로 지적해 FAIL했다. 12개 `item_creator_channel_home_*` layout에서 legacy 공통 카드 영역을 제거하고 `ll_section_items`만 남겼으며, adapter에서 legacy field/helper와 unused `imageUrl()` extension을 제거했다. Source test에는 `getChildAt`, `keepLegacyViewsReferenced`, `fun CreatorChannelHomeSection.imageUrl` 부재와 각 item layout의 legacy id 부재 assertion을 추가했다. 이후 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:mergeDebugResources`, `git diff --check`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `./gradlew :app:assembleDebug`를 실행해 모두 `BUILD SUCCESSFUL` 또는 출력 없음(`git diff --check`)을 확인했다.
|
|
- 2026-06-13: Phase 5 코드 리뷰 Findings 4건(시리즈 가로 row clipping, SNS URL 미사용, schedule type 서버 code 노출, 어두운 header 위 status bar icon 가독성)에 대해 RED로 `CreatorChannelHomeActivitySourceTest`에 source 계약 assertion을 추가했다. 기존 구현에서 `section adapter source는 가로 시리즈와 SNS 링크와 일정 타입 label을 보존한다`, `creator channel home은 어두운 header 위 status bar icon을 밝게 표시한다` 2개 테스트가 실패해 `BUILD FAILED`임을 확인했다.
|
|
- 2026-06-13: Phase 5 코드 리뷰 Findings 수정으로 `CreatorChannelHomeActivity`에서 `WindowCompat.getInsetsController(window, binding.root).isAppearanceLightStatusBars = false`를 설정하고, `CreatorChannelHomeSectionAdapter`에서 시리즈 row를 `HorizontalScrollView`로 감싸며 SNS 버튼이 `Intent(Intent.ACTION_VIEW, Uri.parse(url))`을 실행하도록 변경했다. 일정 row는 `schedule.type.code` 대신 `schedule.type.labelResId`를 `getString()`으로 표시하도록 수정했다.
|
|
- 2026-06-13: Phase 5 코드 리뷰 Findings 수정 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:mergeDebugResources`, `git diff --check`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`를 실행해 모두 `BUILD SUCCESSFUL` 또는 출력 없음(`git diff --check`)을 확인했다. `ktlintCheck`는 `CreatorChannelHomeSectionAdapter.kt` indentation 1건으로 한 차례 실패했고 해당 라인만 수정한 뒤 재실행해 통과했다. `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|
|
- 2026-06-13: Phase 5 추가 리뷰 반영으로 SNS 버튼 크기를 고정 52dp가 아니라 `calculateCreatorChannelSnsButtonSizeDp(screenWidthDp)`로 계산하도록 변경했다. 402dp 이상은 52dp, 402dp 미만은 `52 * width / 402` 비율로 축소한다. `CreatorChannelHomeViewModel.toastLiveData`는 화면 재생성 시 중복 toast가 표시되지 않도록 `CreatorChannelEvent<ToastMessage>`로 변경했고 Activity에서 `event.consume()` 후 표시하도록 수정했다. RED로 `CreatorChannelHomeActivitySourceTest`와 `CreatorChannelHomeViewModelTest`를 실행해 새 계산 함수 및 toast event 소비 계약 미구현 컴파일 실패를 확인했고, 구현 후 두 테스트 모두 `BUILD SUCCESSFUL`을 확인했다.
|
|
- 2026-06-13: Phase 5 추가 리뷰 반영 최종 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`를 실행해 모두 `BUILD SUCCESSFUL` 또는 출력 없음(`git diff --check`)을 확인했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|
|
- 2026-06-13: Phase 5 코드 리뷰 Finding 1/2와 사용자 SNS 아이콘 정책 반영을 위해 RED로 `CreatorChannelHomeActivitySourceTest`에 활동 섹션 단위 format, 오디오 단일 가로 스크롤 row, `ic_sns_` drawable 기반 `ImageView` SNS 버튼 계약을 추가했다. 기존 구현에서 4개 assertion이 실패해 `BUILD FAILED`임을 확인했다.
|
|
- 2026-06-13: Phase 5 코드 리뷰 Finding 1/2와 SNS 아이콘 정책 수정으로 활동 섹션에 `데뷔` label 및 단위 포함 value format resource를 추가하고, 오디오 콘텐츠 섹션을 단일 `HorizontalScrollView` row로 변경했다. SNS는 `CreatorChannelSnsUiItem.iconResId`를 추가해 `ic_sns_instagram`, `ic_sns_youtube`, `ic_sns_x`, `ic_sns_kakao`, `ic_sns_fancimm` 아이콘을 `ImageView`로 표시하도록 변경했다.
|
|
- 2026-06-13: Phase 5 코드 리뷰 Finding 1/2와 SNS 아이콘 정책 수정 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:mergeDebugResources`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`를 실행했다. 모두 `BUILD SUCCESSFUL` 또는 출력 없음(`git diff --check`)을 확인했다. 첫 테스트 실행은 sandbox의 `~/.gradle` lock 파일 접근 제한으로 실패해 승인 후 재실행했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|
|
- 2026-06-14: Phase 5 SNS 후속 리뷰 반영을 위해 RED로 `CreatorChannelHomeMapperTest`에 Figma 순서(`Instagram`, `YouTube`, `X`, `Kakao Open Chat`, `Fancimm`)와 invalid URL 제외 assertion을 추가하고, `CreatorChannelHomeActivitySourceTest`에 SNS intent `resolveActivity()` 확인 및 마지막 아이콘 trailing `marginEnd` 제거 assertion을 추가했다. 기존 구현에서 `CreatorChannelHomeActivitySourceTest`는 URL 안전 실행/마지막 margin 2개 assertion 실패로 `BUILD FAILED`임을 확인했다. 매퍼 테스트는 Android 런타임 의존 없는 검증을 유지하기 위해 `java.net.URI` 기반 URL helper 계약으로 정리했다.
|
|
- 2026-06-14: Phase 5 SNS 후속 리뷰 수정으로 `CreatorChannelHomeMappers`에서 SNS 순서를 Figma 기준으로 변경하고, `isValidCreatorChannelSnsUrl()`로 `http`/`https` scheme과 host가 있는 URL만 UI item으로 매핑하도록 했다. `CreatorChannelHomeSectionAdapter`는 SNS 클릭 시 `Intent.ACTION_VIEW` intent를 만든 뒤 `resolveActivity(itemView.context.packageManager)`가 null이 아닐 때만 실행하고, `forEachIndexed`로 마지막 SNS 아이콘의 `marginEnd`를 0으로 조정했다.
|
|
- 2026-06-14: Phase 5 SNS 후속 리뷰 검증으로 `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeMapperTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeActivitySourceTest"`, `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.creator.channel.*"`, `./gradlew :app:compileDebugKotlin`, `./gradlew :app:ktlintCheck`, `git diff --check`를 실행했다. 모두 `BUILD SUCCESSFUL` 또는 출력 없음(`git diff --check`)을 확인했다. 첫 RED 테스트 시도는 sandbox의 `~/.gradle` lock 파일 접근 제한으로 실패해 승인 후 재실행했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|
|
- 2026-06-15: 사용자 요청에 따라 탭 바 아래 홈 컨텐츠를 전부 삭제 후 Figma `296:14895`의 `SectionTitle`, `Contents`, `Feed`, `ListComment`, `SNS` 컴포넌트 기준으로 다시 구성하는 Phase 5R을 추가했다. 각 홈 섹션을 하나의 Task로 분리했고, 현재 API 응답에 없는 `화보` 섹션은 이번 재구성 구현 범위에서 제외한다고 명시했다. 이번 단계는 문서 수정만 수행했으며 구현/빌드/테스트는 실행하지 않았다.
|
|
- 2026-06-15: Phase 5R.4 공지 섹션 재구성으로 Figma `296:14915` 기준 `SectionTitle`, `ic_pin` Notice label, 프로필/작성자/날짜, 본문, 선택 썸네일을 가진 공지 전용 가로 feed card를 추가했다. 공지는 최대 3개까지 표시하고, item width는 402dp 기준 최대 346dp 및 작은 화면 비율 축소로 계산한다. RED로 공지 row/custom thumbnail 부재와 기존 374dp width 계산 실패를 확인한 뒤 구현했으며, `CreatorChannelHomeActivitySourceTest` 공지 단일 테스트 2개, `kr.co.vividnext.sodalive.v2.creator.channel.*`, `:app:mergeDebugResources`, `:app:compileDebugKotlin`, `:app:ktlintCheck`, `git diff --check`가 모두 PASS했다. `ktlintCheck`의 `.editorconfig disabled_rules` deprecation 경고는 기존 설정 경고로 이번 변경과 무관하다.
|