Skip to content

feat: add web (wasmJs) target with FormattedString refactor - #227

Closed
codebutler wants to merge 2 commits into
masterfrom
formatted-string
Closed

feat: add web (wasmJs) target with FormattedString refactor#227
codebutler wants to merge 2 commits into
masterfrom
formatted-string

Conversation

@codebutler

@codebutler codebutler commented Feb 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • FormattedString sealed class — replaces all StringResource/runBlocking/getStringBlocking usage with deferred string resolution (Literal, Resource, Plural, Concat), unblocking the wasmJs target where runBlocking is unavailable
  • wasmJs target — adds Kotlin/Wasm browser target to all KMP modules, with a working web app shell
  • Web app infrastructure — localStorage persistence, file picker import, MDST station lookup, js-joda timezone support
  • WebUSB NFC — PN533 protocol extracted to commonMain; WebUSB transport enables card detection (UID + type) in Chrome/Edge
  • Maps disabled on web — removed Leaflet overlay approach (canvas-based Compose can't host DOM elements reliably)
  • ISO7816 unselectFile() — call before file selector reads to avoid stale file state
  • DESFire auth + hidden app IDs, Ultralight GET_VERSION, iOS multi-system FeliCa workaround

Known limitations (web)

  • No full card reading over WebUSB — only detection (UID + card type) works. Full reading is blocked by sync/async mismatch between CardTransceiver.transceive() and WebUSB's async API
  • MDST resource loading — uses sync XMLHttpRequest; works in dev, needs validation in production build
  • Clipboard read — returns null (browser clipboard API is async); users can import via file picker instead
  • Browser compatibility — WebUSB requires Chrome/Edge/Opera; import + viewing should work elsewhere but is untested
  • Error UX — raw exception when card detection succeeds but reading fails; needs a friendlier message

Test plan

  • ./gradlew allTests
  • ./gradlew :app:web:wasmJsBrowserDistribution builds successfully
  • make web-run — app loads, can import a card JSON and view transit data with station names
  • Android and iOS targets unaffected by FormattedString changes

🤖 Generated with Claude Code

@codebutler codebutler changed the title refactor: replace StringResource/runBlocking with FormattedString sea… refactor: replace StringResource/runBlocking with FormattedString Feb 16, 2026
@codebutler
codebutler force-pushed the formatted-string branch 2 times, most recently from 0e57185 to 4248725 Compare February 16, 2026 16:15
…led class

Introduce FormattedString sealed class (Literal, Resource, Plural, Concat)
to defer string resolution to the UI layer, eliminating all runBlocking and
getStringBlocking usage that blocked the JS event loop on wasmJs.

Key changes:
- All user-facing string fields (cardName, agencyName, routeName,
  stationName, subscriptionName, warning, emptyStateMessage, etc.) now
  return FormattedString instead of String
- Remove StringResource interface, DefaultStringResource, TestStringResource,
  and all getStringBlocking platform actuals
- Remove ObfuscatedTrip and TripObfuscator (unused)
- Update FareBotUiTree/ListItem/HeaderListItem to use FormattedString
- Update all ~100 transit modules to use FormattedString(Res.string.xxx)
- For @serializable types (Station, TransitBalance), use @transient
  formattedName/formattedStationName fields alongside serializable String fields
- Update App.kt, HelpScreen, TripMapScreen, CardViewModel, HistoryViewModel
- Update all test files to use assertFormattedEquals() helper and
  assertResourceEquals() for resource key comparison
- wasmJs and JVM targets compile and tests pass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codebutler codebutler changed the title refactor: replace StringResource/runBlocking with FormattedString feat: add web (wasmJs) target with FormattedString refactor Feb 16, 2026
@codebutler codebutler closed this Feb 16, 2026
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