- Kotlin 96.5%
- Python 3.5%
- Rewire dark style: source -> tiles.openfreemap.org/planet (TileJSON), glyphs -> openfreemap fonts CDN; Metropolis -> Noto Sans (openfreemap does not host Metropolis). - MapView loads the style directly; remove MbtilesTileReader + the mbtiles placeholder wiring. - Delete generate_tiles.py pipeline and stale refs (.gitignore, README, CLAUDE.md). - Bundled assets 38 MB -> 2.5 MB; tiles/fonts cached to disk by MapLibre's ambient cache (first view of a new area needs network). |
||
|---|---|---|
| .forgejo | ||
| app | ||
| docs/superpowers | ||
| gradle | ||
| scripts | ||
| .gitignore | ||
| build.gradle.kts | ||
| CLAUDE.md | ||
| gradle.properties | ||
| gradlew | ||
| LICENSE | ||
| README.md | ||
| settings.gradle.kts | ||
Gresit
Application Android non officielle pour les transports en commun de l'agglomération grenobloise (M réso).
Carte · Horaires temps réel · Position des véhicules · Perturbations · Itinéraires
Présentation
Application avec carte openfreemap (tuiles vectorielles en ligne + cache disque) et données temps réel via l'API M réso. Interface 100 % Jetpack Compose, thème sombre inspiré de l'identité visuelle M réso.
Fonctionnalités
Carte interactive
- Carte plein écran, tuiles vectorielles openfreemap + cache disque (MapLibre GL), style sombre M réso fondé sur OpenStreetMap
- Rotation à deux doigts, boussole, zoom fluide, animations caméra par coroutines (~60 fps)
- Tous les réseau : trams (A–E), Chrono, Flexo et bus
- Curseur croix central ; l'arrêt le plus proche est mis en surbrillance (logique de distance en pixels)
- Dispersion force-directed des quais : à fort zoom, les quais co-localisés d'un pôle (plusieurs lignes, même position GPS) s'écartent en amas compact piloté par une simulation physique (ressorts vers la position réelle + répulsion, type d3-force), chaque quai à la couleur de sa ligne
- Géolocalisation GPS avec recentrage automatique au fix
Horaires temps réel
- Prochains passages par arrêt, rafraîchis toutes les 15 s (cache TTL 15 s)
- Groupement par ligne / direction / destination ; convention de nommage M réso (tram → Chrono → Flexo → bus)
- Code couleur : vert = temps réel, orange/rouge = retard, gris = théorique
- Flèches de direction calculées depuis les séquences GTFS
- Position estimée des véhicules : curseurs sur la carte indiquant la position approchée des véhicules sur chaque ligne, déduite des horaires temps réel et des géométries (badge couleur de ligne + direction)
- Perturbations & signalisations : alertes par ligne (API dyn M réso), indicateur sur la carte, popup dédié ; plans PDF (page 1) affichés dans le détail, mis en cache app-wide, badge sur les lignes concernées
Recherche
- Recherche répartie sur trois sources : lignes en mémoire (Room, hors-ligne), arrêts via
find/json(clusters), adresses viafind/json(rue/lieux) — l'agglomération M réso (LaMetro) - Tolérante aux accents, correspondance par ville
- Hors-ligne : seules les lignes sont recherchées ; un message signale que les arrêts et adresses sont indisponibles
- Historique des recherches récentes (persistant)
- Exploration d'une ligne : tous ses arrêts, suivi de l'arrêt le plus proche, terminus mis en avant
Calcul d'itinéraires
- Origine / destination : arrêt, adresse, position GPS ou point sur carte
- Choix de l'heure et de la date, en mode « Départ » (partir à) ou « Arrivée » (arriver avant)
- Plusieurs propositions ; tri selon le mode : « Départ » = arrivée la plus tôt, « Arrivée » = arrivée la plus proche de l'heure voulue
- Recalcul automatique à chaque changement d'entrée (heure, date, mode)
- Visualisation carte : segments piétons en pointillé, transports en couleur
- Inversion origine/destination en un tap ; message explicite si aucun itinéraire trouvé
Interface
- Bottom sheet (masqué / aperçu / étendu) avec gestes fluides
- Material Design 3, mode sombre
- UI 100 % Jetpack Compose, single-activity
Architecture
Module unique :app, injection de dépendances manuelle via TransitContainer. Trois couches :
┌──────────────────────────────────────────────────┐
│ UI Layer │
│ Jetpack Compose · ViewModels · TransitEventBus │
└──────────────────────────┬───────────────────────┘
│
┌──────────────────────────▼───────────────────────┐
│ Domain Layer │
│ Pure Kotlin · State Machines · Spatial Index │
└──────────────────────────┬───────────────────────┘
│
┌──────────────────────────▼───────────────────────┐
│ Data Layer │
│ Room · Retrofit · Repository · Bundled Assets │
└──────────────────────────────────────────────────┘
- Domain (
domain/) — Kotlin pur, aucune dépendance UI. Machine à étatsTransitionMachine<S>, index spatialClusterIndex/StopIndex, calculs (distance, bearing, regroupement des passages, interpolation de position des véhicules, dispersion force-directed des quais, simplification Douglas-Peucker, décodage polyline). - Data (
data/) — Room (5 tables en lecture), Retrofit vers l'API OTP M réso, repository avec cache TTL, import des assets embarqués. - UI (
ui/) — 4 ViewModels (Transit / Eta / Search / Plan) découplés parTransitEventBus(SharedFlow). Trois modes :EXPLORE,SEARCH,PLAN.
Points notables :
TransitionMachine<S>— machine à états générique avec transitions validées et effets de bordTransitEventBus— SharedFlow qui découple les ViewModels- Couches carte MapLibre : sources GeoJSON + style data-driven (arrêts, lignes, itinéraires, marqueurs)
- Recherche : lignes en mémoire +
find/jsonM réso (arrêtsclusters, adressesrue/lieux), fusionnée avec debounce - Animations caméra par coroutines avec throttling
Tech Stack
| Composant | Technologie |
|---|---|
| Langage | Kotlin 2.1 |
| UI | Jetpack Compose, Material 3 |
| Carte | MapLibre GL Native (tuiles vectorielles openfreemap + cache) |
| Base de données | Room (KSP) |
| Réseau | Retrofit + kotlinx.serialization |
| Asynchrone | Coroutines, StateFlow, SharedFlow |
| Build | Gradle (Kotlin DSL), version catalog |
| Cible | Android 8.0+ (API 26), compileSdk 35 |
Données embarquées & génération
L'asset suivant est gitignoré et (re)généré par un script Python reproductible :
| Asset | Script | Source |
|---|---|---|
transit-data.json (arrêts, lignes, géométries, séquences) |
generate_transit_data.py |
API M réso |
La recherche d'arrêts et d'adresses ne dépend pas d'un asset : elle interroge en direct l'API M réso
find/json. Les lignes (~60) sont lues en mémoire depuis Room (hors-ligne).
python3 scripts/generate_transit_data.py # données transit → transit-data.json
Les tuiles vectorielles, glyphes et sprite proviennent d'openfreemap (tiles.openfreemap.org) sur HTTPS et sont mis en cache sur disque par MapLibre (aucun MBTiles ni police à embarquer ; réseau requis au premier affichage d'une zone non encore visitée). Au premier lancement, l'app importe les données transit dans Room.
Construction
./gradlew assembleDebug # APK debug
./gradlew assembleRelease # APK release (minifié + réduit, signé)
./gradlew installDebug # Build & installation sur appareil
Prérequis : Android Studio 2024+, Java 17.
Données temps réel
Via l'API OpenTripPlanner de data.mobilites-m.fr :
getStoptimes— prochains passages temps réel par clusterplan— calcul d'itinéraires multimodauxdyn— perturbations et signalisations par ligne
Roadmap
- Recherche de points d'intérêt — POI (Overpass / OSM) en plus des arrêts, lignes et adresses
- Thème clair — variante claire du style carte MapLibre
Contribuer
Les contributions sont les bienvenues ! Pour proposer des changements :
- Fork le projet
- Créer une branche feature (
git checkout -b feature/nom-de-la-feature) - Commit les changements (
git commit -m 'Add une feature') - Push la branche (
git push origin feature/nom-de-la-feature) - Ouvrir une Pull Request
Licence
Ce projet est sous licence MIT.
Copyright (c) 2026 Cyril Leblanc