Compare commits
8 commits
c4033e1cf2
...
f0ce780bba
| Author | SHA1 | Date | |
|---|---|---|---|
| f0ce780bba | |||
| 72b9fb2757 | |||
| b5f2ec102d | |||
| 8925c943ab | |||
| a79c95829e | |||
| aab03ced07 | |||
| 758f9cea01 | |||
| 2b64fdcda9 |
1
.gitignore
vendored
|
|
@ -20,3 +20,4 @@ captures
|
||||||
secrets.properties
|
secrets.properties
|
||||||
shared/src/commonMain/kotlin/moe/lava/banksia/Constants.kt
|
shared/src/commonMain/kotlin/moe/lava/banksia/Constants.kt
|
||||||
/data/
|
/data/
|
||||||
|
/data
|
||||||
|
|
|
||||||
57
androidApp/build.gradle.kts
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.androidApplication)
|
||||||
|
alias(libs.plugins.composeMultiplatform)
|
||||||
|
alias(libs.plugins.composeCompiler)
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
target {
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget.set(JvmTarget.JVM_11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compilerOptions {
|
||||||
|
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(projects.ui)
|
||||||
|
implementation(libs.androidx.activity.compose)
|
||||||
|
implementation(libs.compose.ui.tooling.preview)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
debugImplementation(libs.compose.ui.tooling)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "moe.lava.banksia"
|
||||||
|
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = "moe.lava.banksia"
|
||||||
|
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||||
|
targetSdk = libs.versions.android.targetSdk.get().toInt()
|
||||||
|
versionCode = 1
|
||||||
|
versionName = "1.0"
|
||||||
|
}
|
||||||
|
packaging {
|
||||||
|
resources {
|
||||||
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
getByName("release") {
|
||||||
|
isMinifyEnabled = false
|
||||||
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,9 +13,6 @@
|
||||||
android:enableOnBackInvokedCallback="true"
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
android:theme="@android:style/Theme.Material.Light.NoActionBar">
|
android:theme="@android:style/Theme.Material.Light.NoActionBar">
|
||||||
<meta-data
|
|
||||||
android:name="com.google.android.geo.API_KEY"
|
|
||||||
android:value="${MAPS_API_KEY}" />
|
|
||||||
<activity
|
<activity
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
|
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
|
||||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -2,7 +2,7 @@ plugins {
|
||||||
// this is necessary to avoid the plugins to be loaded multiple times
|
// this is necessary to avoid the plugins to be loaded multiple times
|
||||||
// in each subproject's classloader
|
// in each subproject's classloader
|
||||||
alias(libs.plugins.androidApplication) apply false
|
alias(libs.plugins.androidApplication) apply false
|
||||||
alias(libs.plugins.androidLibrary) apply false
|
alias(libs.plugins.androidMultiplatformLibrary) apply false
|
||||||
alias(libs.plugins.composeMultiplatform) apply false
|
alias(libs.plugins.composeMultiplatform) apply false
|
||||||
alias(libs.plugins.composeCompiler) apply false
|
alias(libs.plugins.composeCompiler) apply false
|
||||||
alias(libs.plugins.kotlinJvm) apply false
|
alias(libs.plugins.kotlinJvm) apply false
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlinMultiplatform)
|
alias(libs.plugins.kotlinMultiplatform)
|
||||||
alias(libs.plugins.kotlinSerialization)
|
alias(libs.plugins.kotlinSerialization)
|
||||||
alias(libs.plugins.androidLibrary)
|
alias(libs.plugins.androidMultiplatformLibrary)
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
androidTarget {
|
android {
|
||||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
namespace = "moe.lava.banksia.client"
|
||||||
|
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||||
|
|
||||||
compilerOptions {
|
compilerOptions {
|
||||||
jvmTarget.set(JvmTarget.JVM_11)
|
jvmTarget.set(JvmTarget.JVM_11)
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +20,6 @@ kotlin {
|
||||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||||
}
|
}
|
||||||
|
|
||||||
iosX64()
|
|
||||||
iosArm64()
|
iosArm64()
|
||||||
iosSimulatorArm64()
|
iosSimulatorArm64()
|
||||||
|
|
||||||
|
|
@ -41,15 +41,3 @@ kotlin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "moe.lava.banksia.client"
|
|
||||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
|
||||||
}
|
|
||||||
defaultConfig {
|
|
||||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package moe.lava.banksia.client.data.stoptime
|
||||||
|
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.todayIn
|
||||||
|
import moe.lava.banksia.model.StopTimeDated
|
||||||
|
import moe.lava.banksia.model.atDate
|
||||||
|
import moe.lava.banksia.room.dao.StopTimeDao
|
||||||
|
import moe.lava.banksia.util.serialise
|
||||||
|
import kotlin.time.Clock
|
||||||
|
|
||||||
|
class StopTimeLocalDataSource(
|
||||||
|
private val stopTimeDao: StopTimeDao,
|
||||||
|
) {
|
||||||
|
suspend fun getAtStop(
|
||||||
|
stopId: String,
|
||||||
|
date: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault()),
|
||||||
|
): List<StopTimeDated> {
|
||||||
|
return stopTimeDao
|
||||||
|
.getForStopDated(
|
||||||
|
stopId,
|
||||||
|
listOf(date.dayOfWeek).serialise(),
|
||||||
|
date.toEpochDays().toInt(),
|
||||||
|
)
|
||||||
|
.map { it.asModel().atDate(date) }
|
||||||
|
.sortedBy { it.departureTime }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package moe.lava.banksia.client.data.stoptime
|
||||||
|
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.call.body
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import io.ktor.client.request.parameter
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.todayIn
|
||||||
|
import moe.lava.banksia.model.StopTimeDated
|
||||||
|
import kotlin.time.Clock
|
||||||
|
|
||||||
|
class StopTimeRemoteDataSource(
|
||||||
|
private val client: HttpClient,
|
||||||
|
) {
|
||||||
|
suspend fun getAtStop(
|
||||||
|
stopId: String,
|
||||||
|
date: LocalDate? = Clock.System.todayIn(TimeZone.currentSystemDefault()),
|
||||||
|
): List<StopTimeDated> {
|
||||||
|
return client.get("stoptimes/by_stop/${stopId}") {
|
||||||
|
parameter("date", date)
|
||||||
|
}.body<List<StopTimeDated>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*suspend fun get(
|
||||||
|
stop: String? = null,
|
||||||
|
trip: String? = null,
|
||||||
|
day: DayOfWeek? = Clock.System.todayIn(TimeZone.currentSystemDefault()).dayOfWeek,
|
||||||
|
): List<StopTime> {
|
||||||
|
return client.get("stoptimes") {
|
||||||
|
stop?.let { parameter("stop", it) }
|
||||||
|
trip?.let { parameter("trip", it) }
|
||||||
|
day?.let { parameter("day", it) }
|
||||||
|
}.body<List<StopTime>>()
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package moe.lava.banksia.client.data.trip
|
||||||
|
|
||||||
|
import io.ktor.client.HttpClient
|
||||||
|
import kotlinx.datetime.DayOfWeek
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.todayIn
|
||||||
|
import moe.lava.banksia.model.Trip
|
||||||
|
import kotlin.time.Clock
|
||||||
|
|
||||||
|
class TripRemoteDataSource(
|
||||||
|
private val client: HttpClient,
|
||||||
|
) {
|
||||||
|
suspend fun get(
|
||||||
|
day: DayOfWeek? = Clock.System.todayIn(TimeZone.currentSystemDefault()).dayOfWeek,
|
||||||
|
): List<Trip> {
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,8 +12,11 @@ import moe.lava.banksia.client.data.route.RouteLocalDataSource
|
||||||
import moe.lava.banksia.client.data.route.RouteRemoteDataSource
|
import moe.lava.banksia.client.data.route.RouteRemoteDataSource
|
||||||
import moe.lava.banksia.client.data.stop.StopLocalDataSource
|
import moe.lava.banksia.client.data.stop.StopLocalDataSource
|
||||||
import moe.lava.banksia.client.data.stop.StopRemoteDataSource
|
import moe.lava.banksia.client.data.stop.StopRemoteDataSource
|
||||||
|
import moe.lava.banksia.client.data.stoptime.StopTimeLocalDataSource
|
||||||
|
import moe.lava.banksia.client.data.stoptime.StopTimeRemoteDataSource
|
||||||
import moe.lava.banksia.client.repository.RouteRepository
|
import moe.lava.banksia.client.repository.RouteRepository
|
||||||
import moe.lava.banksia.client.repository.StopRepository
|
import moe.lava.banksia.client.repository.StopRepository
|
||||||
|
import moe.lava.banksia.client.repository.StopTimeRepository
|
||||||
import moe.lava.banksia.data.ptv.PtvService
|
import moe.lava.banksia.data.ptv.PtvService
|
||||||
import moe.lava.banksia.util.log
|
import moe.lava.banksia.util.log
|
||||||
import org.koin.core.module.dsl.singleOf
|
import org.koin.core.module.dsl.singleOf
|
||||||
|
|
@ -46,8 +49,11 @@ val ClientModule = module {
|
||||||
singleOf(::RouteRemoteDataSource)
|
singleOf(::RouteRemoteDataSource)
|
||||||
singleOf(::StopLocalDataSource)
|
singleOf(::StopLocalDataSource)
|
||||||
singleOf(::StopRemoteDataSource)
|
singleOf(::StopRemoteDataSource)
|
||||||
|
singleOf(::StopTimeLocalDataSource)
|
||||||
|
singleOf(::StopTimeRemoteDataSource)
|
||||||
|
|
||||||
// Repositories
|
// Repositories
|
||||||
singleOf(::RouteRepository)
|
singleOf(::RouteRepository)
|
||||||
singleOf(::StopRepository)
|
singleOf(::StopRepository)
|
||||||
|
singleOf(::StopTimeRepository)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package moe.lava.banksia.client.repository
|
||||||
|
|
||||||
|
import moe.lava.banksia.client.data.stoptime.StopTimeLocalDataSource
|
||||||
|
import moe.lava.banksia.client.data.stoptime.StopTimeRemoteDataSource
|
||||||
|
import moe.lava.banksia.model.StopTimeDated
|
||||||
|
|
||||||
|
class StopTimeRepository(
|
||||||
|
private val local: StopTimeLocalDataSource,
|
||||||
|
private val remote: StopTimeRemoteDataSource,
|
||||||
|
) {
|
||||||
|
suspend fun getForStop(id: String): List<StopTimeDated> {
|
||||||
|
return local
|
||||||
|
.getAtStop(id)
|
||||||
|
.ifEmpty { remote.getAtStop(id) }
|
||||||
|
}
|
||||||
|
}
|
||||||
13
gradle/gradle-daemon-jvm.properties
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#This file is generated by updateDaemonJvm
|
||||||
|
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect
|
||||||
|
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/ecd23fd7707c683afbcd6052998cb6a9/redirect
|
||||||
|
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect
|
||||||
|
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/398ffe3949748bfb1d5636f023d228fd/redirect
|
||||||
|
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e99bae143b75f9a10ead10248f02055e/redirect
|
||||||
|
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/04e088f8677de3b384108493cc9481d0/redirect
|
||||||
|
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/536afcd1dff540251f85e5d2c80458cf/redirect
|
||||||
|
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/398ffe3949748bfb1d5636f023d228fd/redirect
|
||||||
|
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e55dccbfe27cb97945148c61a39c89c5/redirect
|
||||||
|
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/dbd05c4936d573642f94cd149e1356c8/redirect
|
||||||
|
toolchainVendor=JETBRAINS
|
||||||
|
toolchainVersion=21
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[versions]
|
[versions]
|
||||||
agp = "8.13.1"
|
agp = "9.1.0"
|
||||||
android-compileSdk = "36"
|
android-compileSdk = "36"
|
||||||
android-minSdk = "24"
|
android-minSdk = "24"
|
||||||
android-targetSdk = "36"
|
android-targetSdk = "36"
|
||||||
|
|
@ -85,7 +85,7 @@ ui-backhandler = { module = "org.jetbrains.compose.ui:ui-backhandler", version.r
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||||
androidLibrary = { id = "com.android.library", version.ref = "agp" }
|
androidMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
|
||||||
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
|
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
|
||||||
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
|
|
|
||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,24 @@ import io.ktor.server.routing.routing
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.todayIn
|
||||||
import moe.lava.banksia.Constants
|
import moe.lava.banksia.Constants
|
||||||
import moe.lava.banksia.di.CommonModules
|
import moe.lava.banksia.di.CommonModules
|
||||||
|
import moe.lava.banksia.model.atDate
|
||||||
import moe.lava.banksia.room.dao.RouteDao
|
import moe.lava.banksia.room.dao.RouteDao
|
||||||
import moe.lava.banksia.room.dao.StopDao
|
import moe.lava.banksia.room.dao.StopDao
|
||||||
|
import moe.lava.banksia.room.dao.StopTimeDao
|
||||||
import moe.lava.banksia.room.dao.VersionMetadataDao
|
import moe.lava.banksia.room.dao.VersionMetadataDao
|
||||||
import moe.lava.banksia.server.di.ServerModules
|
import moe.lava.banksia.server.di.ServerModules
|
||||||
import moe.lava.banksia.server.gtfs.GtfsHandler
|
import moe.lava.banksia.server.gtfs.GtfsHandler
|
||||||
import moe.lava.banksia.server.gtfsr.GtfsrService
|
import moe.lava.banksia.server.gtfsr.GtfsrService
|
||||||
|
import moe.lava.banksia.util.serialise
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import org.koin.ktor.ext.inject
|
import org.koin.ktor.ext.inject
|
||||||
import org.koin.ktor.plugin.Koin
|
import org.koin.ktor.plugin.Koin
|
||||||
|
import kotlin.time.Clock
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
|
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
|
||||||
|
|
@ -41,8 +48,11 @@ fun Application.module() {
|
||||||
modules(CommonModules, ServerModules)
|
modules(CommonModules, ServerModules)
|
||||||
}
|
}
|
||||||
|
|
||||||
val gtfsr by inject<GtfsrService>()
|
@Suppress("KotlinConstantConditions")
|
||||||
launch { gtfsr.start() }
|
if (!Constants.devMode) {
|
||||||
|
val gtfsr by inject<GtfsrService>()
|
||||||
|
launch { gtfsr.start() }
|
||||||
|
}
|
||||||
|
|
||||||
routing {
|
routing {
|
||||||
get("/update") {
|
get("/update") {
|
||||||
|
|
@ -137,6 +147,24 @@ fun Application.module() {
|
||||||
// .map { it.asModel() }
|
// .map { it.asModel() }
|
||||||
// }
|
// }
|
||||||
// call.respond(stops)
|
// call.respond(stops)
|
||||||
|
|
||||||
|
}
|
||||||
|
get("/stoptimes/by_stop/{stop_id}") {
|
||||||
|
val stopId = call.parameters["stop_id"]!!
|
||||||
|
val date = call.queryParameters["date"]
|
||||||
|
?.let { LocalDate.parse(it, LocalDate.Formats.ISO) }
|
||||||
|
?: Clock.System.todayIn(TimeZone.currentSystemDefault())
|
||||||
|
val times = withContext(context = Dispatchers.IO) {
|
||||||
|
inject<StopTimeDao>().value
|
||||||
|
.getForStopDated(
|
||||||
|
stopId,
|
||||||
|
listOf(date.dayOfWeek).serialise(),
|
||||||
|
date.toEpochDays().toInt(),
|
||||||
|
)
|
||||||
|
.map { it.asModel().atDate(date) }
|
||||||
|
.sortedBy { it.departureTime }
|
||||||
|
}
|
||||||
|
call.respond(times)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,14 @@ import io.ktor.client.statement.bodyAsChannel
|
||||||
import io.ktor.util.cio.writeChannel
|
import io.ktor.util.cio.writeChannel
|
||||||
import io.ktor.util.logging.Logger
|
import io.ktor.util.logging.Logger
|
||||||
import io.ktor.utils.io.copyAndClose
|
import io.ktor.utils.io.copyAndClose
|
||||||
|
import kotlinx.datetime.DayOfWeek
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.modules.EmptySerializersModule
|
import kotlinx.serialization.modules.EmptySerializersModule
|
||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
import moe.lava.banksia.Constants
|
import moe.lava.banksia.Constants
|
||||||
import moe.lava.banksia.model.Route
|
import moe.lava.banksia.model.Route
|
||||||
|
import moe.lava.banksia.model.Service
|
||||||
import moe.lava.banksia.model.Shape
|
import moe.lava.banksia.model.Shape
|
||||||
import moe.lava.banksia.model.Stop
|
import moe.lava.banksia.model.Stop
|
||||||
import moe.lava.banksia.model.StopTime
|
import moe.lava.banksia.model.StopTime
|
||||||
|
|
@ -22,6 +25,7 @@ import moe.lava.banksia.room.Database
|
||||||
import moe.lava.banksia.room.converter.RouteTypeConverter
|
import moe.lava.banksia.room.converter.RouteTypeConverter
|
||||||
import moe.lava.banksia.room.entity.asEntity
|
import moe.lava.banksia.room.entity.asEntity
|
||||||
import moe.lava.banksia.server.gtfs.structures.GtfsRoute
|
import moe.lava.banksia.server.gtfs.structures.GtfsRoute
|
||||||
|
import moe.lava.banksia.server.gtfs.structures.GtfsService
|
||||||
import moe.lava.banksia.server.gtfs.structures.GtfsShape
|
import moe.lava.banksia.server.gtfs.structures.GtfsShape
|
||||||
import moe.lava.banksia.server.gtfs.structures.GtfsStop
|
import moe.lava.banksia.server.gtfs.structures.GtfsStop
|
||||||
import moe.lava.banksia.server.gtfs.structures.GtfsStopTime
|
import moe.lava.banksia.server.gtfs.structures.GtfsStopTime
|
||||||
|
|
@ -65,6 +69,7 @@ class GtfsHandler(
|
||||||
.listFiles { it.isDirectory }
|
.listFiles { it.isDirectory }
|
||||||
.flatMap { d -> d.listFiles { f -> f.extension == "txt" }.toList() }
|
.flatMap { d -> d.listFiles { f -> f.extension == "txt" }.toList() }
|
||||||
.ifEmpty { extractAll(datasetPath) }
|
.ifEmpty { extractAll(datasetPath) }
|
||||||
|
.filter { it.parentFile.name == "2" }
|
||||||
} else {
|
} else {
|
||||||
extractAll(datasetPath)
|
extractAll(datasetPath)
|
||||||
}
|
}
|
||||||
|
|
@ -72,8 +77,9 @@ class GtfsHandler(
|
||||||
addRoutes(files)
|
addRoutes(files)
|
||||||
addStops(files)
|
addStops(files)
|
||||||
addShapes(files)
|
addShapes(files)
|
||||||
addTrips(files)
|
val services = addServices(files)
|
||||||
addStopTimes(files)
|
val trips = addTrips(files, services.associateBy { it.id })
|
||||||
|
addStopTimes(files, trips.associateBy { it.id })
|
||||||
|
|
||||||
updateMetadata(date ?: Clock.System.now().epochSeconds)
|
updateMetadata(date ?: Clock.System.now().epochSeconds)
|
||||||
|
|
||||||
|
|
@ -174,7 +180,7 @@ class GtfsHandler(
|
||||||
)
|
)
|
||||||
} }
|
} }
|
||||||
|
|
||||||
private suspend fun addStopTimes(files: List<File>) {
|
private suspend fun addStopTimes(files: List<File>, trips: Map<String, Trip>) {
|
||||||
val dao = db.stopTimeDao
|
val dao = db.stopTimeDao
|
||||||
dao.deleteAll()
|
dao.deleteAll()
|
||||||
log.info("parsing stop times...")
|
log.info("parsing stop times...")
|
||||||
|
|
@ -182,7 +188,7 @@ class GtfsHandler(
|
||||||
.filter { it.name == "stop_times.txt" }
|
.filter { it.name == "stop_times.txt" }
|
||||||
.forEach { fd ->
|
.forEach { fd ->
|
||||||
log.info("parsing stop times for ${fd.parent}...")
|
log.info("parsing stop times for ${fd.parent}...")
|
||||||
parseStopTimes(fd) { seq ->
|
parseStopTimes(fd, trips) { seq ->
|
||||||
seq.chunked(1000000)
|
seq.chunked(1000000)
|
||||||
.forEach { queue ->
|
.forEach { queue ->
|
||||||
log.info("converting stop times (${queue.size}) for ${fd.parent}...")
|
log.info("converting stop times (${queue.size}) for ${fd.parent}...")
|
||||||
|
|
@ -194,7 +200,7 @@ class GtfsHandler(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun parseStopTimes(fd: File, block: (Sequence<StopTime>) -> Unit) =
|
private inline fun parseStopTimes(fd: File, trips: Map<String, Trip>, block: (Sequence<StopTime>) -> Unit) =
|
||||||
fd.parseCsvSequence<GtfsStopTime> { seq ->
|
fd.parseCsvSequence<GtfsStopTime> { seq ->
|
||||||
seq
|
seq
|
||||||
.map { with(it) {
|
.map { with(it) {
|
||||||
|
|
@ -203,7 +209,7 @@ class GtfsHandler(
|
||||||
stopId = stop_id,
|
stopId = stop_id,
|
||||||
arrivalTime = GtfsStopTime.parseGtfsTime(arrival_time),
|
arrivalTime = GtfsStopTime.parseGtfsTime(arrival_time),
|
||||||
departureTime = GtfsStopTime.parseGtfsTime(departure_time),
|
departureTime = GtfsStopTime.parseGtfsTime(departure_time),
|
||||||
headsign = stop_headsign,
|
headsign = stop_headsign.ifEmpty { trips[trip_id]!!.tripHeadsign },
|
||||||
pickupType = pickup_type,
|
pickupType = pickup_type,
|
||||||
dropOffType = drop_off_type,
|
dropOffType = drop_off_type,
|
||||||
)
|
)
|
||||||
|
|
@ -211,25 +217,61 @@ class GtfsHandler(
|
||||||
.let { block(it) }
|
.let { block(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun addTrips(files: List<File>) {
|
private suspend fun addServices(files: List<File>): List<Service> {
|
||||||
|
val dao = db.serviceDao
|
||||||
|
log.info("parsing services...")
|
||||||
|
val services = files
|
||||||
|
.filter { it.name == "calendar.txt" }
|
||||||
|
.flatMap { fd -> parseServices(fd) }
|
||||||
|
|
||||||
|
log.info("inserting services...")
|
||||||
|
dao.deleteAll()
|
||||||
|
dao.insertOrReplaceAll(*services.map { it.asEntity() }.toTypedArray())
|
||||||
|
|
||||||
|
return services
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseServices(fd: File) =
|
||||||
|
fd.parseCsv<GtfsService>()
|
||||||
|
.map { with(it) {
|
||||||
|
val days = buildList {
|
||||||
|
if (monday == 1) add(DayOfWeek.MONDAY)
|
||||||
|
if (tuesday == 1) add(DayOfWeek.TUESDAY)
|
||||||
|
if (wednesday == 1) add(DayOfWeek.WEDNESDAY)
|
||||||
|
if (thursday == 1) add(DayOfWeek.THURSDAY)
|
||||||
|
if (friday == 1) add(DayOfWeek.FRIDAY)
|
||||||
|
if (saturday == 1) add(DayOfWeek.SATURDAY)
|
||||||
|
if (sunday == 1) add(DayOfWeek.SUNDAY)
|
||||||
|
}
|
||||||
|
Service(
|
||||||
|
id = service_id,
|
||||||
|
days = days,
|
||||||
|
start = LocalDate.parse(start_date, LocalDate.Formats.ISO_BASIC),
|
||||||
|
end = LocalDate.parse(end_date, LocalDate.Formats.ISO_BASIC),
|
||||||
|
)
|
||||||
|
} }
|
||||||
|
|
||||||
|
private suspend fun addTrips(files: List<File>, services: Map<String, Service>): List<Trip> {
|
||||||
val dao = db.tripDao
|
val dao = db.tripDao
|
||||||
log.info("parsing trips...")
|
log.info("parsing trips...")
|
||||||
val trips = files
|
val trips = files
|
||||||
.filter { it.name == "trips.txt" }
|
.filter { it.name == "trips.txt" }
|
||||||
.flatMap { fd -> parseTrips(fd) }
|
.flatMap { fd -> parseTrips(fd, services) }
|
||||||
|
|
||||||
log.info("inserting trips...")
|
log.info("inserting trips...")
|
||||||
dao.deleteAll()
|
dao.deleteAll()
|
||||||
dao.insertOrReplaceAll(*trips.map { it.asEntity() }.toTypedArray())
|
dao.insertOrReplaceAll(*trips.map { it.asEntity() }.toTypedArray())
|
||||||
|
|
||||||
|
return trips
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseTrips(fd: File) =
|
private fun parseTrips(fd: File, services: Map<String, Service>) =
|
||||||
fd.parseCsv<GtfsTrip>()
|
fd.parseCsv<GtfsTrip>()
|
||||||
.map { with(it) {
|
.map { with(it) {
|
||||||
Trip(
|
Trip(
|
||||||
id = trip_id,
|
id = trip_id,
|
||||||
routeId = route_id,
|
routeId = route_id,
|
||||||
serviceId = service_id,
|
service = services[service_id]!!,
|
||||||
shapeId = shape_id.ifEmpty { null },
|
shapeId = shape_id.ifEmpty { null },
|
||||||
tripHeadsign = trip_headsign,
|
tripHeadsign = trip_headsign,
|
||||||
directionId = direction_id,
|
directionId = direction_id,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package moe.lava.banksia.server.gtfs.structures
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Suppress("PropertyName")
|
||||||
|
@Serializable
|
||||||
|
data class GtfsService(
|
||||||
|
val service_id: String,
|
||||||
|
val monday: Int,
|
||||||
|
val tuesday: Int,
|
||||||
|
val wednesday: Int,
|
||||||
|
val thursday: Int,
|
||||||
|
val friday: Int,
|
||||||
|
val saturday: Int,
|
||||||
|
val sunday: Int,
|
||||||
|
val start_date: String,
|
||||||
|
val end_date: String,
|
||||||
|
)
|
||||||
|
|
@ -14,6 +14,9 @@ pluginManagement {
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
plugins {
|
||||||
|
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
repositories {
|
repositories {
|
||||||
|
|
@ -28,7 +31,10 @@ dependencyResolutionManagement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
include(":androidApp")
|
||||||
include(":client")
|
include(":client")
|
||||||
include(":server")
|
include(":server")
|
||||||
include(":shared")
|
include(":shared")
|
||||||
include(":ui")
|
include(":ui")
|
||||||
|
include(":ui:maps")
|
||||||
|
include(":ui:shared")
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlinMultiplatform)
|
alias(libs.plugins.kotlinMultiplatform)
|
||||||
alias(libs.plugins.kotlinSerialization)
|
alias(libs.plugins.kotlinSerialization)
|
||||||
alias(libs.plugins.androidLibrary)
|
alias(libs.plugins.androidMultiplatformLibrary)
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
alias(libs.plugins.room)
|
alias(libs.plugins.room)
|
||||||
alias(libs.plugins.wire)
|
alias(libs.plugins.wire)
|
||||||
|
|
@ -15,8 +14,10 @@ room {
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
androidTarget {
|
android {
|
||||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
namespace = "moe.lava.banksia.shared"
|
||||||
|
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||||
|
|
||||||
compilerOptions {
|
compilerOptions {
|
||||||
jvmTarget.set(JvmTarget.JVM_11)
|
jvmTarget.set(JvmTarget.JVM_11)
|
||||||
}
|
}
|
||||||
|
|
@ -26,7 +27,6 @@ kotlin {
|
||||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||||
}
|
}
|
||||||
|
|
||||||
iosX64()
|
|
||||||
iosArm64()
|
iosArm64()
|
||||||
iosSimulatorArm64()
|
iosSimulatorArm64()
|
||||||
|
|
||||||
|
|
@ -58,27 +58,14 @@ kotlin {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
add("kspAndroid", libs.room.compiler)
|
add("kspAndroid", libs.room.compiler)
|
||||||
add("kspIosX64", libs.room.compiler)
|
|
||||||
add("kspIosArm64", libs.room.compiler)
|
add("kspIosArm64", libs.room.compiler)
|
||||||
add("kspIosSimulatorArm64", libs.room.compiler)
|
add("kspIosSimulatorArm64", libs.room.compiler)
|
||||||
add("kspJvm", libs.room.compiler)
|
add("kspJvm", libs.room.compiler)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "moe.lava.banksia.shared"
|
|
||||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
|
||||||
}
|
|
||||||
defaultConfig {
|
|
||||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wire {
|
wire {
|
||||||
sourcePath {
|
sourcePath {
|
||||||
srcDir("src/commonMain/proto")
|
srcDir("src/commonMain/proto")
|
||||||
}
|
}
|
||||||
kotlin {}
|
kotlin {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
368
shared/schemas/moe.lava.banksia.room.Database/4.json
Normal file
|
|
@ -0,0 +1,368 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 4,
|
||||||
|
"identityHash": "4426fd2ccc826d9d9d9021546b105850",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "Route",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "number",
|
||||||
|
"columnName": "number",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Shape",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "path",
|
||||||
|
"columnName": "path",
|
||||||
|
"affinity": "BLOB",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Stop",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lat",
|
||||||
|
"columnName": "lat",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lng",
|
||||||
|
"columnName": "lng",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parent",
|
||||||
|
"columnName": "parent",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasWheelChairBoarding",
|
||||||
|
"columnName": "hasWheelChairBoarding",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "level",
|
||||||
|
"columnName": "level",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "platformCode",
|
||||||
|
"columnName": "platformCode",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Stop_parent",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"parent"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "StopTime",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "tripId",
|
||||||
|
"columnName": "tripId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "stopId",
|
||||||
|
"columnName": "stopId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "arrivalTime",
|
||||||
|
"columnName": "arrivalTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "departureTime",
|
||||||
|
"columnName": "departureTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "headsign",
|
||||||
|
"columnName": "headsign",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pickupType",
|
||||||
|
"columnName": "pickupType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "dropOffType",
|
||||||
|
"columnName": "dropOffType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId",
|
||||||
|
"stopId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_tripId",
|
||||||
|
"unique": true,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_stopId",
|
||||||
|
"unique": true,
|
||||||
|
"columnNames": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Trip",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Stop",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Trip",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "routeId",
|
||||||
|
"columnName": "routeId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serviceId",
|
||||||
|
"columnName": "serviceId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "shapeId",
|
||||||
|
"columnName": "shapeId",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "tripHeadsign",
|
||||||
|
"columnName": "tripHeadsign",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "directionId",
|
||||||
|
"columnName": "directionId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "blockId",
|
||||||
|
"columnName": "blockId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "wheelchairAccessible",
|
||||||
|
"columnName": "wheelchairAccessible",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Trip_shapeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_Trip_routeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Route",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Shape",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "VersionMetadata",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastUpdated",
|
||||||
|
"columnName": "lastUpdated",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4426fd2ccc826d9d9d9021546b105850')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
368
shared/schemas/moe.lava.banksia.room.Database/5.json
Normal file
|
|
@ -0,0 +1,368 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 5,
|
||||||
|
"identityHash": "4426fd2ccc826d9d9d9021546b105850",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "Route",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "number",
|
||||||
|
"columnName": "number",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Shape",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "path",
|
||||||
|
"columnName": "path",
|
||||||
|
"affinity": "BLOB",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Stop",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lat",
|
||||||
|
"columnName": "lat",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lng",
|
||||||
|
"columnName": "lng",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parent",
|
||||||
|
"columnName": "parent",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasWheelChairBoarding",
|
||||||
|
"columnName": "hasWheelChairBoarding",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "level",
|
||||||
|
"columnName": "level",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "platformCode",
|
||||||
|
"columnName": "platformCode",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Stop_parent",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"parent"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "StopTime",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "tripId",
|
||||||
|
"columnName": "tripId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "stopId",
|
||||||
|
"columnName": "stopId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "arrivalTime",
|
||||||
|
"columnName": "arrivalTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "departureTime",
|
||||||
|
"columnName": "departureTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "headsign",
|
||||||
|
"columnName": "headsign",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pickupType",
|
||||||
|
"columnName": "pickupType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "dropOffType",
|
||||||
|
"columnName": "dropOffType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId",
|
||||||
|
"stopId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_tripId",
|
||||||
|
"unique": true,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_stopId",
|
||||||
|
"unique": true,
|
||||||
|
"columnNames": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Trip",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Stop",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Trip",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "routeId",
|
||||||
|
"columnName": "routeId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serviceId",
|
||||||
|
"columnName": "serviceId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "shapeId",
|
||||||
|
"columnName": "shapeId",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "tripHeadsign",
|
||||||
|
"columnName": "tripHeadsign",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "directionId",
|
||||||
|
"columnName": "directionId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "blockId",
|
||||||
|
"columnName": "blockId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "wheelchairAccessible",
|
||||||
|
"columnName": "wheelchairAccessible",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Trip_shapeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_Trip_routeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Route",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Shape",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "VersionMetadata",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastUpdated",
|
||||||
|
"columnName": "lastUpdated",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4426fd2ccc826d9d9d9021546b105850')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
368
shared/schemas/moe.lava.banksia.room.Database/6.json
Normal file
|
|
@ -0,0 +1,368 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 6,
|
||||||
|
"identityHash": "5f52de4cc0ddbcf02a0d8be4cf4d4cfd",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "Route",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "number",
|
||||||
|
"columnName": "number",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Shape",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "path",
|
||||||
|
"columnName": "path",
|
||||||
|
"affinity": "BLOB",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Stop",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lat",
|
||||||
|
"columnName": "lat",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lng",
|
||||||
|
"columnName": "lng",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parent",
|
||||||
|
"columnName": "parent",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasWheelChairBoarding",
|
||||||
|
"columnName": "hasWheelChairBoarding",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "level",
|
||||||
|
"columnName": "level",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "platformCode",
|
||||||
|
"columnName": "platformCode",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Stop_parent",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"parent"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "StopTime",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "tripId",
|
||||||
|
"columnName": "tripId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "stopId",
|
||||||
|
"columnName": "stopId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "arrivalTime",
|
||||||
|
"columnName": "arrivalTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "departureTime",
|
||||||
|
"columnName": "departureTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "headsign",
|
||||||
|
"columnName": "headsign",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pickupType",
|
||||||
|
"columnName": "pickupType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "dropOffType",
|
||||||
|
"columnName": "dropOffType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId",
|
||||||
|
"stopId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_tripId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_stopId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Trip",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Stop",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Trip",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "routeId",
|
||||||
|
"columnName": "routeId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serviceId",
|
||||||
|
"columnName": "serviceId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "shapeId",
|
||||||
|
"columnName": "shapeId",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "tripHeadsign",
|
||||||
|
"columnName": "tripHeadsign",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "directionId",
|
||||||
|
"columnName": "directionId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "blockId",
|
||||||
|
"columnName": "blockId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "wheelchairAccessible",
|
||||||
|
"columnName": "wheelchairAccessible",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Trip_shapeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_Trip_routeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Route",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Shape",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "VersionMetadata",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastUpdated",
|
||||||
|
"columnName": "lastUpdated",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5f52de4cc0ddbcf02a0d8be4cf4d4cfd')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
415
shared/schemas/moe.lava.banksia.room.Database/7.json
Normal file
|
|
@ -0,0 +1,415 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 7,
|
||||||
|
"identityHash": "15c94df0a62438ff28d451c074c94c59",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "Route",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "number",
|
||||||
|
"columnName": "number",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Service",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `days` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "days",
|
||||||
|
"columnName": "days",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "start",
|
||||||
|
"columnName": "start",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "end",
|
||||||
|
"columnName": "end",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Service_days",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"days"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Service_days` ON `${TABLE_NAME}` (`days`)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Shape",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "path",
|
||||||
|
"columnName": "path",
|
||||||
|
"affinity": "BLOB",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Stop",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lat",
|
||||||
|
"columnName": "lat",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lng",
|
||||||
|
"columnName": "lng",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parent",
|
||||||
|
"columnName": "parent",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasWheelChairBoarding",
|
||||||
|
"columnName": "hasWheelChairBoarding",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "level",
|
||||||
|
"columnName": "level",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "platformCode",
|
||||||
|
"columnName": "platformCode",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Stop_parent",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"parent"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "StopTime",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "tripId",
|
||||||
|
"columnName": "tripId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "stopId",
|
||||||
|
"columnName": "stopId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "arrivalTime",
|
||||||
|
"columnName": "arrivalTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "departureTime",
|
||||||
|
"columnName": "departureTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "headsign",
|
||||||
|
"columnName": "headsign",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pickupType",
|
||||||
|
"columnName": "pickupType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "dropOffType",
|
||||||
|
"columnName": "dropOffType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId",
|
||||||
|
"stopId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_tripId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_stopId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Trip",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Stop",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Trip",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "routeId",
|
||||||
|
"columnName": "routeId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serviceId",
|
||||||
|
"columnName": "serviceId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "shapeId",
|
||||||
|
"columnName": "shapeId",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "tripHeadsign",
|
||||||
|
"columnName": "tripHeadsign",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "directionId",
|
||||||
|
"columnName": "directionId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "blockId",
|
||||||
|
"columnName": "blockId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "wheelchairAccessible",
|
||||||
|
"columnName": "wheelchairAccessible",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Trip_shapeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_Trip_routeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Route",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Shape",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "VersionMetadata",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastUpdated",
|
||||||
|
"columnName": "lastUpdated",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '15c94df0a62438ff28d451c074c94c59')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
426
shared/schemas/moe.lava.banksia.room.Database/8.json
Normal file
|
|
@ -0,0 +1,426 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 8,
|
||||||
|
"identityHash": "6e0f07bf1af88b2e37b5ad7c38a3fb2a",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "Route",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "number",
|
||||||
|
"columnName": "number",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Service",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `days` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "days",
|
||||||
|
"columnName": "days",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "start",
|
||||||
|
"columnName": "start",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "end",
|
||||||
|
"columnName": "end",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Service_days",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"days"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Service_days` ON `${TABLE_NAME}` (`days`)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Shape",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "path",
|
||||||
|
"columnName": "path",
|
||||||
|
"affinity": "BLOB",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Stop",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lat",
|
||||||
|
"columnName": "lat",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lng",
|
||||||
|
"columnName": "lng",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parent",
|
||||||
|
"columnName": "parent",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasWheelChairBoarding",
|
||||||
|
"columnName": "hasWheelChairBoarding",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "level",
|
||||||
|
"columnName": "level",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "platformCode",
|
||||||
|
"columnName": "platformCode",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Stop_parent",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"parent"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "StopTime",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "tripId",
|
||||||
|
"columnName": "tripId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "stopId",
|
||||||
|
"columnName": "stopId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "arrivalTime",
|
||||||
|
"columnName": "arrivalTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "departureTime",
|
||||||
|
"columnName": "departureTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "headsign",
|
||||||
|
"columnName": "headsign",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pickupType",
|
||||||
|
"columnName": "pickupType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "dropOffType",
|
||||||
|
"columnName": "dropOffType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId",
|
||||||
|
"stopId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_tripId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_stopId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Trip",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Stop",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Trip",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`serviceId`) REFERENCES `Service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "routeId",
|
||||||
|
"columnName": "routeId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serviceId",
|
||||||
|
"columnName": "serviceId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "shapeId",
|
||||||
|
"columnName": "shapeId",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "tripHeadsign",
|
||||||
|
"columnName": "tripHeadsign",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "directionId",
|
||||||
|
"columnName": "directionId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "blockId",
|
||||||
|
"columnName": "blockId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "wheelchairAccessible",
|
||||||
|
"columnName": "wheelchairAccessible",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Trip_shapeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_Trip_routeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Route",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Service",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"serviceId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Shape",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "VersionMetadata",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastUpdated",
|
||||||
|
"columnName": "lastUpdated",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6e0f07bf1af88b2e37b5ad7c38a3fb2a')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
426
shared/schemas/moe.lava.banksia.room.Database/9.json
Normal file
|
|
@ -0,0 +1,426 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 9,
|
||||||
|
"identityHash": "6e0f07bf1af88b2e37b5ad7c38a3fb2a",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "Route",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` INTEGER NOT NULL, `number` TEXT, `name` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "number",
|
||||||
|
"columnName": "number",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Service",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `days` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "days",
|
||||||
|
"columnName": "days",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "start",
|
||||||
|
"columnName": "start",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "end",
|
||||||
|
"columnName": "end",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Service_days",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"days"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Service_days` ON `${TABLE_NAME}` (`days`)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Shape",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `path` BLOB NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "path",
|
||||||
|
"columnName": "path",
|
||||||
|
"affinity": "BLOB",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Stop",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `lat` REAL NOT NULL, `lng` REAL NOT NULL, `parent` TEXT NOT NULL, `hasWheelChairBoarding` INTEGER NOT NULL, `level` TEXT NOT NULL, `platformCode` TEXT NOT NULL, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lat",
|
||||||
|
"columnName": "lat",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lng",
|
||||||
|
"columnName": "lng",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parent",
|
||||||
|
"columnName": "parent",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasWheelChairBoarding",
|
||||||
|
"columnName": "hasWheelChairBoarding",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "level",
|
||||||
|
"columnName": "level",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "platformCode",
|
||||||
|
"columnName": "platformCode",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Stop_parent",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"parent"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Stop_parent` ON `${TABLE_NAME}` (`parent`)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "StopTime",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tripId` TEXT NOT NULL, `stopId` TEXT NOT NULL, `arrivalTime` INTEGER NOT NULL, `departureTime` INTEGER NOT NULL, `headsign` TEXT, `pickupType` INTEGER NOT NULL, `dropOffType` INTEGER NOT NULL, PRIMARY KEY(`tripId`, `stopId`), FOREIGN KEY(`tripId`) REFERENCES `Trip`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`stopId`) REFERENCES `Stop`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "tripId",
|
||||||
|
"columnName": "tripId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "stopId",
|
||||||
|
"columnName": "stopId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "arrivalTime",
|
||||||
|
"columnName": "arrivalTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "departureTime",
|
||||||
|
"columnName": "departureTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "headsign",
|
||||||
|
"columnName": "headsign",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pickupType",
|
||||||
|
"columnName": "pickupType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "dropOffType",
|
||||||
|
"columnName": "dropOffType",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId",
|
||||||
|
"stopId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_tripId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_tripId` ON `${TABLE_NAME}` (`tripId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_StopTime_stopId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_StopTime_stopId` ON `${TABLE_NAME}` (`stopId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Trip",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"tripId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Stop",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"stopId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Trip",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `routeId` TEXT NOT NULL, `serviceId` TEXT NOT NULL, `shapeId` TEXT, `tripHeadsign` TEXT NOT NULL, `directionId` TEXT NOT NULL, `blockId` TEXT NOT NULL, `wheelchairAccessible` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`routeId`) REFERENCES `Route`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`serviceId`) REFERENCES `Service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`shapeId`) REFERENCES `Shape`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "routeId",
|
||||||
|
"columnName": "routeId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serviceId",
|
||||||
|
"columnName": "serviceId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "shapeId",
|
||||||
|
"columnName": "shapeId",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "tripHeadsign",
|
||||||
|
"columnName": "tripHeadsign",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "directionId",
|
||||||
|
"columnName": "directionId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "blockId",
|
||||||
|
"columnName": "blockId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "wheelchairAccessible",
|
||||||
|
"columnName": "wheelchairAccessible",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Trip_shapeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_shapeId` ON `${TABLE_NAME}` (`shapeId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_Trip_routeId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Trip_routeId` ON `${TABLE_NAME}` (`routeId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Route",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"routeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Service",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"serviceId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "Shape",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "NO ACTION",
|
||||||
|
"columns": [
|
||||||
|
"shapeId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "VersionMetadata",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`type` TEXT NOT NULL, `lastUpdated` INTEGER NOT NULL, PRIMARY KEY(`type`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastUpdated",
|
||||||
|
"columnName": "lastUpdated",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6e0f07bf1af88b2e37b5ad7c38a3fb2a')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,4 +8,5 @@ object Constants {
|
||||||
// TODO
|
// TODO
|
||||||
const val devMode: Boolean = false
|
const val devMode: Boolean = false
|
||||||
const val updateKey: String = ""
|
const val updateKey: String = ""
|
||||||
|
const val protomapsKey: String = ""
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import kotlinx.serialization.encoding.Decoder
|
||||||
import kotlinx.serialization.encoding.Encoder
|
import kotlinx.serialization.encoding.Encoder
|
||||||
import moe.lava.banksia.model.RouteType
|
import moe.lava.banksia.model.RouteType
|
||||||
|
|
||||||
private object PtvRouteTypeSerialiser : KSerializer<PtvRouteType> {
|
object PtvRouteTypeSerialiser : KSerializer<PtvRouteType> {
|
||||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
|
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
|
||||||
PtvRouteType::class.qualifiedName!!,
|
PtvRouteType::class.qualifiedName!!,
|
||||||
PrimitiveKind.INT)
|
PrimitiveKind.INT)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ val CommonModules = module {
|
||||||
single { Database.build(get<PlatformDatabaseBuilder>().getBuilder()) }
|
single { Database.build(get<PlatformDatabaseBuilder>().getBuilder()) }
|
||||||
single { get<Database>().versionMetadataDao }
|
single { get<Database>().versionMetadataDao }
|
||||||
single { get<Database>().routeDao }
|
single { get<Database>().routeDao }
|
||||||
|
single { get<Database>().serviceDao }
|
||||||
single { get<Database>().shapeDao }
|
single { get<Database>().shapeDao }
|
||||||
single { get<Database>().stopDao }
|
single { get<Database>().stopDao }
|
||||||
single { get<Database>().stopTimeDao }
|
single { get<Database>().stopTimeDao }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
package moe.lava.banksia.model
|
package moe.lava.banksia.model
|
||||||
|
|
||||||
|
import kotlinx.datetime.DateTimeUnit
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.datetime.LocalTime
|
import kotlinx.datetime.LocalTime
|
||||||
|
import kotlinx.datetime.atTime
|
||||||
|
import kotlinx.datetime.plus
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||||
|
|
@ -39,6 +43,10 @@ data class FutureTime(
|
||||||
val minute = time.minute
|
val minute = time.minute
|
||||||
val second = time.second
|
val second = time.second
|
||||||
val trueHour = time.hour + (if (dayOffset) 24 else 0)
|
val trueHour = time.hour + (if (dayOffset) 24 else 0)
|
||||||
|
|
||||||
|
fun atDate(date: LocalDate) = date
|
||||||
|
.let { if (dayOffset) date.plus(1, DateTimeUnit.DAY) else date }
|
||||||
|
.atTime(time)
|
||||||
}
|
}
|
||||||
|
|
||||||
object FutureTimeSerialiser: KSerializer<FutureTime> {
|
object FutureTimeSerialiser: KSerializer<FutureTime> {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package moe.lava.banksia.model
|
||||||
|
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class StopTimeDated(
|
||||||
|
val tripId: String,
|
||||||
|
val stopId: String,
|
||||||
|
val arrivalTime: LocalDateTime,
|
||||||
|
val departureTime: LocalDateTime,
|
||||||
|
val headsign: String?,
|
||||||
|
val pickupType: Int,
|
||||||
|
val dropOffType: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun StopTime.atDate(date: LocalDate) = StopTimeDated(
|
||||||
|
tripId = tripId,
|
||||||
|
stopId = stopId,
|
||||||
|
arrivalTime = arrivalTime.atDate(date),
|
||||||
|
departureTime = departureTime.atDate(date),
|
||||||
|
headsign = headsign,
|
||||||
|
pickupType = pickupType,
|
||||||
|
dropOffType = dropOffType,
|
||||||
|
)
|
||||||
|
|
@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable
|
||||||
data class Trip(
|
data class Trip(
|
||||||
val id: String,
|
val id: String,
|
||||||
val routeId: String,
|
val routeId: String,
|
||||||
val serviceId: String,
|
val service: Service,
|
||||||
val shapeId: String?,
|
val shapeId: String?,
|
||||||
val tripHeadsign: String,
|
val tripHeadsign: String,
|
||||||
val directionId: String,
|
val directionId: String,
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,15 @@ import androidx.sqlite.driver.bundled.BundledSQLiteDriver
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.IO
|
import kotlinx.coroutines.IO
|
||||||
import moe.lava.banksia.room.converter.RouteTypeConverter
|
import moe.lava.banksia.room.converter.RouteTypeConverter
|
||||||
import moe.lava.banksia.room.dao.VersionMetadataDao
|
|
||||||
import moe.lava.banksia.room.dao.RouteDao
|
import moe.lava.banksia.room.dao.RouteDao
|
||||||
|
import moe.lava.banksia.room.dao.ServiceDao
|
||||||
import moe.lava.banksia.room.dao.ShapeDao
|
import moe.lava.banksia.room.dao.ShapeDao
|
||||||
import moe.lava.banksia.room.dao.StopDao
|
import moe.lava.banksia.room.dao.StopDao
|
||||||
import moe.lava.banksia.room.dao.StopTimeDao
|
import moe.lava.banksia.room.dao.StopTimeDao
|
||||||
import moe.lava.banksia.room.dao.TripDao
|
import moe.lava.banksia.room.dao.TripDao
|
||||||
|
import moe.lava.banksia.room.dao.VersionMetadataDao
|
||||||
import moe.lava.banksia.room.entity.RouteEntity
|
import moe.lava.banksia.room.entity.RouteEntity
|
||||||
|
import moe.lava.banksia.room.entity.ServiceEntity
|
||||||
import moe.lava.banksia.room.entity.ShapeEntity
|
import moe.lava.banksia.room.entity.ShapeEntity
|
||||||
import moe.lava.banksia.room.entity.StopEntity
|
import moe.lava.banksia.room.entity.StopEntity
|
||||||
import moe.lava.banksia.room.entity.StopTimeEntity
|
import moe.lava.banksia.room.entity.StopTimeEntity
|
||||||
|
|
@ -22,9 +24,10 @@ import moe.lava.banksia.room.entity.VersionMetadataEntity
|
||||||
import androidx.room.Database as DatabaseAnnotation
|
import androidx.room.Database as DatabaseAnnotation
|
||||||
|
|
||||||
@DatabaseAnnotation(
|
@DatabaseAnnotation(
|
||||||
version = 3,
|
version = 9,
|
||||||
entities = [
|
entities = [
|
||||||
RouteEntity::class,
|
RouteEntity::class,
|
||||||
|
ServiceEntity::class,
|
||||||
ShapeEntity::class,
|
ShapeEntity::class,
|
||||||
StopEntity::class,
|
StopEntity::class,
|
||||||
StopTimeEntity::class,
|
StopTimeEntity::class,
|
||||||
|
|
@ -40,6 +43,7 @@ import androidx.room.Database as DatabaseAnnotation
|
||||||
abstract class Database : RoomDatabase() {
|
abstract class Database : RoomDatabase() {
|
||||||
abstract val versionMetadataDao: VersionMetadataDao
|
abstract val versionMetadataDao: VersionMetadataDao
|
||||||
abstract val routeDao: RouteDao
|
abstract val routeDao: RouteDao
|
||||||
|
abstract val serviceDao: ServiceDao
|
||||||
abstract val shapeDao: ShapeDao
|
abstract val shapeDao: ShapeDao
|
||||||
abstract val stopDao: StopDao
|
abstract val stopDao: StopDao
|
||||||
abstract val stopTimeDao: StopTimeDao
|
abstract val stopTimeDao: StopTimeDao
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package moe.lava.banksia.room.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Delete
|
||||||
|
import androidx.room.Insert
|
||||||
|
import androidx.room.OnConflictStrategy.Companion.REPLACE
|
||||||
|
import androidx.room.Query
|
||||||
|
import moe.lava.banksia.room.entity.ServiceEntity
|
||||||
|
|
||||||
|
@Dao
|
||||||
|
interface ServiceDao {
|
||||||
|
@Query("SELECT * FROM Service")
|
||||||
|
suspend fun getAll(): List<ServiceEntity>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Service WHERE id == :id")
|
||||||
|
suspend fun get(id: String): ServiceEntity?
|
||||||
|
|
||||||
|
@Insert
|
||||||
|
suspend fun insertAll(vararg services: ServiceEntity)
|
||||||
|
|
||||||
|
@Insert(onConflict = REPLACE)
|
||||||
|
suspend fun insertOrReplaceAll(vararg services: ServiceEntity)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun delete(service: ServiceEntity)
|
||||||
|
|
||||||
|
@Query("DELETE FROM Service")
|
||||||
|
suspend fun deleteAll()
|
||||||
|
}
|
||||||
|
|
@ -13,10 +13,22 @@ interface StopTimeDao {
|
||||||
suspend fun getAll(): List<StopTimeEntity>
|
suspend fun getAll(): List<StopTimeEntity>
|
||||||
|
|
||||||
@Query("SELECT * FROM StopTime WHERE tripId == :tripId")
|
@Query("SELECT * FROM StopTime WHERE tripId == :tripId")
|
||||||
suspend fun get(tripId: String): StopTimeEntity?
|
suspend fun getForTrip(tripId: String): StopTimeEntity?
|
||||||
|
|
||||||
@Query("SELECT * FROM StopTime WHERE tripId IN (:tripIds)")
|
@Query("SELECT * FROM StopTime WHERE tripId IN (:tripIds)")
|
||||||
suspend fun get(tripIds: List<String>): List<StopTimeEntity>
|
suspend fun getForTrips(tripIds: List<String>): List<StopTimeEntity>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM StopTime WHERE stopId == :stopId")
|
||||||
|
suspend fun getForStop(stopId: String): List<StopTimeEntity>
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
SELECT * FROM StopTime
|
||||||
|
INNER JOIN Service ON Service.days & :days = :days AND :date BETWEEN Service.start AND Service.`end`
|
||||||
|
INNER JOIN Trip ON Trip.serviceId == Service.id
|
||||||
|
WHERE StopTime.tripId == Trip.id
|
||||||
|
AND StopTime.stopId == :stopId
|
||||||
|
""")
|
||||||
|
suspend fun getForStopDated(stopId: String, days: Int, date: Int): List<StopTimeEntity>
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
suspend fun insertAll(vararg stopTimes: StopTimeEntity)
|
suspend fun insertAll(vararg stopTimes: StopTimeEntity)
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,23 @@
|
||||||
package moe.lava.banksia.room.entity
|
package moe.lava.banksia.room.entity
|
||||||
|
|
||||||
import kotlinx.datetime.DayOfWeek
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
import moe.lava.banksia.model.Service
|
import moe.lava.banksia.model.Service
|
||||||
|
import moe.lava.banksia.util.deserialiseDaysBitflag
|
||||||
|
import moe.lava.banksia.util.serialise
|
||||||
|
|
||||||
|
@Entity("Service")
|
||||||
data class ServiceEntity(
|
data class ServiceEntity(
|
||||||
val id: String,
|
@PrimaryKey val id: String,
|
||||||
val days: Int,
|
@ColumnInfo(index = true) val days: Int,
|
||||||
val start: Int,
|
val start: Int,
|
||||||
val end: Int,
|
val end: Int,
|
||||||
) {
|
) {
|
||||||
object Parser {
|
|
||||||
private fun Int.check(other: Int) = (this and other) != 0
|
|
||||||
|
|
||||||
fun deserialiseDays(days: Int): List<DayOfWeek> = buildList {
|
|
||||||
if (days.check(1))
|
|
||||||
add(DayOfWeek.MONDAY)
|
|
||||||
if (days.check(1 shl 1))
|
|
||||||
add(DayOfWeek.TUESDAY)
|
|
||||||
if (days.check(1 shl 2))
|
|
||||||
add(DayOfWeek.WEDNESDAY)
|
|
||||||
if (days.check(1 shl 3))
|
|
||||||
add(DayOfWeek.THURSDAY)
|
|
||||||
if (days.check(1 shl 4))
|
|
||||||
add(DayOfWeek.FRIDAY)
|
|
||||||
if (days.check(1 shl 5))
|
|
||||||
add(DayOfWeek.SATURDAY)
|
|
||||||
if (days.check(1 shl 6))
|
|
||||||
add(DayOfWeek.SUNDAY)
|
|
||||||
}
|
|
||||||
fun serialiseDays(days: List<DayOfWeek>): Int =
|
|
||||||
days.fold(0) { vl, n ->
|
|
||||||
vl + when (n) {
|
|
||||||
DayOfWeek.MONDAY -> 1
|
|
||||||
DayOfWeek.TUESDAY -> 1 shl 1
|
|
||||||
DayOfWeek.WEDNESDAY -> 1 shl 2
|
|
||||||
DayOfWeek.THURSDAY -> 1 shl 3
|
|
||||||
DayOfWeek.FRIDAY -> 1 shl 4
|
|
||||||
DayOfWeek.SATURDAY -> 1 shl 5
|
|
||||||
DayOfWeek.SUNDAY -> 1 shl 6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fun asModel() = Service(
|
fun asModel() = Service(
|
||||||
id,
|
id,
|
||||||
Parser.deserialiseDays(days),
|
days.deserialiseDaysBitflag(),
|
||||||
LocalDate.fromEpochDays(start),
|
LocalDate.fromEpochDays(start),
|
||||||
LocalDate.fromEpochDays(end),
|
LocalDate.fromEpochDays(end),
|
||||||
)
|
)
|
||||||
|
|
@ -52,7 +25,7 @@ data class ServiceEntity(
|
||||||
|
|
||||||
fun Service.asEntity() = ServiceEntity(
|
fun Service.asEntity() = ServiceEntity(
|
||||||
id,
|
id,
|
||||||
ServiceEntity.Parser.serialiseDays(days),
|
days.serialise(),
|
||||||
start.toEpochDays().toInt(),
|
start.toEpochDays().toInt(),
|
||||||
end.toEpochDays().toInt(),
|
end.toEpochDays().toInt(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package moe.lava.banksia.room.entity
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.ForeignKey
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.ForeignKey.Companion.CASCADE
|
import androidx.room.ForeignKey.Companion.CASCADE
|
||||||
|
import androidx.room.Index
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import moe.lava.banksia.model.FutureTime
|
import moe.lava.banksia.model.FutureTime
|
||||||
import moe.lava.banksia.model.FutureTime.Companion.asInt
|
import moe.lava.banksia.model.FutureTime.Companion.asInt
|
||||||
|
|
@ -11,6 +12,10 @@ import moe.lava.banksia.model.StopTime
|
||||||
@Entity(
|
@Entity(
|
||||||
"StopTime",
|
"StopTime",
|
||||||
primaryKeys = ["tripId", "stopId"],
|
primaryKeys = ["tripId", "stopId"],
|
||||||
|
indices = [
|
||||||
|
Index("tripId", unique = false),
|
||||||
|
Index("stopId", unique = false),
|
||||||
|
],
|
||||||
foreignKeys = [
|
foreignKeys = [
|
||||||
ForeignKey(TripEntity::class, parentColumns = ["id"], childColumns = ["tripId"], onDelete = CASCADE),
|
ForeignKey(TripEntity::class, parentColumns = ["id"], childColumns = ["tripId"], onDelete = CASCADE),
|
||||||
ForeignKey(StopEntity::class, parentColumns = ["id"], childColumns = ["stopId"], onDelete = CASCADE),
|
ForeignKey(StopEntity::class, parentColumns = ["id"], childColumns = ["stopId"], onDelete = CASCADE),
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.ForeignKey
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.ForeignKey.Companion.CASCADE
|
import androidx.room.ForeignKey.Companion.CASCADE
|
||||||
|
import androidx.room.Index
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import moe.lava.banksia.model.Trip
|
import moe.lava.banksia.model.Trip
|
||||||
|
|
||||||
|
|
@ -11,8 +12,10 @@ import moe.lava.banksia.model.Trip
|
||||||
"Trip",
|
"Trip",
|
||||||
foreignKeys = [
|
foreignKeys = [
|
||||||
ForeignKey(RouteEntity::class, parentColumns = ["id"], childColumns = ["routeId"], onDelete = CASCADE),
|
ForeignKey(RouteEntity::class, parentColumns = ["id"], childColumns = ["routeId"], onDelete = CASCADE),
|
||||||
|
ForeignKey(ServiceEntity::class, parentColumns = ["id"], childColumns = ["serviceId"], onDelete = CASCADE),
|
||||||
ForeignKey(ShapeEntity::class, parentColumns = ["id"], childColumns = ["shapeId"], onDelete = CASCADE),
|
ForeignKey(ShapeEntity::class, parentColumns = ["id"], childColumns = ["shapeId"], onDelete = CASCADE),
|
||||||
],
|
],
|
||||||
|
indices = [Index("shapeId")],
|
||||||
)
|
)
|
||||||
data class TripEntity(
|
data class TripEntity(
|
||||||
@PrimaryKey val id: String,
|
@PrimaryKey val id: String,
|
||||||
|
|
@ -23,8 +26,24 @@ data class TripEntity(
|
||||||
val directionId: String,
|
val directionId: String,
|
||||||
val blockId: String,
|
val blockId: String,
|
||||||
val wheelchairAccessible: String,
|
val wheelchairAccessible: String,
|
||||||
) {
|
)
|
||||||
fun asModel() = Trip(id, routeId, serviceId, shapeId, tripHeadsign, directionId, blockId, wheelchairAccessible)
|
|
||||||
|
fun Trip.Companion.from(tripEntity: TripEntity, serviceEntity: ServiceEntity): Trip {
|
||||||
|
if (tripEntity.serviceId != serviceEntity.id) {
|
||||||
|
throw IllegalArgumentException("trip and service id mismatch (${tripEntity.serviceId} != ${serviceEntity.id})")
|
||||||
|
}
|
||||||
|
return with(tripEntity) {
|
||||||
|
Trip(
|
||||||
|
id = id,
|
||||||
|
routeId = routeId,
|
||||||
|
service = serviceEntity.asModel(),
|
||||||
|
shapeId = shapeId,
|
||||||
|
tripHeadsign = tripHeadsign,
|
||||||
|
directionId = directionId,
|
||||||
|
blockId = blockId,
|
||||||
|
wheelchairAccessible = wheelchairAccessible
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Trip.asEntity() = TripEntity(id, routeId, serviceId, shapeId, tripHeadsign, directionId, blockId, wheelchairAccessible)
|
fun Trip.asEntity() = TripEntity(id, routeId, service.id, shapeId, tripHeadsign, directionId, blockId, wheelchairAccessible)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package moe.lava.banksia.util
|
package moe.lava.banksia.util
|
||||||
|
|
||||||
|
/** Wraps an arbitrary value, such that equality checks are forced to be done by reference */
|
||||||
class BoxedValue<T>(val value: T) {
|
class BoxedValue<T>(val value: T) {
|
||||||
operator fun component1() = value
|
operator fun component1() = value
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package moe.lava.banksia.util
|
||||||
|
|
||||||
|
import kotlinx.datetime.DayOfWeek
|
||||||
|
|
||||||
|
private fun Int.check(other: Int) = (this and other) != 0
|
||||||
|
|
||||||
|
fun Int.deserialiseDaysBitflag(): List<DayOfWeek> = buildList {
|
||||||
|
val days = this@deserialiseDaysBitflag
|
||||||
|
if (days.check(1))
|
||||||
|
add(DayOfWeek.MONDAY)
|
||||||
|
if (days.check(1 shl 1))
|
||||||
|
add(DayOfWeek.TUESDAY)
|
||||||
|
if (days.check(1 shl 2))
|
||||||
|
add(DayOfWeek.WEDNESDAY)
|
||||||
|
if (days.check(1 shl 3))
|
||||||
|
add(DayOfWeek.THURSDAY)
|
||||||
|
if (days.check(1 shl 4))
|
||||||
|
add(DayOfWeek.FRIDAY)
|
||||||
|
if (days.check(1 shl 5))
|
||||||
|
add(DayOfWeek.SATURDAY)
|
||||||
|
if (days.check(1 shl 6))
|
||||||
|
add(DayOfWeek.SUNDAY)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun List<DayOfWeek>.serialise(): Int =
|
||||||
|
this.fold(0) { vl, n ->
|
||||||
|
vl + when (n) {
|
||||||
|
DayOfWeek.MONDAY -> 1
|
||||||
|
DayOfWeek.TUESDAY -> 1 shl 1
|
||||||
|
DayOfWeek.WEDNESDAY -> 1 shl 2
|
||||||
|
DayOfWeek.THURSDAY -> 1 shl 3
|
||||||
|
DayOfWeek.FRIDAY -> 1 shl 4
|
||||||
|
DayOfWeek.SATURDAY -> 1 shl 5
|
||||||
|
DayOfWeek.SUNDAY -> 1 shl 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,25 +1,31 @@
|
||||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlinMultiplatform)
|
alias(libs.plugins.kotlinMultiplatform)
|
||||||
alias(libs.plugins.kotlinSerialization)
|
alias(libs.plugins.kotlinSerialization)
|
||||||
alias(libs.plugins.androidApplication)
|
alias(libs.plugins.androidMultiplatformLibrary)
|
||||||
alias(libs.plugins.composeMultiplatform)
|
alias(libs.plugins.composeMultiplatform)
|
||||||
alias(libs.plugins.composeCompiler)
|
alias(libs.plugins.composeCompiler)
|
||||||
alias(libs.plugins.secretsGradle)
|
alias(libs.plugins.secretsGradle)
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
androidTarget {
|
android {
|
||||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
namespace = "moe.lava.banksia.ui"
|
||||||
|
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||||
|
|
||||||
compilerOptions {
|
compilerOptions {
|
||||||
jvmTarget.set(JvmTarget.JVM_11)
|
jvmTarget.set(JvmTarget.JVM_11)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
androidResources {
|
||||||
|
enable = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compilerOptions {
|
compilerOptions {
|
||||||
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||||
|
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
|
|
@ -35,9 +41,6 @@ kotlin {
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
androidMain.dependencies {
|
androidMain.dependencies {
|
||||||
implementation(libs.compose.ui.tooling.preview)
|
|
||||||
implementation(libs.androidx.activity.compose)
|
|
||||||
implementation(libs.kotlinx.coroutines.android)
|
|
||||||
implementation(libs.play.services.location)
|
implementation(libs.play.services.location)
|
||||||
}
|
}
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
|
|
@ -66,47 +69,16 @@ kotlin {
|
||||||
|
|
||||||
implementation(projects.client)
|
implementation(projects.client)
|
||||||
implementation(projects.shared)
|
implementation(projects.shared)
|
||||||
|
implementation(projects.ui.maps)
|
||||||
|
implementation(projects.ui.shared)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
|
||||||
namespace = "moe.lava.banksia"
|
|
||||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
applicationId = "moe.lava.banksia"
|
|
||||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
|
||||||
targetSdk = libs.versions.android.targetSdk.get().toInt()
|
|
||||||
versionCode = 1
|
|
||||||
versionName = "1.0"
|
|
||||||
}
|
|
||||||
packaging {
|
|
||||||
resources {
|
|
||||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buildTypes {
|
|
||||||
getByName("release") {
|
|
||||||
isMinifyEnabled = false
|
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
debugImplementation(compose.uiTooling)
|
androidRuntimeClasspath(libs.compose.ui.tooling)
|
||||||
}
|
}
|
||||||
|
|
||||||
secrets {
|
secrets {
|
||||||
propertiesFileName = "secrets.properties"
|
propertiesFileName = "secrets.properties"
|
||||||
}
|
}
|
||||||
|
|
||||||
compose.resources {
|
|
||||||
publicResClass = true
|
|
||||||
packageOfResClass = "moe.lava.banksia.resources"
|
|
||||||
}
|
|
||||||
|
|
|
||||||
56
ui/maps/build.gradle.kts
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlinMultiplatform)
|
||||||
|
alias(libs.plugins.kotlinSerialization)
|
||||||
|
alias(libs.plugins.androidMultiplatformLibrary)
|
||||||
|
alias(libs.plugins.composeMultiplatform)
|
||||||
|
alias(libs.plugins.composeCompiler)
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
android {
|
||||||
|
namespace = "moe.lava.banksia.ui.map"
|
||||||
|
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||||
|
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget.set(JvmTarget.JVM_11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compilerOptions {
|
||||||
|
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||||
|
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
iosArm64()
|
||||||
|
iosSimulatorArm64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
androidMain.dependencies {
|
||||||
|
implementation(libs.compose.ui.tooling.preview)
|
||||||
|
implementation(libs.androidx.activity.compose)
|
||||||
|
implementation(libs.kotlinx.coroutines.android)
|
||||||
|
implementation(libs.play.services.location)
|
||||||
|
}
|
||||||
|
commonMain.dependencies {
|
||||||
|
implementation(libs.koin.core)
|
||||||
|
implementation(libs.kotlinx.coroutines.core)
|
||||||
|
implementation(libs.kotlinx.datetime)
|
||||||
|
implementation(libs.ktor.serialization.kotlinx.json)
|
||||||
|
|
||||||
|
implementation(libs.maplibre.compose)
|
||||||
|
implementation(libs.moko.geo)
|
||||||
|
implementation(libs.moko.geo.compose)
|
||||||
|
|
||||||
|
implementation(libs.compose.components.resources)
|
||||||
|
implementation(libs.compose.runtime)
|
||||||
|
implementation(libs.compose.foundation)
|
||||||
|
implementation(libs.compose.material3)
|
||||||
|
implementation(libs.compose.ui)
|
||||||
|
|
||||||
|
implementation(projects.shared)
|
||||||
|
implementation(projects.ui.shared)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
package moe.lava.banksia.ui.map
|
||||||
|
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.add
|
||||||
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import moe.lava.banksia.Constants
|
||||||
|
import moe.lava.banksia.ui.map.mappers.routeColorExpression
|
||||||
|
import moe.lava.banksia.ui.platform.BanksiaTheme
|
||||||
|
import org.maplibre.compose.camera.CameraPosition
|
||||||
|
import org.maplibre.compose.camera.rememberCameraState
|
||||||
|
import org.maplibre.compose.expressions.dsl.const
|
||||||
|
import org.maplibre.compose.layers.CircleLayer
|
||||||
|
import org.maplibre.compose.map.MapOptions
|
||||||
|
import org.maplibre.compose.map.MaplibreMap
|
||||||
|
import org.maplibre.compose.map.OrnamentOptions
|
||||||
|
import org.maplibre.compose.sources.GeoJsonData
|
||||||
|
import org.maplibre.compose.sources.rememberGeoJsonSource
|
||||||
|
import org.maplibre.compose.style.BaseStyle
|
||||||
|
import org.maplibre.compose.util.ClickResult
|
||||||
|
import org.maplibre.spatialk.geojson.Feature
|
||||||
|
import org.maplibre.spatialk.geojson.Geometry
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun MapLibreMaps(
|
||||||
|
modifier: Modifier,
|
||||||
|
insets: WindowInsets,
|
||||||
|
positionState: MapsPositionState,
|
||||||
|
stops: GeoJsonData.Features?,
|
||||||
|
// vehicles: GeoJsonData.Features?,
|
||||||
|
stopInnerColor: Color,
|
||||||
|
onStopClicked: (Feature<Geometry, JsonObject?>) -> Unit,
|
||||||
|
) {
|
||||||
|
val camPos = rememberCameraState(
|
||||||
|
CameraPosition(
|
||||||
|
zoom = 16.0,
|
||||||
|
target = MELBOURNE_POS
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val variant = if (isSystemInDarkTheme()) "dark" else "light"
|
||||||
|
|
||||||
|
MaplibreMap(
|
||||||
|
modifier = modifier,
|
||||||
|
baseStyle = BaseStyle.Uri("https://api.protomaps.com/styles/v5/$variant/en.json?key=${Constants.protomapsKey}"),
|
||||||
|
cameraState = camPos,
|
||||||
|
options = MapOptions(
|
||||||
|
ornamentOptions = OrnamentOptions(
|
||||||
|
padding = WindowInsets.safeDrawing.add(insets).asPaddingValues(),
|
||||||
|
isScaleBarEnabled = false,
|
||||||
|
isAttributionEnabled = false,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (stops != null) {
|
||||||
|
val stopsSource = rememberGeoJsonSource(stops)
|
||||||
|
CircleLayer(
|
||||||
|
id = "maps-stops0",
|
||||||
|
source = stopsSource,
|
||||||
|
color = const(BanksiaTheme.colors.surface),
|
||||||
|
radius = const(3.dp),
|
||||||
|
strokeWidth = const(2.dp),
|
||||||
|
strokeColor = routeColorExpression,
|
||||||
|
)
|
||||||
|
CircleLayer(
|
||||||
|
id = "maps-stops0-clickhandler",
|
||||||
|
source = stopsSource,
|
||||||
|
color = const(Color.Transparent),
|
||||||
|
radius = const(12.dp),
|
||||||
|
onClick = { features ->
|
||||||
|
// onEvent(MapScreenEvent.SelectStop(marker.type to feature.id!!.content))
|
||||||
|
// val marker = Json.decodeFromJsonElement<T>(feature.properties!!)
|
||||||
|
onStopClicked(features[0])
|
||||||
|
ClickResult.Consume
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package moe.lava.banksia.ui.map
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import moe.lava.banksia.ui.map.mappers.asFeatures
|
||||||
|
import moe.lava.banksia.ui.map.mappers.toPosition
|
||||||
|
import moe.lava.banksia.ui.map.util.Marker
|
||||||
|
import moe.lava.banksia.ui.platform.BanksiaTheme
|
||||||
|
import moe.lava.banksia.util.Point
|
||||||
|
|
||||||
|
internal val MELBOURNE = Point(-37.8136, 144.9631)
|
||||||
|
internal val MELBOURNE_POS = MELBOURNE.toPosition()
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun Maps(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
insets: WindowInsets = WindowInsets(),
|
||||||
|
stops: List<Marker.Stop> = listOf(),
|
||||||
|
// vehicles: List<Marker.Vehicle> = listOf(),
|
||||||
|
positionState: MapsPositionState = rememberMapsPositionState(),
|
||||||
|
onStopClicked: (id: String) -> Unit = {},
|
||||||
|
// onVehicleClicked: (id: String) -> Unit = {},
|
||||||
|
) {
|
||||||
|
MapLibreMaps(
|
||||||
|
modifier = modifier,
|
||||||
|
insets = insets,
|
||||||
|
positionState = positionState,
|
||||||
|
stops = stops.takeIf { it.isNotEmpty() }?.asFeatures(),
|
||||||
|
// vehicles = vehicles.takeIf { it.isNotEmpty() }?.asFeatures(),
|
||||||
|
stopInnerColor = BanksiaTheme.colors.surface,
|
||||||
|
onStopClicked = { feature -> onStopClicked(feature.id!!.content) },
|
||||||
|
// onVehicleClicked = {},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package moe.lava.banksia.ui.map
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import moe.lava.banksia.util.Point
|
||||||
|
|
||||||
|
class MapsPositionState internal constructor(
|
||||||
|
private val scope: CoroutineScope
|
||||||
|
) {
|
||||||
|
internal val updates: SharedFlow<Point>
|
||||||
|
field = MutableSharedFlow()
|
||||||
|
|
||||||
|
fun update(position: Point) {
|
||||||
|
scope.launch { updates.emit(position) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberMapsPositionState(): MapsPositionState {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
return remember { MapsPositionState(scope) }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package moe.lava.banksia.ui.map.mappers
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import moe.lava.banksia.model.RouteType
|
||||||
|
import moe.lava.banksia.ui.map.util.Marker
|
||||||
|
import org.maplibre.compose.sources.GeoJsonData
|
||||||
|
import org.maplibre.spatialk.geojson.FeatureCollection
|
||||||
|
import org.maplibre.spatialk.geojson.dsl.addFeature
|
||||||
|
import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection
|
||||||
|
import org.maplibre.spatialk.geojson.Point as MLPoint
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class MarkerProps(
|
||||||
|
val type: RouteType,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
internal inline fun Iterable<Marker>.asFeatures() = GeoJsonData.Features(asFeatureCollection())
|
||||||
|
|
||||||
|
internal fun Iterable<Marker>.asFeatureCollection(): FeatureCollection<MLPoint, MarkerProps> {
|
||||||
|
val markers = this
|
||||||
|
return buildFeatureCollection {
|
||||||
|
markers.forEach { marker ->
|
||||||
|
val type = when (marker) {
|
||||||
|
is Marker.Stop -> marker.type
|
||||||
|
is Marker.Vehicle -> marker.type
|
||||||
|
}
|
||||||
|
val id = when (marker) {
|
||||||
|
is Marker.Stop -> marker.id
|
||||||
|
is Marker.Vehicle -> marker.ref
|
||||||
|
}
|
||||||
|
addFeature(
|
||||||
|
geometry = MLPoint(marker.point.toPosition()),
|
||||||
|
properties = MarkerProps(type),
|
||||||
|
) {
|
||||||
|
setId(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package moe.lava.banksia.ui.map.mappers
|
||||||
|
|
||||||
|
import moe.lava.banksia.util.Point
|
||||||
|
import org.maplibre.spatialk.geojson.Position
|
||||||
|
|
||||||
|
internal fun Point.toPosition() = Position(lng, lat)
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package moe.lava.banksia.ui.map.mappers
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import moe.lava.banksia.model.RouteType
|
||||||
|
import moe.lava.banksia.ui.extensions.getUIProperties
|
||||||
|
import moe.lava.banksia.ui.platform.BanksiaTheme
|
||||||
|
import org.maplibre.compose.expressions.dsl.case
|
||||||
|
import org.maplibre.compose.expressions.dsl.const
|
||||||
|
import org.maplibre.compose.expressions.dsl.convertToString
|
||||||
|
import org.maplibre.compose.expressions.dsl.feature
|
||||||
|
import org.maplibre.compose.expressions.dsl.switch
|
||||||
|
|
||||||
|
internal val routeColorExpression @Composable get() = switch(
|
||||||
|
input = feature["type"].convertToString(),
|
||||||
|
cases = RouteType.entries.map {
|
||||||
|
case(label = it.name, output = const(it.getUIProperties().colour))
|
||||||
|
}.toTypedArray(),
|
||||||
|
fallback = const(BanksiaTheme.colors.surface),
|
||||||
|
)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package moe.lava.banksia.ui.utils.map
|
package moe.lava.banksia.ui.map.util
|
||||||
|
|
||||||
import moe.lava.banksia.util.Point
|
import moe.lava.banksia.util.Point
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package moe.lava.banksia.ui.utils.map
|
package moe.lava.banksia.ui.map.util
|
||||||
|
|
||||||
import moe.lava.banksia.util.Point
|
import moe.lava.banksia.util.Point
|
||||||
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package moe.lava.banksia.ui.map.util
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import moe.lava.banksia.model.RouteType
|
||||||
|
import moe.lava.banksia.util.Point
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
sealed class Marker {
|
||||||
|
abstract val point: Point
|
||||||
|
|
||||||
|
sealed class Typed : Marker() {
|
||||||
|
abstract val type: RouteType
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Stop(
|
||||||
|
override val point: Point,
|
||||||
|
override val type: RouteType,
|
||||||
|
val id: String,
|
||||||
|
) : Typed()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Vehicle(
|
||||||
|
override val point: Point,
|
||||||
|
override val type: RouteType,
|
||||||
|
val ref: String,
|
||||||
|
) : Typed()
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package moe.lava.banksia.ui.utils.map
|
package moe.lava.banksia.ui.map.util
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import moe.lava.banksia.util.Point
|
import moe.lava.banksia.util.Point
|
||||||
50
ui/shared/build.gradle.kts
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlinMultiplatform)
|
||||||
|
alias(libs.plugins.kotlinSerialization)
|
||||||
|
alias(libs.plugins.androidMultiplatformLibrary)
|
||||||
|
alias(libs.plugins.composeMultiplatform)
|
||||||
|
alias(libs.plugins.composeCompiler)
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
android {
|
||||||
|
namespace = "moe.lava.banksia.ui.shared"
|
||||||
|
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||||
|
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget.set(JvmTarget.JVM_11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compilerOptions {
|
||||||
|
freeCompilerArgs.add("-opt-in=kotlin.time.ExperimentalTime")
|
||||||
|
freeCompilerArgs.add("-Xexplicit-backing-fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
iosArm64()
|
||||||
|
iosSimulatorArm64()
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
commonMain.dependencies {
|
||||||
|
implementation(libs.compose.components.resources)
|
||||||
|
implementation(libs.compose.runtime)
|
||||||
|
implementation(libs.compose.foundation)
|
||||||
|
implementation(libs.compose.material3)
|
||||||
|
implementation(libs.compose.ui)
|
||||||
|
implementation(libs.compose.ui.tooling.preview)
|
||||||
|
|
||||||
|
implementation(projects.shared)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
androidRuntimeClasspath(libs.compose.ui.tooling)
|
||||||
|
}
|
||||||
|
|
||||||
|
compose.resources {
|
||||||
|
publicResClass = true
|
||||||
|
packageOfResClass = "moe.lava.banksia.resources"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package moe.lava.banksia.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawBehind
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import moe.lava.banksia.model.RouteType
|
||||||
|
import moe.lava.banksia.model.RouteType.MetroBus
|
||||||
|
import moe.lava.banksia.model.RouteType.MetroTrain
|
||||||
|
import moe.lava.banksia.model.RouteType.MetroTram
|
||||||
|
import moe.lava.banksia.ui.extensions.getUIProperties
|
||||||
|
import org.jetbrains.compose.resources.painterResource
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RouteIcon(
|
||||||
|
modifier: Modifier = Modifier.Companion,
|
||||||
|
size: Dp = 40.dp,
|
||||||
|
routeType: RouteType,
|
||||||
|
) {
|
||||||
|
val properties = routeType.getUIProperties()
|
||||||
|
Image(
|
||||||
|
painter = painterResource(properties.icon),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = modifier
|
||||||
|
.size(size)
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.padding(size * ICON_PADDING / 2)
|
||||||
|
.drawBehind {
|
||||||
|
drawCircle(properties.colour, radius = size.toPx() / 2f)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const val ICON_PADDING = 0.25f
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
internal fun RouteIconPreview() {
|
||||||
|
Row {
|
||||||
|
RouteIcon(routeType = MetroTrain)
|
||||||
|
RouteIcon(routeType = MetroTram)
|
||||||
|
RouteIcon(routeType = MetroBus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,27 +1,8 @@
|
||||||
package moe.lava.banksia.ui.components
|
package moe.lava.banksia.ui.extensions
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.drawBehind
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import moe.lava.banksia.data.ptv.structures.PtvRouteType
|
import moe.lava.banksia.data.ptv.structures.PtvRouteType
|
||||||
import moe.lava.banksia.model.RouteType
|
import moe.lava.banksia.model.RouteType
|
||||||
import moe.lava.banksia.model.RouteType.Interstate
|
|
||||||
import moe.lava.banksia.model.RouteType.MetroBus
|
|
||||||
import moe.lava.banksia.model.RouteType.MetroTrain
|
|
||||||
import moe.lava.banksia.model.RouteType.MetroTram
|
|
||||||
import moe.lava.banksia.model.RouteType.RegionalBus
|
|
||||||
import moe.lava.banksia.model.RouteType.RegionalCoach
|
|
||||||
import moe.lava.banksia.model.RouteType.RegionalTrain
|
|
||||||
import moe.lava.banksia.model.RouteType.SkyBus
|
|
||||||
import moe.lava.banksia.resources.Res
|
import moe.lava.banksia.resources.Res
|
||||||
import moe.lava.banksia.resources.bus
|
import moe.lava.banksia.resources.bus
|
||||||
import moe.lava.banksia.resources.bus_background
|
import moe.lava.banksia.resources.bus_background
|
||||||
|
|
@ -33,7 +14,6 @@ import moe.lava.banksia.resources.tram
|
||||||
import moe.lava.banksia.resources.tram_background
|
import moe.lava.banksia.resources.tram_background
|
||||||
import moe.lava.banksia.resources.tram_icon
|
import moe.lava.banksia.resources.tram_icon
|
||||||
import org.jetbrains.compose.resources.DrawableResource
|
import org.jetbrains.compose.resources.DrawableResource
|
||||||
import org.jetbrains.compose.resources.painterResource
|
|
||||||
|
|
||||||
data class RouteTypeProperties(
|
data class RouteTypeProperties(
|
||||||
val colour: Color,
|
val colour: Color,
|
||||||
|
|
@ -49,31 +29,31 @@ const val VLINE_PURPLE = 0xFF8F1A95
|
||||||
|
|
||||||
fun RouteType.getUIProperties(): RouteTypeProperties {
|
fun RouteType.getUIProperties(): RouteTypeProperties {
|
||||||
val colour = when (this) {
|
val colour = when (this) {
|
||||||
MetroTrain -> TRAIN_BLUE
|
RouteType.MetroTrain -> TRAIN_BLUE
|
||||||
MetroTram -> TRAM_GREEN
|
RouteType.MetroTram -> TRAM_GREEN
|
||||||
MetroBus -> BUS_ORANGE
|
RouteType.MetroBus -> BUS_ORANGE
|
||||||
RegionalTrain -> VLINE_PURPLE
|
RouteType.RegionalTrain -> VLINE_PURPLE
|
||||||
RegionalCoach -> VLINE_PURPLE
|
RouteType.RegionalCoach -> VLINE_PURPLE
|
||||||
RegionalBus -> VLINE_PURPLE
|
RouteType.RegionalBus -> VLINE_PURPLE
|
||||||
SkyBus -> BUS_ORANGE
|
RouteType.SkyBus -> BUS_ORANGE
|
||||||
Interstate -> BUS_ORANGE
|
RouteType.Interstate -> BUS_ORANGE
|
||||||
}
|
}
|
||||||
|
|
||||||
val (drawable, background, icon) = when (this) {
|
val (drawable, background, icon) = when (this) {
|
||||||
MetroTrain,
|
RouteType.MetroTrain,
|
||||||
RegionalTrain,
|
RouteType.RegionalTrain,
|
||||||
Interstate -> Triple(
|
RouteType.Interstate -> Triple(
|
||||||
Res.drawable.train, Res.drawable.train_background, Res.drawable.train_icon
|
Res.drawable.train, Res.drawable.train_background, Res.drawable.train_icon
|
||||||
)
|
)
|
||||||
|
|
||||||
MetroTram -> Triple(
|
RouteType.MetroTram -> Triple(
|
||||||
Res.drawable.tram, Res.drawable.tram_background, Res.drawable.tram_icon
|
Res.drawable.tram, Res.drawable.tram_background, Res.drawable.tram_icon
|
||||||
)
|
)
|
||||||
|
|
||||||
MetroBus,
|
RouteType.MetroBus,
|
||||||
RegionalCoach,
|
RouteType.RegionalCoach,
|
||||||
RegionalBus,
|
RouteType.RegionalBus,
|
||||||
SkyBus -> Triple(
|
RouteType.SkyBus -> Triple(
|
||||||
Res.drawable.bus, Res.drawable.bus_background, Res.drawable.bus_icon
|
Res.drawable.bus, Res.drawable.bus_background, Res.drawable.bus_icon
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -102,35 +82,3 @@ fun PtvRouteType.getUIProperties(): RouteTypeProperties {
|
||||||
return RouteTypeProperties(colour, drawable, background, icon)
|
return RouteTypeProperties(colour, drawable, background, icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun RouteIcon(
|
|
||||||
modifier: Modifier = Modifier.Companion,
|
|
||||||
size: Dp = 40.dp,
|
|
||||||
routeType: RouteType,
|
|
||||||
) {
|
|
||||||
val properties = routeType.getUIProperties()
|
|
||||||
Image(
|
|
||||||
painter = painterResource(properties.icon),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = modifier
|
|
||||||
.size(size)
|
|
||||||
.aspectRatio(1f)
|
|
||||||
.padding(size * ICON_PADDING / 2)
|
|
||||||
.drawBehind {
|
|
||||||
drawCircle(properties.colour, radius = size.toPx() / 2f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const val ICON_PADDING = 0.25f
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
private fun RouteIconPreview() {
|
|
||||||
Row {
|
|
||||||
RouteIcon(routeType = MetroTrain)
|
|
||||||
RouteIcon(routeType = MetroTram)
|
|
||||||
RouteIcon(routeType = MetroBus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
|
||||||
|
|
||||||
<path android:fillColor="#FFFFFFFF" android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06C6.83,3.52 3.52,6.83 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L23,13v-2h-2.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
|
|
||||||
|
|
||||||
</vector>
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package moe.lava.banksia.ui.layout
|
package moe.lava.banksia.ui.layout.info
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
|
|
@ -7,19 +7,15 @@ import androidx.compose.animation.scaleIn
|
||||||
import androidx.compose.animation.scaleOut
|
import androidx.compose.animation.scaleOut
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeContent
|
import androidx.compose.foundation.layout.safeContent
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.windowInsetsBottomHeight
|
import androidx.compose.foundation.layout.windowInsetsBottomHeight
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.LoadingIndicator
|
import androidx.compose.material3.LoadingIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -28,17 +24,12 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.layout.onSizeChanged
|
import androidx.compose.ui.layout.onSizeChanged
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.coerceAtMost
|
import androidx.compose.ui.unit.coerceAtMost
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import moe.lava.banksia.ui.components.RouteIcon
|
|
||||||
import moe.lava.banksia.ui.screens.map.MapScreenEvent
|
import moe.lava.banksia.ui.screens.map.MapScreenEvent
|
||||||
import moe.lava.banksia.ui.state.InfoPanelState
|
import moe.lava.banksia.ui.state.InfoPanelState
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
@ -77,7 +68,7 @@ fun InfoPanel(
|
||||||
when (state) {
|
when (state) {
|
||||||
is InfoPanelState.Route -> RouteInfoPanel(state, onEvent)
|
is InfoPanelState.Route -> RouteInfoPanel(state, onEvent)
|
||||||
is InfoPanelState.Stop -> StopInfoPanel(state, onEvent)
|
is InfoPanelState.Stop -> StopInfoPanel(state, onEvent)
|
||||||
is InfoPanelState.Run -> RunInfoPanel(state, onEvent)
|
is InfoPanelState.Trip -> TripInfoPanel(state, onEvent)
|
||||||
is InfoPanelState.None -> throw UnsupportedOperationException()
|
is InfoPanelState.None -> throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,82 +87,3 @@ fun InfoPanel(
|
||||||
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.safeContent))
|
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.safeContent))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private inline fun RouteInfoPanel(
|
|
||||||
state: InfoPanelState.Route,
|
|
||||||
onEvent: (MapScreenEvent) -> Unit,
|
|
||||||
) {
|
|
||||||
Column(Modifier.fillMaxWidth()) {
|
|
||||||
Row {
|
|
||||||
RouteIcon(routeType = state.type)
|
|
||||||
Text(
|
|
||||||
state.name,
|
|
||||||
style = MaterialTheme.typography.titleLarge,
|
|
||||||
fontWeight = FontWeight.SemiBold,
|
|
||||||
textAlign = TextAlign.Start
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private inline fun RunInfoPanel(
|
|
||||||
state: InfoPanelState.Run,
|
|
||||||
onEvent: (MapScreenEvent) -> Unit,
|
|
||||||
) {
|
|
||||||
Column(Modifier.fillMaxWidth()) {
|
|
||||||
Row {
|
|
||||||
RouteIcon(routeType = state.type)
|
|
||||||
Text(
|
|
||||||
"${state.direction} via ${state.routeName ?: "..."}",
|
|
||||||
style = MaterialTheme.typography.titleLarge,
|
|
||||||
fontWeight = FontWeight.SemiBold,
|
|
||||||
textAlign = TextAlign.Start
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private inline fun StopInfoPanel(
|
|
||||||
state: InfoPanelState.Stop,
|
|
||||||
onEvent: (MapScreenEvent) -> Unit,
|
|
||||||
) {
|
|
||||||
Column(Modifier.fillMaxWidth()) {
|
|
||||||
Text(
|
|
||||||
state.name,
|
|
||||||
style = MaterialTheme.typography.titleLarge,
|
|
||||||
fontWeight = FontWeight.SemiBold,
|
|
||||||
textAlign = TextAlign.Start
|
|
||||||
)
|
|
||||||
state.subname?.let {
|
|
||||||
Text(
|
|
||||||
"/ $it",
|
|
||||||
modifier = Modifier.padding(start = 5.dp),
|
|
||||||
style = MaterialTheme.typography.titleSmall,
|
|
||||||
color = Color.Gray,
|
|
||||||
fontWeight = FontWeight.SemiBold,
|
|
||||||
textAlign = TextAlign.Start
|
|
||||||
)
|
|
||||||
}
|
|
||||||
state.departures?.let {
|
|
||||||
Spacer(Modifier.height(5.dp))
|
|
||||||
it.forEach { (name, formatted) ->
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
|
||||||
Text(
|
|
||||||
name,
|
|
||||||
style = MaterialTheme.typography.titleMedium,
|
|
||||||
fontWeight = FontWeight.SemiBold
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
formatted,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = Modifier.padding(horizontal = 5.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package moe.lava.banksia.ui.layout.info
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import moe.lava.banksia.ui.components.RouteIcon
|
||||||
|
import moe.lava.banksia.ui.screens.map.MapScreenEvent
|
||||||
|
import moe.lava.banksia.ui.state.InfoPanelState
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun RouteInfoPanel(
|
||||||
|
state: InfoPanelState.Route,
|
||||||
|
onEvent: (MapScreenEvent) -> Unit,
|
||||||
|
) {
|
||||||
|
Column(Modifier.fillMaxWidth()) {
|
||||||
|
Row {
|
||||||
|
RouteIcon(routeType = state.type)
|
||||||
|
Text(
|
||||||
|
state.name,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
textAlign = TextAlign.Start
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package moe.lava.banksia.ui.layout.info
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import moe.lava.banksia.ui.screens.map.MapScreenEvent
|
||||||
|
import moe.lava.banksia.ui.state.InfoPanelState
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun StopInfoPanel(
|
||||||
|
state: InfoPanelState.Stop,
|
||||||
|
onEvent: (MapScreenEvent) -> Unit,
|
||||||
|
) {
|
||||||
|
Column(Modifier.fillMaxWidth()) {
|
||||||
|
Text(
|
||||||
|
state.name,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
textAlign = TextAlign.Start
|
||||||
|
)
|
||||||
|
state.subname?.let {
|
||||||
|
Text(
|
||||||
|
"/ $it",
|
||||||
|
modifier = Modifier.padding(start = 5.dp),
|
||||||
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
color = Color.Gray,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
textAlign = TextAlign.Start
|
||||||
|
)
|
||||||
|
}
|
||||||
|
state.departures?.let {
|
||||||
|
Spacer(Modifier.height(5.dp))
|
||||||
|
it.forEach { (name, formatted) ->
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Text(
|
||||||
|
name,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
formatted,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.padding(horizontal = 5.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package moe.lava.banksia.ui.layout.info
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import moe.lava.banksia.ui.components.RouteIcon
|
||||||
|
import moe.lava.banksia.ui.screens.map.MapScreenEvent
|
||||||
|
import moe.lava.banksia.ui.state.InfoPanelState
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun TripInfoPanel(
|
||||||
|
state: InfoPanelState.Trip,
|
||||||
|
onEvent: (MapScreenEvent) -> Unit,
|
||||||
|
) {
|
||||||
|
Column(Modifier.fillMaxWidth()) {
|
||||||
|
Row {
|
||||||
|
RouteIcon(routeType = state.type)
|
||||||
|
Text(
|
||||||
|
"${state.direction} via ${state.routeName ?: "..."}",
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
textAlign = TextAlign.Start
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -35,17 +35,15 @@ import kotlinx.coroutines.launch
|
||||||
import moe.lava.banksia.resources.Res
|
import moe.lava.banksia.resources.Res
|
||||||
import moe.lava.banksia.resources.my_location_24
|
import moe.lava.banksia.resources.my_location_24
|
||||||
import moe.lava.banksia.ui.layout.AppBottomSheet
|
import moe.lava.banksia.ui.layout.AppBottomSheet
|
||||||
import moe.lava.banksia.ui.layout.InfoPanel
|
|
||||||
import moe.lava.banksia.ui.layout.Searcher
|
import moe.lava.banksia.ui.layout.Searcher
|
||||||
import moe.lava.banksia.ui.layout.SheetStateWrapper
|
import moe.lava.banksia.ui.layout.SheetStateWrapper
|
||||||
|
import moe.lava.banksia.ui.layout.info.InfoPanel
|
||||||
|
import moe.lava.banksia.ui.map.Maps
|
||||||
import moe.lava.banksia.ui.platform.BanksiaTheme
|
import moe.lava.banksia.ui.platform.BanksiaTheme
|
||||||
import moe.lava.banksia.ui.state.InfoPanelState
|
import moe.lava.banksia.ui.state.InfoPanelState
|
||||||
import moe.lava.banksia.util.Point
|
|
||||||
import org.jetbrains.compose.resources.painterResource
|
import org.jetbrains.compose.resources.painterResource
|
||||||
import org.koin.compose.viewmodel.koinViewModel
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
|
|
||||||
val MELBOURNE = Point(-37.8136, 144.9631)
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MapScreen(
|
fun MapScreen(
|
||||||
|
|
@ -78,14 +76,20 @@ fun MapScreen(
|
||||||
Scaffold {
|
Scaffold {
|
||||||
Maps(
|
Maps(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
state = mapState,
|
insets = WindowInsets(top = with(LocalDensity.current) {
|
||||||
onEvent = viewModel::handleEvent,
|
|
||||||
cameraPositionFlow = viewModel.cameraChangeEmitter,
|
|
||||||
extInsets = WindowInsets(top = with(LocalDensity.current) {
|
|
||||||
SearchBarDefaults.InputFieldHeight.roundToPx()
|
SearchBarDefaults.InputFieldHeight.roundToPx()
|
||||||
}, bottom = sheetState.bottomInset),
|
}, bottom = sheetState.bottomInset),
|
||||||
setLastKnownLocation = viewModel::setLastKnownLocation,
|
stops = mapState.stops,
|
||||||
|
// vehicles = mapState.vehicles,
|
||||||
|
onStopClicked = { stop ->
|
||||||
|
viewModel.handleEvent(MapScreenEvent.SelectStop(stop))
|
||||||
|
},
|
||||||
|
// onEvent = viewModel::handleEvent,
|
||||||
|
// cameraPositionFlow = viewModel.cameraChangeEmitter,
|
||||||
|
// setLastKnownLocation = viewModel::setLastKnownLocation,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// onEvent()
|
||||||
Searcher(
|
Searcher(
|
||||||
state = searchState,
|
state = searchState,
|
||||||
onEvent = viewModel::handleEvent,
|
onEvent = viewModel::handleEvent,
|
||||||
|
|
|
||||||
|
|
@ -13,41 +13,41 @@ import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.takeWhile
|
import kotlinx.coroutines.flow.takeWhile
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.toInstant
|
||||||
import moe.lava.banksia.client.repository.RouteRepository
|
import moe.lava.banksia.client.repository.RouteRepository
|
||||||
import moe.lava.banksia.client.repository.StopRepository
|
import moe.lava.banksia.client.repository.StopRepository
|
||||||
|
import moe.lava.banksia.client.repository.StopTimeRepository
|
||||||
import moe.lava.banksia.data.ptv.PtvService
|
import moe.lava.banksia.data.ptv.PtvService
|
||||||
import moe.lava.banksia.data.ptv.structures.PtvRoute
|
|
||||||
import moe.lava.banksia.model.Route
|
import moe.lava.banksia.model.Route
|
||||||
import moe.lava.banksia.model.RouteType
|
import moe.lava.banksia.model.RouteType
|
||||||
import moe.lava.banksia.ui.components.getUIProperties
|
import moe.lava.banksia.ui.map.util.CameraPosition
|
||||||
|
import moe.lava.banksia.ui.map.util.CameraPositionBounds
|
||||||
|
import moe.lava.banksia.ui.map.util.Marker
|
||||||
import moe.lava.banksia.ui.state.InfoPanelState
|
import moe.lava.banksia.ui.state.InfoPanelState
|
||||||
import moe.lava.banksia.ui.state.MapState
|
import moe.lava.banksia.ui.state.MapState
|
||||||
import moe.lava.banksia.ui.state.SearchState
|
import moe.lava.banksia.ui.state.SearchState
|
||||||
import moe.lava.banksia.ui.utils.map.CameraPosition
|
|
||||||
import moe.lava.banksia.ui.utils.map.CameraPositionBounds
|
|
||||||
import moe.lava.banksia.ui.utils.map.Marker
|
|
||||||
import moe.lava.banksia.ui.utils.map.Polyline
|
|
||||||
import moe.lava.banksia.util.BoxedValue
|
import moe.lava.banksia.util.BoxedValue
|
||||||
import moe.lava.banksia.util.BoxedValue.Companion.box
|
import moe.lava.banksia.util.BoxedValue.Companion.box
|
||||||
import moe.lava.banksia.util.LoopFlow.Companion.waitUntilSubscribed
|
import moe.lava.banksia.util.LoopFlow.Companion.waitUntilSubscribed
|
||||||
import moe.lava.banksia.util.Point
|
import moe.lava.banksia.util.Point
|
||||||
import moe.lava.banksia.util.log
|
import moe.lava.banksia.util.log
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Duration.Companion.minutes
|
||||||
|
|
||||||
sealed class MapScreenEvent {
|
sealed class MapScreenEvent {
|
||||||
data object DismissState : MapScreenEvent()
|
data object DismissState : MapScreenEvent()
|
||||||
|
|
||||||
data class SelectRoute(val id: String?) : MapScreenEvent()
|
data class SelectRoute(val id: String?) : MapScreenEvent()
|
||||||
data class SelectRun(val ref: String?) : MapScreenEvent()
|
data class SelectRun(val ref: String?) : MapScreenEvent()
|
||||||
data class SelectStop(val typeIdPair: Pair<RouteType, String>?) : MapScreenEvent()
|
data class SelectStop(val id: String?) : MapScreenEvent()
|
||||||
|
|
||||||
data class SearchUpdate(val text: String) : MapScreenEvent()
|
data class SearchUpdate(val text: String) : MapScreenEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class InternalState(
|
data class InternalState(
|
||||||
val route: String? = null,
|
val route: String? = null,
|
||||||
val stop: Pair<RouteType, String>? = null,
|
val stop: String? = null,
|
||||||
val run: String? = null,
|
val run: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -55,6 +55,7 @@ class MapScreenViewModel(
|
||||||
private val ptvService: PtvService,
|
private val ptvService: PtvService,
|
||||||
private val routeRepository: RouteRepository,
|
private val routeRepository: RouteRepository,
|
||||||
private val stopRepository: StopRepository,
|
private val stopRepository: StopRepository,
|
||||||
|
private val stopTimeRepository: StopTimeRepository,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private var state = InternalState()
|
private var state = InternalState()
|
||||||
set(value) {
|
set(value) {
|
||||||
|
|
@ -92,7 +93,7 @@ class MapScreenViewModel(
|
||||||
is MapScreenEvent.DismissState -> dismissState()
|
is MapScreenEvent.DismissState -> dismissState()
|
||||||
is MapScreenEvent.SelectRoute -> state = InternalState(route = event.id)
|
is MapScreenEvent.SelectRoute -> state = InternalState(route = event.id)
|
||||||
is MapScreenEvent.SelectRun -> state = state.copy(run = event.ref, stop = null)
|
is MapScreenEvent.SelectRun -> state = state.copy(run = event.ref, stop = null)
|
||||||
is MapScreenEvent.SelectStop -> state = state.copy(stop = event.typeIdPair, run = null)
|
is MapScreenEvent.SelectStop -> state = state.copy(stop = event.id, run = null)
|
||||||
is MapScreenEvent.SearchUpdate -> searchUpdate(event.text)
|
is MapScreenEvent.SearchUpdate -> searchUpdate(event.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -186,7 +187,7 @@ class MapScreenViewModel(
|
||||||
.onEach { run ->
|
.onEach { run ->
|
||||||
if (routeName == null) {
|
if (routeName == null) {
|
||||||
iInfoState.update {
|
iInfoState.update {
|
||||||
InfoPanelState.Run(
|
InfoPanelState.Trip(
|
||||||
direction = run.destinationName,
|
direction = run.destinationName,
|
||||||
type = RouteType.MetroTrain, // XXX HACK TODO FIXME
|
type = RouteType.MetroTrain, // XXX HACK TODO FIXME
|
||||||
)
|
)
|
||||||
|
|
@ -195,7 +196,7 @@ class MapScreenViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
iInfoState.update {
|
iInfoState.update {
|
||||||
InfoPanelState.Run(
|
InfoPanelState.Trip(
|
||||||
direction = run.destinationName,
|
direction = run.destinationName,
|
||||||
type = RouteType.MetroTrain, // FIXME HACK XXX TODO
|
type = RouteType.MetroTrain, // FIXME HACK XXX TODO
|
||||||
routeName = routeName,
|
routeName = routeName,
|
||||||
|
|
@ -206,12 +207,11 @@ class MapScreenViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
// [TODO]: Cleanup
|
// [TODO]: Cleanup
|
||||||
private suspend fun switchStop(pair: Pair<RouteType, String>?) {
|
private suspend fun switchStop(id: String?) {
|
||||||
if (pair == null) {
|
if (id == null) {
|
||||||
iInfoState.update { InfoPanelState.None }
|
iInfoState.update { InfoPanelState.None }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val (type, id) = pair
|
|
||||||
|
|
||||||
val stop = stopRepository.get(id)
|
val stop = stopRepository.get(id)
|
||||||
// val stop = ptvService.stop(routeType, stopId)
|
// val stop = ptvService.stop(routeType, stopId)
|
||||||
|
|
@ -226,36 +226,24 @@ class MapScreenViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val res = ptvService.departures(type, stop.id)
|
val departures = stopTimeRepository.getForStop(id)
|
||||||
// Map<
|
.filter { !it.headsign.isNullOrBlank() }
|
||||||
// Pair<DirectionId, RouteId>,
|
.groupBy { it.headsign!! }
|
||||||
// Pair<DirectionName, List<DepartureTimes>>
|
.map { (headsign, stopTimes) ->
|
||||||
// >
|
val now = Clock.System.now()
|
||||||
val timetable = HashMap<Pair<Int, Int>, Pair<String, MutableList<String>>>()
|
val times = stopTimes
|
||||||
res.departures.forEach { dep ->
|
.map { it.arrivalTime.toInstant(TimeZone.currentSystemDefault()) }
|
||||||
val key = Pair(dep.directionId, dep.routeId)
|
.filter { it >= (now - 1.minutes) }
|
||||||
val direction = ptvService.direction(dep.directionId, dep.routeId)
|
.joinToString(" | ") {
|
||||||
val route = res.routes[dep.routeId.toString()]
|
val diff = (it - now).inWholeMinutes.coerceAtLeast(0)
|
||||||
val prefix = route?.let { if (it.routeNumber == "") "" else "${it.routeNumber} - " } ?: ""
|
if (diff >= 65) {
|
||||||
val element = timetable.getOrPut(key) { Pair(prefix + direction.directionName, mutableListOf()) }.second
|
"${((diff + 30.0) / 60.0).toInt()}hr"
|
||||||
if (element.size >= 5)
|
} else {
|
||||||
return@forEach
|
"${diff}mn"
|
||||||
|
}
|
||||||
val date = Instant.parse(dep.estimatedDepartureUtc ?: dep.scheduledDepartureUtc)
|
}
|
||||||
val min = (date - Clock.System.now()).inWholeMinutes
|
InfoPanelState.Stop.Departure(headsign, times)
|
||||||
if (min <= -5)
|
}
|
||||||
return@forEach
|
|
||||||
if (min >= 65)
|
|
||||||
element.add("${((min + 30.0) / 60.0).toInt()}hr")
|
|
||||||
else
|
|
||||||
element.add("${min}mn")
|
|
||||||
}
|
|
||||||
val departures = timetable.values.sortedBy { it.first }.map { (name, list) ->
|
|
||||||
if (list.isEmpty())
|
|
||||||
InfoPanelState.Stop.Departure(name, "No departures")
|
|
||||||
else
|
|
||||||
InfoPanelState.Stop.Departure(name, list.joinToString(" | "))
|
|
||||||
}
|
|
||||||
iInfoState.update {
|
iInfoState.update {
|
||||||
if (it !is InfoPanelState.Stop)
|
if (it !is InfoPanelState.Stop)
|
||||||
it
|
it
|
||||||
|
|
@ -264,7 +252,7 @@ class MapScreenViewModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun buildPolylines(route: PtvRoute) {
|
/*private suspend fun buildPolylines(route: PtvRoute) {
|
||||||
val routeWithGeo = if (route.geopath.isEmpty())
|
val routeWithGeo = if (route.geopath.isEmpty())
|
||||||
ptvService.route(route.routeId, true)
|
ptvService.route(route.routeId, true)
|
||||||
else
|
else
|
||||||
|
|
@ -294,9 +282,9 @@ class MapScreenViewModel(
|
||||||
|
|
||||||
iMapState.update { it.copy(polylines = polylines) }
|
iMapState.update { it.copy(polylines = polylines) }
|
||||||
newCameraPosition?.let { iCameraChangeEmitter.emit(it.box()) }
|
newCameraPosition?.let { iCameraChangeEmitter.emit(it.box()) }
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private fun buildRuns(route: PtvRoute) {
|
/*private fun buildRuns(route: PtvRoute) {
|
||||||
ptvService
|
ptvService
|
||||||
.runsFlow(route.routeId)
|
.runsFlow(route.routeId)
|
||||||
.waitUntilSubscribed(iInfoState)
|
.waitUntilSubscribed(iInfoState)
|
||||||
|
|
@ -317,19 +305,16 @@ class MapScreenViewModel(
|
||||||
iMapState.update { it.copy(vehicles = markers) }
|
iMapState.update { it.copy(vehicles = markers) }
|
||||||
}
|
}
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
}*/
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun buildStops(route: Route) {
|
private suspend fun buildStops(route: Route) {
|
||||||
val stops = stopRepository.getByRoute(route.id)
|
val stops = stopRepository.getByRoute(route.id)
|
||||||
val colour = route.type.getUIProperties().colour
|
|
||||||
|
|
||||||
val markers = stops
|
val markers = stops
|
||||||
.map { stop ->
|
.map { stop ->
|
||||||
Marker.Stop(
|
Marker.Stop(
|
||||||
point = stop.pos,
|
point = stop.pos,
|
||||||
id = stop.id,
|
id = stop.id,
|
||||||
colour = colour,
|
|
||||||
type = route.type,
|
type = route.type,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,210 +0,0 @@
|
||||||
@file:Suppress("COMPOSE_APPLIER_CALL_MISMATCH")
|
|
||||||
|
|
||||||
package moe.lava.banksia.ui.screens.map
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.add
|
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.safeDrawing
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import kotlinx.serialization.json.decodeFromJsonElement
|
|
||||||
import moe.lava.banksia.model.RouteType
|
|
||||||
import moe.lava.banksia.ui.components.getUIProperties
|
|
||||||
import moe.lava.banksia.ui.platform.BanksiaTheme
|
|
||||||
import moe.lava.banksia.ui.state.MapState
|
|
||||||
import moe.lava.banksia.ui.utils.map.CameraPosition
|
|
||||||
import moe.lava.banksia.ui.utils.map.Marker
|
|
||||||
import moe.lava.banksia.util.BoxedValue
|
|
||||||
import moe.lava.banksia.util.Point
|
|
||||||
import moe.lava.banksia.util.log
|
|
||||||
import org.maplibre.compose.camera.rememberCameraState
|
|
||||||
import org.maplibre.compose.expressions.dsl.case
|
|
||||||
import org.maplibre.compose.expressions.dsl.const
|
|
||||||
import org.maplibre.compose.expressions.dsl.convertToString
|
|
||||||
import org.maplibre.compose.expressions.dsl.feature
|
|
||||||
import org.maplibre.compose.expressions.dsl.switch
|
|
||||||
import org.maplibre.compose.layers.CircleLayer
|
|
||||||
import org.maplibre.compose.map.MapOptions
|
|
||||||
import org.maplibre.compose.map.MaplibreMap
|
|
||||||
import org.maplibre.compose.map.OrnamentOptions
|
|
||||||
import org.maplibre.compose.sources.GeoJsonData
|
|
||||||
import org.maplibre.compose.sources.rememberGeoJsonSource
|
|
||||||
import org.maplibre.compose.style.BaseStyle
|
|
||||||
import org.maplibre.compose.util.ClickResult
|
|
||||||
import org.maplibre.spatialk.geojson.BoundingBox
|
|
||||||
import org.maplibre.spatialk.geojson.FeatureCollection
|
|
||||||
import org.maplibre.spatialk.geojson.Position
|
|
||||||
import org.maplibre.spatialk.geojson.dsl.addFeature
|
|
||||||
import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection
|
|
||||||
import org.maplibre.compose.camera.CameraPosition as MLCameraPosition
|
|
||||||
import org.maplibre.spatialk.geojson.Point as MLPoint
|
|
||||||
|
|
||||||
fun Point.toPos(): Position = Position(this.lng, this.lat)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class MarkerProps(
|
|
||||||
val type: RouteType,
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun buildMarkers(markers: List<Marker>): FeatureCollection<MLPoint, MarkerProps> {
|
|
||||||
return buildFeatureCollection {
|
|
||||||
markers.forEach { marker ->
|
|
||||||
val type = when (marker) {
|
|
||||||
is Marker.Stop -> marker.type
|
|
||||||
is Marker.Vehicle -> marker.type
|
|
||||||
}
|
|
||||||
val id = when (marker) {
|
|
||||||
is Marker.Stop -> marker.id
|
|
||||||
is Marker.Vehicle -> marker.ref
|
|
||||||
}
|
|
||||||
addFeature(
|
|
||||||
geometry = MLPoint(marker.point.toPos()),
|
|
||||||
properties = MarkerProps(type),
|
|
||||||
) {
|
|
||||||
setId(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val colorTypeExpression @Composable get() = switch(
|
|
||||||
input = feature["type"].convertToString(),
|
|
||||||
cases = RouteType.entries.map {
|
|
||||||
case(label = it.name, output = const(it.getUIProperties().colour))
|
|
||||||
}.toTypedArray(),
|
|
||||||
fallback = const(BanksiaTheme.colors.surface),
|
|
||||||
)
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
fun Maps(
|
|
||||||
modifier: Modifier,
|
|
||||||
state: MapState,
|
|
||||||
onEvent: (MapScreenEvent) -> Unit,
|
|
||||||
cameraPositionFlow: Flow<BoxedValue<CameraPosition>>,
|
|
||||||
setLastKnownLocation: (Point) -> Unit,
|
|
||||||
extInsets: WindowInsets,
|
|
||||||
) {
|
|
||||||
val camPos = rememberCameraState(
|
|
||||||
MLCameraPosition(
|
|
||||||
zoom = 16.0,
|
|
||||||
target = MELBOURNE.toPos()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val newCameraPos by cameraPositionFlow.collectAsStateWithLifecycle(null)
|
|
||||||
LaunchedEffect(newCameraPos) {
|
|
||||||
log("maps", "newPos ${newCameraPos?.value}")
|
|
||||||
val pos = newCameraPos?.value ?: return@LaunchedEffect
|
|
||||||
if (pos.bounds != null) {
|
|
||||||
val (northeast, southwest) = pos.bounds
|
|
||||||
camPos.animateTo(
|
|
||||||
boundingBox = BoundingBox(
|
|
||||||
southwest.toPos(),
|
|
||||||
northeast.toPos()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
camPos.animateTo(MLCameraPosition(
|
|
||||||
target = pos.centre.toPos(),
|
|
||||||
zoom = 16.0,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// val ctx = LocalContext.current
|
|
||||||
// val fusedLocation = remember { LocationServices.getFusedLocationProviderClient(ctx) }
|
|
||||||
// LaunchedEffect(Unit) {
|
|
||||||
// @SuppressLint("MissingPermission")
|
|
||||||
// fusedLocation.lastLocation.addOnSuccessListener {
|
|
||||||
// if (it != null) {
|
|
||||||
// camPos.position = MLCameraPosition(
|
|
||||||
// zoom = 16.0,
|
|
||||||
// target = Position(it.longitude, it.latitude)
|
|
||||||
// )
|
|
||||||
// setLastKnownLocation(Point(it.latitude, it.longitude))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
MaplibreMap(
|
|
||||||
modifier = modifier,
|
|
||||||
baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/positron"),
|
|
||||||
cameraState = camPos,
|
|
||||||
options = MapOptions(
|
|
||||||
ornamentOptions = OrnamentOptions(
|
|
||||||
padding = WindowInsets.safeDrawing.add(extInsets).asPaddingValues(),
|
|
||||||
isScaleBarEnabled = false,
|
|
||||||
isAttributionEnabled = false,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
if (state.stops.isNotEmpty()) {
|
|
||||||
val stopsSource = rememberGeoJsonSource(
|
|
||||||
GeoJsonData.Features(buildMarkers(state.stops))
|
|
||||||
)
|
|
||||||
CircleLayer(
|
|
||||||
id = "maps-stops0",
|
|
||||||
source = stopsSource,
|
|
||||||
color = const(BanksiaTheme.colors.surface),
|
|
||||||
radius = const(3.dp),
|
|
||||||
strokeWidth = const(2.dp),
|
|
||||||
strokeColor = colorTypeExpression,
|
|
||||||
)
|
|
||||||
CircleLayer(
|
|
||||||
id = "maps-stops0-clickhandler",
|
|
||||||
source = stopsSource,
|
|
||||||
color = const(Color.Transparent),
|
|
||||||
radius = const(12.dp),
|
|
||||||
onClick = { features ->
|
|
||||||
val feature = features[0]
|
|
||||||
val marker = Json.decodeFromJsonElement<MarkerProps>(feature.properties!!)
|
|
||||||
onEvent(MapScreenEvent.SelectStop(marker.type to feature.id!!.content))
|
|
||||||
ClickResult.Consume
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// if (state.vehicles.isNotEmpty()) {
|
|
||||||
// val stopsSource = rememberGeoJsonSource(
|
|
||||||
// GeoJsonData.Features(buildMarkers(state.vehicles))
|
|
||||||
// )
|
|
||||||
// SymbolLayer
|
|
||||||
// CircleLayer(
|
|
||||||
// id = "maps-vehicles0",
|
|
||||||
// source = stopsSource,
|
|
||||||
// color = const(BanksiaTheme.colors.surface),
|
|
||||||
// radius = const(3.dp),
|
|
||||||
// strokeWidth = const(2.dp),
|
|
||||||
// strokeColor = colorTypeExpression,
|
|
||||||
// onClick = { features ->
|
|
||||||
// val feature = features[0]
|
|
||||||
// val marker = Json.decodeFromJsonElement<MarkerProps>(feature.properties!!)
|
|
||||||
// onEvent(MapScreenEvent.SelectStop(marker.type to feature.id!!.content))
|
|
||||||
// ClickResult.Consume
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (state.polylines.isNotEmpty()) {
|
|
||||||
// val polySource = rememberGeoJsonSource(
|
|
||||||
//
|
|
||||||
// )
|
|
||||||
// LineLayer(
|
|
||||||
// id = "maps-routeline",
|
|
||||||
// source = polySource,
|
|
||||||
// color = colorTypeExpression,
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16,14 +16,6 @@ sealed class InfoPanelState {
|
||||||
override val loading = false
|
override val loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Run(
|
|
||||||
val direction: String,
|
|
||||||
val type: RouteType,
|
|
||||||
val routeName: String? = null,
|
|
||||||
) : InfoPanelState() {
|
|
||||||
override val loading = routeName == null
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Stop(
|
data class Stop(
|
||||||
val id: String,
|
val id: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
|
|
@ -35,4 +27,12 @@ sealed class InfoPanelState {
|
||||||
|
|
||||||
data class Departure(val directionName: String, val formattedTimes: String)
|
data class Departure(val directionName: String, val formattedTimes: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Trip(
|
||||||
|
val direction: String,
|
||||||
|
val type: RouteType,
|
||||||
|
val routeName: String? = null,
|
||||||
|
) : InfoPanelState() {
|
||||||
|
override val loading = routeName == null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package moe.lava.banksia.ui.state
|
package moe.lava.banksia.ui.state
|
||||||
|
|
||||||
import moe.lava.banksia.ui.utils.map.Marker
|
import moe.lava.banksia.ui.map.util.Marker
|
||||||
import moe.lava.banksia.ui.utils.map.Polyline
|
import moe.lava.banksia.ui.map.util.Polyline
|
||||||
|
|
||||||
data class MapState(
|
data class MapState(
|
||||||
val stops: List<Marker.Stop> = listOf(),
|
val stops: List<Marker.Stop> = listOf(),
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
package moe.lava.banksia.ui.utils.map
|
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import moe.lava.banksia.model.RouteType
|
|
||||||
import moe.lava.banksia.util.Point
|
|
||||||
|
|
||||||
sealed class Marker {
|
|
||||||
abstract val point: Point
|
|
||||||
|
|
||||||
data class Stop(
|
|
||||||
override val point: Point,
|
|
||||||
val id: String,
|
|
||||||
val type: RouteType,
|
|
||||||
val colour: Color,
|
|
||||||
) : Marker()
|
|
||||||
|
|
||||||
data class Vehicle(
|
|
||||||
override val point: Point,
|
|
||||||
val ref: String,
|
|
||||||
val type: RouteType,
|
|
||||||
) : Marker()
|
|
||||||
}
|
|
||||||