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 30 commits February 10, 2026 06:54
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>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename modules to a consistent farebot-app* family:
- farebot-shared → farebot-app (KMP app framework)
- farebot-android → farebot-app-android (thin Android shell)
- farebot-ios → farebot-app-ios (thin iOS shell)

Move Android platform code (DI, NFC, scanner, platform actions) from
farebot-app-android into farebot-app/androidMain, mirroring how iOS
platform code lives in farebot-app/iosMain. The Android app module
is now a thin shell with just Activities, manifest, and resources.

Remove 60+ redundant farebot-card-*/farebot-transit-* dependencies
from the Android app module since farebot-app exports them via api().

Update generated resource imports (farebot_shared → farebot_app),
Makefile, Xcode project.yml, CLAUDE.md, and README.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Import from Clipboard, Share, and Save menu items are removed from
the home screen. Share/Save remain available on the single card view.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…only on Scan tab

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

- Add Ventra.json sample (from metrodroid#855) and wire up in SupportedCardsData
- Add MetrodroidDumpIntegrationTest with 3 tests: Ventra UL ($8.44 balance),
  Troika Classic E/3 (0 RUB), Troika Classic E/5 (50 RUB)
- Update TODO-flipper-dumps.md with newly discovered GitHub dumps (Venezia UL,
  Andante Blue, Riga E-talons, Mexico City) and mark Ventra/Troika as done
- Remove obsolete TODO.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the broken JSON-transformation approach in CardImporter with a
proper MetrodroidJsonParser that directly constructs RawCard objects from
Metrodroid JSON format. This fixes sample card loading on the Explore
screen and enables integration tests for Metrodroid-format dump files.

The parser handles DESFire, Ultralight, Classic, ISO7816 (with SFI
extraction from FCI), and CEPAS compat format (with pre-parsed card
wrapper for decoded fields).

Integration tests cover: Opal, HSL v2, HSL Ultralight, Troika UL,
T-Money, EZ-Link, Holo, and Mobib.

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

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

Add parseFelica() method to MetrodroidJsonParser supporting FeliCa card
dumps with systems/services/blocks structure. Create Octopus sample dump
from OctopusTransitTest data (system 0x8008, service 0x0117) with
balance verification (-HKD 14.40).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reflect 21 cards now having both Explore samples and integration tests,
including new additions: Compass, SEQ Go, LAX TAP, MSP GoTo, Myki, and
Octopus.

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

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, split keyless from keys-required

Restructures the "dumps still needed" section into clear priority tiers:
- Full implementations (keyless Classic, keys-required Classic, DESFire, FeliCa, etc.)
- Serial-only and preview cards (low priority)
- Suica-compatible variants and low-priority Calypso (lowest priority)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add two new toggle options to the Explore tab menu, matching the
existing "Show unsupported cards" pattern. Serial-only cards and
cards requiring key cracking are hidden by default since most users
can't use them. Cards with built-in keys still show.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nner, translucent Explore top bar

- Move card deletion from history list to card detail screen overflow menu
- Add requiresActiveScan to CardScanner interface (Android=false, iOS=true)
- Show NFC listening banner on Android scan tab instead of scan FAB
- Make Explore tab top bar translucent so map extends behind it
- Pass topPadding to PlatformCardsMap for proper map content insets
- Only show NFC disabled banner on scan tab

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Lift search query state out of ExploreContent so parent can control it
- Search Explore cards by location name in addition to card name
- Track current region by viewport center instead of first visible item
- Keep map visible during search, reduce map height
- Rename Scan tab to Cards, add cards stack icon
- Fix card detail info item layout: add spacer and weight for value text
- Fix iOS file picker: use NSTimer delay for presentation, scene-based
  window API, dispatch result to next run loop after picker dismisses
- Remove unused material-icons-extended Android dependency
- Remove simulator framework build from iOS Makefile target

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