Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ private fun wireClicks(
cb.onMapClick(GeoPoint(latLng.latitude, latLng.longitude))
}

map.setOnMapLongClickListener { latLng ->
cb.onMapLongClick(GeoPoint(latLng.latitude, latLng.longitude))
}

map.setOnMarkerClickListener { marker -> routeMarkerTap(marker, renderer, infoWindows, cb) }

map.setOnInfoWindowClickListener { marker ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ interface ObaMapCallbacks {

fun onMapClick(point: GeoPoint?)

/** A long-press on the map at [point] — the host offers "directions from/to here". */
fun onMapLongClick(point: GeoPoint) {}

fun onBikeClick(station: BikeStation)

/** A vehicle marker tap — the host selects it (e.g. to show its most-recent-data marker). */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import org.onebusaway.android.ui.arrivals.ArrivalsUiState
import org.onebusaway.android.ui.nav.ReminderEditorArgs
import org.onebusaway.android.map.RouteHeader
import org.onebusaway.android.map.MapViewModel
import org.onebusaway.android.map.render.GeoPoint
import org.onebusaway.android.ui.arrivals.ArrivalsViewModel
import org.onebusaway.android.ui.compose.ListUiState
import org.onebusaway.android.ui.compose.findActivity
Expand All @@ -85,6 +86,7 @@ import org.onebusaway.android.ui.home.chrome.MAP_TOP_CHROME_CLEARANCE
import org.onebusaway.android.ui.home.chrome.MapTopChrome
import org.onebusaway.android.ui.home.chrome.mapTopChromeOverlayInset
import org.onebusaway.android.ui.home.directions.DirectionsFormCard
import org.onebusaway.android.ui.home.directions.DirectionsLongPressMenu
import org.onebusaway.android.ui.home.directions.DirectionsMessageCard
import org.onebusaway.android.ui.home.directions.DirectionsPickOverlay
import org.onebusaway.android.ui.home.directions.DirectionsPickTarget
Expand Down Expand Up @@ -551,6 +553,8 @@ fun HomeScreen(
val directionsLoading = tripPlanResult is PlanResult.Loading
// Which endpoint (if any) is being picked directly on the map (crosshair + confirm).
var pickTarget by rememberSaveable { mutableStateOf<DirectionsPickTarget?>(null) }
// A long-pressed map point awaiting the "directions from/to here" choice.
var longPressPoint by remember { mutableStateOf<GeoPoint?>(null) }
// Leaving directions ends any in-progress map pick.
LaunchedEffect(directionsActive) { if (!directionsActive) pickTarget = null }
// While planning but not yet submittable (no results), clear any stale drawn itinerary.
Expand Down Expand Up @@ -580,6 +584,7 @@ fun HomeScreen(
mapViewModel = mapViewModel,
homeViewModel = homeViewModel,
fabBottomInset = fabInsetTarget,
onMapLongPress = { longPressPoint = it },
modifier = Modifier.fillMaxSize(),
)
// The floating top chrome + the map overlays draw over the (now edge-to-edge) map.
Expand Down Expand Up @@ -706,6 +711,24 @@ fun HomeScreen(
onCancel = { pickTarget = null },
)
}
// Long-press → "directions from/to here": enters directions and fills the endpoint
// with the pressed point (which auto-plans once both endpoints are set).
longPressPoint?.let { point ->
val mapPoint = TripEndpoint.MapPoint(point.latitude, point.longitude)
DirectionsLongPressMenu(
onFromHere = {
homeViewModel.enterDirections(mapViewModel.viewport)
tripPlanViewModel.setFrom(mapPoint)
longPressPoint = null
},
onToHere = {
homeViewModel.enterDirections(mapViewModel.viewport)
tripPlanViewModel.setTo(mapPoint)
longPressPoint = null
},
onDismiss = { longPressPoint = null },
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import android.content.Context
import android.text.format.DateFormat
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
Expand All @@ -37,13 +38,17 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Place
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
Expand Down Expand Up @@ -238,6 +243,35 @@ fun DirectionsResultsSheet(
}
}

/**
* The modal menu shown when the user long-presses the map: "directions from here" / "directions to
* here", each of which enters directions focus and fills that endpoint with the pressed point.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DirectionsLongPressMenu(
onFromHere: () -> Unit,
onToHere: () -> Unit,
onDismiss: () -> Unit,
) {
ModalBottomSheet(onDismissRequest = onDismiss) {
Column(Modifier.navigationBarsPadding()) {
ListItem(
headlineContent = { Text(stringResource(R.string.directions_from_here)) },
leadingContent = {
Icon(painterResource(R.drawable.ic_my_location), contentDescription = null)
},
modifier = Modifier.clickable(onClick = onFromHere),
)
ListItem(
headlineContent = { Text(stringResource(R.string.directions_to_here)) },
leadingContent = { Icon(Icons.Default.Place, contentDescription = null) },
modifier = Modifier.clickable(onClick = onToHere),
)
}
}
}

/**
* A compact message over the map for the non-results plan states — a plan error or an empty result
* (e.g. endpoints outside the transit network). Sits where the results sheet would be so the user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
Expand Down Expand Up @@ -124,10 +125,14 @@ fun MapFeature(
// The sheet-driven FAB lift, computed by HomeScreen from its live SheetState (the map composes only
// when HOME is the destination, so this lives with the sheet rather than round-tripping the VM).
fabBottomInset: Dp,
// A long-press on the map surfaces the "directions from/to here" menu; HomeScreen owns that state.
onMapLongPress: (GeoPoint) -> Unit = {},
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val resources = LocalResources.current
// Keep the remembered ObaMapCallbacks calling HomeScreen's latest long-press handler.
val currentOnMapLongPress by rememberUpdatedState(onMapLongPress)

// Compose-native permission launcher: deliver the result to the map view model (blue dot) + the
// home view model (the deferred first-launch region check).
Expand Down Expand Up @@ -165,6 +170,10 @@ fun MapFeature(
homeViewModel.unfocusMapOneLevel()
}

override fun onMapLongClick(point: GeoPoint) {
currentOnMapLongPress(point)
}

override fun onBikeClick(station: BikeStation) {
val bikeId = homeViewModel.currentFocus.value.focusedBikeStationId
if (bikeId == null || !bikeId.equals(station.id, ignoreCase = true)) {
Expand Down
2 changes: 2 additions & 0 deletions onebusaway-android/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,8 @@
<string name="trip_plan_pick_on_map">Pick location on map</string>
<string name="trip_plan_use_this_location">Use this location</string>
<string name="trip_plan_map_location">Selected location</string>
<string name="directions_from_here">Directions from here</string>
<string name="directions_to_here">Directions to here</string>
<string name="trip_plan_clear_endpoint">Clear</string>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@ private fun wireClicks(
callbacks.onMapClick(null)
false
}
map.addOnMapLongClickListener { point ->
callbacks.onMapLongClick(GeoPoint(point.latitude, point.longitude))
true
}
map.setOnMarkerClickListener { tapped ->
// A tap on the ping ripple routes through to the vehicle it's centered on (maplibre classic markers
// can't be made non-interactive like Google's Circle), so it doesn't swallow the vehicle tap (#1764).
Expand Down