# 타이틀바 및 탭 텍스트바 컴포넌트 ## 작업 목표 - XML 레이아웃 기반 재사용 가능한 Title Bar Component를 개발한다. - XML 레이아웃 기반 재사용 가능한 Tab-Text Bar Component를 개발한다. - 구현 범위는 컴포넌트 추가로 한정하고 기존 화면 일괄 적용은 제외한다. ## 구현 계획 ### Task 1: 기존 리소스 및 유사 UI 확인 **Files:** - Read: `app/src/main/res/layout/toolbar_audio_content_main.xml` - Read: `app/src/main/res/layout/activity_audio_content_main.xml` - Read: `app/src/main/res/layout/activity_can_status.xml` - Read: `app/src/main/res/values/colors.xml` - Read: `app/src/main/res/values/typography.xml` - [x] **Step 1: 기존 타이틀 바 패턴 확인** Run: `rg -n "toolbar|Toolbar|title|Title" app/src/main/res/layout app/src/main/java/kr/co/vividnext/sodalive` Expected: 기존 화면에서 include 또는 개별 toolbar 사용 패턴을 확인한다. - [x] **Step 2: 기존 탭 바 패턴 확인** Run: `rg -n "TabLayout|tabText|ContentMainTabText|color_tabbar" app/src/main/res app/src/main/java/kr/co/vividnext/sodalive` Expected: 기존 TabLayout 및 탭 텍스트 스타일 사용 패턴을 확인한다. - [x] **Step 3: 필수 리소스 확인** Run: `rg -n "img_text_logo_v2|gray_600|Typography\.Heading3| TextTabBarView.kt)` - `apply_patch(app/src/main/java/kr/co/vividnext/sodalive/v2/widget/TabTextSelectionState.kt -> TextTabSelectionState.kt)` - `apply_patch(app/src/test/java/kr/co/vividnext/sodalive/v2/widget/TabTextSelectionStateTest.kt -> TextTabSelectionStateTest.kt)` - `apply_patch(app/src/main/res/layout/view_tab_text_bar.xml -> view_text_tab_bar.xml)` - `apply_patch(app/src/main/res/color/color_tab_text_bar.xml -> color_text_tab_bar.xml)` - 결과: - `TabTextBarView`는 `TextTabBarView`로 변경했다. - `TabTextSelectionState`는 `TextTabSelectionState`로 변경했다. - `TabTextSelectionStateTest`는 `TextTabSelectionStateTest`로 변경했다. - `view_tab_text_bar.xml`은 `view_text_tab_bar.xml`로 변경했다. - `color_tab_text_bar.xml`은 `color_text_tab_bar.xml`로 변경했다. - Text Tab 내부 view id도 `tv_text_tab_first`, `tv_text_tab_second`, `tv_text_tab_third`로 정리했다. - 추가 검증: - Kotlin/XML LSP 서버가 현재 환경에 설정되어 있지 않아 `lsp_diagnostics`는 실행 불가했다. - 병렬 Gradle 실행 중 Kotlin compile 캐시 접근 오류가 한 번 발생해 순차 실행으로 재검증했다. - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.TextTabSelectionStateTest"`는 `BUILD SUCCESSFUL`로 완료됐다. - `./gradlew :app:assembleDebug`는 `BUILD SUCCESSFUL`로 완료됐다. - `./gradlew :app:ktlintCheck`는 `BUILD SUCCESSFUL`로 완료됐다. - `ViewTextTabBarBinding`, `ViewTitleBarDefaultBinding`, `ViewTitleBarHomeBinding` 생성 파일을 확인해 신규 컴포넌트 ViewBinding 생성 가능성을 확인했다. - `git status --short` 기준 기존 화면 Activity/Fragment/Layout 파일은 변경하지 않았다. - 2026-05-19 - 무엇/왜/어떻게: 코드 리뷰 피드백을 검토해 숨김 탭의 selected 상태가 남을 가능성을 제거하고, 이미 선택된 탭 재선택 시 중복 콜백을 발생시키지 않도록 보완했다. - 실행 명령/도구: - `oracle` read-only code review - `apply_patch(app/src/main/java/kr/co/vividnext/sodalive/v2/widget/TextTabBarView.kt)` - 결과: - `TextTabBarView`는 메뉴가 줄어들어 숨겨지는 탭에도 `isSelected = false`를 적용한다. - `TextTabBarView.selectTab()`은 이미 선택된 index를 다시 선택하면 상태와 콜백을 변경하지 않는다. - `view_title_bar_home.xml`은 `@drawable/img_text_logo_v2`를 참조하며, 현재 해당 이미지 파일은 git 기준 untracked 상태이므로 커밋 시 함께 포함해야 한다. - 추가 검증: - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.TextTabSelectionStateTest"`는 `BUILD SUCCESSFUL`로 완료됐다. - `./gradlew :app:assembleDebug`는 `BUILD SUCCESSFUL`로 완료됐다. - `./gradlew :app:ktlintCheck`는 `BUILD SUCCESSFUL`로 완료됐다. - 2026-05-19 - 무엇/왜/어떻게: 추가 요청에 따라 TitleBar 좌우 padding을 20dp로 지정하고, Tab-Text Bar 텍스트를 왼쪽 정렬 및 텍스트 사이 20dp 간격 구조로 변경했다. - 실행 명령/도구: - `read(app/src/main/res/layout/view_title_bar_home.xml)` - `read(app/src/main/res/layout/view_title_bar_default.xml)` - `read(app/src/main/res/layout/view_text_tab_bar.xml)` - `apply_patch(app/src/main/res/layout/view_title_bar_home.xml)` - `apply_patch(app/src/main/res/layout/view_title_bar_default.xml)` - `apply_patch(app/src/main/res/layout/view_text_tab_bar.xml)` - `lsp_diagnostics` on modified XML files - `rg -n "paddingHorizontal=\"20dp\"|gravity=\"start\|center_vertical\"|layout_marginEnd=\"20dp\"|layout_width=\"wrap_content\"" app/src/main/res/layout/view_title_bar_home.xml app/src/main/res/layout/view_title_bar_default.xml app/src/main/res/layout/view_text_tab_bar.xml` - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.TextTabSelectionStateTest"` - `./gradlew :app:assembleDebug` - `./gradlew :app:ktlintCheck` - 결과: - `view_title_bar_home.xml`, `view_title_bar_default.xml` 루트에 `android:paddingHorizontal="20dp"`를 적용했다. - `view_text_tab_bar.xml` 루트 gravity를 `start|center_vertical`로 변경했다. - Tab-Text Bar의 각 TextView는 `wrap_content` 폭을 사용하고, 첫 번째/두 번째 텍스트에 `android:layout_marginEnd="20dp"`를 적용해 텍스트 사이 간격을 20dp로 맞췄다. - XML LSP 서버가 현재 환경에 설정되어 있지 않아 `lsp_diagnostics`는 실행 불가했다. - `TextTabSelectionStateTest`는 `BUILD SUCCESSFUL`로 완료됐다. - `:app:assembleDebug`는 `BUILD SUCCESSFUL`로 완료됐다. - `:app:ktlintCheck`는 `BUILD SUCCESSFUL`로 완료됐다. - 2026-05-19 - 무엇/왜/어떻게: 추가 요청에 따라 이번에 추가한 컴포넌트 XML의 하드코딩 color/spacing/radius 값을 점검하고, 기존 `colors.xml`, `dimens.xml`에 정의된 값으로 변경 가능한 항목을 치환했다. - 실행 명령/도구: - `read(app/src/main/res/layout/view_title_bar_home.xml)` - `read(app/src/main/res/layout/view_title_bar_default.xml)` - `read(app/src/main/res/layout/view_text_tab_bar.xml)` - `read(app/src/main/res/color/color_text_tab_bar.xml)` - `read(app/src/main/res/values/colors.xml)` - `read(app/src/main/res/values/dimens.xml)` - `apply_patch(app/src/main/res/layout/view_title_bar_home.xml)` - `apply_patch(app/src/main/res/layout/view_title_bar_default.xml)` - `apply_patch(app/src/main/res/layout/view_text_tab_bar.xml)` - `rg -n "\b[0-9]+dp\b|#[0-9A-Fa-f]{6,8}" app/src/main/res/layout/view_title_bar_home.xml app/src/main/res/layout/view_title_bar_default.xml app/src/main/res/layout/view_text_tab_bar.xml app/src/main/res/color/color_text_tab_bar.xml` - `./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.widget.TextTabSelectionStateTest"` - `./gradlew :app:assembleDebug` - `./gradlew :app:ktlintCheck` - 결과: - `20dp`로 하드코딩되어 있던 TitleBar horizontal padding, Tab-Text Bar horizontal padding, Tab-Text 간격을 `@dimen/spacing_20`으로 변경했다. - Color 값은 이미 `@color/black`, `@color/white`, `@color/gray_600`, `@color/color_text_tab_bar`를 사용하고 있어 추가 치환할 하드코딩 hex 값은 없었다. - Radius 값은 이번 컴포넌트에 없었다. - 남아 있는 `60dp`, `52dp`는 컴포넌트 고정 높이 요구사항 값이며 현재 `dimens.xml`에 대응 토큰이 없어 변경하지 않았다. - spacer용 `0dp`는 `layout_weight` 사용을 위한 Android 레이아웃 관례 값이므로 리소스로 치환하지 않았다. - `TextTabSelectionStateTest`는 `BUILD SUCCESSFUL`로 완료됐다. - `:app:assembleDebug`는 `BUILD SUCCESSFUL`로 완료됐다. - `:app:ktlintCheck`는 `BUILD SUCCESSFUL`로 완료됐다.