368 lines
23 KiB
Markdown
368 lines
23 KiB
Markdown
# 메인 페이지 하단 내비게이션 신규 개발
|
|
|
|
## 작업 목표
|
|
- 메인 페이지를 `홈`, `콘텐츠`, `채팅`, `마이` 4개 하단 내비게이션 탭 구조로 구성한다.
|
|
- 기존 `MainActivity`에 신규 구조를 덧씌우지 않고 `kr.co.vividnext.sodalive.v2` 하위 신규 메인 Activity를 개발한다.
|
|
- 하단 내비게이션은 Material `BottomNavigationView`를 사용한다.
|
|
- `마이` 탭은 기존 `MyPageFragment`를 재사용한다.
|
|
- `홈`, `콘텐츠`, `채팅` 탭은 신규 빈 Fragment를 만들어 표시한다.
|
|
- 초기 문서 작성 완료 후, 사용자 승인에 따라 계획 문서 기준으로 앱 소스 구현까지 진행한다.
|
|
|
|
## 근거 문서
|
|
- PRD: `docs/prd/20260519_메인페이지하단내비게이션신규개발_prd.md`
|
|
- 문서 규칙: `docs/agent-guides/workflow-docs-commits.md`
|
|
- 빌드/테스트 규칙: `docs/agent-guides/build-test-style.md`
|
|
|
|
## 현재 구조 요약
|
|
- 기존 `MainActivity`는 `activity_main.xml`의 `FrameLayout#fl_container`에 탭별 Fragment를 표시한다.
|
|
- 기존 탭 전환은 `supportFragmentManager`의 `add`/`hide`/`show`/`commitNow()` 패턴을 사용한다.
|
|
- 기존 하단 탭 UI는 `activity_main.xml`의 `LinearLayout#ll_tab`과 `item_main_tab.xml` include 구조로 구성되어 있다.
|
|
- 기존 `MainViewModel.CurrentTab`은 `HOME`, `LIVE`, `MY`, `CHAT`을 가진다.
|
|
- 신규 구조는 기존 `MainActivity`를 직접 개편하지 않고 별도 v2 메인 Activity로 분리한다.
|
|
- 신규 요구 탭 순서는 `HOME`, `CONTENT`, `CHAT`, `MY`이다.
|
|
|
|
## 구현 계획
|
|
|
|
### Task 1: 신규 메인 Activity 골격 추가
|
|
|
|
**Files:**
|
|
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt`
|
|
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2ViewModel.kt`
|
|
- Create: `app/src/main/res/layout/activity_main_v2.xml`
|
|
- Modify: `app/src/main/AndroidManifest.xml`
|
|
- Reference: `app/src/main/java/kr/co/vividnext/sodalive/splash/SplashActivity.kt`
|
|
- Reference: `app/src/main/java/kr/co/vividnext/sodalive/user/login/LoginActivity.kt`
|
|
- Reference: `app/src/main/java/kr/co/vividnext/sodalive/user/signup/SignUpActivity.kt`
|
|
- Reference: `app/src/main/java/kr/co/vividnext/sodalive/main/DeepLinkActivity.kt`
|
|
- Reference: `app/src/main/java/kr/co/vividnext/sodalive/audio_content/player/AudioContentPlayerService.kt`
|
|
|
|
- [x] **Step 1: 기존 MainActivity 책임 확인**
|
|
|
|
Run: `rg -n "class MainActivity|checkPermissions|showLoginActivity|getEventPopup|initAndVisibleMiniPlayer|executeDeeplink|setupBottomTabLayout|changeFragment" app/src/main/java/kr/co/vividnext/sodalive/main/MainActivity.kt`
|
|
|
|
Expected: 기존 인증, 이벤트 팝업, 미니 플레이어, 딥링크, 탭 전환 관련 메서드가 조회된다.
|
|
|
|
- [x] **Step 2: 신규 v2 Activity와 ViewModel 작성**
|
|
|
|
`MainV2Activity`와 `MainV2ViewModel`은 `kr.co.vividnext.sodalive.v2.main` 패키지 하위에 작성한다. 기존 `MainActivity` 파일은 수정 대상으로 삼지 않는다.
|
|
|
|
- [x] **Step 3: 신규 Activity 레이아웃 작성**
|
|
|
|
`activity_main_v2.xml`은 Fragment 컨테이너, 미니 플레이어 영역, `BottomNavigationView`를 분리해 배치한다. 미니 플레이어는 `BottomNavigationView` 위에 위치해야 한다.
|
|
|
|
- [x] **Step 4: AndroidManifest 등록**
|
|
|
|
신규 Activity를 `AndroidManifest.xml`에 등록한다. 런처 Activity는 기존처럼 `SplashActivity`를 유지한다.
|
|
|
|
- [x] **Step 5: MainActivity 진입점 전환 대상 확인**
|
|
|
|
Run: `rg -n "MainActivity::class|kr\.co\.vividnext\.sodalive\.main\.MainActivity" app/src/main/java app/src/main/AndroidManifest.xml`
|
|
|
|
Expected: `SplashActivity`, 로그인/회원가입 완료, 딥링크, 플레이어 서비스 알림 등 기존 `MainActivity` 진입점이 조회된다. 구현 시 신규 메인으로 전환할 대상과 레거시 유지 대상을 이 목록에서 명시적으로 분류한다.
|
|
|
|
### Task 2: 탭 상태와 라벨 정의 정리
|
|
|
|
**Files:**
|
|
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Tab.kt`
|
|
- Modify: `app/src/main/res/values/strings.xml`
|
|
|
|
- [x] **Step 1: 신규 탭 enum 정의**
|
|
|
|
`MainV2Tab`은 신규 메인 탭 기준으로 `HOME`, `CONTENT`, `CHAT`, `MY`를 가진다.
|
|
|
|
- [x] **Step 2: 기존 MainViewModel 탭 enum은 수정하지 않음 확인**
|
|
|
|
Run: `rg -n "enum class CurrentTab" app/src/main/java/kr/co/vividnext/sodalive/main/MainViewModel.kt`
|
|
|
|
Expected: 기존 `MainViewModel.CurrentTab`은 레거시 메인 화면용으로 유지한다.
|
|
|
|
- [x] **Step 3: 콘텐츠 탭 문자열 추가**
|
|
|
|
`strings.xml`의 Main/Home 문자열 영역에 `tab_content`를 추가한다.
|
|
|
|
```xml
|
|
<string name="tab_content">콘텐츠</string>
|
|
```
|
|
|
|
- [x] **Step 4: 문자열 리소스 확인**
|
|
|
|
Run: `rg -n 'name="tab_(home|content|chat|my)"' app/src/main/res/values/strings.xml`
|
|
|
|
Expected: `tab_home`, `tab_content`, `tab_chat`, `tab_my`가 모두 조회된다.
|
|
|
|
### Task 3: 신규 빈 페이지 Fragment 추가
|
|
|
|
**Files:**
|
|
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/HomeMainFragment.kt`
|
|
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/ContentMainFragment.kt`
|
|
- Create: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/ChatMainFragment.kt`
|
|
- Create: `app/src/main/res/layout/fragment_v2_main_home.xml`
|
|
- Create: `app/src/main/res/layout/fragment_v2_main_content.xml`
|
|
- Create: `app/src/main/res/layout/fragment_v2_main_chat.xml`
|
|
|
|
- [x] **Step 1: 신규 패키지 위치 생성**
|
|
|
|
신규 Fragment는 저장소 규칙에 따라 `kr.co.vividnext.sodalive.v2.main` 패키지 하위에 둔다.
|
|
|
|
- [x] **Step 2: 홈 빈 Fragment 작성**
|
|
|
|
`HomeMainFragment`는 `BaseFragment`와 ViewBinding 패턴을 사용하고, 별도 로직 없이 빈 홈 페이지 레이아웃을 표시한다.
|
|
|
|
- [x] **Step 3: 콘텐츠 빈 Fragment 작성**
|
|
|
|
`ContentMainFragment`는 `BaseFragment`와 ViewBinding 패턴을 사용하고, 별도 로직 없이 빈 콘텐츠 페이지 레이아웃을 표시한다.
|
|
|
|
- [x] **Step 4: 채팅 빈 Fragment 작성**
|
|
|
|
`ChatMainFragment`는 `BaseFragment`와 ViewBinding 패턴을 사용하고, 별도 로직 없이 빈 채팅 페이지 레이아웃을 표시한다.
|
|
|
|
- [x] **Step 5: 빈 페이지 레이아웃 작성**
|
|
|
|
각 XML 레이아웃은 `match_parent` 크기의 최소 루트 뷰를 사용하고, 네트워크/리스트/상태 UI는 추가하지 않는다.
|
|
|
|
- [x] **Step 6: 신규 Fragment 참조 확인**
|
|
|
|
Run: `rg -n "class (HomeMainFragment|ContentMainFragment|ChatMainFragment)" app/src/main/java/kr/co/vividnext/sodalive/v2/main`
|
|
|
|
Expected: 신규 Fragment 3개가 모두 조회된다.
|
|
|
|
### Task 4: BottomNavigationView와 아이콘 연결
|
|
|
|
**Files:**
|
|
- Modify: `app/src/main/res/layout/activity_main_v2.xml`
|
|
- Create: `app/src/main/res/menu/menu_main_v2_bottom_navigation.xml`
|
|
- Create or Modify: tab icon selector drawable files under `app/src/main/res/drawable/`
|
|
- Create or Modify: bottom navigation text color selector under `app/src/main/res/color/`
|
|
- Reference: existing PNG resources under `app/src/main/res/drawable-mdpi/` and `app/src/main/res/drawable-xxhdpi/`
|
|
- Reference: `app/src/main/res/values/typography.xml`
|
|
|
|
- [x] **Step 1: BottomNavigationView 배치 확인**
|
|
|
|
Run: `rg -n "BottomNavigationView|bottom_navigation" app/src/main/res/layout/activity_main_v2.xml`
|
|
|
|
Expected: 신규 Activity 레이아웃에 `BottomNavigationView`가 조회된다.
|
|
|
|
- [x] **Step 2: menu 리소스 작성**
|
|
|
|
`menu_main_v2_bottom_navigation.xml`의 item은 `home`, `content`, `chat`, `my` 순서로 정의한다.
|
|
|
|
- [x] **Step 3: 탭 라벨과 아이콘 연결**
|
|
|
|
각 menu item은 `android:title`과 `android:icon`을 가진다. 접근성을 위해 title을 비워두지 않는다.
|
|
|
|
- [x] **Step 4: 탭 아이콘 selector 구성**
|
|
|
|
선택/미선택 상태 모두 아이콘 tint나 파란 선택 리소스를 사용하지 않고 다음 원본 리소스를 사용한다.
|
|
|
|
| 탭 | 미선택 | 선택 |
|
|
| --- | --- | --- |
|
|
| 홈 | `ic_nav_home` | `ic_nav_home` |
|
|
| 콘텐츠 | `ic_nav_content` | `ic_nav_content` |
|
|
| 채팅 | `ic_nav_chat` | `ic_nav_chat` |
|
|
| 마이 | `ic_nav_my` | `ic_nav_my` |
|
|
|
|
- [x] **Step 5: 아이콘 리소스 존재 확인**
|
|
|
|
Run: `rg --files app/src/main/res | rg 'ic_nav_(home|content|chat|my)(_|\.)|ic_tabbar_my_selected'`
|
|
|
|
Expected: `ic_nav_home`, `ic_nav_content`, `ic_nav_chat`, `ic_nav_my`가 조회된다.
|
|
|
|
- [x] **Step 6: BottomNavigationView 시각 스타일 조정**
|
|
|
|
`activity_main_v2.xml`의 `BottomNavigationView`는 배경 `@color/black`, 아이콘 tint 없음, 라벨 색상 selector, `Typography.Caption3`, item padding 축소를 적용한다.
|
|
|
|
Expected:
|
|
- `app:itemIconTint="@null"`을 유지한다.
|
|
- 미선택 라벨은 `@color/gray_600`, 선택 라벨은 `@color/white`를 사용한다.
|
|
- `app:itemTextAppearanceActive`와 `app:itemTextAppearanceInactive`는 `@style/Typography.Caption3`을 사용한다.
|
|
- 과도한 내부 padding을 줄이기 위해 `app:itemPaddingTop`과 `app:itemPaddingBottom`을 `0dp`로 지정한다.
|
|
|
|
- [x] **Step 7: edge-to-edge 하단 inset과 아이콘 색상 원인 수정**
|
|
|
|
`MainV2Activity`는 `BaseActivity`의 루트 bottom system inset padding을 화면 범위에서만 제거한다. 탭 아이콘 selector는 checked 상태에서도 원본 아이콘 리소스를 사용해 `#3BB9F1` 선택 아이콘이 표시되지 않게 한다.
|
|
|
|
Expected:
|
|
- `BaseActivity`는 수정하지 않는다.
|
|
- `MainV2Activity`에서 root bottom padding을 `0`으로 재적용한다.
|
|
- `ic_nav_home_tab`, `ic_nav_content_tab`, `ic_nav_chat_tab`, `ic_nav_my_tab`은 checked/default 모두 원본 아이콘을 사용한다.
|
|
|
|
### Task 5: 신규 MainV2Activity 탭 연결과 Fragment 전환
|
|
|
|
**Files:**
|
|
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt`
|
|
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2ViewModel.kt`
|
|
|
|
- [x] **Step 1: BottomNavigationView 선택 리스너 연결**
|
|
|
|
`BottomNavigationView.setOnItemSelectedListener`에서 선택된 menu item id를 `MainV2Tab`으로 매핑한다.
|
|
|
|
- [x] **Step 2: 탭별 Fragment 매핑 변경**
|
|
|
|
`HOME`은 `HomeMainFragment`, `CONTENT`는 `ContentMainFragment`, `CHAT`은 `ChatMainFragment`, `MY`는 기존 `MyPageFragment`를 반환하도록 매핑한다.
|
|
|
|
- [x] **Step 3: 탭별 back stack 미사용 전환 구현**
|
|
|
|
Fragment 전환은 탭별 back stack을 만들지 않는다. `addToBackStack()`은 사용하지 않는다.
|
|
|
|
- [x] **Step 4: 채팅 배지 확장 지점 확보**
|
|
|
|
이번 구현에서 실제 배지 데이터는 붙이지 않더라도, `chat` menu item id는 향후 `BottomNavigationView.getOrCreateBadge()`로 확장할 수 있도록 안정적인 이름으로 정의한다.
|
|
|
|
### Task 6: 기존 필수 프로세스 선별 이관
|
|
|
|
**Files:**
|
|
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt`
|
|
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2ViewModel.kt`
|
|
|
|
- [x] **Step 1: 권한/인증 흐름 이관**
|
|
|
|
기존 `MainActivity`의 권한 요청과 로그인 진입 흐름을 신규 Activity에 필요한 범위로 이관한다.
|
|
|
|
- [x] **Step 2: 이벤트 팝업 흐름 이관**
|
|
|
|
로그인 상태에서 이벤트 팝업을 조회하고 표시하는 기존 사용자 경험을 신규 Activity에서도 유지한다.
|
|
|
|
- [x] **Step 3: 미니 플레이어 흐름 이관**
|
|
|
|
오디오 플레이어 서비스 상태를 관찰해 미니 플레이어를 표시/해제하는 흐름을 신규 Activity에서도 유지한다.
|
|
|
|
- [x] **Step 4: 딥링크 라우팅 진입점 분리**
|
|
|
|
딥링크 정리 계획을 고려해 신규 Activity 내부에 탭 라우팅 진입점을 분리한다. 상세 딥링크 정책 확장은 별도 작업에서 다룬다.
|
|
|
|
### Task 7: 검증
|
|
|
|
**Files:**
|
|
- Modify: `docs/plan-task/20260519_메인페이지하단내비게이션신규개발.md`
|
|
|
|
- [x] **Step 1: 변경 파일 LSP 진단 실행**
|
|
|
|
Run: `lsp_diagnostics` on changed Kotlin/XML files.
|
|
|
|
Expected: 이번 변경으로 인한 오류가 없다. XML LSP가 환경에 없으면 검증 기록에 남긴다.
|
|
|
|
- [x] **Step 2: 리소스/문자열/Menu 조회 검증**
|
|
|
|
Run: `rg -n 'BottomNavigationView|menu_main_v2_bottom_navigation|tab_content|ic_nav_home|ic_nav_content|ic_nav_chat|ic_nav_my|ic_tabbar_my_selected|MainV2Activity' app/src/main/res app/src/main/java/kr/co/vividnext/sodalive`
|
|
|
|
Expected: 신규 Activity, BottomNavigationView, menu, 신규 탭 문자열과 아이콘 참조가 조회된다.
|
|
|
|
- [x] **Step 3: 디버그 빌드 실행**
|
|
|
|
Run: `./gradlew :app:assembleDebug`
|
|
|
|
Expected: `BUILD SUCCESSFUL`
|
|
|
|
- [x] **Step 4: 검증 기록 누적**
|
|
|
|
이 문서 하단 `검증 기록`에 실행한 명령, 목적, 결과를 한국어로 누적 기록한다.
|
|
|
|
## 체크리스트
|
|
- [x] AC1: 하단 탭이 `홈`, `콘텐츠`, `채팅`, `마이` 순서로 표시된다.
|
|
- [x] AC2: 신규 메인 화면은 기존 `MainActivity`에 덧씌우지 않고 `kr.co.vividnext.sodalive.v2` 하위 신규 Activity로 구성된다.
|
|
- [x] AC3: 하단 내비게이션은 `BottomNavigationView`를 사용한다.
|
|
- [x] AC4: `마이` 탭은 기존 `MyPageFragment`를 표시한다.
|
|
- [x] AC5: `홈`, `콘텐츠`, `채팅` 탭은 신규 빈 Fragment를 표시한다.
|
|
- [x] AC6: 선택/미선택 아이콘은 tint 없이 원본 아이콘 리소스를 사용한다.
|
|
- [x] AC7: checked 상태에서 `#3BB9F1` 선택 아이콘 리소스로 바뀌지 않는다.
|
|
- [x] AC8: 탭별 back stack을 사용하지 않는다.
|
|
- [x] AC9: 인증, 이벤트 팝업, 미니 플레이어 흐름은 신규 Activity에서도 기존 사용자 경험을 유지한다.
|
|
- [x] AC10: `./gradlew :app:assembleDebug`가 성공한다.
|
|
|
|
## 검증 기록
|
|
- 2026-05-19
|
|
- 무엇/왜/어떻게: 구현 전 문서 작성을 위해 기존 메인 탭 구조와 문서 규칙을 조사했다.
|
|
- 실행 명령/도구:
|
|
- `rg --files docs app/src/main | rg '(^docs/|MainActivity|fragment_.*main|activity_.*main|menu|nav|tabbar|ic_nav|ic_tabbar)'`
|
|
- `read(app/src/main/java/kr/co/vividnext/sodalive/main/MainActivity.kt)`
|
|
- `read(app/src/main/java/kr/co/vividnext/sodalive/main/MainViewModel.kt)`
|
|
- `read(app/src/main/res/layout/activity_main.xml)`
|
|
- `read(app/src/main/res/layout/item_main_tab.xml)`
|
|
- `read(docs/agent-guides/workflow-docs-commits.md)`
|
|
- `read(docs/prd/sample-prd.md)`
|
|
- 결과:
|
|
- 현재 메인 화면은 커스텀 하단 탭바와 수동 `FragmentTransaction` 패턴을 사용한다.
|
|
- 현재 탭은 `HOME`, `CHAT`, `LIVE`, `MY` 구성이며 신규 요구는 `HOME`, `CONTENT`, `CHAT`, `MY`이다.
|
|
- 저장소 규칙에 따라 PRD는 `docs/prd/`, 계획/TASK 문서는 `docs/plan-task/`에 작성해야 한다.
|
|
- 사용자 지시에 따라 현재 단계에서는 문서만 작성하고 구현 파일은 변경하지 않는다.
|
|
- 2026-05-19
|
|
- 무엇/왜/어떻게: PRD 검토 중 결정된 `BottomNavigationView` 사용과 신규 v2 메인 Activity 개발 방향을 문서에 반영했다.
|
|
- 실행 명령/도구:
|
|
- `read(docs/prd/20260519_메인페이지하단내비게이션신규개발_prd.md)`
|
|
- `read(docs/plan-task/20260519_메인페이지하단내비게이션신규개발.md)`
|
|
- `rg -n "BottomNavigationView|커스텀|MainActivity|신규|v2|FragmentTransaction|tabbar|탭바" docs/prd/20260519_메인페이지하단내비게이션신규개발_prd.md docs/plan-task/20260519_메인페이지하단내비게이션신규개발.md`
|
|
- 결과:
|
|
- 기존 `MainActivity`에 신규 구조를 덧씌우지 않고 신규 v2 메인 Activity를 개발하는 방향으로 계획을 변경했다.
|
|
- 하단 내비게이션은 커스텀 탭바 대신 Material `BottomNavigationView`를 사용하는 것으로 정리했다.
|
|
- 탭별 back stack은 사용하지 않고, 인증/이벤트 팝업/미니 플레이어 흐름은 신규 Activity에 필요한 범위로 이관하는 것으로 정리했다.
|
|
- 2026-05-19
|
|
- 무엇/왜/어떻게: 계획 문서 기준으로 신규 v2 메인 Activity와 BottomNavigationView 기반 하단 내비게이션을 구현하고 검증했다.
|
|
- 실행 명령/도구:
|
|
- `task(subagent_type="explore", description="v2 메인 패턴 조사")`
|
|
- `task(subagent_type="librarian", description="BottomNavigationView API 조사")`
|
|
- `rg -n "com.google.android.material|viewBinding|koin|BaseActivity|BaseFragment|EventPopupDialogFragment|NotificationSettingsDialog|isPlayerServiceRunningFlow|MediaController|BottomNavigationView|MainActivity::class|class MainActivity|class MainViewModel" app/build.gradle build.gradle settings.gradle app/src/main/java app/src/main/res app/src/main/AndroidManifest.xml`
|
|
- `lsp_diagnostics(app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt)`
|
|
- `lsp_diagnostics(app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2ViewModel.kt)`
|
|
- `lsp_diagnostics(app/src/main/java/kr/co/vividnext/sodalive/mypage/MyPageFragment.kt)`
|
|
- `rg -n "class (HomeMainFragment|ContentMainFragment|ChatMainFragment)|MainV2Activity::class|MainActivity::class|showLoginActivity\(\)|menu_main_v2_|BottomNavigationView|getOrCreateBadge|addToBackStack" app/src/main/java app/src/main/res app/src/main/AndroidManifest.xml`
|
|
- `./gradlew :app:ktlintCheck`
|
|
- `./gradlew :app:assembleDebug`
|
|
- `adb devices`
|
|
- `test -f app/build/outputs/apk/debug/app-debug.apk`
|
|
- 결과:
|
|
- Kotlin LSP는 현재 환경에 설정되어 있지 않아 실행 불가(`No LSP server configured for extension: .kt`)였다.
|
|
- 신규 `MainV2Activity`, `MainV2ViewModel`, `MainV2Tab`, 홈/콘텐츠/채팅 빈 Fragment, `BottomNavigationView` menu/selector 리소스를 추가했다.
|
|
- `SplashActivity`, 로그인/회원가입 완료, `DeepLinkActivity`, 오디오 플레이어 알림 진입점을 `MainV2Activity`로 전환했다.
|
|
- 기존 `MyPageFragment`는 `MainActivity`와 `MainV2Activity` 양쪽 host에서 로그인 진입을 처리하도록 수정했다.
|
|
- `./gradlew :app:ktlintCheck`는 중간 fresh 실행에서 `BUILD SUCCESSFUL`로 완료됐으나, 이후 추가 확인 과정에서 최종 diff에 남지 않는 `LiveReservationCancelActivity`, `LiveRoomActivity`의 기존 ktlint 위반이 다시 보고되어 현재 명령은 실패한다.
|
|
- 최종 ktlint 보고서에서 이번 변경 파일 관련 위반은 조회되지 않았다.
|
|
- `./gradlew :app:assembleDebug`는 fresh 실행 기준 `BUILD SUCCESSFUL`로 완료됐다.
|
|
- `adb devices` 결과 연결된 기기/에뮬레이터가 없어 실제 앱 실행 수동 QA는 수행하지 못했다.
|
|
- 디버그 APK `app/build/outputs/apk/debug/app-debug.apk` 생성은 확인했다.
|
|
- 2026-05-19
|
|
- 무엇/왜/어떻게: 사용자 요청에 따라 `MainV2Activity`의 `BottomNavigationView` 시각 스타일을 조정하고 검증했다.
|
|
- 실행 명령/도구:
|
|
- `task(category="quick", description="BottomNavigation 패턴 조사")`
|
|
- `task(subagent_type="librarian", description="Material nav API 조사")`
|
|
- `rg -n "BottomNavigationView|bottom_navigation|menu_main_v2|itemIconTint|itemTextColor|itemTextAppearance|itemPadding|padding|fitsSystemWindows|WindowInsets|gray600|caption|TextAppearance|colorBlack|black" app/src/main/res app/src/main/java/kr/co/vividnext/sodalive/v2 app/src/main/java/kr/co/vividnext/sodalive/main app/src/main/AndroidManifest.xml`
|
|
- `lsp_diagnostics(app/src/main/res/layout/activity_main_v2.xml)`
|
|
- `rg -n "itemIconTint=\"@null\"|itemPadding(Bottom|Top)=\"0dp\"|itemTextAppearance(Active|Inactive)=\"@style/Typography.Caption3\"|itemTextColor=\"@color/color_main_v2_bottom_navigation_label\"|android:background=\"@color/black\"" app/src/main/res/layout/activity_main_v2.xml`
|
|
- `rg -n "state_checked=\"true\"|state_selected=\"true\"|gray_600|white" app/src/main/res/color/color_main_v2_bottom_navigation_label.xml`
|
|
- `./gradlew :app:assembleDebug`
|
|
- 결과:
|
|
- 과도한 하단 padding의 주요 후보는 `BottomNavigationView` 기본 item padding과 `BaseActivity`의 system bar inset padding 조합으로 확인했다.
|
|
- 전역 inset 처리는 변경하지 않고, `BottomNavigationView`의 item padding을 `0dp`로 줄였다.
|
|
- 하단 내비게이션 배경은 `@color/black`으로 변경했다.
|
|
- 아이콘은 `app:itemIconTint="@null"`을 유지해 원본 색상을 사용하도록 했다.
|
|
- 라벨 색상은 선택 `@color/white`, 미선택 `@color/gray_600` selector로 분리했다.
|
|
- 라벨 typography는 사용자 확정에 따라 active/inactive 모두 `@style/Typography.Caption3`을 적용했다.
|
|
- XML LSP는 현재 환경에 설정되어 있지 않아 실행 불가(`No LSP server configured for extension: .xml`)였다.
|
|
- `./gradlew :app:assembleDebug`는 `BUILD SUCCESSFUL`로 완료됐다.
|
|
- 2026-05-19
|
|
- 무엇/왜/어떻게: `BottomNavigationView` 하단 빈 공간과 아이콘의 `#3BB9F1` 색상 표시 원인을 추적하고 MainV2 범위에서 수정했다.
|
|
- 실행 명령/도구:
|
|
- `task(category="quick", description="Insets 원인 조사")`
|
|
- `task(category="quick", description="Icon tint 원인 조사")`
|
|
- `task(subagent_type="librarian", description="Material inset tint 조사")`
|
|
- `rg -n "setDecorFitsSystemWindows|setOnApplyWindowInsetsListener|WindowInsets|systemBars|ime\)|navigationBarColor|BottomNavigationView|itemIconTint|color_3bb9f1|3BB9F1|ic_nav_.*tab|ic_tabbar_my_selected|itemPadding|fitsSystemWindows|paddingBottom|state_checked|state_selected" app/src/main/java app/src/main/res`
|
|
- `read(app/src/main/java/kr/co/vividnext/sodalive/base/BaseActivity.kt)`
|
|
- `read(app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt)`
|
|
- `read(app/src/main/res/drawable/ic_nav_home_tab.xml)`
|
|
- `read(app/src/main/res/drawable/ic_nav_content_tab.xml)`
|
|
- `read(app/src/main/res/drawable/ic_nav_chat_tab.xml)`
|
|
- `read(app/src/main/res/drawable/ic_nav_my_tab.xml)`
|
|
- `rg -n "overrideRootWindowInsets|setOnApplyWindowInsetsListener|setPadding\(left, top, right, 0\)|requestApplyInsets" app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt`
|
|
- `rg -n "ic_nav_(home|content|chat|my)(_selected)?|ic_tabbar_my_selected|color_3bb9f1|#3BB9F1" app/src/main/res/drawable/ic_nav_home_tab.xml app/src/main/res/drawable/ic_nav_content_tab.xml app/src/main/res/drawable/ic_nav_chat_tab.xml app/src/main/res/drawable/ic_nav_my_tab.xml`
|
|
- `lsp_diagnostics(app/src/main/java/kr/co/vividnext/sodalive/v2/main/MainV2Activity.kt)`
|
|
- `lsp_diagnostics(app/src/main/res/drawable/ic_nav_home_tab.xml)`
|
|
- `./gradlew :app:assembleDebug`
|
|
- `./gradlew :app:ktlintCheck`
|
|
- 결과:
|
|
- 하단 빈 공간의 원인은 `BaseActivity`가 edge-to-edge 상태에서 루트에 `systemBars.bottom` padding을 적용하는 구조로 확인했다.
|
|
- `BaseActivity`는 변경하지 않고 `MainV2Activity`에서 루트 inset listener를 재등록해 bottom padding만 `0`으로 재적용했다.
|
|
- 아이콘의 `#3BB9F1` 표시는 `BottomNavigationView` tint가 아니라 checked 상태 selector가 선택용 아이콘 리소스를 보여주는 구조에서 발생한 것으로 확인했다.
|
|
- `ic_nav_home_tab`, `ic_nav_content_tab`, `ic_nav_chat_tab`, `ic_nav_my_tab`은 checked/default 모두 원본 아이콘 리소스를 사용하도록 변경했다.
|
|
- Kotlin/XML LSP는 현재 환경에 설정되어 있지 않아 실행 불가였다.
|
|
- `./gradlew :app:assembleDebug`는 `BUILD SUCCESSFUL`로 완료됐다.
|
|
- `./gradlew :app:ktlintCheck`는 `BUILD SUCCESSFUL`로 완료됐다.
|