feat: display selected route more prominently
This commit is contained in:
parent
81cdfcc9c5
commit
7281f6e1ba
2 changed files with 94 additions and 6 deletions
|
|
@ -15,6 +15,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
|||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SearchBarDefaults
|
||||
import androidx.compose.material3.SheetValue
|
||||
import androidx.compose.material3.rememberBottomSheetScaffoldState
|
||||
import androidx.compose.material3.rememberStandardBottomSheetState
|
||||
|
|
@ -126,13 +127,13 @@ fun App() {
|
|||
|
||||
LaunchedEffect(route) {
|
||||
val route = route
|
||||
polylines.clear()
|
||||
if (route == null)
|
||||
return@LaunchedEffect
|
||||
val geoRoute = ptvService.route(route.routeId, true)
|
||||
val colour = route.routeType.getProperties().colour
|
||||
|
||||
val allPoints = mutableListOf<Point>()
|
||||
polylines.clear()
|
||||
geoRoute.geopath.forEach { pp ->
|
||||
// TODO: use gtfs colours
|
||||
pp.paths.forEach { sp ->
|
||||
|
|
@ -159,6 +160,7 @@ fun App() {
|
|||
var stop by remember { mutableStateOf<PtvStop?>(null) }
|
||||
var markers by remember { mutableStateOf(listOf<Marker>()) }
|
||||
LaunchedEffect(route) {
|
||||
markers = listOf()
|
||||
route?.let { route ->
|
||||
markers = buildStops(ptvService, route) {
|
||||
stop = it
|
||||
|
|
@ -196,7 +198,9 @@ fun App() {
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
newCameraPosition = newCameraPosition,
|
||||
cameraPositionUpdated = { newCameraPosition = null },
|
||||
extInsets = WindowInsets(top = with(LocalDensity.current) { 56.dp.roundToPx() }, bottom = extInsets),
|
||||
extInsets = WindowInsets(top = with(LocalDensity.current) {
|
||||
SearchBarDefaults.InputFieldHeight.roundToPx()
|
||||
}, bottom = extInsets),
|
||||
markers = markers,
|
||||
polylines = polylines,
|
||||
)
|
||||
|
|
@ -208,6 +212,7 @@ fun App() {
|
|||
if (it)
|
||||
scope.launch { scaffoldState.bottomSheetState.hide() }
|
||||
},
|
||||
route = route,
|
||||
text = searchTextState,
|
||||
onTextChange = { searchTextState = it },
|
||||
onRouteChange = { route = it }
|
||||
|
|
|
|||
|
|
@ -1,17 +1,25 @@
|
|||
package moe.lava.banksia.ui
|
||||
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Clear
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
|
@ -21,26 +29,34 @@ import androidx.compose.material3.Text
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.backhandler.PredictiveBackHandler
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import moe.lava.banksia.api.ptv.PtvService
|
||||
import moe.lava.banksia.api.ptv.structures.ComposableIcon
|
||||
import moe.lava.banksia.api.ptv.structures.PtvRoute
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
import kotlin.math.pow
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun Searcher(
|
||||
ptvService: PtvService,
|
||||
expanded: Boolean,
|
||||
onExpandedChange: (Boolean) -> Unit,
|
||||
route: PtvRoute?,
|
||||
text: String,
|
||||
onTextChange: (String) -> Unit,
|
||||
onRouteChange: (PtvRoute) -> Unit,
|
||||
onRouteChange: (PtvRoute?) -> Unit,
|
||||
) {
|
||||
val animatedPadding by animateDpAsState(
|
||||
if (expanded) {
|
||||
|
|
@ -63,13 +79,41 @@ fun Searcher(
|
|||
)
|
||||
}
|
||||
SearchBar(
|
||||
colors = SearchBarDefaults.colors(containerColor = MaterialTheme.colorScheme.surfaceContainer),
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = animatedPadding),
|
||||
shadowElevation = 6.dp, // Elevation level 3
|
||||
inputField = {
|
||||
var backProgress by remember { mutableFloatStateOf(1f) }
|
||||
var backEdgeIsLeft by remember { mutableStateOf<Boolean?>(null) }
|
||||
val boxOpacityState by animateFloatAsState((1f - backProgress).pow(3))
|
||||
val slideState by animateDpAsState((50 * backProgress).dp)
|
||||
val slidePadding = if (backEdgeIsLeft == true)
|
||||
PaddingValues(start = slideState)
|
||||
else if (backEdgeIsLeft == false)
|
||||
PaddingValues(end = slideState)
|
||||
else
|
||||
PaddingValues()
|
||||
|
||||
PredictiveBackHandler(enabled = route != null) { progress ->
|
||||
try {
|
||||
progress.collect { backEvent ->
|
||||
backProgress = backEvent.progress
|
||||
backEdgeIsLeft = backEvent.swipeEdge == 0
|
||||
}
|
||||
backProgress = 1f
|
||||
onRouteChange(null)
|
||||
} catch (_: CancellationException) {
|
||||
backProgress = 0f
|
||||
}
|
||||
backEdgeIsLeft = null
|
||||
}
|
||||
SearchBarDefaults.InputField(
|
||||
enabled = route == null,
|
||||
modifier = Modifier
|
||||
.alpha(1f - boxOpacityState)
|
||||
.padding(horizontal = 20.dp - animatedPadding),
|
||||
query = text,
|
||||
onQueryChange = onTextChange,
|
||||
onSearch = {},
|
||||
|
|
@ -85,6 +129,45 @@ fun Searcher(
|
|||
)
|
||||
}
|
||||
)
|
||||
LaunchedEffect(route) {
|
||||
backProgress = if (route != null) 0f else 1f;
|
||||
}
|
||||
if (route != null) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.alpha(boxOpacityState)
|
||||
.sizeIn(
|
||||
minHeight = SearchBarDefaults.InputFieldHeight,
|
||||
maxHeight = SearchBarDefaults.InputFieldHeight,
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.padding(slidePadding)
|
||||
) {
|
||||
IconButton(
|
||||
modifier = Modifier.align(Alignment.CenterStart),
|
||||
onClick = {
|
||||
onRouteChange(null)
|
||||
}
|
||||
) {
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, "Clear route")
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 50.dp)
|
||||
.align(Alignment.Center),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
route.routeType.ComposableIcon()
|
||||
Spacer(Modifier.width(15.dp))
|
||||
Text(
|
||||
route.routeNumber.ifEmpty { route.routeName },
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
expanded = expanded,
|
||||
onExpandedChange = onExpandedChange,
|
||||
|
|
@ -108,7 +191,7 @@ fun Searcher(
|
|||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 4.dp)
|
||||
.clickable {
|
||||
onTextChange(route.getShortFullName())
|
||||
onTextChange("")
|
||||
onExpandedChange(false)
|
||||
onRouteChange(route)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue