fix(main): 현재 라이브 전체 버튼을 고정한다

This commit is contained in:
Yu Sung
2026-08-04 01:03:24 +09:00
parent f671f4f76c
commit 89c070875c
4 changed files with 215 additions and 7 deletions

View File

@@ -7,16 +7,19 @@ struct MainHomeLiveSection: View {
var body: some View { var body: some View {
if !items.isEmpty { if !items.isEmpty {
HStack(alignment: .top, spacing: SodaSpacing.s12) {
ScrollView(.horizontal, showsIndicators: false) { ScrollView(.horizontal, showsIndicators: false) {
LazyHStack(alignment: .top, spacing: SodaSpacing.s12) { LazyHStack(alignment: .top, spacing: SodaSpacing.s12) {
ForEach(items, id: \.self) { item in ForEach(items, id: \.self) { item in
MainHomeLiveItemView(item: item, onTapLive: onTapLive) MainHomeLiveItemView(item: item, onTapLive: onTapLive)
} }
}
.padding(.leading, SodaSpacing.s20)
}
.frame(maxWidth: .infinity, alignment: .leading)
MainHomeLiveAllItemView(onTapAll: onTapAll) MainHomeLiveAllItemView(onTapAll: onTapAll)
} }
.padding(.horizontal, SodaSpacing.s20)
}
} }
} }
} }

View File

@@ -85,6 +85,46 @@
- `plutil -lint SodaLive.xcodeproj/project.pbxproj` 실행, `OK` - `plutil -lint SodaLive.xcodeproj/project.pbxproj` 실행, `OK`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 실행, `BUILD SUCCEEDED` - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 실행, `BUILD SUCCEEDED`
### 2026-08-03 Phase 8.3 현재 라이브 `전체` 우측 고정
**Goal 실행 `P8-T3`:** 현재 라이브 아이템만 가로로 스크롤하고 `전체` 버튼은 섹션 오른쪽 끝에 고정한다.
- **시작 조건:** PRD 8.5와 2026-08-03 Decision Log 확정.
- **완료 증거:** 정적 RED/GREEN, `SodaLive-dev` 빌드, 여러 아이템 렌더에서 스크롤 전후 `전체` 위치 확인.
- **범위 밖:** API, 모델, ViewModel, 라우팅, `전체` 버튼 스타일 변경.
- **TDD 대체 사유:** 프로젝트에 XCTest 번들 타깃이 없으므로 기존 Preview를 실제 렌더 harness로 사용하고 레이아웃 구조를 정적 RED/GREEN으로 검증한다.
**Files:**
- Modify: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift`
- Verify: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift``MainHomeLiveSection_Previews`
- [x] **RED:** `MainHomeLiveAllItemView``LazyHStack` 내부 마지막 항목으로 포함된 현재 구조를 확인한다.
- [x] **RED 확인:** `rg -n '^ {20}MainHomeLiveAllItemView\\(onTapAll' SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift``LazyHStack` 내부 들여쓰기의 기존 스크롤 종속 구조를 찾는지 확인한다.
- [x] **GREEN:** `HStack`에서 라이브 목록 `ScrollView``MainHomeLiveAllItemView`를 형제 뷰로 분리하고 기존 가장자리 여백을 유지한다.
- [x] **GREEN 확인:** `MainHomeLiveAllItemView``ScrollView` 밖에 한 번만 존재하고 `onTapLive`, `onTapAll`, 빈 배열 guard가 유지되는지 확인한다.
- [x] **REFACTOR:** 추가 abstraction 없이 변경 파일의 diff와 빌드를 검증한다.
- [x] **SURFACE:** iPhone 16 Pro 시뮬레이터에서 추천 홈을 캡처했으나 dev 응답의 `lives`가 비어 대상 섹션은 표시되지 않았다. 두 독립 리뷰에서 제품 결함 없음과 non-empty 상태 증거 부족을 확인했고, 사용자가 이 증거 제한을 명시적으로 수용했다.
### 2026-08-04 Phase 8.4 현재 라이브 `전체` 우측 여백 제거
**Goal 실행 `P8-R1`:** `전체` 버튼의 중복 trailing padding을 제거해 버튼 자체 프레임이 화면 오른쪽 끝에 붙도록 한다.
- **시작 조건:** 사용자 피드백과 `REV-P8-002` 확정.
- **완료 증거:** 정적 RED/GREEN, `git diff --check`, `SodaLive-dev` Debug 빌드.
- **범위 밖:** 라이브 목록의 왼쪽 여백, 목록·버튼 간격, 버튼 프레임·스타일·콜백 변경.
**Files:**
- Modify: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift`
- Review: `reviews/phase8-live-all-fixed.md`
- [x] **RED:** `.padding(.trailing, SodaSpacing.s20)`이 존재해 버튼 외부 우측 여백이 중복 적용됨을 확인한다.
- [x] **RED 확인:** focused `rg`가 기존 22행과 `RED LIVE-ALL-TRAILING-INSET`을 출력한다.
- [x] **GREEN:** `MainHomeLiveAllItemView`의 별도 trailing padding만 제거한다.
- [x] **GREEN 확인:** focused `rg`가 trailing padding을 찾지 못하고 왼쪽 `s20`, `HStack``s12`, 콜백이 유지되는지 확인한다.
- [x] **REFACTOR:** 추가 변경 없이 diff와 빌드를 검증한다.
### 2026-07-12 장르 크리에이터 섹션 미표시 반영 ### 2026-07-12 장르 크리에이터 섹션 미표시 반영
- 목적: 메인 홈 추천 탭에서 서버 응답의 `genreCreators` 기반 장르(카테고리)별 크리에이터 UI를 표시하지 않는다. - 목적: 메인 홈 추천 탭에서 서버 응답의 `genreCreators` 기반 장르(카테고리)별 크리에이터 UI를 표시하지 않는다.
@@ -2101,3 +2141,33 @@
- `rg "createdAt|Capsule\(\)|onChange\(of: proxy.size.height\)" SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift SodaLive/Sources/V2/Component/Text/ExpandableTextView.swift` 실행, 생성 시간 입력/표시, pay capsule, 높이 변화 감지 검색 확인 - `rg "createdAt|Capsule\(\)|onChange\(of: proxy.size.height\)" SodaLive/Sources/V2/Component/Card/CommunityPostCard.swift SodaLive/Sources/V2/Component/Text/ExpandableTextView.swift` 실행, 생성 시간 입력/표시, pay capsule, 높이 변화 감지 검색 확인
- `git diff --check` 실행, 출력 없이 성공 확인 - `git diff --check` 실행, 출력 없이 성공 확인
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 실행, `BUILD SUCCEEDED` 확인 - `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 실행, `BUILD SUCCEEDED` 확인
### P8-T3 1차 실행 — 2026-08-03
- 상태: 완료
- 무엇을: `MainHomeLiveSection`의 라이브 목록 `ScrollView``전체` 버튼을 `HStack`의 형제 뷰로 분리해 `전체`를 오른쪽 끝에 고정했다.
- 왜: 기존에는 `전체``LazyHStack` 마지막 항목이라 라이브 목록과 함께 스크롤됐다.
- 어떻게:
- RED 정적 검증 — 기존 16행에서 `MainHomeLiveAllItemView``LazyHStack` 내부에 있음을 확인했다.
- GREEN 정적 검증 — `MainHomeLiveAllItemView``ScrollView` 밖으로 이동하고 빈 배열 guard, `onTapLive`, `onTapAll`, 좌우 `SodaSpacing.s20`, 간격 `SodaSpacing.s12`가 유지됨을 확인했다.
- `git diff --check` — 출력 없이 성공했다.
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build``BUILD SUCCEEDED`.
- iPhone 16 Pro(iOS 18.3) simulator build — 초기 전체 Pods 컴파일이 600초 제한으로 중단됐으나 동일 DerivedData의 `ONLY_ACTIVE_ARCH=YES` 증분 재실행은 `BUILD SUCCEEDED`.
- simulator 설치/실행 — 성공, 추천 홈의 1206x2622 RGBA PNG 캡처가 정상 합성됨을 확인했다. dev 응답의 `lives`가 비어 대상 섹션은 표시되지 않았다.
- 독립 시각 QA 2건 — 제품 결함 없음, non-empty 라이브 상태의 스크롤 전후 캡처 부재만 evidence blocker로 판정했다. 사용자가 해당 증거 제한을 수용했다.
- teardown — iPhone 16 Pro simulator를 종료하고 임시 QA DerivedData와 캡처 디렉터리를 제거했다.
- 남은 항목: 없음. non-empty 상태의 자동 시각 회귀는 테스트 타깃 또는 deterministic fixture가 도입될 때 추가한다.
- 리뷰: `reviews/phase8-live-all-fixed.md`
### P8-R1 1차 실행 — 2026-08-04
- 상태: 완료
- 무엇을: 고정된 `전체` 버튼의 `.padding(.trailing, SodaSpacing.s20)` 한 줄을 제거했다.
- 왜: 버튼의 70pt 프레임 자체에 좌우 간격이 포함되어 외부 trailing padding이 우측 간격을 중복시켰다.
- 어떻게:
- RED — focused `rg`가 기존 22행의 trailing `s20``RED LIVE-ALL-TRAILING-INSET`을 출력했다.
- GREEN — 같은 `rg`가 trailing padding을 찾지 못했고, 스크롤 목록의 leading `s20`, `HStack``s12`, 빈 상태와 콜백이 유지됨을 확인했다.
- `git diff --check` — 출력 없이 성공했다.
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build``BUILD SUCCEEDED`.
- 남은 항목: 없음.
- 리뷰: `reviews/phase8-live-all-fixed.md``REV-P8-002` 수정 완료.

View File

@@ -321,6 +321,12 @@ MainHomeView
- 여러 페이지에서 재사용 가능한 Card/Banner/Text/Button/Creator widget: `SodaLive/Sources/V2/Component/**` - 여러 페이지에서 재사용 가능한 Card/Banner/Text/Button/Creator widget: `SodaLive/Sources/V2/Component/**`
- 기존 로직 수정이 아닌 신규 View/ViewModel/Repository는 `SodaLive/Sources/V2/**` 아래에 둔다. - 기존 로직 수정이 아닌 신규 View/ViewModel/Repository는 `SodaLive/Sources/V2/**` 아래에 둔다.
### 8.5 현재 라이브 `전체` 고정 배치
- 현재 라이브 아이템 목록만 가로로 스크롤한다.
- `전체` 버튼은 스크롤 위치와 관계없이 섹션 오른쪽 끝에 고정한다.
- 라이브 스크롤 목록의 왼쪽 20pt 여백은 유지하고, `전체` 버튼에는 별도 오른쪽 여백을 적용하지 않는다.
- 라이브 목록이 비어 있으면 기존처럼 현재 라이브 섹션과 `전체` 버튼을 표시하지 않는다.
## 9. Technical Constraints ## 9. Technical Constraints
- 앱 소스 변경은 `SodaLive/Sources/**`에서 수행한다. - 앱 소스 변경은 `SodaLive/Sources/**`에서 수행한다.
- `Pods/**`, `generated/**`, `build/**`는 직접 수정하지 않는다. - `Pods/**`, `generated/**`, `build/**`는 직접 수정하지 않는다.
@@ -340,6 +346,7 @@ MainHomeView
- 추천 탭에서 `GET /api/v2/home/recommendations`를 호출하고 `success == true` 응답 데이터를 섹션별로 렌더링한다. - 추천 탭에서 `GET /api/v2/home/recommendations`를 호출하고 `success == true` 응답 데이터를 섹션별로 렌더링한다.
- 응답 배열이 비어 있는 섹션은 화면에 표시하지 않는다. - 응답 배열이 비어 있는 섹션은 화면에 표시하지 않는다.
- 현재 라이브 섹션의 마지막 `전체` 항목은 배경 없이 medium 14 텍스트, `soda400` 색상, 세로 가운데 정렬로 표시된다. - 현재 라이브 섹션의 마지막 `전체` 항목은 배경 없이 medium 14 텍스트, `soda400` 색상, 세로 가운데 정렬로 표시된다.
- 현재 라이브 섹션의 `전체` 버튼은 라이브 아이템의 가로 스크롤과 관계없이 오른쪽 끝에 고정된다.
- 현재 라이브 `전체` 진입 화면의 상단 제목은 `On Air`로 표시하고, 라이브 아이템은 Figma `185:4509`의 리스트형 구조를 따른다. - 현재 라이브 `전체` 진입 화면의 상단 제목은 `On Air`로 표시하고, 라이브 아이템은 Figma `185:4509`의 리스트형 구조를 따른다.
- 현재 라이브 `전체` 진입 화면의 유료 라이브는 `ic_bar_cash`와 가격을 표시하고, 무료 라이브는 가격과 캔 아이콘 대신 `무료`만 표시한다. - 현재 라이브 `전체` 진입 화면의 유료 라이브는 `ic_bar_cash`와 가격을 표시하고, 무료 라이브는 가격과 캔 아이콘 대신 `무료`만 표시한다.
- `추천 필모그래피`, `또 다른 모습`은 코드와 화면에 포함하지 않는다. - `추천 필모그래피`, `또 다른 모습`은 코드와 화면에 포함하지 않는다.
@@ -376,6 +383,7 @@ MainHomeView
- 기능 검증: 추천 API 성공/실패, 빈 섹션, 활동 타입 I18n, 상세 진입 guard, 최근 활동 `LIVE``targetId` 유무별 이동, `creatorId` 양수 검사, `LIVE_REPLAY`의 콘텐츠 상세 이동, 다른 활동 타입의 회귀 여부, 커뮤니티 카드 상태, 사업자 정보 더보기/접기를 확인한다. - 기능 검증: 추천 API 성공/실패, 빈 섹션, 활동 타입 I18n, 상세 진입 guard, 최근 활동 `LIVE``targetId` 유무별 이동, `creatorId` 양수 검사, `LIVE_REPLAY`의 콘텐츠 상세 이동, 다른 활동 타입의 회귀 여부, 커뮤니티 카드 상태, 사업자 정보 더보기/접기를 확인한다.
- 모두 팔로우 기능 검증: 로그인/비로그인 상태를 구분해 Dialog 표시 여부를 확인하고, 확인 전·취소·dimmed 영역 터치에는 API 요청이 0회이며 `팔로우 하기` 선택 시에만 요청이 1회인지 확인한다. - 모두 팔로우 기능 검증: 로그인/비로그인 상태를 구분해 Dialog 표시 여부를 확인하고, 확인 전·취소·dimmed 영역 터치에는 API 요청이 0회이며 `팔로우 하기` 선택 시에만 요청이 1회인지 확인한다.
- 다국어 검증: 앱 언어를 ko/en/ja로 전환해 모두 팔로우 Dialog의 제목, 설명, 확인, 취소 문구를 확인한다. - 다국어 검증: 앱 언어를 ko/en/ja로 전환해 모두 팔로우 Dialog의 제목, 설명, 확인, 취소 문구를 확인한다.
- 현재 라이브 고정 배치 검증: 여러 라이브 아이템이 표시된 상태에서 목록을 가로로 스크롤해 라이브 아이템만 이동하고 `전체` 버튼의 오른쪽 위치가 유지되는지 확인한다.
## 13. Decision Log ## 13. Decision Log
@@ -386,3 +394,14 @@ MainHomeView
- 로그인 사용자는 `팔로우 하기`를 명시적으로 선택한 경우에만 API를 호출한다. - 로그인 사용자는 `팔로우 하기`를 명시적으로 선택한 경우에만 API를 호출한다.
- `취소`와 dimmed 영역 터치는 모두 보류 action 폐기 및 API 미호출로 처리한다. - `취소`와 dimmed 영역 터치는 모두 보류 action 폐기 및 API 미호출로 처리한다.
- Dialog 문구는 7.6의 ko/en/ja 문구로 확정하며 관련 열린 질문은 없다. - Dialog 문구는 7.6의 ko/en/ja 문구로 확정하며 관련 열린 질문은 없다.
### 2026-08-03 현재 라이브 `전체` 고정 배치
- `MainHomeLiveSection`에서 라이브 목록 `ScrollView``전체` 버튼을 형제 뷰로 분리한다.
- 오버레이 방식은 항목 가림과 터치 충돌 방지 여백이 추가로 필요하므로 사용하지 않는다.
- API, 모델, ViewModel, 라우팅과 `전체` 버튼 스타일은 변경하지 않는다.
### 2026-08-04 현재 라이브 `전체` 우측 여백 제거
- `전체` 버튼 자체 프레임에 좌우 간격이 포함되어 있으므로 별도 trailing padding을 제거한다.
- 라이브 스크롤 목록의 왼쪽 `SodaSpacing.s20`과 목록·버튼 사이 `SodaSpacing.s12`는 유지한다.

View File

@@ -0,0 +1,116 @@
# Phase 8 현재 라이브 `전체` 우측 고정 리뷰
## 1. 리뷰 정보
| 항목 | 내용 |
|---|---|
| 리뷰 대상 | Phase 8.3 / `P8-T3` |
| 기준 commit 또는 working tree | working tree |
| 리뷰 일자 | 2026-08-03 |
| 리뷰어 | Sisyphus, 독립 Oracle 2건 |
| 기준 문서 | `../prd.md`, `../plan-task.md` |
| 리뷰 상태 | 판정 완료 |
## 2. 리뷰 목적과 범위
### 목적
- 현재 라이브 아이템만 가로로 스크롤하고 `전체` 버튼이 오른쪽 끝에 고정되는지 검토한다.
- 빈 상태, 탭 callback, 기존 스타일과 여백에 회귀가 없는지 검토한다.
### 포함 범위
- 코드: `SodaLive/Sources/V2/Main/Home/Recommendation/Components/MainHomeLiveSection.swift`
- 문서: PRD 8.5, Success Criteria, Verification Plan, `P8-T3`
- 검증: 정적 RED/GREEN, device/simulator 빌드, simulator 실행, 독립 시각 QA
### 제외 범위
- API, 모델, ViewModel, 라우팅, `전체` 버튼 스타일 변경
## 3. 판정 기준
- `MainHomeLiveAllItemView`가 수평 `ScrollView` 밖에 있어야 한다.
- 스크롤 영역과 고정 버튼이 겹치지 않고 기존 `SodaSpacing` 토큰을 유지해야 한다.
- 빈 배열 guard와 `onTapLive`, `onTapAll` 경로가 유지되어야 한다.
- 컴파일과 앱 실행이 성공해야 한다.
## 4. 검토한 근거
| 명령 또는 수동 검증 | 결과 | 핵심 증거 |
|---|---|---|
| RED 정적 검증 | 의도한 실패 | 기존 16행의 `전체``LazyHStack` 내부에 있음 |
| GREEN 정적 검증 | 성공 | `전체``ScrollView` 밖 형제 뷰로 이동 |
| `git diff --check` | 성공 | 출력 없음 |
| `SodaLive-dev` Debug device build | 성공 | `BUILD SUCCEEDED` |
| iPhone 16 Pro simulator build | 성공 | 증분 재실행 `BUILD SUCCEEDED` |
| simulator 설치·실행·캡처 | 제한적 성공 | 앱 정상 실행, 캡처 정상; `lives`가 비어 대상 섹션 미표시 |
| 독립 기능 무결성 리뷰 | REVISE | 제품 blocker 없음, non-empty 캡처만 evidence blocker |
| 독립 시각/CJK 리뷰 | REVISE | 제품 결함 없음, 노출된 한글 clipping 없음, 대상 상태 증거 부족 |
## 5. 발견 사항 요약
확정 제품 발견 사항 없음.
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|---|---|---|---|---|---|
| REV-P8-001 | Low | 보류 | non-empty 라이브 상태의 스크롤 전후 캡처 부재 | `P8-T3` | 사용자 증거 제한 수용으로 종료 |
| REV-P8-002 | Medium | 수정 완료 | `전체` 버튼 외부 trailing 여백 중복 | `P8-R1` | Phase 8.4에서 수정 및 빌드 검증 완료 |
## 6. 발견 사항 상세
### REV-P8-001 — non-empty 라이브 상태 시각 증거 부재
- **심각도:** Low
- **상태:** 보류
- **관련 요구사항:** PRD 8.5
- **소유 Task:** `P8-T3`
**관찰 내용**
dev 서버의 추천 응답에서 `lives`가 비어 있어 빈 상태는 확인했지만 `전체` 버튼이 표시되는 상태는 캡처하지 못했다. GUI 자동화 권한이 없고 별도 touch driver도 설치되어 있지 않았다.
**근거**
- 코드는 `전체` 버튼을 `ScrollView` 밖 형제 뷰로 배치한다.
- 두 독립 리뷰 모두 제품 결함 없이 실제 non-empty 캡처 부재만 evidence blocker로 판정했다.
- 사용자가 2026-08-03 해당 증거 제한을 명시적으로 수용했다.
**영향**
구현과 빌드의 완료 판정에는 영향이 없지만, non-empty 상태의 자동 시각 회귀 증거는 남지 않는다.
**권장 조치**
향후 테스트 타깃 또는 deterministic fixture가 도입되면 overflow 라이브 아이템의 스크롤 전후 캡처를 추가한다.
## 7. 확정 항목의 plan·goal 전환
`REV-P8-002``plan-task.md`의 Phase 8.4 `P8-R1`으로 전환했다.
## 8. 리뷰 종료 판정
| 판정 항목 | 결과 | 근거 |
|---|---|---|
| 리뷰 범위 전체 확인 | 충족 | 코드, 문서, build, simulator 실행 검토 |
| 후보 항목 판정 완료 | 충족 | 제품 결함 없음, evidence 제한만 분리 |
| 확정 항목 plan 반영 | 충족 | Phase 8.4 `P8-R1` |
| 보류 항목의 담당·재개 조건 기록 | 충족 | 테스트 타깃 또는 fixture 도입 시 재개 |
| 검증 명령과 결과 기록 | 충족 | `P8-T3` Progress와 본 문서에 기록 |
**최종 결론:** 수정 검증 완료
**남은 항목:** 없음. non-empty 시각 증거 제한은 기존 사용자 수용을 유지한다.
## 9. 수정 후 검증 기록
### 1차 수정 검증 — 2026-08-04
- 무엇을: `REV-P8-002``MainHomeLiveAllItemView` 외부 trailing `s20`을 제거했다.
- 왜: 버튼 자체 70pt 프레임과 외부 padding이 우측 간격을 중복시켰다.
- 어떻게:
- RED focused `rg` — 기존 trailing padding과 실패 메시지 확인.
- GREEN focused `rg` — trailing padding 없음, leading `s20``HStack` `s12` 유지 확인.
- `git diff --check` — 출력 없이 성공.
- `SodaLive-dev` Debug build — `BUILD SUCCEEDED`.
- 남은 항목: 없음.