diff --git a/README.md b/README.md new file mode 100644 index 0000000..e55d05c --- /dev/null +++ b/README.md @@ -0,0 +1,163 @@ +# MyIce Kotlin Multiplatform + +Ice hockey schedule and convocation viewer for Android, iOS, and Desktop (macOS/Windows/Linux). +Port of the [Flutter app](https://gitea.parano.ch/herel/myice/myice_mobile) to Kotlin Multiplatform with Compose Multiplatform. + +## Features + +- **OAuth login** via Infomaniak OIDC (platform-specific: Custom Tabs on Android, ASWebAuthenticationSession on iOS, local HTTP server on Desktop) +- **Schedule viewing** — games and practices with colored event cards +- **Filtering** — by account, age group, sub-group, and event type (all/games/practices) +- **Event details** — convocations with player rosters and staff lists +- **Offline caching** — schedule data persisted locally for offline access +- **Sub-group extraction** — automatically parses team sub-groups from event names + +## Tech Stack + +| Component | Technology | +|-----------|-----------| +| UI | Compose Multiplatform 1.11.1 (Material 3) | +| Language | Kotlin 2.3.20 | +| Networking | Ktor 3.5.1 (CIO on Android/Desktop, Darwin on iOS) | +| Serialization | kotlinx.serialization 1.11.0 | +| State | androidx.lifecycle ViewModel + StateFlow | +| Storage | multiplatform-settings 1.3.0 | +| Build | Gradle 9.5.1, AGP 8.13.2 | + +## Project Structure + +``` +composeApp/ +├── src/ +│ ├── commonMain/kotlin/ch/parano/myice/ +│ │ ├── App.kt # Root composable + routing +│ │ ├── models/ # Serializable data models +│ │ ├── network/ # ApiService, AuthTokenHolder, ApiConfig +│ │ ├── auth/ # OAuthClient interface, AuthSettings, TokenParser +│ │ ├── cache/ # ScheduleCache (chunked storage) +│ │ ├── filter/ # TypeFilter, EventFilter logic +│ │ ├── viewmodel/ # AuthViewModel, ScheduleViewModel, EventDetailViewModel +│ │ └── ui/ +│ │ ├── theme/ # MyIceTheme (Material 3, indigo) +│ │ ├── components/ # EventCard, FilterDropdown, LoadingIndicator +│ │ └── screens/ # LoginScreen, ScheduleScreen, EventDetailScreen +│ ├── androidMain/ # Android OAuth, MainActivity, CIO engine +│ ├── iosMain/ # iOS OAuth, MainViewController, Darwin engine +│ ├── desktopMain/ # Desktop OAuth, Main.kt, CIO engine +│ └── commonTest/ # Unit tests (47 tests) +├── build.gradle.kts +└── src/androidMain/AndroidManifest.xml +``` + +## Build & Run + +### Prerequisites + +- JDK 11+ +- Android SDK (for Android builds) +- Xcode (for iOS builds, macOS only) +- Kotlin Multiplatform Mobile plugin (for iOS) + +### Desktop (macOS) + +```bash +# Run directly +./gradlew composeApp:run + +# Build distributable DMG +./gradlew composeApp:packageDistributionForCurrentOS +# Output: composeApp/build/compose/binaries/main/dmg/myice-1.0.0.dmg +``` + +### Android + +```bash +# Debug APK +./gradlew composeApp:assembleDebug + +# Release APK (requires keystore, see below) +./gradlew composeApp:assembleRelease + +# Install and launch on connected device +~/Library/Android/sdk/platform-tools/adb install -r composeApp/build/outputs/apk/debug/composeApp-debug.apk +~/Library/Android/sdk/platform-tools/adb shell am start -n ch.parano.myice/.MainActivity +``` + +#### Release Signing + +Create `keystore.properties` at the project root (gitignored): + +```properties +storeFile=myice.keystore +storePassword= +keyAlias= +keyPassword= +``` + +Generate a keystore: + +```bash +keytool -genkeypair -v \ + -keystore myice.keystore \ + -alias myice \ + -keyalg RSA -keysize 2048 \ + -validity 10000 +``` + +### iOS + +The Swift source files and `Info.plist` are in `iosApp/`. The Xcode project (`.xcodeproj`) must be created manually: + +1. Open Xcode → New Project → iOS App +2. Name it `MyIceApp`, bundle ID `ch.parano.myice` +3. Add the Swift files from `iosApp/` +4. Set the custom URL scheme `myice` in the URL Types +5. Build and run on a simulator or device + +### Tests + +```bash +./gradlew composeApp:desktopTest +``` + +## Architecture + +``` +┌─────────────────────────────────┐ +│ UI (Compose) │ +│ LoginScreen ScheduleScreen │ +│ EventDetailScreen │ +└──────────────┬──────────────────┘ + │ StateFlow +┌──────────────┴──────────────────┐ +│ ViewModels │ +│ AuthVM ScheduleVM EventDetVM │ +└──────────────┬──────────────────┘ + │ +┌──────────────┴──────────────────┐ +│ AuthSettings + Cache │ +│ (multiplatform-settings) │ +└──────────────┬──────────────────┘ + │ +┌──────────────┴──────────────────┐ +│ ApiService (Ktor) │ +│ /userinfo /accounts /schedule│ +│ /game/{id} │ +└─────────────────────────────────┘ +``` + +## Backend + +The app communicates with the MyIce FastAPI backend at `https://myice.parano.ch`. + +| Endpoint | Description | +|----------|-------------| +| `GET /login` | OAuth login redirect (Infomaniak OIDC) | +| `GET /userinfo` | Current user info (email) | +| `GET /accounts` | Available accounts/teams | +| `GET /schedule?account=` | Events for an account | +| `GET /game/{id}?account=` | Event detail with convocation | + +## License + +Private project.