feat: basic stop markers on route
This commit is contained in:
parent
6a5a9b4974
commit
67f18afc01
5 changed files with 108 additions and 6 deletions
|
|
@ -2,17 +2,23 @@ package moe.lava.banksia.native.maps
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.add
|
import androidx.compose.foundation.layout.add
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.safeDrawing
|
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.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
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.DefaultMapProperties
|
||||||
import com.google.maps.android.compose.DefaultMapUiSettings
|
import com.google.maps.android.compose.DefaultMapUiSettings
|
||||||
import com.google.maps.android.compose.GoogleMap
|
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.Polyline
|
||||||
import com.google.maps.android.compose.rememberCameraPositionState
|
import com.google.maps.android.compose.rememberCameraPositionState
|
||||||
|
import com.google.maps.android.compose.rememberMarkerState
|
||||||
import moe.lava.banksia.R
|
import moe.lava.banksia.R
|
||||||
|
import moe.lava.banksia.native.BanksiaTheme
|
||||||
|
|
||||||
fun Point.toLatLng(): LatLng = LatLng(this.lat, this.lng)
|
fun Point.toLatLng(): LatLng = LatLng(this.lat, this.lng)
|
||||||
|
|
||||||
|
|
@ -97,11 +105,24 @@ actual fun Maps(
|
||||||
),
|
),
|
||||||
contentPadding = WindowInsets.safeDrawing.add(extInsets).asPaddingValues()
|
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) {
|
for (marker in markers) {
|
||||||
Marker(
|
val state = rememberMarkerState()
|
||||||
name = marker.name,
|
state.position = marker.point.toLatLng()
|
||||||
onClick = marker.onClick
|
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) {
|
for (polyline in polylines) {
|
||||||
Polyline(
|
Polyline(
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,12 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import moe.lava.banksia.api.ptv.PtvService
|
import moe.lava.banksia.api.ptv.PtvService
|
||||||
import moe.lava.banksia.api.ptv.structures.PtvRoute
|
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.api.ptv.structures.getProperties
|
||||||
import moe.lava.banksia.native.BanksiaTheme
|
import moe.lava.banksia.native.BanksiaTheme
|
||||||
import moe.lava.banksia.native.maps.Maps
|
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.Point
|
||||||
import moe.lava.banksia.native.maps.Polyline
|
import moe.lava.banksia.native.maps.Polyline
|
||||||
import moe.lava.banksia.native.maps.getScreenHeight
|
import moe.lava.banksia.native.maps.getScreenHeight
|
||||||
|
|
@ -147,6 +150,9 @@ fun App() {
|
||||||
var peekHeight by remember { mutableStateOf(128.dp) }
|
var peekHeight by remember { mutableStateOf(128.dp) }
|
||||||
var peekHeightMultiplier by remember { mutableFloatStateOf(1F) }
|
var peekHeightMultiplier by remember { mutableFloatStateOf(1F) }
|
||||||
|
|
||||||
|
var markers by remember { mutableStateOf(listOf<Marker>()) }
|
||||||
|
LaunchedEffect(route) { route?.let { markers = buildStops(ptvService, it) {} } }
|
||||||
|
|
||||||
BanksiaTheme {
|
BanksiaTheme {
|
||||||
BottomSheetScaffold(
|
BottomSheetScaffold(
|
||||||
scaffoldState = scaffoldState,
|
scaffoldState = scaffoldState,
|
||||||
|
|
@ -160,6 +166,7 @@ fun App() {
|
||||||
newCameraPosition = newCameraPosition,
|
newCameraPosition = newCameraPosition,
|
||||||
cameraPositionUpdated = { newCameraPosition = null },
|
cameraPositionUpdated = { newCameraPosition = null },
|
||||||
extInsets = WindowInsets(top = with(LocalDensity.current) { 56.dp.roundToPx() }, bottom = extInsets),
|
extInsets = WindowInsets(top = with(LocalDensity.current) { 56.dp.roundToPx() }, bottom = extInsets),
|
||||||
|
markers = markers,
|
||||||
polylines = polylines,
|
polylines = polylines,
|
||||||
)
|
)
|
||||||
Searcher(
|
Searcher(
|
||||||
|
|
@ -208,3 +215,37 @@ fun App() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun buildStops(
|
||||||
|
ptvService: PtvService,
|
||||||
|
route: PtvRoute,
|
||||||
|
launchInfoPanel: (PtvStop) -> Unit,
|
||||||
|
): List<Marker> {
|
||||||
|
var stops = ptvService.stopsByRoute(route.routeId, route.routeType)
|
||||||
|
var res = mutableListOf<Marker>()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,16 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
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 Point(val lat: Double, val lng: Double)
|
||||||
data class Polyline(val points: List<Point>, val colour: Color)
|
data class Polyline(val points: List<Point>, val colour: Color)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import moe.lava.banksia.Constants
|
import moe.lava.banksia.Constants
|
||||||
import moe.lava.banksia.api.ptv.structures.PtvRoute
|
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 moe.lava.banksia.log
|
||||||
import okio.ByteString.Companion.encodeUtf8
|
import okio.ByteString.Companion.encodeUtf8
|
||||||
|
|
||||||
|
|
@ -22,6 +24,9 @@ object Responses {
|
||||||
data class PtvRouteResponse(val route: PtvRoute)
|
data class PtvRouteResponse(val route: PtvRoute)
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PtvRoutesResponse(val routes: List<PtvRoute>)
|
data class PtvRoutesResponse(val routes: List<PtvRoute>)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PtvStopsResponse(val stops: List<PtvStop>)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PtvService {
|
class PtvService {
|
||||||
|
|
@ -61,4 +66,17 @@ class PtvService {
|
||||||
val response: Responses.PtvRoutesResponse = client.get("routes").body()
|
val response: Responses.PtvRoutesResponse = client.get("routes").body()
|
||||||
return response.routes
|
return response.routes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun stopsByRoute(routeId: Int, routeType: PtvRouteType): List<PtvStop> {
|
||||||
|
val response: Responses.PtvStopsResponse = client.get("stops/route") {
|
||||||
|
url {
|
||||||
|
appendPathSegments(
|
||||||
|
routeId.toString(),
|
||||||
|
"route_type",
|
||||||
|
routeType.ordinal.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.body()
|
||||||
|
return response.stops
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue