docs: add README with project overview, build instructions, and architecture
This commit is contained in:
@@ -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=<your-password>
|
||||
keyAlias=<your-alias>
|
||||
keyPassword=<your-password>
|
||||
```
|
||||
|
||||
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.
|
||||
Reference in New Issue
Block a user