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
10 changes: 10 additions & 0 deletions app/src/main/java/ch/opentransportdata/domain/VehicleOption.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ch.opentransportdata.domain

/**
* Created by Nico Brandenberger on 18.02.2026
*/

data class VehicleOption(
val vehicleType: String,
val isSelected: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@ package ch.opentransportdata.presentation.components

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.SwapCalls
import androidx.compose.material3.*
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import ch.opentransportdata.R
import ch.opentransportdata.presentation.theme.OJPAndroidSDKTheme

/**
Expand All @@ -22,7 +30,8 @@ fun TripResultHeader(
modifier: Modifier = Modifier,
originName: String,
destinationName: String,
swapSearch: () -> Unit
swapSearch: () -> Unit,
onSettingsClick: () -> Unit,
) {

Surface(
Expand All @@ -44,13 +53,25 @@ fun TripResultHeader(
style = MaterialTheme.typography.titleLarge
)
}
OutlinedIconButton(
Row(
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 8.dp),
onClick = swapSearch
) {
Icon(imageVector = Icons.Default.SwapCalls, contentDescription = null)
OutlinedIconButton(
modifier = Modifier,
onClick = onSettingsClick,
) {
Icon(
painter = painterResource(id = R.drawable.ic_settings),
contentDescription = "Filter Option",
)
}
OutlinedIconButton(
onClick = swapSearch
) {
Icon(imageVector = Icons.Default.SwapCalls, contentDescription = null)
}
}
}
}
Expand All @@ -63,7 +84,8 @@ private fun TripResultHeaderPreview() {
TripResultHeader(
originName = "Bern, Eigerplatz",
destinationName = "Basel SBB",
swapSearch = {}
swapSearch = {},
onSettingsClick = {}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import ch.opentransportdata.presentation.utils.toFormattedString
import java.time.Duration
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import kotlin.math.roundToInt

/**
* Created by Michael Ruppen on 12.07.2024
Expand All @@ -75,7 +76,8 @@ fun TripDetailScreen(
requestTripUpdate: (TripDto) -> Unit,
refineTrip: (String) -> Unit,
showMapText: String,
showMap: (String, Boolean) -> Unit
showMap: (String, Boolean) -> Unit,
walkingSpeed: Int,
) {
val scrollState = rememberScrollState()
val timedLegs = trip.legs.mapNotNull { it.legType as? TimedLegDto }
Expand Down Expand Up @@ -148,7 +150,7 @@ fun TripDetailScreen(
when (val legType = leg.legType) {
is TransferLegDto -> {
isZoomed = true
TransferLeg(modifier = Modifier.padding(all = 16.dp), leg = legType)
TransferLeg(modifier = Modifier.padding(all = 16.dp),walkingSpeed = walkingSpeed, leg = legType)
}
is ContinuousLegDto -> {
isZoomed = true
Expand Down Expand Up @@ -468,6 +470,7 @@ private fun ContinuousLeg(
@Composable
private fun TransferLeg(
modifier: Modifier = Modifier,
walkingSpeed: Int,
leg: TransferLegDto
) {
Row(
Expand All @@ -486,6 +489,12 @@ private fun TransferLeg(
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface
)
Text(
modifier = Modifier.padding(start = 4.dp),
text = "Duration ${(leg.duration.toMinutes() / (walkingSpeed / 100.0)).roundToInt()} (min)",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface
)
}
}

Expand Down Expand Up @@ -567,7 +576,8 @@ private fun TripDetailScreenPreview() {
requestTripUpdate = {},
refineTrip = {},
showMapText = "Show way on map",
showMap = {_ , _ ->}
showMap = {_ , _ ->},
walkingSpeed = 100
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package ch.opentransportdata.presentation.tir.filter

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import ch.opentransportdata.domain.VehicleOption

@Composable
fun FilterScreen(
currentWalkingSpeed: Int,
onSelectWalkingSpeed: (Int) -> Unit,
isDirectConnection: Boolean,
onCheckDirectConnection: () -> Unit,
isFewerTransfers: Boolean,
onCheckFewerTransfers: () -> Unit,
vehicleOptions: List<VehicleOption>,
onToggleVehicle: (String) -> Unit,
vehicleSubOptions: List<VehicleOption>,
onToggleSubVehicle: (String) -> Unit,
minDistance: String,
onMinDistanceChange: (String) -> Unit,
maxDistance: String,
onMaxDistanceChange: (String) -> Unit,
minDuration: String,
onMinDurationChange: (String) -> Unit,
maxDuration: String,
onMaxDurationChange: (String) -> Unit,
isBikeTransport: Boolean,
onCheckBikeTransport: () -> Unit,
) {
val selectedWalkingSpeed = remember { mutableIntStateOf(currentWalkingSpeed) }
val walkingSpeedOptions = listOf(50, 75, 100, 150, 200, 400)

Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.padding(horizontal = 12.dp)
) {
Text(text = "Deviation from average walking speed in percent. (100% == average)", textAlign = TextAlign.Center)
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
walkingSpeedOptions.forEach { walkingSpeed ->
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
RadioButton(
modifier = Modifier.size(40.dp),
selected = selectedWalkingSpeed.intValue == walkingSpeed,
onClick = {
onSelectWalkingSpeed(walkingSpeed)
selectedWalkingSpeed.value = walkingSpeed
},
)
Text("${walkingSpeed}%")
}
}
}
OptionItem(
text = "Only direct connections",
isSelected = isDirectConnection,
onClick = {
onCheckDirectConnection()
}
)
OptionItem(
text = "Fewer transfers",
enabled = !isDirectConnection,
isSelected = isFewerTransfers && !isDirectConnection,
onClick = {
onCheckFewerTransfers()
},
)
OptionItem(
text = "Bike Transport",
isSelected = isBikeTransport,
onClick = {
onCheckBikeTransport()
}
)
Text("Select your travel modes")
vehicleOptions.forEach { option ->
OptionItem(
text = option.vehicleType,
isSelected = option.isSelected,
onClick = { onToggleVehicle(option.vehicleType) }
)
}
Text("Select your rail sub mode")
vehicleSubOptions.forEach { option ->
OptionItem(
text = option.vehicleType,
isSelected = if (vehicleOptions.first().isSelected) option.isSelected else false,
enabled = vehicleOptions.first().isSelected,
onClick = { onToggleSubVehicle(option.vehicleType) }
)
}
Text("Select your distance")
Column {
DistanceItem(
text = "Min Distance (meter)",
distance = minDistance,
onValueChange = { onMinDistanceChange(it) }
)
DistanceItem(
text = "Max Distance (meter)",
distance = maxDistance,
onValueChange = { onMaxDistanceChange(it) }
)
}
Text("Select your duration")
Column {
DistanceItem(
text = "Min Duration (min)",
distance = minDuration,
onValueChange = { onMinDurationChange(it) }
)
DistanceItem(
text = "Max Duration (min)",
distance = maxDuration,
onValueChange = { onMaxDurationChange(it) }
)
}
}
}

@Composable
private fun OptionItem(
text: String,
isSelected: Boolean,
enabled: Boolean = true,
onClick: () -> Unit,
) {
ListItem(
headlineContent = {
Text(
text = text,
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onSurface
)
},
trailingContent = {
Switch(
checked = isSelected,
onCheckedChange = { onClick() },
enabled = enabled
)
}
)
}

@Composable
private fun DistanceItem(
text: String,
distance: String,
onValueChange: (String) -> Unit,
) {
ListItem(
headlineContent = {
Text(
text = text,
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onSurface
)
},
trailingContent = {
TextField(
modifier = Modifier.fillMaxWidth(0.5f),
value = distance,
onValueChange = { onValueChange(it) },
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number)
)
}
)
}
Loading
Loading