herel ed97b2a1f0 license: add GPL-3.0-or-later license
- Add full LICENSE file (GPL-3.0)
- Add SPDX headers to all 44 Kotlin source files
- Add SPDX headers to 3 iOS Swift/Info.plist files
- Update README.md and AGENTS.md with license info
2026-07-09 16:19:38 +02:00
2026-07-09 16:19:38 +02:00

MyIce Kotlin Multiplatform

Ice hockey schedule and convocation viewer for Android, iOS, and Desktop (macOS/Windows/Linux). Port of the Flutter app 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)

# Run directly
./gradlew composeApp:run

# Build distributable DMG
./gradlew composeApp:packageDistributionForCurrentOS
# Output: composeApp/build/compose/binaries/main/dmg/myice-1.0.0.dmg

Android

# 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):

storeFile=myice.keystore
storePassword=<your-password>
keyAlias=<your-alias>
keyPassword=<your-password>

Generate a keystore:

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

./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

Copyright (C) 2026 parano.ch

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License v3.0 as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

S
Description
No description provided
Readme GPL-3.0 320 KiB
Languages
Kotlin 98.3%
Swift 1.7%