Compare commits

..

2 Commits

Author SHA1 Message Date
ca2c5fe385 add GTFS static data 2026-01-28 15:00:44 +01:00
077c26eec7 add checkbox and golemio api 2026-01-22 11:55:46 +01:00
9 changed files with 384 additions and 230 deletions

View File

@ -3,7 +3,7 @@
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DIALOG" />
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-01-19T17:27:16.298528612Z">
<Target type="DEFAULT_BOOT">
<handle>

View File

@ -0,0 +1,184 @@
package org.pupes.mhdrunpathfinder
import android.app.Activity
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import kotlinx.serialization.Serializable
import okhttp3.OkHttpClient
import okhttp3.Request
import ovh.plrapps.mapcompose.api.addMarker
import java.net.URL
@Serializable
data class GTFSRoute(
val agency_id: String,
val is_night: Boolean,
val route_color: String,
val route_desc: String? = null,
val route_id: String,
val route_long_name: String,
val route_short_name: String,
val route_text_color: String,
val route_type: Int,
val route_url: String,
val is_regional: Boolean,
val is_substitute_transport: Boolean
)
// Type alias for array of GTFS routes
typealias GTFSRoutes = List<GTFSRoute>
var gtfsRoutes: GTFSRoutes? = null
@Serializable
data class GTFSStopGeometry(
val coordinates: List<Double>,
val type: String
)
@Serializable
data class GTFSStopProperties(
val location_type: Int,
val parent_station: String? = null,
val platform_code: String? = null,
val stop_id: String,
val stop_name: String,
val wheelchair_boarding: Int,
val zone_id: String? = null,
val level_id: String? = null
)
@Serializable
data class GTFSStop(
val geometry: GTFSStopGeometry,
val properties: GTFSStopProperties,
val type: String
)
@Serializable
data class GTFSStops(
val features: List<GTFSStop>,
val type: String
)
var gtfsStops: GTFSStops? = null
// OkHttpClient for making HTTP requests
val gtfshttpClient = OkHttpClient.Builder()
.build()
private val GTFSMainHandler = Handler(Looper.getMainLooper())
private var GTFSTrackingThread: Thread? = null
private var GTFSIsTracking = false
private fun fetchGTFSPosition(gtfsUrl: URL,api_key: String, callee: Activity) {
try {
val request = Request.Builder()
.url("${gtfsUrl.protocol}://${gtfsUrl.host}${"/"}")
.header("User-Agent", "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} (Android)")
.build()
gtfshttpClient.newCall(request).execute().use { response ->
var message = if (response.isSuccessful) {
response.body?.string() ?: "Empty response"
} else {
"Error: ${response.code} ${response.message}"
}
// TODO: Handle response
}
} catch (e: Exception) {
// Post UI update to main thread
GTFSMainHandler.post {
Toast.makeText(callee, e.message ?: "Unknown error", Toast.LENGTH_SHORT).show()
}
}
}
// Start the timer with a URL:
fun startGTFSTracking(url: String, api_key: String, callee: Activity) {
if (GTFSIsTracking) return
GTFSIsTracking = true
GTFSTrackingThread = Thread {
var gtfsUrl = URL(url);
try {
if(gtfsRoutes == null) {
val request = Request.Builder()
.url("${gtfsUrl.protocol}://${gtfsUrl.host}${callee.getString(R.string.routes_path)}")
.header(
"User-Agent",
"${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} (Android)"
)
.header("X-Access-Token", api_key).build();
gtfshttpClient.newCall(request).execute().use { response ->
var message = if (response.isSuccessful) {
response.body?.string() ?: "Empty response"
} else {
"Error: ${response.code} ${response.message}"
}
gtfsRoutes = json.decodeFromString<GTFSRoutes>(message)
}}
if(gtfsStops == null) {
val request = Request.Builder()
.url("${gtfsUrl.protocol}://${gtfsUrl.host}${callee.getString(R.string.stops_path)}")
.header(
"User-Agent",
"${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} (Android)"
)
.header("X-Access-Token", api_key).build();
gtfshttpClient.newCall(request).execute().use { response ->
var message = if (response.isSuccessful) {
response.body?.string() ?: "Empty response"
} else {
"Error: ${response.code} ${response.message}"
}
gtfsStops = json.decodeFromString<GTFSStops>(message)
// put all stops on the map
for (stop in gtfsStops!!.features) {
GTFSMainHandler.post {
mapState.addMarker(stop.properties.stop_id, x = longitudeToXNormalized(stop.geometry.coordinates[0]), y = latitudeToYNormalized(stop.geometry.coordinates[0])) {
Icon(
painter = painterResource(id = R.drawable.outline_directions_bus_24),
contentDescription = null,
modifier = Modifier.size(17.dp),
tint = Color(0xFF0000FF)
)
}
}
}
}}
} catch(e: Exception) {
Toast.makeText(callee, e.message ?: "Unknown error", Toast.LENGTH_SHORT).show()
GTFSMainHandler.post { stopGTFSTracking() }
return@Thread
}
while (GTFSIsTracking) {
fetchGTFSPosition(gtfsUrl,api_key, callee)
try {
Thread.sleep(1000) // Wait 1 second between requests
} catch (e: InterruptedException) {
break
}
}
}.apply { start() }
}
fun stopGTFSTracking() {
GTFSIsTracking = false
GTFSTrackingThread?.interrupt()
GTFSTrackingThread = null
}

View File

@ -4,13 +4,26 @@ import android.app.Activity
import android.os.Handler
import android.os.Looper
import android.widget.Toast
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient
import ovh.plrapps.mapcompose.api.moveMarker
import java.net.URL
@Serializable
data class HaukResponse(
val type: Int,
val expire: Long,
val serverTime: Double,
val interval: Int,
val points: List<List<Double?>>,
val encrypted: Boolean,
val salt: String? = null
)
// OkHttpClient for making HTTP requests
val httpClient = OkHttpClient.Builder()
val haukhttpClient = OkHttpClient.Builder()
.build()
private val HaukMainHandler = Handler(Looper.getMainLooper())
@ -27,7 +40,7 @@ private fun fetchHaukPosition(haukUrl: String, callee: Activity) {
.header("User-Agent", "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} (Android)")
.build()
httpClient.newCall(request).execute().use { response ->
haukhttpClient.newCall(request).execute().use { response ->
var message = if (response.isSuccessful) {
response.body?.string() ?: "Empty response"
} else {
@ -35,17 +48,21 @@ private fun fetchHaukPosition(haukUrl: String, callee: Activity) {
}
message = "{" + message.substringAfter("{");
val hauk_response = Json.decodeFromString<HaukResponse>(message)
val hauk_response = json.decodeFromString<HaukResponse>(message)
val lat = hauk_response.points.last()?.getOrNull(0)
val lon = hauk_response.points.last()?.getOrNull(1)
if (lat != null && lon != null) {
HaukMainHandler.post {
mapState.moveMarker("target_position", x = longitudeToXNormalized(hauk_response.points.last()[1]), y = latitudeToYNormalized(hauk_response.points.last()[0]))
mapState.moveMarker("target_position", x = longitudeToXNormalized(lon), y = latitudeToYNormalized(lat))
}
}
} else {
Toast.makeText(callee, "TARGET LOCATION NOT AVAILABLE", Toast.LENGTH_SHORT).show()
}}
} catch (e: Exception) {
// Post UI update to main thread
HaukMainHandler.post {
Toast.makeText(callee, e.message ?: "Unknown error", Toast.LENGTH_LONG).show()
Toast.makeText(callee, e.message ?: "Unknown error", Toast.LENGTH_SHORT).show()
}
}
}

View File

@ -1,9 +1,14 @@
package org.pupes.mhdrunpathfinder
import kotlinx.serialization.json.Json
import kotlin.math.PI
import kotlin.math.ln
import kotlin.math.tan
val json = Json {
coerceInputValues = true // Coerce nulls to default values if applicable
ignoreUnknownKeys = true // Ignore fields in JSON not present in the data class
}
fun longitudeToXNormalized(longitude: Double): Double {
return (longitude + 180.0) / 360.0
}

View File

@ -1,17 +1,22 @@
package org.pupes.mhdrunpathfinder
import android.app.Activity
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
@ -33,7 +38,7 @@ import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.serialization.Serializable
import androidx.core.content.edit
import ovh.plrapps.mapcompose.api.addLayer
import ovh.plrapps.mapcompose.api.addMarker
import ovh.plrapps.mapcompose.api.scrollTo
@ -42,21 +47,11 @@ import ovh.plrapps.mapcompose.ui.MapUI
import ovh.plrapps.mapcompose.ui.state.MapState
import java.net.URL
@Serializable
data class HaukResponse(
val type: Int,
val expire: Long,
val serverTime: Double,
val interval: Int,
val points: List<List<Double>>,
val encrypted: Boolean,
val salt: String? = null
)
// MapState configuration for OpenStreetMap
// Max zoom level is 18, tile size is 256x256
// At zoom level 18, there are 2^18 = 262144 tiles in each dimension
// So fullWidth/Height = 256 * 262144
// So fullWidth/Height = 256 * 2^18
val mapState = MapState(
levelCount = 19, // zoom levels 0-18
fullWidth = 67108864, // 256 * 2^18
@ -78,11 +73,10 @@ class MainActivity : ComponentActivity() {
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
MainScreen()
MainScreen(this)
}
}
}
startHaukTracking("https://hauk.limit6.eu/?M4SJ-SH7I",this)
startLocationTracking(this)
}
@ -95,8 +89,18 @@ class MainActivity : ComponentActivity() {
}
@Composable
fun MainScreen() {
fun MainScreen(callee: Activity) {
val sharedPreferences = remember { callee.getSharedPreferences("PREFERENCES", Context.MODE_PRIVATE) }
var showSettings by remember { mutableStateOf(false) }
var haukUrl by remember { mutableStateOf("") }
var golemioAPIkey by remember { mutableStateOf(sharedPreferences.getString("golemioAPIkey", "")?: "" ) }
var haukState by remember { mutableStateOf(false) }
var golemioState by remember { mutableStateOf(false)}
if (golemioAPIkey.isNotEmpty()) {
golemioState = true
startGTFSTracking(callee.getString(R.string.golemio_base_url), golemioAPIkey, callee);
}
Box(modifier = Modifier.fillMaxSize()) {
OpenStreetMapScreen()
@ -107,7 +111,55 @@ fun MainScreen() {
.padding(end = 5.dp, bottom = 5.dp)
)
if (showSettings) {
ShowSettingsMenu(onDismiss = { showSettings = false })
ShowSettingsMenu(
onDismiss = { showSettings = false },
haukUrl = haukUrl,
onHaukUrlChange = { haukUrl = it },
onHaukApply = {
if (haukUrl.isNotEmpty()) {
haukState = true
stopHaukTracking()
startHaukTracking(haukUrl, callee)
}
},
haukState = haukState,
onHaukStateChange = {
haukState = it
if (it) {
if (haukUrl.isNotEmpty()) {
stopHaukTracking()
startHaukTracking(haukUrl, callee)
}
} else {
stopHaukTracking()
}
},
golemioAPIkey = golemioAPIkey,
onGolemioAPIChange = { golemioAPIkey = it },
onGolemioApply = {
if (golemioAPIkey.isNotEmpty()) {
golemioState = true
sharedPreferences.edit {
putString("golemioAPIkey", golemioAPIkey)
}
startGTFSTracking(callee.getString(R.string.golemio_base_url), golemioAPIkey, callee);
}
},
golemioState = golemioState,
onGolemioStateChange = {
golemioState = it
if (it) {
if (golemioAPIkey.isNotEmpty()) {
sharedPreferences.edit {
putString("golemioAPIkey", golemioAPIkey)
}
startGTFSTracking(callee.getString(R.string.golemio_base_url), golemioAPIkey, callee);
}
} else {
stopGTFSTracking();
}
}
)
}
}
}
@ -134,22 +186,52 @@ fun SettingsButton(modifier: Modifier = Modifier, onClick: () -> Unit = {}) {
@Preview
@Composable
@OptIn(ExperimentalMaterial3Api::class)
fun ShowSettingsMenu(modifier: Modifier = Modifier, onDismiss: () -> Unit = {}) {
fun ShowSettingsMenu(
modifier: Modifier = Modifier,
onDismiss: () -> Unit = {},
haukUrl: String = "",
onHaukUrlChange: (String) -> Unit = {},
onHaukApply: () -> Unit = {},
haukState: Boolean = false,
onHaukStateChange: (Boolean) -> Unit = {},
golemioAPIkey: String = "",
onGolemioAPIChange: (String) -> Unit = {},
onGolemioApply: () -> Unit = {},
golemioState: Boolean = false,
onGolemioStateChange: (Boolean) -> Unit = {}
) {
ModalBottomSheet(onDismissRequest = onDismiss) {
Column() {
Column( verticalArrangement = Arrangement.spacedBy(10.dp)) {
Row() {
TextField(
state = rememberTextFieldState(),
label = { Text("Target Hauk URL") },
Checkbox(
checked = haukState,
onCheckedChange = { onHaukStateChange(it) }
)
ElevatedButton(onClick = { },modifier = Modifier.padding(start = 5.dp), shape = RectangleShape) {
TextField(
value = haukUrl,
onValueChange = onHaukUrlChange,
label = { Text("Target Hauk URL") },
modifier = Modifier
.width(250.dp)
)
ElevatedButton(onClick = onHaukApply, modifier = Modifier.padding(start = 5.dp), shape = RectangleShape) {
Text("Apply")
}
}
Row() {
Checkbox(
checked = golemioState,
onCheckedChange = { onGolemioStateChange(it) }
)
TextField(value = golemioAPIkey, onValueChange = onGolemioAPIChange, label = { Text("Golemio API Key") },
modifier = Modifier
.width(250.dp));
ElevatedButton(onClick = onGolemioApply, modifier = Modifier.padding(start = 5.dp), shape = RectangleShape) {
Text("Apply")
}
}
}
}
}}
@Preview
@Composable

View File

@ -1,170 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
android:width="512dp"
android:height="512dp"
android:viewportWidth="135.47"
android:viewportHeight="135.47">
<path
android:pathData="M0,0h135.47v135.47h-135.47z"
android:strokeWidth="4.99999"
android:fillColor="#aa8800"/>
</vector>

View File

@ -1,30 +1,48 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
android:width="512dp"
android:height="512dp"
android:viewportWidth="135.47"
android:viewportHeight="135.47">
<path
android:pathData="m12.87,44.98c-1.1,-2.47 -1.39,-5.2 -1.61,-7.87 -0.26,-4.74 -0.15,-9.48 -0.02,-14.22 0.04,-1.85 0.14,-3.7 0.32,-5.54 0.07,-0.69 0.16,-1.33 0.35,-1.99 0.03,-0.05 0.04,-0.12 0.09,-0.16 0.06,-0.05 0.23,0.3 0.07,0.22 -1.1,-0.55 -2.12,-1.25 -3.22,-1.81 -0.13,-0.06 0.2,0.21 0.29,0.32 0.15,0.18 0.28,0.38 0.42,0.57 1.74,2.9 3.83,5.56 6.06,8.11 1,1.14 2.05,2.25 3.12,3.32 0.21,0.21 0.38,0.46 0.63,0.62 1.24,0.8 2.49,1.59 3.82,2.23 0.16,0.08 0.33,-0.09 0.5,-0.14 0.15,-0.27 0.32,-0.52 0.44,-0.81 0.51,-1.29 0.65,-2.74 1.04,-4.07 0.51,-1.76 0.7,-2.06 1.42,-3.77 0.77,-1.57 1.63,-3.11 2.67,-4.52 0.11,-0.15 1,-1.28 1.25,-1.48 0.11,-0.08 0.26,-0.09 0.38,-0.14 -1.07,-0.53 -2.03,-1.35 -3.2,-1.59 -0.33,-0.07 0.2,0.65 0.23,0.99 0.05,0.59 0.04,1.19 0.03,1.78 -0.06,2.64 -0.33,5.28 -0.59,7.91 -0.32,3.38 -0.73,6.76 -1.24,10.11 -0.23,1.15 -0.21,2.29 -0.11,3.45 0.09,0.87 0.14,1.75 0.16,2.63 0.01,0.42 0.01,0.84 0.01,1.27 0,0 3.53,1.79 3.53,1.79v0c-0,-0.43 -0.01,-0.86 -0.02,-1.28 -0.03,-0.89 -0.09,-1.77 -0.18,-2.66 -0.1,-1.14 -0.16,-2.26 0.02,-3.4 0.34,-3.42 0.7,-6.84 0.99,-10.26 0.43,-4.45 0.1,-0.96 0.51,-5.43 0.2,-2.14 0.25,-2.27 0.31,-4.21 0.01,-0.41 0.32,-0.96 0.01,-1.23 -1.07,-0.93 -2.5,-1.34 -3.75,-2.02 -0.7,0.5 -1.12,1.15 -1.6,1.87 -0.99,1.47 -1.84,3.03 -2.62,4.63 -0.62,1.44 -1.04,2.3 -1.51,3.78 -0.41,1.28 -0.59,2.66 -1.11,3.91 -0.07,0.17 -0.19,0.31 -0.28,0.47 -1.33,-0.15 -1.21,-0.18 2.46,1.64 0.28,0.14 -0.46,-0.42 -0.68,-0.63 -1.13,-1.07 -2.22,-2.18 -3.26,-3.35 -2.21,-2.47 -4.28,-5.06 -5.88,-7.98 -0.12,-0.19 -0.25,-0.39 -0.37,-0.58 -0.08,-0.12 -0.12,-0.27 -0.24,-0.35 -0.35,-0.23 -3.34,-3.47 -4.06,-1.63 -0.16,0.71 -0.21,1.4 -0.25,2.13 -0.09,1.88 -0.15,3.76 -0.16,5.64 -0.11,4.73 -0.33,9.47 -0.11,14.2 0.18,2.66 0.47,5.34 1.32,7.89z"
android:strokeWidth="0.529167"
android:fillColor="#000000"/>
<path
android:pathData="m41.24,45.04c0.17,-7.19 0.46,-14.39 0.64,-21.58 0.11,-4.72 0.2,-9.45 0.05,-14.17 0,0 -3.34,-1.68 -3.34,-1.68v0c0.4,4.77 0.41,9.57 0.38,14.35 -0.14,7.1 -0.39,14.21 -1.2,21.27z"
android:strokeWidth="0.529167"
android:fillColor="#ff0000"/>
<path
android:pathData="m42.31,31.69c3.85,-0.37 7.73,-0.29 11.6,-0.27 3.13,0.05 6.26,0.17 9.39,0.29 0,0 -2.87,-2.1 -2.87,-2.1v0c-3.11,-0.08 -6.22,-0.17 -9.34,-0.24 -4.01,-0.06 -8.03,-0.18 -12.03,0.04z"
android:strokeWidth="0.529167"
android:fillColor="#ff0000"/>
<path
android:pathData="m58.57,15.76c1.49,4.69 1.44,9.72 1.48,14.59 -0.06,5.45 -0.41,10.9 -1.12,16.31 -0.07,0.35 -0.13,0.7 -0.2,1.06 0,0 3.38,1.79 3.38,1.79v0c0.05,-0.37 0.09,-0.74 0.14,-1.11 0.45,-5.49 0.77,-10.99 0.85,-16.49 0.01,-4.54 0.08,-9.15 -0.76,-13.64 -0.05,-0.28 -0.15,-0.56 -0.23,-0.84z"
android:strokeWidth="0.529167"
android:fillColor="#ff0000"/>
<path
android:pathData="M77.39,47.99C76.9,41.81 76.72,35.62 76.54,29.43 76.42,25.33 76.27,21.22 76.14,17.12c0.1,0.06 -0.14,-1.27 0.08,-1.17 0.04,0.02 0.07,0.06 0.1,0.09 1.32,0.52 2.58,1.2 3.84,1.85 0.61,0.3 1.11,0.55 1.71,0.87 0.24,0.13 0.94,0.54 0.71,0.4 -0.92,-0.53 -3.67,-2.11 -2.75,-1.58 1.27,0.73 2.55,1.45 3.81,2.19 0.99,0.58 -1.99,-1.14 -2.98,-1.71 0.95,0.65 1.88,1.33 2.83,1.99 2.99,2.23 5.84,4.63 8.61,7.12 1.1,1.03 2.18,2.14 2.7,3.59 0.26,0.73 0.3,1.16 0.43,1.91 0.18,1.75 -0.37,3.3 -1.13,4.84 -1.15,1.98 -2.92,3.42 -4.73,4.77 -1.71,1.31 -3.54,2.43 -5.27,3.71 -1.4,1.2 -2.67,2.58 -4.34,3.41 -1.27,0.53 -2.65,0.19 -3.83,-0.41 -1.9,-1.09 1.73,0.99 2.43,1.37 0.12,0.06 -0.21,-0.17 -0.31,-0.27 -0.23,-0.22 -0.38,-0.46 -0.53,-0.73 -0.2,-0.35 -0.34,-0.71 -0.39,-1.1 -0,-0.47 -0.12,-0.93 -0.25,-1.38 0,0 -3.57,-1.68 -3.57,-1.68v0c0.15,0.42 0.3,0.84 0.27,1.29 0.01,0.45 0.11,0.86 0.34,1.25 0.09,0.19 0.17,0.38 0.28,0.56 1.02,1.65 3.14,2.2 4.79,3.11 1.3,0.51 2.72,0.79 4.03,0.13 1.63,-0.92 2.88,-2.33 4.33,-3.49 1.73,-1.27 3.55,-2.41 5.25,-3.73 1.84,-1.4 3.66,-2.89 4.87,-4.89 0.83,-1.67 1.36,-3.15 1.23,-5.06 -0.1,-0.63 -0.18,-1.39 -0.38,-2 -0.49,-1.54 -1.6,-2.71 -2.75,-3.79 -2.76,-2.46 -5.6,-4.84 -8.5,-7.12 -0.62,-0.45 -1.27,-0.86 -1.87,-1.33 -0.19,-0.14 -0.35,-0.32 -0.54,-0.45 -0.1,-0.07 -0.21,-0.13 -0.32,-0.19 -1.24,-0.73 -2.49,-1.44 -3.72,-2.18 -0.95,-0.57 3.83,2.21 2.87,1.66 -2.09,-1.18 -4.12,-2.46 -6.29,-3.48 -1.23,-0.63 -0.63,-0.32 -1.81,-0.92 -0.72,-0.36 -1.45,-0.82 -2.28,-0.83 -0.73,0.38 -0.44,0.93 -0.39,1.64 0.39,4.17 0.68,8.35 0.86,12.53 0.2,6.1 0.34,12.2 0.36,18.3z"
android:strokeWidth="0.529167"
android:fillColor="#ffff00"/>
<path
android:pathData="m13.25,113.41c-0.35,-2.84 -0.37,-5.72 -0.44,-8.58 -0.12,-6.06 0.06,-12.13 0.29,-18.19 0.08,-0.53 -0.01,-2.93 0.36,-3.4 0.13,-0.16 0.44,-0.01 0.55,0.02 1.86,1.05 -2.19,-1.23 -2.28,-1.28 -0.23,-0.12 0.43,0.3 0.62,0.46 0.6,0.51 1.05,1.15 1.52,1.77 1.29,1.77 2.54,3.56 3.57,5.5 0.64,1.27 1.16,2.64 0.81,4.07 -0.07,0.31 -0.22,0.59 -0.33,0.89 -0.17,0.27 -0.3,0.56 -0.5,0.8 -1.32,1.57 -2.98,1.32 -4.78,0.99 -1.12,-0.25 -2.22,-0.58 -3.26,-1.07 -0.08,-0.04 -0.23,-0.22 -0.22,-0.13 0.02,0.3 0.18,0.57 0.27,0.86 5.56,3.3 10,8.11 14.48,12.68 2.98,3.15 5.93,6.34 8.84,9.55 0,0 3.37,1.41 3.37,1.41v0c-3.07,-3.23 -6.14,-6.47 -9.2,-9.71 -2.5,-2.58 -3.71,-3.88 -6.25,-6.34 -2.35,-2.27 -4.79,-4.49 -7.6,-6.19 -0.27,0.07 -0.56,0.09 -0.81,0.21 -0.06,0.03 0.13,0.05 0.19,0.07 0.18,0.07 0.37,0.14 0.55,0.21 0.53,0.19 1.09,0.38 1.64,0.51 0.35,0.09 0.7,0.15 1.05,0.23 2,0.28 3.64,0.38 5.05,-1.35 0.21,-0.26 0.36,-0.57 0.53,-0.86 0.13,-0.32 0.3,-0.63 0.39,-0.96 0.42,-1.52 -0.04,-2.96 -0.74,-4.3 -1.02,-1.94 -2.24,-3.74 -3.5,-5.53 -0.18,-0.24 -0.75,-1.04 -0.94,-1.28 -1.38,-1.66 -3.67,-3 -5.66,-3.53 -0.37,0.08 -0.58,0.04 -0.8,0.4 -0.4,0.66 -0.13,2.88 -0.21,3.6 0.03,6.09 0.01,12.17 -0.17,18.26 -0.02,2.82 -0.12,5.64 0.06,8.45z"
android:strokeWidth="0.529167"
android:fillColor="#0000ff"/>
<path
android:pathData="m38.7,84.07c0.34,7.18 0.25,14.38 0.21,21.56 0.01,6.71 -0.32,13.41 -0.41,20.12 0.05,0.35 0.06,0.7 0.15,1.04 0.51,1.78 3.54,2.21 4.7,2.36 0.6,0.07 1.07,-0.58 1.52,-0.97 1.49,-1.31 3.13,-3.5 4.33,-5 3.1,-4.3 5.72,-8.94 7.48,-13.95 0.9,-2.56 1.33,-4.38 2.01,-6.98 0.81,-3.38 1.41,-6.8 1.83,-10.25 0,0 -3.38,-1.76 -3.38,-1.76v0c-0.23,3.49 -0.71,6.96 -1.48,10.37 -0.66,2.67 -1.01,4.35 -1.93,6.98 -1.73,4.98 -4.3,9.63 -7.47,13.84 -1.49,1.75 -2.68,3.35 -4.52,4.73 -0.46,0.35 -1.7,0.24 -1.54,0.8 0.27,1 1.52,1.4 2.33,2.05 0.44,0.36 -2.06,-2.07 -0.7,-1.56 -0.33,-6.79 -0.11,-13.6 -0.15,-20.39 0.1,-7.07 0.22,-14.14 0.51,-21.2z"
android:strokeWidth="0.529167"
android:fillColor="#55d400"/>
<path
android:pathData="m74.44,117.26c-0.56,-8.07 -1.22,-16.14 -1.81,-24.22 -0.23,-3.25 -0.45,-6.5 -0.62,-9.75 -0.08,-1.44 -0.15,-2.85 -0.05,-4.29 0.09,-0.54 0.71,0.32 0.52,0.28 -0.84,-0.18 -1.77,-1.46 -2.41,-0.89 -0.57,0.51 0.88,1.24 1.31,1.87 1.6,2.36 2.22,3.39 3.78,5.87 4.01,6.47 7.65,13.15 11.24,19.86 0.24,0.44 3,5.46 3.35,6.08 0.43,0.76 0.86,1.51 1.32,2.25 1.12,1.8 2.25,3.52 5.21,2.92 0.83,-0.17 0.5,-1.62 0.75,-2.43 1.27,-6.7 1.96,-13.5 2.67,-20.28 0,0 -3.22,-1.67 -3.22,-1.67v0c-0.42,6.78 -0.99,13.59 -2.62,20.2 -0.93,2.43 -1.67,2.47 1.63,4.21 0.56,0.29 -0.79,-0.98 -1.15,-1.51 -1.81,-2.67 -3.23,-5.6 -4.84,-8.39C85.9,100.67 82.27,93.98 78.27,87.5 77.17,85.69 75.85,83.54 74.72,81.72 74.33,81.1 74.08,80.37 73.54,79.88 72.29,78.72 70.85,77.76 69.42,76.83 69.25,76.72 69.01,76.72 68.83,76.81c-0.16,0.07 -0.2,0.29 -0.3,0.43 -0,1.49 0.13,2.96 0.27,4.44 0.31,3.31 0.64,6.61 0.94,9.91 0.7,7.93 1.47,15.9 1.19,23.88z"
android:strokeWidth="0.529167"
android:fillColor="#ff6600"/>
<path
android:pathData="M5.92,35.36a31.41,32.73 0,1 0,62.82 0a31.41,32.73 0,1 0,-62.82 0z"
android:strokeWidth="5"
android:fillColor="#00000000"
android:strokeColor="#aa8800"/>
<path
android:pathData="M56.24,59.53 L130.9,131.56"
android:strokeWidth="4.99999"
android:fillColor="#00000000"
android:strokeColor="#aa8800"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M240,840Q223,840 211.5,828.5Q200,817 200,800L200,718Q182,698 171,673.5Q160,649 160,620L160,240Q160,157 237,118.5Q314,80 480,80Q652,80 726,117Q800,154 800,240L800,620Q800,649 789,673.5Q778,698 760,718L760,800Q760,817 748.5,828.5Q737,840 720,840L680,840Q663,840 651.5,828.5Q640,817 640,800L640,760L320,760L320,800Q320,817 308.5,828.5Q297,840 280,840L240,840ZM482,200Q592,200 641.5,200Q691,200 706,200L258,200Q276,200 325.5,200Q375,200 482,200ZM640,480L320,480Q287,480 263.5,480Q240,480 240,480L240,480L720,480L720,480Q720,480 696.5,480Q673,480 640,480ZM240,400L720,400L720,280L240,280L240,400ZM340,640Q365,640 382.5,622.5Q400,605 400,580Q400,555 382.5,537.5Q365,520 340,520Q315,520 297.5,537.5Q280,555 280,580Q280,605 297.5,622.5Q315,640 340,640ZM620,640Q645,640 662.5,622.5Q680,605 680,580Q680,555 662.5,537.5Q645,520 620,520Q595,520 577.5,537.5Q560,555 560,580Q560,605 577.5,622.5Q595,640 620,640ZM258,200L706,200Q691,183 641.5,171.5Q592,160 482,160Q375,160 325.5,172.5Q276,185 258,200ZM320,680L640,680Q673,680 696.5,656.5Q720,633 720,600L720,480L240,480L240,600Q240,633 263.5,656.5Q287,680 320,680Z"/>
</vector>

View File

@ -1,3 +1,6 @@
<resources>
<string name="app_name">MHD run Pathfinder</string>
<string name="routes_path">/v2/gtfs/routes</string>
<string name="stops_path">/v2/gtfs/stops</string>
<string name="golemio_base_url">https://api.golemio.cz</string>
</resources>