Skip to content

Migrate to Kotlin DSL, Compose, and modern Android stack#209

Open
codebutler wants to merge 100 commits intomasterfrom
claude/update-android-dependencies-87n3T
Open

Migrate to Kotlin DSL, Compose, and modern Android stack#209
codebutler wants to merge 100 commits intomasterfrom
claude/update-android-dependencies-87n3T

Conversation

@codebutler
Copy link
Owner

Summary

This is a major modernization of the FareBot build system and Android codebase. The project has been migrated from Groovy-based Gradle to Kotlin DSL, updated to use Jetpack Compose for UI, and upgraded all dependencies to current versions. The build now uses Koin for dependency injection instead of Dagger, and Kotlinx Serialization instead of Gson.

Key Changes

Build System & Dependencies

  • Migrated build.gradlebuild.gradle.kts (Kotlin DSL)
  • Removed dependencies.gradle and inlined dependency management
  • Updated Android Gradle Plugin from 3.5.0-alpha13 to 8.8.0
  • Updated Kotlin from 1.3.31 to 2.1.20
  • Updated compile/target SDK from 28 to 35, minSdk to 21
  • Updated Java source/target compatibility from 1.7 to 17
  • Removed Fabric/Crashlytics integration (replaced with simple logging)
  • Removed jcenter() repository (deprecated)
  • Added Compose Gradle plugin and Compose BOM

Dependency Injection

  • Replaced Dagger with Koin for simpler, more maintainable DI
  • Created AndroidModule.kt with all Android-specific bindings
  • Refactored FareBotApplication to use Koin's startKoin()
  • Removed generated DaggerFareBotApplicationComponent

Serialization

  • Replaced Gson with Kotlinx Serialization
  • Created KotlinxCardKeysSerializer for card key serialization
  • Updated all card/transit classes to use Instant instead of java.util.Date

UI & Platform

  • Added Jetpack Compose support with Material 3
  • Created AndroidPlatformActions for platform-specific operations (clipboard, file picker, NFC settings, etc.)
  • Updated sample cards to use StringResource abstraction instead of Android Context
  • Refactored NfcStream to use Kotlin Flow for reactive tag events

Manifest & Configuration

  • Removed package attribute from AndroidManifest (now in build.gradle.kts namespace)
  • Added android:exported="true" to activities (required for API 31+)
  • Removed Fabric API key metadata
  • Updated farebot-android/build.gradle.kts with modern Android DSL

Documentation

  • Added comprehensive CLAUDE.md with proxy configuration guide for authenticated HTTP proxy environments
  • Includes troubleshooting section for common Gradle/proxy issues

Cleanup

  • Removed .gitmodules (nfc-felica-lib submodule)
  • Added .kotlin to .gitignore
  • Removed deprecated Fabric/Crashlytics dependencies

Notable Implementation Details

  • Proxy Configuration: The new CLAUDE.md documents a sophisticated local proxy setup for environments behind authenticated HTTP proxies, with health checks and credential rotation support
  • Kotlin Multiplatform Ready: The DI and serialization layers are now structured to support future multiplatform expansion
  • Compose Integration: Full Compose support with Material 3, navigation, and lifecycle integration
  • Coroutines: Integrated Kotlin Coroutines for async operations (NFC, database, etc.)
  • SQLDelight: Migrated to SQLDelight 2.1.0 for type-safe database access

https://claude.ai/code/session_016GBryRuV3PUzuQhuW2gArG

codebutler and others added 30 commits February 5, 2026 08:53
…P 9.0

Convert the entire build system from Groovy to Kotlin DSL. Add a Gradle
version catalog (libs.versions.toml) for centralized dependency management.
Update all dependencies to latest stable versions.

Key version changes:
- Kotlin: 2.3.0
- Android Gradle Plugin: 9.0.0
- Compose Multiplatform: 1.10.0
- kotlinx-serialization: 1.10.0
- kotlinx-coroutines: 1.10.2
- kotlinx-datetime: 0.7.1
- SQLDelight: 2.2.1
- Koin: 4.1.1
- Compile SDK: 35, Min SDK: 23
…restructure

Migrate all core modules to Kotlin Multiplatform with commonMain/androidMain/iosMain
source sets. Convert all remaining Java files to Kotlin. Absorb nfc-felica-lib
submodule into farebot-card-felica.

Major changes:
- farebot-app renamed to farebot-android
- Replace Hilt DI with Koin (cross-platform)
- Replace Gson with kotlinx.serialization
- Replace custom ByteArray wrapper with kotlin.ByteArray + extension functions
- Remove Room, use SQLDelight for cross-platform persistence
- Add MDST (Metrodroid Station Data Table) reader for protobuf station databases
- Add NFC abstraction layer for KMP readiness (CardTransceiver, NfcTechnology)
- Add StringResource abstraction for cross-platform string formatting
- Add TransitCurrency, TransitBalance, Transaction, TransactionTrip abstractions
- Add MDST station databases (38 files) for worldwide transit station lookups
- Add 220+ tests across 29 test files
Ported from Metrodroid (https://github.com/metrodroid/metrodroid)
to Kotlin Multiplatform.

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
Ported from Metrodroid (https://github.com/metrodroid/metrodroid)
to Kotlin Multiplatform.

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
Ported from Metrodroid (https://github.com/metrodroid/metrodroid)
to Kotlin Multiplatform.

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
Ported from Metrodroid (https://github.com/metrodroid/metrodroid)
to Kotlin Multiplatform.

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
For transit systems where only the card serial number can be read,
with a reason code (LOCKED, NOT_STORED, MORE_RESEARCH_NEEDED).

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
Shared framework for ERG-based transit systems (used by Australian
and New Zealand systems like Opal, SmartRider, seq:go).

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
Shared framework for Cubic Nextfare-based transit systems.

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
codebutler and others added 26 commits February 5, 2026 21:25
Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Wilbert Duijvenvoorde <w.a.n.duijvenvoorde@gmail.com>
Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
…Zealand)

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Michael Farrell <micolous+git@gmail.com>
New farebot-shared module with cross-platform UI shared between Android
and iOS:

- Compose Multiplatform screens: Home, History, Card Details, Keys,
  Settings, Help, Trip Map
- MVVM architecture with StateFlow and SharedFlow
- Jetpack Navigation with typed routes
- Koin dependency injection (sharedModule)
- Card artwork drawables for all supported transit systems
- Comprehensive string resources
Xcode project for the iOS app using Compose Multiplatform for shared UI.

- Swift entry point with ComposeView bridge
- CoreNFC integration for reading transit cards
- iOS NFC abstractions: IosCardTransceiver, IosNfcFTechnology
- App entitlements for NFC tag reading
- Bundled FeliCa station database
- CLAUDE.md: Project rules and development guidelines
- REMAINING-WORK.md: Metrodroid port status tracking
- metrodroid-analysis.md: Comprehensive FareBot vs Metrodroid comparison
- tools/local_proxy.py: Local proxy script for development
Port ISO7816Protocol from Metrodroid for APDU communication with ISO7816-4
cards. Add ISO7816CardReader to read files, records, and balances from
ISO7816 applications (China transit, KSX6924/T-Money).

Update TagReaderFactory (Android) and IosNfcScanner (iOS) to try ISO7816
SELECT BY NAME for known AIDs before falling back to DESFire protocol.
This enables reading balances from China and KSX6924 cards that were
previously always returning zero.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tralia)

DESFire/EN1545-based transit card for Adelaide Metro (buses, trams, trains).
Supports trip history, subscriptions, purse balance display, and serial number.
Also registers Pisa and Venezia Ultralight transit factory variants.

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…fik)

Multi-operator MIFARE Classic framework for Scandinavian transit cards.
Supports Rejsekort (Denmark), SL Access (Stockholm), and Västtrafik (Gothenburg).
Full trip history, purse balance, subscription parsing, and multi-leg trip support.

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add JVM compilation target for all KMP modules with SQLDelight SQLite
driver. Improve test asset loading on iOS (read from source tree instead
of NSBundle). Remove skippable test guards in favor of proper assertions.
Add string resources for Japan IC cards to TestStringResource. Remove
obsolete felica_stations.db3 from Xcode project.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend FlipperNfcParser to handle Mifare DESFire and FeliCa card dumps
in addition to Classic and Ultralight. Add integration tests with sample
Flipper dump files for Clipper (DESFire), ORCA (DESFire), and Japanese
IC cards (FeliCa: ICOCA, PASMO, Suica).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use safe casts (as?) for DESFire file reads in Clipper to handle locked
or unreadable files gracefully. Fix EasyCard timestamp parsing to treat
raw values as Taipei local time rather than UTC. Update EasyCard test
station name expectations to match MDST database values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full rewrite of Helsinki transit card support to use the EN1545
framework. Adds V1, V2, and Waltti variant detection and parsing.
New files: HSLTransaction, HSLArvo (value tickets), HSLKausi (season
passes), HSLLookup (zone/area names), HSLVariant (variant enum).
HSL Ultralight factory now imports shared code from farebot-transit-hsl
instead of duplicating ~300 lines. Adds Oulu/Lahti Waltti zones, MDST
region lookup, proper pluralization, and purchase date display.

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full rewrite of Dutch OV-chipkaart support to use the EN1545 framework.
OVChipTransaction and OVChipSubscription now extend En1545Transaction
and En1545Subscription respectively. New OvcLookup provides MDST station
lookup with agency-based station IDs and 25 Dutch subscription names.
Trip deduplication uses TransactionTripLastPrice.merge(). Adds autocharge
info, banned status, and BCD birthdate display. Removes 6 legacy helper
files (OVChipParser, OVChipPreamble, OVChipCredit, OVChipInfo,
OVChipUtil, OVChipTrip) replaced by EN1545 framework.

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace Snapper serial-only stub with full KSX6924 implementation.
Adds NZD balance reading, trip parsing with tap-on/tap-off merging
(paired SFI 3+4 records via TransactionTrip.merge()), and purse info
display. New files: SnapperTransaction (extends Transaction with journey
grouping), SnapperPurseInfoResolver (issuer mapping). Move Snapper
registration after KROCAP for correct KSX6924 detection ordering.

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
KMT: Display transaction counter and last transaction amount in card
info, matching Metrodroid. SeqGo: Add system code verification in
factory check(), pass refills to SeqGoTransitInfo constructor.

Ported from Metrodroid (https://github.com/metrodroid/metrodroid)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document file-by-file audit of all 66 FareBot transit modules against
their Metrodroid counterparts. 63 modules pass faithfully, 2 have
acceptable minor differences (Clipper extra enhancement, Manly legacy
ERG architecture). All previously identified FAIL and KNOWN LIMITATION
items have been resolved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace smoke tests with exact assertions on balances, trip counts,
fares, modes, timestamps, station names, agency names, and route names
for all 5 Flipper card dumps (ORCA, Clipper, Suica, PASMO, ICOCA).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move each ultralight factory to live alongside its parent transit system:
- Troika UL -> farebot-transit-troika
- HSL UL -> farebot-transit-hsl
- OVChip UL -> farebot-transit-ovc
- Pisa/Venezia UL -> farebot-transit-calypso
- Amiibo -> new farebot-transit-amiibo module
- Blank/Locked UL + MRT -> farebot-transit-serialonly
- Blank/Unauthorized Classic/DESFire -> farebot-transit-serialonly

Net -1 module (deleted 2, created 1).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse EMV BER-TLV tags from NDEF payload and display additional card
fields (full PAN, issuer country, expiration/effective dates, interchange
control, Kyiv Digital UID) matching Metrodroid's PiletTransitData.TAG_MAP.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Myki: extend SerialOnlyTransitInfo with Reason.LOCKED, add moreInfoPage URL
- LAX TAP: add onlineServicesPage URL
- SeqGo: add moreInfoPage and onlineServicesPage URLs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add architectural differences table, document resolved Pilet, Myki,
LaxTap, SeqGo, MRT Ultralight, and Subscription findings. Add transit
system coverage table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codebutler codebutler force-pushed the claude/update-android-dependencies-87n3T branch from 09a4ebf to 1292b12 Compare February 6, 2026 17:48
codebutler and others added 3 commits February 6, 2026 13:06
Replace legacy record parsing with ERG base classes, matching the
CHC Metrocard pattern. ManlyFastFerryTransitInfo now extends ErgTransitInfo,
ManlyFastFerryTrip extends ErgTrip, and ManlyFastFerryRefill extends ErgRefill.

Deleted 6 redundant record classes that duplicated ERG framework logic.
Added agency ID 0x0227 check for proper card detection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add missing Metrodroid test coverage:
- Suica: Hayakaken/NIMOCA card detection with full service ID sets,
  ambiguous service ID edge case (falls back to Japan IC)
- EasyCard: route name assertion (Bannan line), Chinese locale test
- Myki: DESFire application ID verification (4594, 15732978)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Station.Builder only accepted a single lineName(), so all 11 call sites
using .lineName(result.lineNames.firstOrNull()) silently discarded
multi-line station data from MDST. This broke Trip.getRouteName() which
relies on finding common lines between start/end stations.

Fix: Replace Builder.lineName(String?) with Builder.lineNames(List<String>)
and update all 11 call sites to pass the full list.

Also fix MdstStationLookup.getStation() to prefer short line names
(matching Metrodroid's selectBestName(isShort=true) for lines), so
e.g. EasyCard shows "Red" instead of "Tamsui-Xinyi".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant