feat(fantalk): 쓰기 입력 제한을 적용한다
This commit is contained in:
@@ -38,6 +38,10 @@
|
||||
- 팬Talk 쓰기 화면은 크리에이터 채널 팬Talk 탭의 우측하단 plus button, empty state의 `응원남기기` 버튼, 내가 쓴 글의 `수정하기`에서 진입한다.
|
||||
- 팬Talk 쓰기 화면 진입 시 키보드가 올라온 상태를 기본으로 하며, 입력 값 유무에 따라 보내기 버튼 disabled/enabled 상태를 분리한다.
|
||||
- 입력 값이 있는 상태에서 취소 버튼을 터치하면 입력 종료 안내 모달을 표시한다. 입력 값이 없으면 별도 모달 없이 이전 화면으로 닫는다.
|
||||
- 취소 문구의 고정 `width: 64`, `height: 56`만 제거하고 내비게이션 높이 `56`과 보내기 capsule 높이 `44`는 유지한다.
|
||||
- 입력 영역은 `I18n.CreatorChannelFanTalk`의 ko/en/ja placeholder를 사용한다.
|
||||
- 입력은 Swift `String.count` 기준 500자까지 허용하고, 501번째 이후 사용자 입력은 `prefix(500)`으로 반영하지 않는다.
|
||||
- 예외적으로 content가 500자를 초과하면 메시지 본문과 현재 글자 수를 `Color.red400`으로 표시하고 보내기 버튼을 비활성화한다.
|
||||
- 공용 모달은 요청 명칭상 `V2/Components` 대상이지만, 현재 저장소 경로 관례에 맞춰 `SodaLive/Sources/V2/Component/Modal/**` 아래에 작성한다.
|
||||
|
||||
## 주요 대상 파일
|
||||
@@ -489,3 +493,95 @@
|
||||
|
||||
- 2026-08-14: 사용자 인터뷰로 팬레터 탭 empty 문구와 작성 버튼의 ko/en/ja 값을 확정하고 Phase 11에 미완료 후속 Task로 추가했다. 기존 작성 route와 내 채널 버튼 숨김 규칙은 유지하며 이번 작업은 문서만 보강했다.
|
||||
- 2026-08-14: Phase 11 구현을 완료했다. 팬레터 탭 empty 문구와 작성 버튼을 ko/en/ja I18n으로 교체하고 기존 작성 route 및 내 채널 버튼 숨김 규칙을 유지했다. 사용자 후속 요청에 따라 작성 버튼은 `Color.gray800` 배경과 white 아이콘·텍스트로 변경했다. 23개 정적 계약, `git diff --check`, iPhone 16 Pro 시뮬레이터 Debug 빌드가 통과했고, 세 언어 재캡처와 두 독립 색상·CJK 리뷰에서 차단 항목 없이 PASS를 확인했다.
|
||||
|
||||
### Phase 12: 팬Talk 쓰기 입력 UX 보강
|
||||
|
||||
**Phase 결과:** 팬Talk 쓰기 화면에서 취소 문구가 잘리지 않고, 다국어 placeholder와 500자 입력 제한 및 초과 예외 상태가 일관되게 동작한다.
|
||||
|
||||
**선행조건:** PRD `§5.10`, `DEC-FANTALK-WRITE-001~003` 확정.
|
||||
|
||||
**Phase 완료 조건:** `P12-T1`, `P12-T2`, `P12-GATE` 완료와 검증 기록 누적.
|
||||
|
||||
#### Task 12.1 다국어 placeholder와 입력 상태 계약
|
||||
|
||||
**Goal 실행 `P12-T1`:** placeholder 문구와 500자 제한에 필요한 ViewModel 상태를 기존 타입에 최소 추가한다.
|
||||
|
||||
- **시작 조건:** Phase 12 선행조건 충족.
|
||||
- **완료 증거:** ko/en/ja 문구, 500자 허용 경계, 초과 상태 및 전송 비활성화 조건이 코드와 정적 검사에서 확인된다.
|
||||
- **범위 밖:** 신규 입력 컴포넌트, dependency, route, API 변경.
|
||||
- **TDD 예외 사유:** 현재 프로젝트에 unit test bundle target이 없으며 이번 범위에서 신규 test target을 추가하지 않는다.
|
||||
- **대체 검증 방법:** `rg` 정적 계약 검사, Swift 표준 문자열 경계 확인, Phase Gate의 앱 빌드와 수동 입력 검증을 사용한다.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `SodaLive/Sources/I18n/I18n.swift`
|
||||
- Modify: `SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteViewModel.swift`
|
||||
|
||||
**Interfaces:**
|
||||
|
||||
- Consumes: 기존 `I18n.pick(ko:en:ja:)`, `content`, `maxContentCount`, `canSend`.
|
||||
- Produces: `I18n.CreatorChannelFanTalk.writePlaceholder`, `content.count > maxContentCount` 초과 상태, 초과 상태를 포함한 `canSend`.
|
||||
|
||||
- [x] `I18n.CreatorChannelFanTalk.writePlaceholder`에 한국어 `응원 메시지를 입력해 주세요.`, 영어 `Enter a message of support.`, 일본어 `応援メッセージを入力してください。`를 추가한다.
|
||||
- [x] `maxContentCount`는 `500`을 유지하고 500자는 유효, 500자 초과만 예외인 상태를 제공한다.
|
||||
- [x] `canSend`는 기존 공백·줄바꿈 검증에 더해 content가 500자를 초과하면 `false`가 되게 한다.
|
||||
- [x] 수정 모드의 초기 content는 임의로 자르지 않아 500자 초과 예외 상태를 화면에서 판정할 수 있게 한다.
|
||||
- [x] `rg -n "writePlaceholder|maxContentCount|content.count|canSend|whitespacesAndNewlines" SodaLive/Sources/I18n/I18n.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteViewModel.swift`로 상태 계약을 확인한다.
|
||||
|
||||
#### Task 12.2 내비게이션·placeholder·500자 UI 적용
|
||||
|
||||
**Goal 실행 `P12-T2`:** 기존 쓰기 View 안에서 취소 문구 잘림을 제거하고 입력 제한과 초과 표시를 연결한다.
|
||||
|
||||
- **시작 조건:** `P12-T1` 완료.
|
||||
- **완료 증거:** View 정적 검사와 ko/en/ja 및 499·500·501자 수동 검증 통과.
|
||||
- **범위 밖:** 내비게이션 전체 높이, 보내기 capsule 높이, `/500` 색상, 작성·수정 API 흐름 변경.
|
||||
- **TDD 예외 사유:** 현재 프로젝트에 UI test bundle target이 없으며 이번 범위에서 신규 test target을 추가하지 않는다.
|
||||
- **대체 검증 방법:** View 정적 계약 검사와 Phase Gate의 시뮬레이터 수동 검증을 사용한다.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteView.swift`
|
||||
|
||||
**Interfaces:**
|
||||
|
||||
- Consumes: `P12-T1`의 `writePlaceholder`, `maxContentCount`, 초과 상태, `canSend`.
|
||||
- Produces: 500자로 제한된 `TextEditor` binding과 정상·초과 입력 UI 상태.
|
||||
|
||||
- [x] 취소 `Text`의 `.frame(width: 64, height: 56, alignment: .leading)`만 제거한다.
|
||||
- [x] 내비게이션 `.frame(height: 56)`과 보내기 capsule `.frame(height: 44)`는 유지한다.
|
||||
- [x] content가 비어 있을 때 `writePlaceholder`를 표시하고 입력이 시작되면 숨긴다.
|
||||
- [x] `TextEditor`가 전달한 새 content는 `String(newValue.prefix(viewModel.maxContentCount))`까지만 반영해 타이핑과 붙여넣기 모두 500자를 넘지 않게 한다.
|
||||
- [x] ViewModel에 이미 500자를 초과한 content가 있으면 메시지 본문과 현재 글자 수를 `Color.red400`으로 표시한다.
|
||||
- [x] 500자 초과 상태에서는 `canSend == false`에 따라 보내기 버튼을 비활성화하고 `/500`은 기존 `Color.gray500`을 유지한다.
|
||||
- [x] 기존 focus, 키보드, 취소 모달, 작성·수정 submit 흐름은 변경하지 않는다.
|
||||
- [x] `rg -n "writePlaceholder|prefix\(viewModel.maxContentCount\)|Color.red400|frame\(width: 64, height: 56|frame\(height: 56\)|frame\(height: 44\)" SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteView.swift`로 추가·유지·제거 계약을 확인한다.
|
||||
|
||||
#### Phase 12 Gate
|
||||
|
||||
**Goal 실행 `P12-GATE`:** Phase 12 요구사항과 기존 작성·수정 흐름의 회귀 여부를 최종 판정한다.
|
||||
|
||||
- **시작 조건:** `P12-T1`, `P12-T2` 완료.
|
||||
- **완료 증거:** 아래 자동·수동 검증 통과와 실제 결과를 검증 기록에 누적.
|
||||
- **범위 밖:** Gate 통과를 위한 기존 검증 완화나 관련 없는 소스 수정.
|
||||
|
||||
```bash
|
||||
rg -n "응원 메시지를 입력해 주세요|Enter a message of support|応援メッセージを入力してください|writePlaceholder" SodaLive/Sources/I18n/I18n.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteView.swift
|
||||
rg -n "maxContentCount|content.count|prefix\(viewModel.maxContentCount\)|Color.red400|canSend" SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteView.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteViewModel.swift
|
||||
git diff --check -- SodaLive/Sources/I18n/I18n.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteView.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteViewModel.swift docs/20260704_크리에이터_채널_팬Talk_탭/prd.md docs/20260704_크리에이터_채널_팬Talk_탭/plan-task.md
|
||||
xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build
|
||||
```
|
||||
|
||||
**Expected:** 다국어 문구와 500자 경계 및 초과 상태 계약이 확인되고, 공백 오류 없이 `** BUILD SUCCEEDED **`가 출력된다.
|
||||
|
||||
수동 검증:
|
||||
|
||||
- [x] ko/en/ja에서 취소 문구가 잘리지 않고 placeholder가 정확히 표시된다.
|
||||
- [x] 499자와 500자는 입력되며 유효 content일 때 보내기 버튼이 활성화된다.
|
||||
- [x] 501번째 타이핑 문자와 500자를 초과하는 붙여넣기 문자는 반영되지 않고 글자 수가 500을 넘지 않는다.
|
||||
- [x] 수정 초기값 등으로 500자를 초과한 예외 상태를 주입하면 메시지 본문과 현재 글자 수가 `Color.red400`으로 표시되고 보내기 버튼이 비활성화된다.
|
||||
- [x] 공백·줄바꿈만 입력한 상태, 취소 모달, 작성·수정 submit 흐름이 기존과 동일하다.
|
||||
|
||||
- 2026-08-25: 사용자 인터뷰에서 500자 허용·501번째 이후 입력 차단, 500자 초과 예외 상태의 본문·현재 글자 수 붉은 표시와 보내기 비활성화, 취소 문구의 고정 크기만 제거하는 범위를 확정했다. PRD와 Phase 12 계획만 추가했으며 Swift 구현과 빌드 검증은 수행하지 않았다.
|
||||
- 2026-08-25: Phase 12 구현을 완료했다. `writePlaceholder`, 500자 제한 binding, 500자 초과 상태와 전송 비활성화, 취소 문구의 고정 frame 제거를 적용했으며 기존 내비게이션·보내기 높이와 작성·수정 흐름은 유지했다.
|
||||
- 2026-08-25: Phase 12의 두 `rg` 정적 계약 검사, Swift `String.count`/`prefix(_:)` 499·500·501자 경계 검사, `git diff --check`, `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build`를 실행했고 `** BUILD SUCCEEDED **`를 확인했다.
|
||||
- 2026-08-25: 사용자 요청에 따라 visual QA와 시뮬레이터 수동 검증은 수행하지 않았다. ko/en/ja 표시와 실제 입력 동작에 관한 수동 검증 체크박스 5개는 사용자 확인 전까지 미완료로 유지한다.
|
||||
|
||||
Reference in New Issue
Block a user