Skip to content

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 7 commits February 6, 2026 11:02
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 22 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>
Port Metrodroid's TroikaHybridTransitData to detect and parse combined
Troika+Podorozhnik and Troika+Strelka cards as a unified composite view,
showing trips, balances, and info from all card systems together.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete dead code that has been superseded by the shared KMP module:
analytics, sample data, card key serializers, preference activity,
string resource wrapper, and Kotlin utility extensions. Remove
Android-only card images (moved to shared composeResources), legacy
drawable XML icons, localized string files, dimension/style/plural
resources, and the OVChipkaart README.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ~95 card images to shared composeResources for transit systems
worldwide, including cards from Russia, France, China, New Zealand,
Australia, and many other regions. Images include PNG, JPEG, and SVG
formats sourced from Metrodroid.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move transit factory registration from platform-specific files into a
shared createTransitFactoryRegistry() builder in commonMain. This
eliminates the duplicated factory lists in Android's
TransitFactoryRegistry and iOS's MainViewController, replacing them
with a single source of truth that filters by supported card types.

Also simplify AndroidCardScanner to use Json directly instead of the
removed CardKeysSerializer abstraction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Redesign CardInfo to use StringResource references (nameRes, locationRes)
instead of pre-resolved strings, add serialOnly flag, GPS coordinates
(latitude/longitude), and remove iOS-specific fields.

Enhance TransitRegion with flag emoji support, device-aware sorting
that prioritizes the user's country, and add Qatar as a region. Update
CardInfoRegistry to deduplicate by nameRes and remove the
allCardsAlphabetical accessor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate all transit factory CARD_INFO companion objects to use the new
nameRes/locationRes/extraNoteRes fields instead of hardcoded strings.
Affected factories: Clipper, EasyCard, Octopus, Opal, ORCA, Suica,
and RKF (SLaccess/Rejsekort/Vasttrafikkortet).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the 25-card hardcoded SupportedCardInfo list with a
comprehensive 120+ CardInfo catalog covering transit systems across
40+ countries, with GPS coordinates and card images for each entry.

Redesign the Help screen to group cards by country with sticky headers
and flag emoji, support filtering by device-compatible card types,
show/hide unsupported cards via overflow menu, and prioritize the
user's country region. Pass supportedCardTypes set and deviceRegion
through the app and platform layers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a new CardsMapScreen accessible from the Help screen toolbar that
displays all supported transit cards as markers on a world map using
their GPS coordinates. Includes platform-specific map implementations
for Android (Google Maps), iOS (MapKit), and a JVM placeholder.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite README.md with platform compatibility table, full supported
cards list organized by region, architecture overview, and build
instructions for the KMP project. Add TODO.md for tracking remaining
work, TODO-flipper-dumps.md for Flipper NFC dump integration notes,
and iosApp/RENAME-PLAN.md for the iOS project rename plan.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete the Android-specific TransitFactoryRegistry.kt that was
superseded by the shared TransitFactoryRegistryBuilder.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keys are exclusively used for MIFARE Classic sector authentication —
no other card type has key infrastructure in either FareBot or
Metrodroid. Make onNavigateToKeys nullable and only show the menu
item when MifareClassic is in the supported card types set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All settings toggles were dead code — values were saved but never read.
The only functional usage (appSettings.region for sorting supported cards
by proximity) is replaced with a simple expect/actual getDeviceRegion()
function. This removes ~800 lines of dead code including SettingsScreen,
SettingsViewModel, AppSettings (all platforms), RawLevel, and ~30 pref_*
string resources.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ary null assertions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the splash-based home screen with a two-tab layout (Scan |
Explore) and a floating action button for NFC scanning. Embed history
and supported cards as tab content, add an inline map with search and
region-based pan/zoom to the Explore tab, and connect the locked card
error dialog to the Add Key screen with pre-filled card data. Remove
unused standalone History, Help, and CardsMap screens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Aligns the iOS module naming with the farebot-* convention used by all
other modules (farebot-android, farebot-shared, etc.).

- Rename iosApp/ → farebot-ios/, iosApp/iosApp/ → farebot-ios/FareBot/
- Rename iosApp.entitlements → FareBot.entitlements
- Update project.yml target name, sources, and paths
- Regenerate Xcode project via xcodegen
- Update Makefile references
- Update CLAUDE.md module listing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The persist module was tiny (2 interfaces, 2 implementations, 2 models,
2 SQL schemas) and only consumed by farebot-shared and farebot-android.
Since farebot-shared already exported it via api(), the separate module
added complexity without benefit.

- Move all source files and SQLDelight schemas into farebot-shared
- Add sqldelight plugin and driver dependencies to farebot-shared
- Remove farebot-app-persist from settings.gradle.kts and build files
- Package names unchanged (com.codebutler.farebot.persist)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tapping a card with a sample dump in the Explore tab now parses and
displays its transit info (balance, trips, subscriptions) without
saving to history. Includes 14 bundled dump files (Flipper .nfc,
Metrodroid JSON, and binary .mfc) for Clipper, ORCA, Suica, PASMO,
ICOCA, EasyCard, Opal, HSL, Troika, TMoney, EZLink, Mobib, and Holo.

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