- Kotlin 93.5%
- Python 6.5%
Data v3 adds 19 SNCF lines (TGV, TER, RE coaches) with stop-chained
substitute geometry; their stoptimes already flow through the existing
ETA pipeline untouched.
- EtaGrouper: badge names now come from the line shortName (K6, C1, P24)
instead of the raw route id, and train lines sort as their own tier
ahead of the urban hierarchy so SNC:C1 and SEM:C1 never interleave
- C1 disambiguation: SNCF badges are squared (train family) instead of
circular, everywhere a line id is known — stop sheet, search results,
search peek, disruption chips and rows
- search: lines match on longName too ("Grenoble Chambery" finds the
TER C1) and the row shows the full route name under the badge; match
ranking considers the subtitle
- map: synthetic geometries render dashed via the existing dashed
property expression, so a station-resolution polyline never reads as
the real track; SNCF lines stay out of ALWAYS_VISIBLE_IDS (too long a
range for a wide viewport)
- vehicle cursors: trains interpolate at rail speed (70 km/h) instead of
bus speed
- Room v6: lines gains longName and syntheticGeometry, migrated in place
with absent-value defaults so existing installs keep working
PublishedGeometry.synthetic and both new LineEntity columns are optional
with defaults, so a v2 payload still parses and imports cleanly.
|
||
|---|---|---|
| .forgejo | ||
| app | ||
| docs/superpowers | ||
| gradle | ||
| scripts | ||
| .gitignore | ||
| build.gradle.kts | ||
| CLAUDE.md | ||
| gradle.properties | ||
| gradlew | ||
| LICENSE | ||
| README.md | ||
| settings-gradle.lockfile | ||
| 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