Skip to content

Migrate MoveNodeFragment speech bubble content to Compose (commonMain)#6797

Open
michaelabon wants to merge 1 commit intostreetcomplete:masterfrom
michaelabon:compose/move-node-form
Open

Migrate MoveNodeFragment speech bubble content to Compose (commonMain)#6797
michaelabon wants to merge 1 commit intostreetcomplete:masterfrom
michaelabon:compose/move-node-form

Conversation

@michaelabon
Copy link
Copy Markdown

@michaelabon michaelabon commented Mar 30, 2026

Summary

Addresses #6796

  • Extract MoveNodeFragment's speech bubble content (title, description, cancel/OK buttons) into a MoveNodeForm composable in commonMain
  • Move MeasureDisplayUnit to commonMain (replace String.format with the project's NumberFormatter expect/actual for locale-aware formatting on both platforms)
  • Fragment wrapper in androidMain keeps arrow drawable, pin positioning, map interfaces, survey confirmation, and edit submission

Approach

The split follows the bottom-up pattern from PR #6022 (BuildingLevelsForm): portable UI in commonMain, platform wrapper in androidMain. The Fragment now passes a MoveNodeDistanceState sealed interface to the composable instead of imperatively updating TextViews and toggling popIn/popOut on the OK button.

No changes to MainActivity, MoveNodeFragment.Listener, or DI wiring.

Test plan

  • Android: ./gradlew assembleDebug compiles cleanly
  • iOS: ./gradlew :app:compileKotlinIosSimulatorArm64 compiles cleanly (with fix branches merged)
  • Manual: open move-node bottom sheet on a POI, verify title updates as map is dragged, OK button appears/disappears at correct distances, cancel and OK actions work as before

Again, I'm very happy to change the approach or anything here, based on your feedback.

MoveNodeFragment's UI is split between Android-specific map interaction
(arrow drawing, pin positioning, screen coordinate conversion) and
portable speech bubble content (title, description, buttons). Only the
latter needs to differ per platform, so extracting it to a shared
composable lets the upcoming iOS port reuse the same UI without
duplicating the layout logic.

MeasureDisplayUnit moves to commonMain because the composable's caller
needs it to format distances. The file is pure Kotlin (kotlin.math +
kotlinx.serialization) with one exception: String.format is unavailable
in Kotlin/Native, so it's replaced with a small formatFixed helper that
produces identical output for the 0/1/2 decimal cases this class uses.

The Fragment wrapper keeps all its existing responsibilities (arrow
drawable, pin marker, IsCloseableBottomSheet/IsMapPositionAware
interfaces, survey confirmation, edit submission) and passes a
MoveNodeDistanceState to the composable instead of imperatively updating
TextViews. No changes to MainActivity or the Listener interface.

Addresses streetcomplete#6796
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