Skip to content

Tap an itinerary line item to focus the map on that step#1955

Merged
bmander merged 2 commits into
mainfrom
feature/itinerary-step-tap-focus
Jul 19, 2026
Merged

Tap an itinerary line item to focus the map on that step#1955
bmander merged 2 commits into
mainfrom
feature/itinerary-step-tap-focus

Conversation

@bmander

@bmander bmander commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

What

Adds reactivity to the trip planner's directions list: tapping a leaf line item recenters the map on that step's location and zooms to a street-level default. Expandable rows (with a chevron) keep toggling their sub-steps and never move the map — only leaves send-to-map (in practice the walk-leg / board rows expand; their turn-by-turn steps and intermediate stops focus).

How

  • Coordinates through the projection. Each step's point is threaded from the domain legs (TripLeg/TripPlace/TripStep) via DirectionsGenerator/Direction into a single DirectionItem.focusPoint: GeoPoint? (leg endpoint for board/alight/walk rows; each intermediate stop / turn-by-turn step for sub-items).
  • Tap wiring reuses the existing seam. A new onFocusPoint callback rides the same path as the existing itinerary selection: DirectionRowTripResultsSheet/DirectionsResultsSheetHomeViewModel.focusItineraryPointOnMapMapDirective.FocusItineraryPoint(GeoPoint)MapViewModel.focusItineraryPointCameraCommand.MoveToLocation. Reuses the flavor-neutral camera command, so no per-flavor code.
  • Centers within map content padding so the point lands in the visible band, not behind the results sheet or the directions form:
    • The directions form card reports its bottom edge as the map's top inset (folded into focusBannerTopEdge / setFocusBannerBottomEdge).
    • The results sheet reports its height as an independent bottom inset; MapRenderState combines the arrivals and directions bottom insets by max (mirroring applyTopPadding), so neither writer has to assume the two never coexist.
    • Google honors content padding on newCameraPosition automatically; MapLibre folds renderState.padding into the CameraPosition (it ignores persistent map padding on point moves).

Testing

  • New on-device Compose test DirectionRowFocusTest (drives rows by node text, not coordinates): a leaf row focuses its point; an expandable row only expands (asserts no focus) and its revealed leaf sub-step focuses its own point; a point-less row is inert. 3/3 passing on a physical Pixel 7 Pro.
  • Clean launch on device; both obaGoogle and obaMaplibre compile clean under -PwarningsAsErrors=true; JVM unit suite green.

Follow-up

While wiring the padding centering, noticed a pre-existing, separate issue: the route zoom-to that fires on a route request returning doesn't respect map padding (it races the route-header inset). Filed as #1954.


🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Tapping a trip direction now focuses and recenters the map on that step when coordinates are available.
    • Map positioning now accounts for directions UI spacing so focused points stay visible above/below the panels.
    • Directions results provide focus points for walking steps, boarding/alighting stops, and intermediate stops.
  • Bug Fixes
    • Directions steps without coordinates no longer trigger map focusing.
    • Expanding a direction no longer causes unintended map movement.
  • Tests
    • Added UI coverage for direction-row focus and expandable/leaf interaction behavior.

In the trip planner, tapping a leaf line item in the directions list now
recenters the map on that step's location (board/alight stop, walk-leg
endpoint, intermediate stop, or turn-by-turn step), zooming to a street-level
default. Expandable rows (those with a chevron) keep toggling their sub-steps
and never move the map — only leaf rows send-to-map.

The tap rides the existing showItinerary directive seam:
DirectionRow -> onFocusPoint -> HomeViewModel.focusItineraryPointOnMap ->
MapDirective.FocusItineraryPoint -> MapViewModel.focusItineraryPoint ->
CameraCommand.MoveToLocation, reusing the flavor-neutral camera command (no new
per-flavor code). Each step's GeoPoint is threaded from the domain legs through
DirectionsGenerator/Direction into the Compose DirectionItem model.

The focused point is centered within the map's content padding so it lands in
the visible band, not behind the results sheet or the directions form:
- The directions form card reports its bottom edge as the map's top inset
  (folded into focusBannerTopEdge/setFocusBannerBottomEdge).
- The results sheet reports its height as an independent bottom inset;
  MapRenderState combines the arrivals and directions bottom insets by max
  (mirroring applyTopPadding), so neither writer assumes the two never coexist.
- Google honors the content padding on newCameraPosition automatically;
  MapLibre folds renderState.padding into the CameraPosition since it ignores
  persistent map padding on point moves.

Verified on device (DirectionRowFocusTest) and clean on both flavors under
-PwarningsAsErrors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5db1f673-79ba-4d0d-92e5-319a154cdb83

📥 Commits

Reviewing files that changed from the base of the PR and between c92699f and 7eb3789.

📒 Files selected for processing (1)
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/tripresults/TripResultsScreen.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/tripresults/TripResultsScreen.kt

📝 Walkthrough

Walkthrough

The change adds geographic focus points to direction steps, focuses the map when coordinate-bearing itinerary rows are tapped, preserves expansion behavior for parent rows, and measures directions overlays so camera positioning uses combined map padding.

Changes

Itinerary map focus

Layer / File(s) Summary
Direction focus data
onebusaway-android/src/main/java/org/onebusaway/android/directions/..., onebusaway-android/src/main/java/org/onebusaway/android/ui/tripresults/...
Generated directions and DirectionItem mappings now carry nullable geographic focus points for main steps and sub-steps.
Trip-result focus interaction
onebusaway-android/src/main/java/org/onebusaway/android/ui/home/directions/DirectionsFeature.kt, onebusaway-android/src/main/java/org/onebusaway/android/ui/tripresults/TripResultsScreen.kt, onebusaway-android/src/androidTest/.../DirectionRowFocusTest.kt
Focus callbacks flow through the results sheets; leaf rows invoke them, expandable parents retain expansion behavior, and Compose tests cover coordinate-bearing and coordinate-less rows.
Directions overlay insets
onebusaway-android/src/main/java/org/onebusaway/android/ui/home/HomeScreen.kt, HomeSheetLogic.kt, HomeViewModel.kt, MapHost.kt, MapRenderState.kt, MapFeature.kt
Directions form and results-sheet geometry are measured and propagated as a separate inset, combined with arrivals padding using the maximum value.
Map focus camera
onebusaway-android/src/main/java/org/onebusaway/android/map/..., onebusaway-android/src/maplibre/..., onebusaway-android/src/main/java/org/onebusaway/android/ui/home/map/MapFeature.kt
A directions-only map directive recenters itinerary points, and camera commands apply current content padding on supported map implementations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DirectionRow
  participant HomeViewModel
  participant MapFeature
  participant MapViewModel
  participant MapCamera
  DirectionRow->>HomeViewModel: emit focused GeoPoint
  HomeViewModel->>MapFeature: dispatch FocusItineraryPoint
  MapFeature->>MapViewModel: focusItineraryPoint(point)
  MapViewModel->>MapCamera: issue MoveToLocation
  MapCamera->>MapCamera: apply overlay-aware content padding
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 73.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: tapping itinerary items now focuses the map on that step.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/itinerary-step-tap-focus

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@onebusaway-android/src/main/java/org/onebusaway/android/ui/tripresults/TripResultsScreen.kt`:
- Around line 340-341: Update the expanded state declaration in DirectionRow to
key remember with item, ensuring expanded state resets when the row’s underlying
DirectionItem changes while preserving state for the same item.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b3fda9fe-8f84-48a5-80d8-a40d8ea30334

📥 Commits

Reviewing files that changed from the base of the PR and between a7d6217 and c92699f.

📒 Files selected for processing (18)
  • onebusaway-android/src/androidTest/java/org/onebusaway/android/ui/tripresults/DirectionRowFocusTest.kt
  • onebusaway-android/src/google/java/org/onebusaway/android/map/googlemapsv2/compose/GoogleCameraCommands.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/directions/model/Direction.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/directions/util/DirectionsGenerator.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/map/MapHost.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/map/MapViewModel.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/map/render/CameraCommand.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/map/render/MapRenderState.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/home/HomeScreen.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/home/HomeSheetLogic.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/home/HomeViewModel.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/home/directions/DirectionsFeature.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/home/map/MapFeature.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/tripresults/TripResultsRepository.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/tripresults/TripResultsScreen.kt
  • onebusaway-android/src/main/java/org/onebusaway/android/ui/tripresults/TripResultsUiState.kt
  • onebusaway-android/src/maplibre/java/org/onebusaway/android/map/maplibre/compose/MapLibreCameraCommands.kt
  • onebusaway-android/src/maplibre/java/org/onebusaway/android/map/maplibre/compose/MapLibreComposeAdapter.kt

DirectionRows are keyed by index in the LazyColumn, so switching
itineraries reuses a slot for a different DirectionItem. A parameterless
remember let a stale expanded state leak into the new itinerary's row;
key it on the item so it resets on the swap. (PR #1955 review)
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