A jeepney fare calculator for Philippine commuters.
A Kotlin Multiplatform (Android + iOS) app that computes jeepney fares from the official LTFRB fare matrix — pick your pick-up and drop-off on a map (or type the distance), say which fare you qualify for, and see the full breakdown so you know exactly what you should be paying.
It is built for the person riding the jeep, not the one driving it: you pick your own fare type once and the receipt leads with your fare. Paying for other people is possible but optional and tucked away, so the app never reads like a conductor's tally sheet.
-
Traditional & Modern PUJ rates — LTFRB fare matrix effective March 19, 2026:
Base fare (first 4 km) Per succeeding km Traditional ₱14.00 ₱2.00 Modern ₱17.00 ₱2.40 -
Map picker — tap your pick-up and drop-off on a MapLibre map (OpenFreeMap tiles, no API key); route distance comes from the public OSRM router, with a straight-line ×1.3 estimate as offline fallback.
-
Manual distance entry — no signal? Type the kilometers directly.
-
Your fare type — pick Regular / Student / Senior / PWD once; the 20% discount is applied automatically.
-
Optional companions — covering someone else's fare? Add up to 8 riders per fare type; otherwise the app assumes you're riding alone.
-
Itemized breakdown — base fare, extra kilometers × rate, discounts, and your own line on the receipt, so overcharging is easy to spot.
-
Receipt as a picture — share or download the resibo as a PNG of exactly what is on screen; downloads land in
Pictures/Pamasaheon Android and in Photos on iOS. -
Motion that explains itself — screens push and pop, the segmented pill slides between options, companion rows unfold, and the resibo rises into place when a fare is ready. All specs live in one file,
Motion.kt. -
English UI
| Layer | Library |
|---|---|
| UI (shared) | Compose Multiplatform 1.10.3 |
| Maps | maplibre-compose 0.13.0 |
| Networking | Ktor 3.5.1 |
| Routing | OSRM public demo server |
| Language | Kotlin 2.3.21 |
All fare logic lives in commonMain (ph.jeepfare.domain) as pure functions
with unit tests in commonTest — shared unchanged between Android and iOS.
Every push to main triggers the Release APK workflow,
which runs the unit tests, builds the signed APKs, and publishes them on the
Releases page — grab the
arm64-v8a APK for a modern phone.
./gradlew :composeApp:assembleDebug # debug APK
./gradlew :composeApp:assembleRelease # release APKs (per-ABI + universal)
./gradlew :composeApp:testDebugUnitTest # unit testsAPKs land in composeApp/build/outputs/apk/. Release builds are signed with
the checked-in self-signed keystore (keystore/pamasahe.jks, passwords in
composeApp/build.gradle.kts) — good enough for sideloading; generate your own
keystore before publishing anywhere.
Note: MapLibre Android 13 renders with Vulkan, and its manifest marks
Vulkan 1.0 as required — fine for sideloading, but it filters out pre-2017
non-Vulkan devices on Google Play. If you need those devices, switch to the
org.maplibre.gl:android-sdk-opengl fallback per the
maplibre-compose docs.
Requires macOS + Xcode. Open iosApp/iosApp.xcodeproj and run; the build phase
compiles the Kotlin framework via
./gradlew :composeApp:embedAndSignAppleFrameworkForXcode, and the MapLibre
native framework is pulled in via Swift Package Manager. The iOS target has no
app icon asset catalog yet — add one in Xcode before shipping.
When the LTFRB adjusts fares, edit the single table in
FareRules.kt
and update the tests. Rounding conventions (nearest ₱0.25, per-started-km
charging) are named constants in the same file.
Fare sources: LTFRB fare hike, March 2026 — Rappler, Philippine News Agency.
Fares shown are computed from the published fare matrix and the measured route distance; actual conductor fares may vary with the route's official distance matrix. Not affiliated with the LTFRB.