yayacal/CLAUDE.md

81 lines
5.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
YaYa is a calendar app built with pure Android + Jetpack Compose, targeting Android only. The UI is written entirely in Jetpack Compose with Material 3.
## Build Commands
```bash
# Build Android debug APK
./gradlew :app:assembleDebug
# Install Android debug APK to connected device
./gradlew :app:installDebug
# Run core module tests
./gradlew :core:testDebugUnitTest
# Run a single test class
./gradlew :core:testDebugUnitTest --tests "plus.rua.project.ui.CalendarUtilsTest"
```
Gradle configuration cache and build cache are enabled by default (`gradle.properties`).
## Architecture
**Three-module structure:**
- `:core` — all Compose UI, ViewModel, and business logic (`com.android.library`)
- `:app` — thin Android shell (`MainActivity``App()`)
- `:macrobenchmark` — Macrobenchmark module for Baseline Profile generation
**Calendar UI composition** (all in `plus.rua.project.ui`):
```
CalendarMonthView ← top-level screen (MonthHeader + WeekdayHeader + pager + BottomCard)
├── MonthHeader ← year/month label + ISO week number
├── WeekdayHeader ← fixed "一二三四五六日" row
├── CalendarPager ← HorizontalPager with Int.MAX_VALUE pages (month view)
│ └── CalendarMonthPage ← 6×7 grid of DayCell with collapse animation
│ └── DayCell ← single day circle with selection/today states
├── WeekPager ← HorizontalPager for single-week view (collapsed state)
│ └── DayCell
├── YearGridView ← 4×3 mini-month grid with year navigation (year view)
│ └── MiniMonth ← compact month: title + weekday row + day numbers
└── BottomCard ← drag handle card, drives collapse/expand gestures
```
`ShiftPattern` (in `plus.rua.project`) defines personal shift cycles (WORK/OFF) independent of public holidays. Uses modular arithmetic: `(date - anchorDate) mod cycle.size`.
`CalendarUtils` (in `plus.rua.project.ui`) holds pager constants (`START_PAGE = Int.MAX_VALUE/2`, `COLLAPSE_THRESHOLD = 0.25f`) and page↔date arithmetic (`pageToYearMonth`, `yearMonthToPage`, `pageToWeekMonday`).
**Collapse/expand animation:** `CalendarMonthView` supports month↔week transition via `CalendarViewModel.collapseProgress` (0f=month, 1f=week). `BottomCard` captures vertical drag gestures and calls `viewModel.onDrag()`/`onExpandDrag()`. When progress crosses 50% on release, a spring animation snaps to the nearest state. `CalendarMonthPage` compresses non-selected weeks toward zero height during collapse. When fully collapsed, `WeekPager` replaces `CalendarPager` for efficient single-week paging.
**Pager page mapping:** Both `CalendarPager` and `WeekPager` use `Int.MAX_VALUE` pages centered at `Int.MAX_VALUE / 2`. Page-to-date conversion is arithmetic — no index-based list. `CalendarPager` maps pages to yearMonth; `WeekPager` maps pages to week-Monday dates. Both skip the initial `snapshotFlow` emission (`.drop(1)`) to preserve the "today" selection on first render.
`CalendarViewModel` holds `selectedDate` and `isCollapsed` state, computes month day grids (6×7=42 cells) and ISO week numbers. Week starts on Monday (ISO 8601).
**Performance tracing:** `ComposeTrace.kt` provides `composeTraceBeginSection`/`composeTraceEndSection` wrapping `android.os.Trace`. Custom markers are inserted at key points (e.g., `MonthView:Compose`, `YearView:Compose`, `VM:collapseProgress`) for Perfetto/Systrace analysis. See `DEVELOPMENT.md` for trace recording and Python parsing scripts.
## Key Dependencies
- Kotlin 2.3.21, Compose Multiplatform 1.11.0, Material 3 1.10.0-alpha05
- `kotlinx-datetime` 0.8.0 for all date logic (no java.util.Calendar)
- `tyme4kt` for Chinese traditional calendar (lunar dates, solar terms, festivals)
- `sketch` 4.4.0 for animated GIF display (`AsyncImage` with `sketch-animated-gif`)
- AGP 9.2.1, compileSdk/targetSdk 37, minSdk 24
- JVM target: 17
- R8 full mode enabled (`android.enableR8.fullMode=true`)
## Conventions
- Package: `plus.rua.project` (core), `plus.rua.project.ui` (UI composables)
- Version catalog at `gradle/libs.versions.toml` — all dependency versions declared there
- `@Suppress("DEPRECATION")` used for `monthNumber` access on `kotlinx.datetime.LocalDate` — must include inline comment explaining reason
- UI text is in Chinese (weekday labels, month header format "2026年5月")
- Public `@Composable` functions require KDoc per `COMMENTS.md`
- `Modifier` parameter always last in composable signatures
- Callback parameters use `on` prefix (`onDateClick`, `onMonthChanged`)
- **Clickable list items:** Use `Card(onClick = ...)` with `CardDefaults.cardElevation(defaultElevation = 0.dp)` instead of `Modifier.clickable()` on `Box`/`Row`. This ensures consistent Material 3 press-state feedback (ripple + background color change) across all interactive list/menu items. See `LicensesScreen`, `ToolsScreen`, and `CalendarMonthView.MenuItem` for reference.