diff --git a/composeApp/src/androidMain/kotlin/moe/lava/banksia/native/maps/Maps.android.kt b/composeApp/src/androidMain/kotlin/moe/lava/banksia/native/maps/Maps.android.kt index 5ce665b..274ee72 100644 --- a/composeApp/src/androidMain/kotlin/moe/lava/banksia/native/maps/Maps.android.kt +++ b/composeApp/src/androidMain/kotlin/moe/lava/banksia/native/maps/Maps.android.kt @@ -2,17 +2,23 @@ package moe.lava.banksia.native.maps import android.Manifest import android.content.pm.PackageManager +import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.add import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity @@ -28,10 +34,12 @@ import com.google.maps.android.compose.ComposeMapColorScheme import com.google.maps.android.compose.DefaultMapProperties import com.google.maps.android.compose.DefaultMapUiSettings import com.google.maps.android.compose.GoogleMap +import com.google.maps.android.compose.MarkerComposable import com.google.maps.android.compose.Polyline import com.google.maps.android.compose.rememberCameraPositionState +import com.google.maps.android.compose.rememberMarkerState import moe.lava.banksia.R - +import moe.lava.banksia.native.BanksiaTheme fun Point.toLatLng(): LatLng = LatLng(this.lat, this.lng) @@ -97,11 +105,24 @@ actual fun Maps( ), contentPadding = WindowInsets.safeDrawing.add(extInsets).asPaddingValues() ) { + // [TODO]: Slight lag when routes with many stops such as the 901 bus is set for (marker in markers) { - Marker( - name = marker.name, - onClick = marker.onClick - ) + val state = rememberMarkerState() + state.position = marker.point.toLatLng() + MarkerComposable( + keys = arrayOf(marker.colour), + state = state, + title = marker.name, + onClick = { marker.onClick() } + ) { + Box( + modifier = Modifier + .size(12.dp) + .clip(CircleShape) + .background(BanksiaTheme.colors.surface) + .border(2.dp, marker.colour, CircleShape) + ) + } } for (polyline in polylines) { Polyline( diff --git a/composeApp/src/commonMain/kotlin/moe/lava/banksia/App.kt b/composeApp/src/commonMain/kotlin/moe/lava/banksia/App.kt index 3004f54..d65dfb3 100644 --- a/composeApp/src/commonMain/kotlin/moe/lava/banksia/App.kt +++ b/composeApp/src/commonMain/kotlin/moe/lava/banksia/App.kt @@ -37,9 +37,12 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch import moe.lava.banksia.api.ptv.PtvService import moe.lava.banksia.api.ptv.structures.PtvRoute +import moe.lava.banksia.api.ptv.structures.PtvStop import moe.lava.banksia.api.ptv.structures.getProperties import moe.lava.banksia.native.BanksiaTheme import moe.lava.banksia.native.maps.Maps +import moe.lava.banksia.native.maps.Marker +import moe.lava.banksia.native.maps.MarkerType import moe.lava.banksia.native.maps.Point import moe.lava.banksia.native.maps.Polyline import moe.lava.banksia.native.maps.getScreenHeight @@ -147,6 +150,9 @@ fun App() { var peekHeight by remember { mutableStateOf(128.dp) } var peekHeightMultiplier by remember { mutableFloatStateOf(1F) } + var markers by remember { mutableStateOf(listOf()) } + LaunchedEffect(route) { route?.let { markers = buildStops(ptvService, it) {} } } + BanksiaTheme { BottomSheetScaffold( scaffoldState = scaffoldState, @@ -160,6 +166,7 @@ fun App() { newCameraPosition = newCameraPosition, cameraPositionUpdated = { newCameraPosition = null }, extInsets = WindowInsets(top = with(LocalDensity.current) { 56.dp.roundToPx() }, bottom = extInsets), + markers = markers, polylines = polylines, ) Searcher( @@ -208,3 +215,37 @@ fun App() { } } } + +suspend fun buildStops( + ptvService: PtvService, + route: PtvRoute, + launchInfoPanel: (PtvStop) -> Unit, +): List { + var stops = ptvService.stopsByRoute(route.routeId, route.routeType) + var res = mutableListOf() + val colour = route.routeType.getProperties().colour + + for (stop in stops) { + if (stop.stopLatitude != null && stop.stopLongitude != null) { + val pos = Point(stop.stopLatitude!!, stop.stopLongitude!!) + + var name = stop.stopName; + if (name.endsWith(" Station")) + name = name.replace(" Station", "") + + val marker = Marker( + name = name, + point = pos, + type = MarkerType.GENERIC_STOP, + colour = colour, + onClick = { + launchInfoPanel(stop) + false + } + ) + res.add(marker) + } + } + + return res +} diff --git a/composeApp/src/commonMain/kotlin/moe/lava/banksia/native/maps/Maps.kt b/composeApp/src/commonMain/kotlin/moe/lava/banksia/native/maps/Maps.kt index 509174a..1f18bb8 100644 --- a/composeApp/src/commonMain/kotlin/moe/lava/banksia/native/maps/Maps.kt +++ b/composeApp/src/commonMain/kotlin/moe/lava/banksia/native/maps/Maps.kt @@ -6,7 +6,16 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -data class Marker(val name: String, val onClick: () -> Boolean) +enum class MarkerType { + GENERIC_STOP, +} +data class Marker( + val point: Point, + val name: String, + val type: MarkerType, + val colour: Color, + val onClick: () -> Boolean +) data class Point(val lat: Double, val lng: Double) data class Polyline(val points: List, val colour: Color) diff --git a/shared/src/commonMain/kotlin/moe/lava/banksia/api/ptv/PtvService.kt b/shared/src/commonMain/kotlin/moe/lava/banksia/api/ptv/PtvService.kt index 861f34e..22bd3f2 100644 --- a/shared/src/commonMain/kotlin/moe/lava/banksia/api/ptv/PtvService.kt +++ b/shared/src/commonMain/kotlin/moe/lava/banksia/api/ptv/PtvService.kt @@ -14,6 +14,8 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import moe.lava.banksia.Constants import moe.lava.banksia.api.ptv.structures.PtvRoute +import moe.lava.banksia.api.ptv.structures.PtvRouteType +import moe.lava.banksia.api.ptv.structures.PtvStop import moe.lava.banksia.log import okio.ByteString.Companion.encodeUtf8 @@ -22,6 +24,9 @@ object Responses { data class PtvRouteResponse(val route: PtvRoute) @Serializable data class PtvRoutesResponse(val routes: List) + + @Serializable + data class PtvStopsResponse(val stops: List) } class PtvService { @@ -61,4 +66,17 @@ class PtvService { val response: Responses.PtvRoutesResponse = client.get("routes").body() return response.routes } + + suspend fun stopsByRoute(routeId: Int, routeType: PtvRouteType): List { + val response: Responses.PtvStopsResponse = client.get("stops/route") { + url { + appendPathSegments( + routeId.toString(), + "route_type", + routeType.ordinal.toString() + ) + } + }.body() + return response.stops + } } diff --git a/shared/src/commonMain/kotlin/moe/lava/banksia/api/ptv/structures/PtvStop.kt b/shared/src/commonMain/kotlin/moe/lava/banksia/api/ptv/structures/PtvStop.kt new file mode 100644 index 0000000..0fb4b40 --- /dev/null +++ b/shared/src/commonMain/kotlin/moe/lava/banksia/api/ptv/structures/PtvStop.kt @@ -0,0 +1,13 @@ +package moe.lava.banksia.api.ptv.structures + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class PtvStop( + @SerialName("stop_id") val stopId: Int, + @SerialName("stop_name") val stopName: String, + @SerialName("stop_latitude") val stopLatitude: Double?, + @SerialName("stop_longitude") val stopLongitude: Double?, + @SerialName("route_type") val routeType: PtvRouteType, +)