Merge branch 'DefectingCat:main' into main
17
CLAUDE.md
@ -12,13 +12,22 @@ YaYa is a calendar app built with Kotlin Multiplatform (KMP) + Compose Multiplat
|
||||
# Build Android debug APK
|
||||
./gradlew :androidApp:assembleDebug
|
||||
|
||||
# Run shared module tests
|
||||
# Install Android debug APK to connected device
|
||||
./gradlew :androidApp:installDebug
|
||||
|
||||
# Run all shared module tests
|
||||
./gradlew :shared:allTests
|
||||
|
||||
# Run shared module tests on Android host only
|
||||
./gradlew :shared:testAndroidHostTest
|
||||
|
||||
# Run a single test class
|
||||
./gradlew :shared:testAndroidHostTest --tests "plus.rua.project.ui.CalendarUtilsTest"
|
||||
|
||||
# Build iOS app — open iosApp/ in Xcode and run from there
|
||||
# Generate iOS framework (required before first Xcode open or after clean)
|
||||
./gradlew :shared:generateDummyFramework
|
||||
|
||||
# Build iOS app — open iosApp/iosApp.xcworkspace in Xcode and run from there
|
||||
```
|
||||
|
||||
Gradle configuration cache and build cache are enabled by default (`gradle.properties`).
|
||||
@ -62,13 +71,17 @@ CalendarMonthView ← top-level screen (MonthHeader + WeekdayHeader + p
|
||||
|
||||
`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` via expect/actual — Android routes to `android.os.Trace`, iOS is a no-op. 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
|
||||
|
||||
|
||||
24
README.md
@ -1,20 +1,20 @@
|
||||
# YaYa
|
||||
|
||||
基于 Kotlin Multiplatform 与 Compose Multiplatform 的日历应用,Android 和 iOS 共享 UI。
|
||||
基于 Kotlin Multiplatform 与 Compose Multiplatform 的跨平台日历应用,Android 与 iOS 共享同一套 UI 与业务逻辑。
|
||||
|
||||
月视图与周视图之间支持流畅的折叠/展开过渡——拖拽切换,弹簧动画自动吸附。无限分页,ISO 8601 周起始,Material 3。
|
||||
## 特性
|
||||
|
||||
## 构建
|
||||
|
||||
```bash
|
||||
# Android
|
||||
./gradlew :androidApp:assembleDebug
|
||||
|
||||
# iOS — 在 Xcode 中打开 iosApp/ 运行
|
||||
```
|
||||
- **流畅的视图切换** —— 月视图、周视图、年视图三种模式,拖拽手势驱动月↔周折叠,弹簧动画自动吸附
|
||||
- **无限滑动分页** —— 基于 `Int.MAX_VALUE` 的虚拟分页,前后无边界翻页
|
||||
- **完整中式日历** —— 公历 + 农历 + 二十四节气 + 传统节日,ISO 8601 周起始(周一)
|
||||
- **个人排班周期** —— 自定义工作/休息循环,与公共节假日独立
|
||||
- **Material 3 设计** —— 动态配色,深色模式
|
||||
|
||||
## 技术栈
|
||||
|
||||
- Kotlin 2.3 · Compose Multiplatform 1.10 · Material 3
|
||||
- Kotlin 2.3 · Compose Multiplatform 1.11 · Material 3
|
||||
- `kotlinx-datetime` 处理所有日期逻辑
|
||||
- 双模块:`:shared`(UI + 逻辑)· `:androidApp`(薄壳)
|
||||
- `tyme4kt` 提供农历、节气与传统节日
|
||||
- `sketch` 渲染 GIF 动画
|
||||
- 双模块:`:shared`(UI + 逻辑) · `:androidApp`(薄壳)
|
||||
- iOS 入口为 `MainViewController.kt`,Xcode 工程位于 `iosApp/`
|
||||
|
||||
3
androidApp/proguard-rules.pro
vendored
@ -8,9 +8,6 @@
|
||||
# tyme4kt (Chinese traditional calendar)
|
||||
-keep class cn.tyme.** { *; }
|
||||
|
||||
# Compose runtime reflective lookups
|
||||
-keep class androidx.compose.runtime.** { *; }
|
||||
|
||||
# ViewModel (used by CalendarViewModel)
|
||||
-keep class * extends androidx.lifecycle.ViewModel { *; }
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
|
||||
BIN
androidApp/src/main/assets/app_icon.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
androidApp/src/main/assets/gifs/001.gif
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
androidApp/src/main/assets/gifs/002.gif
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
androidApp/src/main/assets/gifs/003.gif
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
androidApp/src/main/assets/gifs/004.gif
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
androidApp/src/main/assets/gifs/005.gif
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
androidApp/src/main/assets/gifs/006.gif
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
androidApp/src/main/assets/gifs/007.gif
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
androidApp/src/main/assets/gifs/008.gif
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
androidApp/src/main/assets/gifs/009.gif
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
androidApp/src/main/assets/gifs/010.gif
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
androidApp/src/main/assets/gifs/011.gif
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
androidApp/src/main/assets/gifs/012.gif
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
androidApp/src/main/assets/gifs/013.gif
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
androidApp/src/main/assets/gifs/014.gif
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
androidApp/src/main/assets/gifs/015.gif
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
androidApp/src/main/assets/gifs/016.gif
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
androidApp/src/main/assets/gifs/017.gif
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
androidApp/src/main/assets/gifs/018.gif
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
androidApp/src/main/assets/gifs/019.gif
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
androidApp/src/main/assets/gifs/020.gif
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
androidApp/src/main/assets/gifs/021.gif
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
androidApp/src/main/assets/gifs/022.gif
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
androidApp/src/main/assets/gifs/023.gif
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
androidApp/src/main/assets/gifs/024.gif
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
androidApp/src/main/assets/gifs/025.gif
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
androidApp/src/main/assets/gifs/026.gif
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
androidApp/src/main/assets/gifs/027.gif
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
androidApp/src/main/assets/gifs/028.gif
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
androidApp/src/main/assets/gifs/029.gif
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
androidApp/src/main/assets/gifs/030.gif
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
androidApp/src/main/assets/gifs/031.gif
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
BIN
androidApp/src/main/assets/gifs/033.gif
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
androidApp/src/main/assets/gifs/034.gif
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
androidApp/src/main/assets/gifs/035.gif
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
androidApp/src/main/assets/gifs/036.gif
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
androidApp/src/main/assets/gifs/037.gif
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
androidApp/src/main/assets/gifs/038.gif
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
androidApp/src/main/assets/gifs/039.gif
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
androidApp/src/main/assets/gifs/040.gif
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
androidApp/src/main/assets/gifs/041.gif
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
androidApp/src/main/assets/gifs/042.gif
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
androidApp/src/main/assets/gifs/043.gif
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
androidApp/src/main/assets/gifs/044.gif
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
androidApp/src/main/assets/gifs/045.gif
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
androidApp/src/main/assets/gifs/046.gif
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
androidApp/src/main/assets/gifs/047.gif
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
androidApp/src/main/assets/gifs/048.gif
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
androidApp/src/main/assets/gifs/049.gif
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
androidApp/src/main/assets/gifs/050.gif
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
androidApp/src/main/assets/gifs/051.gif
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
androidApp/src/main/assets/gifs/052.gif
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
androidApp/src/main/assets/gifs/053.gif
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
androidApp/src/main/assets/gifs/054.gif
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
androidApp/src/main/assets/gifs/055.gif
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
androidApp/src/main/assets/gifs/056.gif
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
androidApp/src/main/assets/gifs/057.gif
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
androidApp/src/main/assets/gifs/058.gif
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
androidApp/src/main/assets/gifs/059.gif
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
androidApp/src/main/assets/gifs/060.gif
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
androidApp/src/main/assets/gifs/061.gif
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
androidApp/src/main/assets/gifs/062.gif
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
androidApp/src/main/assets/gifs/063.gif
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
androidApp/src/main/assets/gifs/064.gif
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
androidApp/src/main/assets/gifs/065.gif
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
androidApp/src/main/assets/gifs/066.gif
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
androidApp/src/main/assets/gifs/067.gif
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
androidApp/src/main/assets/gifs/068.gif
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
androidApp/src/main/assets/gifs/069.gif
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
androidApp/src/main/assets/gifs/070.gif
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
androidApp/src/main/assets/gifs/071.gif
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
androidApp/src/main/assets/gifs/072.gif
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
androidApp/src/main/assets/gifs/073.gif
Normal file
|
After Width: | Height: | Size: 281 KiB |
BIN
androidApp/src/main/assets/gifs/074.gif
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
androidApp/src/main/assets/gifs/075.gif
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
androidApp/src/main/assets/gifs/076.gif
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
androidApp/src/main/assets/gifs/077.gif
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
androidApp/src/main/assets/gifs/078.gif
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
androidApp/src/main/assets/gifs/079.gif
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
androidApp/src/main/assets/gifs/080.gif
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
androidApp/src/main/assets/gifs/081.gif
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
androidApp/src/main/assets/gifs/082.gif
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
androidApp/src/main/assets/gifs/083.gif
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
androidApp/src/main/assets/gifs/084.gif
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
androidApp/src/main/assets/gifs/085.gif
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
androidApp/src/main/assets/gifs/086.gif
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
androidApp/src/main/assets/gifs/087.gif
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
androidApp/src/main/assets/gifs/088.gif
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
androidApp/src/main/assets/gifs/089.gif
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
androidApp/src/main/assets/gifs/090.gif
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
androidApp/src/main/assets/gifs/091.gif
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
androidApp/src/main/assets/gifs/092.gif
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
androidApp/src/main/assets/gifs/093.gif
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
androidApp/src/main/assets/gifs/094.gif
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
androidApp/src/main/assets/gifs/095.gif
Normal file
|
After Width: | Height: | Size: 8.4 KiB |