feat(mac): readability pass for Designed-for-iPad on Mac
- 실사용 보고: 맥에서 아이패드 앱 실행 시 버튼·정보가 전반적으로 매우 작게 보임
(아이패드 포인트의 맥 축소 매핑 + 폭이 넓어져도 콘텐츠를 키우지 않는 레이아웃)
- DeviceLayout.isMac(isiOSAppOnMac) 신설, 맥에서만:
① 전역 dynamicTypeSize 최소 xLarge (사용자가 시스템에서 더 키우면 그 값 존중)
② 모음 탭 목표 카드 폭 430~640 / 행동 버튼 폭 200~280으로 상향
③ 사이드바에서 일기 탭 숨김 (AppTab.sidebarCases — 펜슬 필기 전제 기능이라
맥에선 진입점 제거, 데이터는 보존되어 아이패드에서 계속 사용)
- 아이폰·아이패드 무영향 (isMac=false 경로 불변, 아이패드 심 회귀 스크린샷 확인)
- 검증: -forceMacLayout 인자 신설(아이패드 심에서 맥 분기 강제) — 일기 숨김·
버튼 확대·글자 확대 확인. 맥(Designed for iPad) 대상 빌드 성공. 새 문자열 없음
- CLAUDE.md §6 맥 보정·§14 인자 기재. 맥 위젯·일기 마우스 입력은 출시 후 과제
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CkLDi8Lr21vGqo4SjZaTp
This commit is contained in:
parent
1283c1f799
commit
003859ee10
@ -169,6 +169,7 @@ xcrun xcstringstool sync Widgets/Localizable.xcstrings --stringsdata "${widget_f
|
||||
- **iPhone 기본**: 하단 탭바에 **노출 탭 1~3개**(기본 모음·행동·기록) + "더보기" 탭(나머지 목록). 설정에서 구성
|
||||
- **iPhone 실험 옵션**: "글래스 버블 메뉴"(`RadialNavigationView`) — 하단 중앙 FAB를 누르면 리퀴드 글라스(`glassEffect(.regular.interactive())`) 유리 구슬 탭 버튼들이 부채꼴로 펼쳐짐. 아이콘+이름이 구슬 안에 함께. 모든 유리 요소는 하나의 `GlassEffectContainer`에서 한 패스로 렌더링(성능)되고 FAB 근처에서 액체처럼 분리·합체 모핑. 2단계 연출: 삽입(FAB에서 모핑) → bloomed(스태거 스프링으로 아치 확산). ⚠️ 컨테이너 안 유리 요소에는 glassEffect 뒤 opacity/scale이 콘텐츠에 온전히 적용되지 않음 — 숨김은 계층 제거(`if`), 이동은 `offset`으로만. 순서는 설정에서 편집(기기 로컬). **두 번 눌러 바로 이동**(설정 토글+탭 선택, `settings.radialDoubleTapTab` 빈 값=꺼짐): 닫힌 FAB를 0.35초 안에 두 번 누르면 지정 탭으로 즉시 이동 — 첫 탭을 지연시키는 더블탭 제스처 대신 첫 탭은 즉시 열고 두 번째 탭에서 분기(반응성 유지, 버블이 피어나다 흡수되는 연출)
|
||||
- **iPad·Mac**: 항상 `NavigationSplitView` 사이드바 (`SidebarRootView`, `DeviceLayout.isPad`로 판정)
|
||||
- **맥(Designed for iPad) 보정** (`DeviceLayout.isMac` = isiOSAppOnMac): 아이패드 포인트가 맥 화면에 축소 매핑돼 작게 보이는 것 보정 — ①전역 dynamicTypeSize 최소 xLarge(사용자가 더 키우면 존중, ContentView) ②모음 탭 목표 카드 폭 430~640·행동 버튼 폭 200~280으로 상향(§6.1) ③**사이드바에서 일기 탭 숨김**(`AppTab.sidebarCases` — 펜슬 필기 전제 기능이라 진입점만 제거, 데이터는 보존돼 아이패드에서 계속 보임). 아이폰·아이패드는 무영향. 검증은 아이패드 심 + `-forceMacLayout`(§14). 맥 위젯·구매 흐름 실검증과 일기 마우스 입력 허용 여부는 출시 후 과제
|
||||
- `AppRouter`: 탭 전환 + 탭 간 전달값(모음 탭 롱프레스 → 기록/통계 탭 행동 필터 예약, 더보기 내부 경로 진입 포함)
|
||||
|
||||
### 6.1 모음 탭 (`MainView`)
|
||||
@ -326,7 +327,7 @@ xcrun xcstringstool sync Widgets/Localizable.xcstrings --stringsdata "${widget_f
|
||||
|
||||
## 14. DEBUG 런치 인자 (검증용, 모두 DEBUG 빌드 전용)
|
||||
|
||||
공통: `-seedDemo YES`(데모 데이터: 태그3·행동7·기록 7일치·목표8·자정 걸친 세션·마감 시각 다짐 1개[아침 루틴 08:00, 기대: 하루 100%·연속 1일 — 시드 기록이 고정 시각이라 오전 7:30 이전에 실행하면 오늘 기록이 미래 시각으로 연속 계산에서 빠져 연속 0일이 정상]. **시드 이름·메모는 String(localized:) — 실행 로케일을 따르므로(마케팅 스크린샷용) 이름으로 찾는 인자(-autoStart·-openStatsFor·-excludeActions·-endGoalYesterday)는 그 로케일의 이름을 넘길 것**, ko 기본 사용은 기존과 동일), `-seedBulk YES`(성능 검증용 과거 500일 약 1만 건 — 벌크 행동 4개), `-seedEmptyGoal YES`(다짐 없는 진행 중 목표 1개 추가 — '다짐 없음' 표기 검증용, 기본 시드와 분리), `-premium YES/NO`(**인자가 있는 콜드 스타트 동안만 유효** — 다음 실행에 인자를 빼면 실권한으로 복귀하므로 프리미엄 화면 검증 시 매 런치에 함께 줄 것. 지속 강제는 설정의 DEBUG 테스트 토글), `-startTab <main|action|tag|goal|history|stats|diary|settings>`, `-navStyle radial`, `-themeAutoToggle YES`
|
||||
공통: `-seedDemo YES`(데모 데이터: 태그3·행동7·기록 7일치·목표8·자정 걸친 세션·마감 시각 다짐 1개[아침 루틴 08:00, 기대: 하루 100%·연속 1일 — 시드 기록이 고정 시각이라 오전 7:30 이전에 실행하면 오늘 기록이 미래 시각으로 연속 계산에서 빠져 연속 0일이 정상]. **시드 이름·메모는 String(localized:) — 실행 로케일을 따르므로(마케팅 스크린샷용) 이름으로 찾는 인자(-autoStart·-openStatsFor·-excludeActions·-endGoalYesterday)는 그 로케일의 이름을 넘길 것**, ko 기본 사용은 기존과 동일), `-seedBulk YES`(성능 검증용 과거 500일 약 1만 건 — 벌크 행동 4개), `-seedEmptyGoal YES`(다짐 없는 진행 중 목표 1개 추가 — '다짐 없음' 표기 검증용, 기본 시드와 분리), `-premium YES/NO`(**인자가 있는 콜드 스타트 동안만 유효** — 다음 실행에 인자를 빼면 실권한으로 복귀하므로 프리미엄 화면 검증 시 매 런치에 함께 줄 것. 지속 강제는 설정의 DEBUG 테스트 토글), `-startTab <main|action|tag|goal|history|stats|diary|settings>`, `-navStyle radial`, `-themeAutoToggle YES`, `-forceMacLayout YES`(아이패드 심에서 맥(Designed for iPad) 분기 강제 — §6 맥 보정 검증)
|
||||
|
||||
| 영역 | 인자 |
|
||||
|---|---|
|
||||
|
||||
@ -41,6 +41,11 @@ struct ContentView: View {
|
||||
}
|
||||
.tint(AppTheme.green)
|
||||
.preferredColorScheme(theme == "dark" ? .dark : .light)
|
||||
// 맥(Designed for iPad)은 아이패드 포인트가 축소 매핑돼 글자가 작게 보임 —
|
||||
// 전역 글자 크기를 한 단계 키운다. 사용자가 시스템에서 더 크게 쓰면 그 값을 존중
|
||||
.transformEnvironment(\.dynamicTypeSize) { size in
|
||||
if DeviceLayout.isMac, size < .xLarge { size = .xLarge }
|
||||
}
|
||||
.task {
|
||||
#if DEBUG
|
||||
DebugSeed.seedIfRequested(context: context)
|
||||
@ -211,6 +216,13 @@ enum AppTab: String, CaseIterable, Identifiable {
|
||||
allCases.filter { $0 != .diary }
|
||||
}
|
||||
|
||||
/// 사이드바(iPad·Mac)에 노출되는 탭.
|
||||
/// 일기는 펜슬 필기를 전제로 한 기능이라 맥(Designed for iPad)에서는 숨긴다 —
|
||||
/// 데이터는 그대로 두므로 아이패드에서는 계속 보이고, 진입점만 없어진다.
|
||||
static var sidebarCases: [AppTab] {
|
||||
DeviceLayout.isMac ? allCases.filter { $0 != .diary } : allCases
|
||||
}
|
||||
|
||||
var id: String { rawValue }
|
||||
|
||||
var label: String {
|
||||
|
||||
@ -157,7 +157,12 @@ struct MainView: View {
|
||||
if DeviceLayout.isPad {
|
||||
// 넓은 화면: 페이징 대신 카드를 여러 장 나란히 배치 (폭도 카드 단위로 제한).
|
||||
// 비-lazy 레이아웃인 이유는 AdaptiveColumnsLayout 주석 참고 (스크롤 진동 버그)
|
||||
AdaptiveColumnsLayout(minWidth: 340, maxWidth: 520, spacing: 10) {
|
||||
// 맥은 아이패드 포인트가 축소 매핑돼 카드가 작아 보임 — 폭을 키워 보정 (§6.1)
|
||||
AdaptiveColumnsLayout(
|
||||
minWidth: DeviceLayout.isMac ? 430 : 340,
|
||||
maxWidth: DeviceLayout.isMac ? 640 : 520,
|
||||
spacing: 10
|
||||
) {
|
||||
ForEach(pinnedGoals) { goal in
|
||||
GoalSummaryCard(goal: goal)
|
||||
}
|
||||
@ -272,7 +277,12 @@ struct MainView: View {
|
||||
private var grid: some View {
|
||||
Group {
|
||||
if DeviceLayout.isPad {
|
||||
AdaptiveColumnsLayout(minWidth: 150, maxWidth: 220, spacing: 12) {
|
||||
// 맥은 축소 매핑 보정으로 버튼 폭을 키운다 (§6.1)
|
||||
AdaptiveColumnsLayout(
|
||||
minWidth: DeviceLayout.isMac ? 200 : 150,
|
||||
maxWidth: DeviceLayout.isMac ? 280 : 220,
|
||||
spacing: 12
|
||||
) {
|
||||
gridCells
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -15,6 +15,16 @@ import UIKit
|
||||
/// 크기 클래스 대신 기기 종류로 판정해 iPhone(가로 모드 포함)은 항상 기존 UI를 유지한다.
|
||||
enum DeviceLayout {
|
||||
static let isPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
/// 맥에서 실행 중인 아이패드 앱(Designed for iPad) 여부.
|
||||
/// 아이패드 포인트가 맥 화면에 축소 매핑돼 전반적으로 작게 보이므로,
|
||||
/// 맥에서만 글자 크기·모음 탭 카드/버튼 폭을 키운다 (아이폰·아이패드 무영향)
|
||||
static let isMac: Bool = {
|
||||
#if DEBUG
|
||||
// 검증용: -forceMacLayout YES → 아이패드 시뮬레이터에서 맥 분기 강제 (§14)
|
||||
if UserDefaults.standard.bool(forKey: "forceMacLayout") { return true }
|
||||
#endif
|
||||
return ProcessInfo.processInfo.isiOSAppOnMac
|
||||
}()
|
||||
}
|
||||
|
||||
struct SidebarRootView: View {
|
||||
@ -45,7 +55,7 @@ struct SidebarRootView: View {
|
||||
NavigationSplitView {
|
||||
List(selection: sidebarSelection) {
|
||||
Section {
|
||||
ForEach(AppTab.allCases) { tab in
|
||||
ForEach(AppTab.sidebarCases) { tab in
|
||||
Label {
|
||||
Text(tab.label)
|
||||
} icon: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user