Bimba.git

commit f899aa8d63d0d231eca037ee5d9c5c9c1388096b

Author: Adam <git@apiote.xyz>

show results

%!v(PANIC=String method: strings: negative Repeat count)


diff --git a/app/build.gradle b/app/build.gradle
index 531c315cc944a899545d8da178ed65f28e05ef7d..3d4a926b038c33d79e7f9a00f2117c12261ca0c8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -36,7 +36,7 @@ }
 
 dependencies {
     implementation 'androidx.core:core-ktx:1.8.0'
-    implementation 'androidx.appcompat:appcompat:1.4.2'
+    implementation 'androidx.appcompat:appcompat:1.4.0'
     implementation 'com.google.android.material:material:1.6.1'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
     implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
@@ -44,6 +44,8 @@     implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
     implementation 'androidx.navigation:navigation-fragment-ktx:2.5.1'
     implementation 'androidx.navigation:navigation-ui-ktx:2.5.1'
     implementation 'com.github.mancj:MaterialSearchBar:0.8.5'
+    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+    implementation 'com.google.openlocationcode:openlocationcode:1.0.4'
     testImplementation 'junit:junit:4.13.2'
     androidTestImplementation 'androidx.test.ext:junit:1.1.3'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'




diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9c503d0a03800560f34ad69ca50f72d79c28c148..88fa50c2e6286f4d53688dce0b3860a058798f69 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,29 +1,37 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    package="ml.adamsprogs.bimba">
+	xmlns:tools="http://schemas.android.com/tools"
+	package="ml.adamsprogs.bimba">
 
-    <uses-permission android:name="android.permission.INTERNET" />
+	<uses-permission android:name="android.permission.INTERNET" />
+	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 
-    <application
-        android:allowBackup="true"
-        android:dataExtractionRules="@xml/data_extraction_rules"
-        android:fullBackupContent="@xml/backup_rules"
-        android:icon="@mipmap/ic_launcher"
-        android:label="@string/app_name"
-        android:roundIcon="@mipmap/ic_launcher_round"
-        android:supportsRtl="true"
-        android:theme="@style/Theme.Bimba.Style"
-        tools:targetApi="31">
-        <activity
-            android:windowSoftInputMode="adjustPan"
-            android:name=".MainActivity"
-            android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
+	<application
+		android:allowBackup="true"
+		android:dataExtractionRules="@xml/data_extraction_rules"
+		android:fullBackupContent="@xml/backup_rules"
+		android:icon="@mipmap/ic_launcher"
+		android:label="@string/app_name"
+		android:roundIcon="@mipmap/ic_launcher_round"
+		android:supportsRtl="true"
+		android:theme="@style/Theme.Bimba.Style"
+		tools:targetApi="31">
+		<activity
+			android:name=".search.ResultsActivity"
+			android:exported="false"
+			android:label="@string/title_activity_results"
+			android:theme="@style/Theme.Bimba.Style" />
+		<activity
+			android:name=".dashboard.MainActivity"
+			android:exported="true"
+			android:windowSoftInputMode="adjustPan">
+			<intent-filter>
+				<action android:name="android.intent.action.MAIN" />
+
+				<category android:name="android.intent.category.LAUNCHER" />
+			</intent-filter>
+		</activity>
+	</application>
 
 </manifest>
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt
deleted file mode 100644
index 8d14f2452cbe85342ece2b487ee42417fe7cd3c3..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-package ml.adamsprogs.bimba
-
-import android.os.Bundle
-import android.view.View
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.get
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentManager
-import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
-import androidx.navigation.fragment.NavHostFragment
-import androidx.navigation.ui.setupWithNavController
-import com.google.android.material.bottomnavigation.BottomNavigationView
-import ml.adamsprogs.bimba.databinding.ActivityMainBinding
-import ml.adamsprogs.bimba.ui.home.HomeFragment
-import ml.adamsprogs.bimba.ui.map.MapFragment
-import ml.adamsprogs.bimba.ui.voyage.VoyageFragment
-
-
-class MainActivity : AppCompatActivity() {
-
-	private lateinit var binding: ActivityMainBinding
-
-	override fun onCreate(savedInstanceState: Bundle?) {
-		super.onCreate(savedInstanceState)
-
-		binding = ActivityMainBinding.inflate(layoutInflater)
-		setContentView(binding.root)
-
-		supportFragmentManager.registerFragmentLifecycleCallbacks(
-			object : FragmentLifecycleCallbacks() {
-				override fun onFragmentViewCreated(
-					fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?
-				) {
-					setNavbarIcons(f)
-					super.onFragmentViewCreated(fm, f, v, savedInstanceState)
-				}
-			}, true
-		)
-
-		val navView: BottomNavigationView = binding.bottomNavigation
-		val navHostFragment =
-			supportFragmentManager.findFragmentById(R.id.nav_host_fragment_activity_main) as NavHostFragment
-		val navController = navHostFragment.navController
-		navView.setupWithNavController(navController)
-	}
-
-	override fun onBackPressed() {
-		if (binding.container.isDrawerOpen(binding.navigationDrawer)) {
-			binding.container.closeDrawer(binding.navigationDrawer)
-		}else {
-			super.onBackPressed()
-		}
-	}
-
-	fun onNavigationClicked() {
-		if (binding.container.isDrawerOpen(binding.navigationDrawer)) {
-			binding.container.closeDrawer(binding.navigationDrawer)
-		} else {
-			binding.container.openDrawer(binding.navigationDrawer)
-		}
-	}
-
-	private fun setNavbarIcons(f: Fragment) {
-		binding.bottomNavigation.menu[2].setIcon(R.drawable.ic_voyage_outline_24dp)
-		binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_outline_24dp)
-		binding.bottomNavigation.menu[0].setIcon(R.drawable.ic_map_outline_24dp)
-		when (f) {
-			is HomeFragment -> {
-				binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_black_24dp)
-			}
-			is VoyageFragment -> {
-				binding.bottomNavigation.menu[2].setIcon(R.drawable.ic_voyage_black_24dp)
-			}
-			is MapFragment -> {
-				binding.bottomNavigation.menu[0].setIcon(R.drawable.ic_map_black_24dp)
-			}
-			else -> {
-				binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_black_24dp)
-			}
-		}
-	}
-}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt b/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt
deleted file mode 100644
index e15982f0f24088c350a771969939eb12bb11fb86..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt
+++ /dev/null
@@ -1,161 +0,0 @@
-package ml.adamsprogs.bimba.api
-
-import android.util.Log
-import xyz.apiote.fruchtfleisch.Reader
-import java.io.InputStream
-
-data class Stop(
-	val name: String,
-	val code: String,
-	val zone: String,
-	val position: String,
-	val changeOptions: List<ChangeOption>
-) {
-	override fun toString(): String {
-		var result = "$name ($code) [$zone] $position\n"
-		for (chOpt in changeOptions)
-			result += "${chOpt.line} → ${chOpt.headsign}\n"
-		return result
-	}
-
-	companion object {
-		fun unmarshall(stream: InputStream): Stop {
-			val reader = Reader(stream)
-			val code = reader.readString()
-			val zone = reader.readString()
-			val position = reader.readString()
-			val chOptionsNum = reader.readUInt()
-			val changeOptions = mutableListOf<ChangeOption>()
-			for (i in 0UL until chOptionsNum) {
-				changeOptions.add(ChangeOption.unmarshall(stream))
-			}
-			val name = reader.readString()
-			return Stop(
-				name = name,
-				code = code,
-				zone = zone,
-				position = position,
-				changeOptions = changeOptions
-			)
-		}
-	}
-}
-
-data class Line(
-	val name: String,
-	val textColour: UInt,
-	val colour: UInt,
-	val type: LineType,
-	val headsignsThere: List<String>,
-	val headsignsBack: List<String>,
-	val graphThere: LineGraph,
-	val graphBack: LineGraph
-) {
-	override fun toString(): String {
-		return "$name ($type) [$textColour/$colour]\n→ [${headsignsThere.joinToString()}]\n→ [${headsignsBack.joinToString()}]\n"
-	}
-
-	companion object {
-		fun unmarshall(stream: InputStream): Line {
-			val reader = Reader(stream)
-			val textColour = reader.readUInt().toUInt()
-			val colour = reader.readUInt().toUInt()
-			val type = reader.readUInt()
-			val headsignsThereNum = reader.readUInt()
-			val headsignsThere = mutableListOf<String>()
-			for (i in 0UL until headsignsThereNum) {
-				headsignsThere.add(reader.readString())
-			}
-			val headsignsBackNum = reader.readUInt()
-			val headsignsBack = mutableListOf<String>()
-			for (i in 0UL until headsignsBackNum) {
-				headsignsBack.add(reader.readString())
-			}
-			val graphThere = LineGraph.unmarshall(stream)
-			val graphBack = LineGraph.unmarshall(stream)
-			val name = reader.readString()
-			return Line(
-				name = name, textColour = textColour,
-				colour = colour, type = LineType(type.toUInt()), headsignsThere = headsignsThere,
-				headsignsBack = headsignsBack, graphThere = graphThere, graphBack = graphBack
-			)
-		}
-	}
-}
-
-enum class LineType {
-	TRAM, BUS, UNKNOWN
-}
-
-fun LineType(type: UInt): LineType {
-	Log.d("LineType", "$type")
-	return when (type) {
-		0U -> LineType.valueOf("TRAM")
-		3U -> LineType.valueOf("BUS")
-		else -> LineType.valueOf("UNKNOWN")
-	}
-}
-
-data class ChangeOption(val line: String, val headsign: String) {
-	companion object {
-		fun unmarshall(stream: InputStream): ChangeOption {
-			val reader = Reader(stream)
-			return ChangeOption(line = reader.readString(), headsign = reader.readString())
-		}
-	}
-}
-
-data class LineGraph(
-	val stops: List<StopStub>,
-	val nextNodes: Map<Long, List<Long>>,
-	val prevNodes: Map<Long, List<Long>>
-) {
-	companion object {
-		fun unmarshall(stream: InputStream): LineGraph {
-			val reader = Reader(stream)
-			val stopsNum = reader.readUInt()
-			val stops = mutableListOf<StopStub>()
-			for (i in 0UL until stopsNum) {
-				stops.add(StopStub.unmarshall(stream))
-			}
-			val nextNodesNum = reader.readUInt()
-			val nextNodes = mutableMapOf<Long, List<Long>>()
-			for (i in 0UL until nextNodesNum) {
-				val from = reader.readInt()
-				val toNum = reader.readUInt()
-				val to = mutableListOf<Long>()
-				for (j in 0UL until toNum) {
-					to.add(reader.readInt())
-				}
-				nextNodes[from] = to
-			}
-			val prevNodesNum = reader.readUInt()
-			val prevNodes = mutableMapOf<Long, List<Long>>()
-			for (i in 0UL until prevNodesNum) {
-				val from = reader.readInt()
-				val toNum = reader.readUInt()
-				val to = mutableListOf<Long>()
-				for (j in 0UL until toNum) {
-					to.add(reader.readInt())
-				}
-				prevNodes[from] = to
-			}
-
-			return LineGraph(stops = stops, nextNodes = nextNodes, prevNodes = prevNodes)
-		}
-	}
-}
-
-data class StopStub(val name: String, val code: String, val zone: String, val onDemand: Boolean) {
-	companion object {
-		fun unmarshall(stream: InputStream): StopStub {
-			val reader = Reader(stream)
-			return StopStub(
-				code = reader.readString(),
-				name = reader.readString(),
-				zone = reader.readString(),
-				onDemand = reader.readBoolean()
-			)
-		}
-	}
-}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt b/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f99673af949bfcf97a51726de147d4a816d77846
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt
@@ -0,0 +1,163 @@
+package ml.adamsprogs.bimba.api
+
+import android.util.Log
+import xyz.apiote.fruchtfleisch.Reader
+import java.io.InputStream
+
+interface Item
+
+data class Stop(
+	val code: String,
+	val zone: String,
+	val position: String,
+	val changeOptions: List<ChangeOption>,
+	val name: String
+) : Item {
+	override fun toString(): String {
+		var result = "$name ($code) [$zone] $position\n"
+		for (chOpt in changeOptions)
+			result += "${chOpt.line} → ${chOpt.headsign}\n"
+		return result
+	}
+
+	companion object {
+		fun unmarshall(stream: InputStream): Stop {
+			val reader = Reader(stream)
+			val code = reader.readString()
+			val zone = reader.readString()
+			val position = reader.readString()
+			val chOptionsNum = reader.readUInt()
+			val changeOptions = mutableListOf<ChangeOption>()
+			for (i in 0UL until chOptionsNum) {
+				changeOptions.add(ChangeOption.unmarshall(stream))
+			}
+			val name = reader.readString()
+			return Stop(
+				name = name,
+				code = code,
+				zone = zone,
+				position = position,
+				changeOptions = changeOptions
+			)
+		}
+	}
+}
+
+data class Line(
+	val textColour: Int,
+	val colour: Int,
+	val type: LineType,
+	val headsignsThere: List<String>,
+	val headsignsBack: List<String>,
+	val graphThere: LineGraph,
+	val graphBack: LineGraph,
+	val name: String
+) : Item {
+	override fun toString(): String {
+		return "$name ($type) [$textColour/$colour]\n→ [${headsignsThere.joinToString()}]\n→ [${headsignsBack.joinToString()}]\n"
+	}
+
+	companion object {
+		fun unmarshall(stream: InputStream): Line {
+			val reader = Reader(stream)
+			val textColour = reader.readInt().toInt()
+			val colour = reader.readInt().toInt()
+			val type = reader.readUInt()
+			val headsignsThereNum = reader.readUInt()
+			val headsignsThere = mutableListOf<String>()
+			for (i in 0UL until headsignsThereNum) {
+				headsignsThere.add(reader.readString())
+			}
+			val headsignsBackNum = reader.readUInt()
+			val headsignsBack = mutableListOf<String>()
+			for (i in 0UL until headsignsBackNum) {
+				headsignsBack.add(reader.readString())
+			}
+			val graphThere = LineGraph.unmarshall(stream)
+			val graphBack = LineGraph.unmarshall(stream)
+			val name = reader.readString()
+			return Line(
+				name = name, textColour = textColour,
+				colour = colour, type = LineType(type.toUInt()), headsignsThere = headsignsThere,
+				headsignsBack = headsignsBack, graphThere = graphThere, graphBack = graphBack
+			)
+		}
+	}
+}
+
+enum class LineType {
+	TRAM, BUS, UNKNOWN
+}
+
+fun LineType(type: UInt): LineType {
+	Log.d("LineType", "$type")
+	return when (type) {
+		0U -> LineType.valueOf("TRAM")
+		3U -> LineType.valueOf("BUS")
+		else -> LineType.valueOf("UNKNOWN")
+	}
+}
+
+data class ChangeOption(val line: String, val headsign: String) {
+	companion object {
+		fun unmarshall(stream: InputStream): ChangeOption {
+			val reader = Reader(stream)
+			return ChangeOption(line = reader.readString(), headsign = reader.readString())
+		}
+	}
+}
+
+data class LineGraph(
+	val stops: List<StopStub>,
+	val nextNodes: Map<Long, List<Long>>,
+	val prevNodes: Map<Long, List<Long>>
+) {
+	companion object {
+		fun unmarshall(stream: InputStream): LineGraph {
+			val reader = Reader(stream)
+			val stopsNum = reader.readUInt()
+			val stops = mutableListOf<StopStub>()
+			for (i in 0UL until stopsNum) {
+				stops.add(StopStub.unmarshall(stream))
+			}
+			val nextNodesNum = reader.readUInt()
+			val nextNodes = mutableMapOf<Long, List<Long>>()
+			for (i in 0UL until nextNodesNum) {
+				val from = reader.readInt()
+				val toNum = reader.readUInt()
+				val to = mutableListOf<Long>()
+				for (j in 0UL until toNum) {
+					to.add(reader.readInt())
+				}
+				nextNodes[from] = to
+			}
+			val prevNodesNum = reader.readUInt()
+			val prevNodes = mutableMapOf<Long, List<Long>>()
+			for (i in 0UL until prevNodesNum) {
+				val from = reader.readInt()
+				val toNum = reader.readUInt()
+				val to = mutableListOf<Long>()
+				for (j in 0UL until toNum) {
+					to.add(reader.readInt())
+				}
+				prevNodes[from] = to
+			}
+
+			return LineGraph(stops = stops, nextNodes = nextNodes, prevNodes = prevNodes)
+		}
+	}
+}
+
+data class StopStub(val name: String, val code: String, val zone: String, val onDemand: Boolean) {
+	companion object {
+		fun unmarshall(stream: InputStream): StopStub {
+			val reader = Reader(stream)
+			return StopStub(
+				code = reader.readString(),
+				name = reader.readString(),
+				zone = reader.readString(),
+				onDemand = reader.readBoolean()
+			)
+		}
+	}
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5963e6ff2bfd57957699339564f7d6dec9890bb1
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt
@@ -0,0 +1,142 @@
+package ml.adamsprogs.bimba.dashboard
+
+import android.Manifest
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.view.View
+import android.widget.Toast
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.core.view.get
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
+import androidx.navigation.fragment.NavHostFragment
+import androidx.navigation.ui.setupWithNavController
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import ml.adamsprogs.bimba.R
+import ml.adamsprogs.bimba.databinding.ActivityMainBinding
+import ml.adamsprogs.bimba.search.ResultsActivity
+import ml.adamsprogs.bimba.dashboard.ui.home.HomeFragment
+import ml.adamsprogs.bimba.dashboard.ui.map.MapFragment
+import ml.adamsprogs.bimba.dashboard.ui.voyage.VoyageFragment
+
+
+class MainActivity : AppCompatActivity() {
+
+	private lateinit var binding: ActivityMainBinding
+	private lateinit var locationPermissionRequest: ActivityResultLauncher<Array<String>>
+
+	override fun onCreate(savedInstanceState: Bundle?) {
+		super.onCreate(savedInstanceState)
+
+		binding = ActivityMainBinding.inflate(layoutInflater)
+		setContentView(binding.root)
+
+		supportFragmentManager.registerFragmentLifecycleCallbacks(
+			object : FragmentLifecycleCallbacks() {
+				override fun onFragmentViewCreated(
+					fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?
+				) {
+					setNavbarIcons(f)
+					super.onFragmentViewCreated(fm, f, v, savedInstanceState)
+				}
+			}, true
+		)
+
+		val navView: BottomNavigationView = binding.bottomNavigation
+		val navHostFragment =
+			supportFragmentManager.findFragmentById(R.id.nav_host_fragment_activity_main) as NavHostFragment
+		val navController = navHostFragment.navController
+		navView.setupWithNavController(navController)
+
+		locationPermissionRequest = registerForActivityResult(
+			ActivityResultContracts.RequestMultiplePermissions()
+		) { permissions ->
+			when {
+				permissions[Manifest.permission.ACCESS_FINE_LOCATION] ?: false ||
+								permissions[Manifest.permission.ACCESS_COARSE_LOCATION] ?: false -> {
+					showResults(ResultsActivity.Mode.MODE_LOCATION)
+				}
+				else -> {
+					Toast.makeText(this, "No location access given", Toast.LENGTH_SHORT).show()
+				}
+			}
+		}
+	}
+
+	override fun onBackPressed() {
+		if (binding.container.isDrawerOpen(binding.navigationDrawer)) {
+			binding.container.closeDrawer(binding.navigationDrawer)
+		} else {
+			super.onBackPressed()
+		}
+	}
+
+	fun onNavigationClicked() {
+		if (binding.container.isDrawerOpen(binding.navigationDrawer)) {
+			binding.container.closeDrawer(binding.navigationDrawer)
+		} else {
+			binding.container.openDrawer(binding.navigationDrawer)
+		}
+	}
+
+	fun onGpsClicked(fab: View) {
+
+		when (PackageManager.PERMISSION_GRANTED) {
+			ContextCompat.checkSelfPermission(
+				this,
+				Manifest.permission.ACCESS_COARSE_LOCATION
+			) -> {
+				/* todo animation
+					https://developer.android.com/guide/fragments/animate
+					https://github.com/raheemadamboev/fab-explosion-animation-app
+				*/
+				showResults(ResultsActivity.Mode.MODE_LOCATION)
+			}
+			else -> {
+				locationPermissionRequest.launch(
+					arrayOf(
+						Manifest.permission.ACCESS_FINE_LOCATION,
+						Manifest.permission.ACCESS_COARSE_LOCATION
+					)
+				)
+			}
+		}
+	}
+
+	fun onSearchClicked(text: CharSequence?) {
+		showResults(ResultsActivity.Mode.MODE_SEARCH, text.toString())
+	}
+
+	private fun showResults(mode: ResultsActivity.Mode, query: String = "") {
+		val intent = Intent(this, ResultsActivity::class.java).apply {
+			putExtra("mode", mode)
+			putExtra("query", query)
+		}
+		startActivity(intent)
+	}
+
+	private fun setNavbarIcons(f: Fragment) {
+		binding.bottomNavigation.menu[2].setIcon(R.drawable.ic_voyage_outline_24dp)
+		binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_outline_24dp)
+		binding.bottomNavigation.menu[0].setIcon(R.drawable.ic_map_outline_24dp)
+		when (f) {
+			is HomeFragment -> {
+				binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_black_24dp)
+			}
+			is VoyageFragment -> {
+				binding.bottomNavigation.menu[2].setIcon(R.drawable.ic_voyage_black_24dp)
+			}
+			is MapFragment -> {
+				binding.bottomNavigation.menu[0].setIcon(R.drawable.ic_map_black_24dp)
+			}
+			else -> {
+				binding.bottomNavigation.menu[1].setIcon(R.drawable.ic_home_black_24dp)
+			}
+		}
+	}
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..744d3b43f1476c3916ee2fd2a3e48920efe4cf9f
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeFragment.kt
@@ -0,0 +1,98 @@
+package ml.adamsprogs.bimba.dashboard.ui.home
+
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.mancj.materialsearchbar.MaterialSearchBar
+import com.mancj.materialsearchbar.MaterialSearchBar.BUTTON_NAVIGATION
+import ml.adamsprogs.bimba.search.BimbaSuggestionsAdapter
+import ml.adamsprogs.bimba.dashboard.MainActivity
+import ml.adamsprogs.bimba.api.Item
+import ml.adamsprogs.bimba.databinding.FragmentHomeBinding
+
+class HomeFragment : Fragment() {
+
+	private var _binding: FragmentHomeBinding? = null
+
+	private val binding get() = _binding!!
+
+	override fun onCreateView(
+		inflater: LayoutInflater,
+		container: ViewGroup?,
+		savedInstanceState: Bundle?
+	): View {
+		val homeViewModel =
+			ViewModelProvider(this)[HomeViewModel::class.java]
+
+		_binding = FragmentHomeBinding.inflate(inflater, container, false)
+		val root: View = binding.root
+
+		binding.searchBar.lastSuggestions = listOf<Item>()
+		homeViewModel.items.observe(viewLifecycleOwner) {
+			binding.searchBar.updateLastSuggestions(it.take(6))  // xxx workaround for suggestions behind navbar; should be paginated server-side
+		}
+		binding.searchBar.addTextChangeListener(SearchBarWatcher(homeViewModel))
+		binding.searchBar.setOnSearchActionListener(object : MaterialSearchBar.OnSearchActionListener {
+			override fun onButtonClicked(buttonCode: Int) {
+				when (buttonCode) {
+					BUTTON_NAVIGATION -> {
+						(context as MainActivity).onNavigationClicked()
+					}
+				}
+			}
+
+			override fun onSearchStateChanged(enabled: Boolean) {
+			}
+
+			override fun onSearchConfirmed(text: CharSequence?) {
+				binding.searchBar.clearSuggestions()
+				(context as MainActivity).onSearchClicked(text)
+			}
+		})
+		binding.searchBar.setCardViewElevation(0)
+		binding.searchBar.setCustomSuggestionAdapter(BimbaSuggestionsAdapter(layoutInflater, context){
+			TODO("On click suggestion")
+		})
+
+		binding.floatingActionButton.setOnClickListener {
+			binding.searchBar.clearSuggestions()
+			(context as MainActivity).onGpsClicked(it)
+		}
+		// todo on suggestion click go to line or stop
+		// todo on searchbar focus && if != '' -> populate suggestions
+
+		return root
+	}
+
+	override fun onDestroyView() {
+		super.onDestroyView()
+		_binding = null
+	}
+}
+
+class SearchBarWatcher(private val homeViewModel: HomeViewModel) : TextWatcher {
+	private val handler = Handler(Looper.getMainLooper())
+	private var workRunnable = Runnable {}
+
+	override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
+	}
+
+	override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
+	}
+
+	override fun afterTextChanged(s: Editable?) {
+		handler.removeCallbacks(workRunnable)
+		workRunnable = Runnable {
+			val text = s.toString()
+			homeViewModel.getItems(text)
+		}
+		handler.postDelayed(workRunnable, 1000) // todo make good time (probably between 500, 1000ms)
+	}
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..48254fc128da6829a73a41991af55f70db50b0be
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/home/HomeViewModel.kt
@@ -0,0 +1,46 @@
+package ml.adamsprogs.bimba.dashboard.ui.home
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import ml.adamsprogs.bimba.api.*
+import java.io.InputStream
+
+class HomeViewModel : ViewModel() {
+
+	private val mutableItems = MutableLiveData<List<Item>>()
+	val items: LiveData<List<Item>> = mutableItems
+
+	fun getItems(query: String) {
+		viewModelScope.launch {
+			val itemsStream = queryItems(query)
+			mutableItems.value = unmarshallItemResponse(itemsStream)
+		}
+	}
+
+	private suspend fun unmarshallItemResponse(stream: InputStream): List<Item> {
+		return withContext(Dispatchers.IO) {
+			when (val response = ItemsResponse.unmarshall(stream)) {
+				is ItemsSuccess -> {
+					return@withContext response.items
+				}
+				else -> {
+					 TODO("Error response")
+				}
+			}
+		}
+	}
+
+	private fun String.printable() = map {
+		when (Character.getType(it).toByte()) {
+			Character.CONTROL, Character.FORMAT, Character.PRIVATE_USE,
+			Character.SURROGATE, Character.UNASSIGNED, Character.OTHER_SYMBOL
+			-> "\\u%04x".format(it.code)
+			else -> it.toString()
+		}
+	}.joinToString("")
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5088bd52954aa7946746eca869c2ed21dc03647e
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapFragment.kt
@@ -0,0 +1,42 @@
+package ml.adamsprogs.bimba.dashboard.ui.map
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import ml.adamsprogs.bimba.databinding.FragmentMapBinding
+
+class MapFragment : Fragment() {
+
+	private var _binding: FragmentMapBinding? = null
+
+	// This property is only valid between onCreateView and
+	// onDestroyView.
+	private val binding get() = _binding!!
+
+	override fun onCreateView(
+		inflater: LayoutInflater,
+		container: ViewGroup?,
+		savedInstanceState: Bundle?
+	): View {
+		val mapViewModel =
+			ViewModelProvider(this).get(MapViewModel::class.java)
+
+		_binding = FragmentMapBinding.inflate(inflater, container, false)
+		val root: View = binding.root
+
+		val textView: TextView = binding.textNotifications
+		mapViewModel.text.observe(viewLifecycleOwner) {
+			textView.text = it
+		}
+		return root
+	}
+
+	override fun onDestroyView() {
+		super.onDestroyView()
+		_binding = null
+	}
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f811e9b19b6ffd84189117f0c2e1e04114a79f61
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/map/MapViewModel.kt
@@ -0,0 +1,13 @@
+package ml.adamsprogs.bimba.dashboard.ui.map
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+
+class MapViewModel : ViewModel() {
+
+	private val _text = MutableLiveData<String>().apply {
+		value = "This is notifications Fragment"
+	}
+	val text: LiveData<String> = _text
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0a610b07b30f546c98f712b8aea6584b9e06a094
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageFragment.kt
@@ -0,0 +1,42 @@
+package ml.adamsprogs.bimba.dashboard.ui.voyage
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import ml.adamsprogs.bimba.databinding.FragmentVoyageBinding
+
+class VoyageFragment : Fragment() {
+
+	private var _binding: FragmentVoyageBinding? = null
+
+	// This property is only valid between onCreateView and
+	// onDestroyView.
+	private val binding get() = _binding!!
+
+	override fun onCreateView(
+		inflater: LayoutInflater,
+		container: ViewGroup?,
+		savedInstanceState: Bundle?
+	): View {
+		val voyageViewModel =
+			ViewModelProvider(this)[VoyageViewModel::class.java]
+
+		_binding = FragmentVoyageBinding.inflate(inflater, container, false)
+		val root: View = binding.root
+
+		val textView: TextView = binding.textDashboard
+		voyageViewModel.text.observe(viewLifecycleOwner) {
+			textView.text = it
+		}
+		return root
+	}
+
+	override fun onDestroyView() {
+		super.onDestroyView()
+		_binding = null
+	}
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5348f5356cbc3108ab63a8f2980936d1e7409d5b
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/ui/voyage/VoyageViewModel.kt
@@ -0,0 +1,13 @@
+package ml.adamsprogs.bimba.dashboard.ui.voyage
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+
+class VoyageViewModel : ViewModel() {
+
+	private val _text = MutableLiveData<String>().apply {
+		value = "This is dashboard Fragment"
+	}
+	val text: LiveData<String> = _text
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/departures/DeparturesActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/departures/DeparturesActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..299c9d06176c355fa85f0baacc6a124817d232b2
--- /dev/null
+++ b/app/src/main/java/ml/adamsprogs/bimba/departures/DeparturesActivity.kt
@@ -0,0 +1,21 @@
+package ml.adamsprogs.bimba.departures
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.util.Log
+import ml.adamsprogs.bimba.databinding.ActivityDeparturesBinding
+
+class DeparturesActivity : AppCompatActivity() {
+	private var _binding: ActivityDeparturesBinding? = null
+
+	private val binding get() = _binding!!
+	override fun onCreate(savedInstanceState: Bundle?) {
+		super.onCreate(savedInstanceState)
+		_binding = ActivityDeparturesBinding.inflate(layoutInflater)
+		setContentView(binding.root)
+
+//		setSupportActionBar(binding.departuresAppBar)
+//		supportActionBar?.title = "Półwiejska"
+		binding.collapsingLayout.title = "Very long stop name that should span over multpile lines" // intent?.extras?.getString("name")
+	}
+}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeFragment.kt
deleted file mode 100644
index cc0dadedf1b16914aa539554619a9d7400348e3a..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeFragment.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package ml.adamsprogs.bimba.ui.home
-
-import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
-import com.mancj.materialsearchbar.MaterialSearchBar
-import com.mancj.materialsearchbar.MaterialSearchBar.BUTTON_BACK
-import com.mancj.materialsearchbar.MaterialSearchBar.BUTTON_NAVIGATION
-import ml.adamsprogs.bimba.MainActivity
-import ml.adamsprogs.bimba.R
-import ml.adamsprogs.bimba.databinding.FragmentHomeBinding
-
-class HomeFragment : Fragment() {
-
-	private var _binding: FragmentHomeBinding? = null
-
-	private val binding get() = _binding!!
-
-	override fun onCreateView(
-		inflater: LayoutInflater,
-		container: ViewGroup?,
-		savedInstanceState: Bundle?
-	): View {
-		val homeViewModel =
-			ViewModelProvider(this)[HomeViewModel::class.java]
-
-		_binding = FragmentHomeBinding.inflate(inflater, container, false)
-		val root: View = binding.root
-
-		binding.searchBar.lastSuggestions = listOf<String>()
-		homeViewModel.text.observe(viewLifecycleOwner) {
-			binding.searchBar.updateLastSuggestions(it.take(6))  // xxx workaround for suggestions behind navbar; should be paginated server-side
-		}
-		binding.searchBar.addTextChangeListener(SearchBarWatcher(homeViewModel))
-		binding.searchBar.setOnSearchActionListener(object : MaterialSearchBar.OnSearchActionListener {
-			override fun onButtonClicked(buttonCode: Int) {
-				when (buttonCode) {
-					BUTTON_NAVIGATION -> {
-						(context as MainActivity).onNavigationClicked()
-					}
-				}
-			}
-
-			override fun onSearchStateChanged(enabled: Boolean) {
-			}
-
-			override fun onSearchConfirmed(text: CharSequence?) {
-				// todo on search show results activity with more results
-			}
-		})
-		binding.searchBar.setCardViewElevation(0)
-		// todo on suggestion click go to line or stop
-		// todo adapter for suggestions
-
-		// todo gps button in fab (with animation https://stackoverflow.com/questions/68663679/how-to-transform-the-floating-action-buttons-to-full-screen-and-open-new-activit https://codesnipps.simolation.com/post/android/create-circular-reveal-animation-when-starting-activitys/)
-
-		return root
-	}
-
-	override fun onDestroyView() {
-		super.onDestroyView()
-		_binding = null
-	}
-}
-
-class SearchBarWatcher(private val homeViewModel: HomeViewModel) : TextWatcher {
-	private val handler = Handler(Looper.getMainLooper())
-	private var workRunnable = Runnable {}
-
-	override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
-	}
-
-	override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
-	}
-
-	override fun afterTextChanged(s: Editable?) {
-		handler.removeCallbacks(workRunnable)
-		workRunnable = Runnable {
-			val text = s.toString()
-			homeViewModel.getItems(text)
-		}
-		handler.postDelayed(workRunnable, 1000) // todo make good time (probably between 500, 1000ms)
-	}
-}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeViewModel.kt
deleted file mode 100644
index 5a654f6bddceac3fb8d1d26380a392f6a03f1f7c..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/ui/home/HomeViewModel.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-package ml.adamsprogs.bimba.ui.home
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import ml.adamsprogs.bimba.api.Line
-import ml.adamsprogs.bimba.api.Stop
-import xyz.apiote.fruchtfleisch.Reader
-import java.io.InputStream
-import java.net.HttpURLConnection
-import java.net.URL
-
-class HomeViewModel : ViewModel() {
-
-	private val _text = MutableLiveData<List<String>>()
-	val text: LiveData<List<String>> = _text
-
-	fun getItems(query: String) {
-		viewModelScope.launch {
-			val itemsStream = queryItems(query)
-			_text.value = unmarshallItemResponse(itemsStream)
-		}
-	}
-
-	@Suppress("BlockingMethodInNonBlockingContext")
-	private suspend fun queryItems(query: String): InputStream {
-		return withContext(Dispatchers.IO) {
-			val url = URL("https://bimba.apiote.xyz/api/poznan_ztm/items?q=${query}")
-			val c = (url.openConnection() as HttpURLConnection).apply {
-				setRequestProperty("X-Bimba-Token", "ef0179272e7270e1a2da1710a8ba24e1")
-			}
-			c.inputStream
-		}
-	}
-
-	private suspend fun unmarshallItemResponse(r: InputStream): List<String> {
-		val items = mutableListOf<String>()
-		val reader = Reader(r)
-		withContext(Dispatchers.IO) {
-			// todo ItemResponse from .api.unmarshallItemResponse(stream)
-			when (reader.readUInt()) {
-				0UL -> {
-					TODO("error response")
-				}
-				1UL -> {
-					val itemsNum = reader.readUInt()
-					for (i in 0UL until itemsNum) {
-						when (reader.readUInt()) {
-							0UL -> {
-								val stop = Stop.unmarshall(r)
-								items.add(stop.toString())
-							}
-							1UL -> {
-								val line = Line.unmarshall(r)
-								items.add(line.toString())
-							}
-							else -> {
-								TODO("throw unknown tag")
-							}
-						}
-					}
-				}
-				else -> {
-					TODO("throw unknown tag")
-				}
-			}
-		}
-		return items
-	}
-
-	private fun String.printable() = map {
-		when (Character.getType(it).toByte()) {
-			Character.CONTROL, Character.FORMAT, Character.PRIVATE_USE,
-			Character.SURROGATE, Character.UNASSIGNED, Character.OTHER_SYMBOL
-			-> "\\u%04x".format(it.code)
-			else -> it.toString()
-		}
-	}.joinToString("")
-}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapFragment.kt
deleted file mode 100644
index 5600d90bfca6343124171f020138f196213fd3d2..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapFragment.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package ml.adamsprogs.bimba.ui.map
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
-import ml.adamsprogs.bimba.databinding.FragmentMapBinding
-
-class MapFragment : Fragment() {
-
-	private var _binding: FragmentMapBinding? = null
-
-	// This property is only valid between onCreateView and
-	// onDestroyView.
-	private val binding get() = _binding!!
-
-	override fun onCreateView(
-		inflater: LayoutInflater,
-		container: ViewGroup?,
-		savedInstanceState: Bundle?
-	): View {
-		val mapViewModel =
-			ViewModelProvider(this).get(MapViewModel::class.java)
-
-		_binding = FragmentMapBinding.inflate(inflater, container, false)
-		val root: View = binding.root
-
-		val textView: TextView = binding.textNotifications
-		mapViewModel.text.observe(viewLifecycleOwner) {
-			textView.text = it
-		}
-		return root
-	}
-
-	override fun onDestroyView() {
-		super.onDestroyView()
-		_binding = null
-	}
-}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapViewModel.kt
deleted file mode 100644
index f754ec2f19f3586f8ce460242021c16cf105dcc6..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/ui/map/MapViewModel.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package ml.adamsprogs.bimba.ui.map
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-
-class MapViewModel : ViewModel() {
-
-	private val _text = MutableLiveData<String>().apply {
-		value = "This is notifications Fragment"
-	}
-	val text: LiveData<String> = _text
-}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageFragment.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageFragment.kt
deleted file mode 100644
index e8985169ac60d3e4e9e2276cbf41fedbf043d652..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageFragment.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package ml.adamsprogs.bimba.ui.voyage
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
-import ml.adamsprogs.bimba.databinding.FragmentVoyageBinding
-
-class VoyageFragment : Fragment() {
-
-	private var _binding: FragmentVoyageBinding? = null
-
-	// This property is only valid between onCreateView and
-	// onDestroyView.
-	private val binding get() = _binding!!
-
-	override fun onCreateView(
-		inflater: LayoutInflater,
-		container: ViewGroup?,
-		savedInstanceState: Bundle?
-	): View {
-		val voyageViewModel =
-			ViewModelProvider(this).get(VoyageViewModel::class.java)
-
-		_binding = FragmentVoyageBinding.inflate(inflater, container, false)
-		val root: View = binding.root
-
-		val textView: TextView = binding.textDashboard
-		voyageViewModel.text.observe(viewLifecycleOwner) {
-			textView.text = it
-		}
-		return root
-	}
-
-	override fun onDestroyView() {
-		super.onDestroyView()
-		_binding = null
-	}
-}
\ No newline at end of file




diff --git a/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageViewModel.kt b/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageViewModel.kt
deleted file mode 100644
index fe98671efbb3b5a93df99e9e8b6086dcdf592dc3..0000000000000000000000000000000000000000
--- a/app/src/main/java/ml/adamsprogs/bimba/ui/voyage/VoyageViewModel.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package ml.adamsprogs.bimba.ui.voyage
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-
-class VoyageViewModel : ViewModel() {
-
-	private val _text = MutableLiveData<String>().apply {
-		value = "This is dashboard Fragment"
-	}
-	val text: LiveData<String> = _text
-}
\ No newline at end of file




diff --git a/app/src/main/java/xyz/apiote/fruchtfleisch/Reader.kt b/app/src/main/java/xyz/apiote/fruchtfleisch/Reader.kt
index ca86beb025fe7110395f2cf2dbbab391fe154c32..cf700941c0f505541b2e818365e5535880ba7fa1 100644
--- a/app/src/main/java/xyz/apiote/fruchtfleisch/Reader.kt
+++ b/app/src/main/java/xyz/apiote/fruchtfleisch/Reader.kt
@@ -1,5 +1,6 @@
 package xyz.apiote.fruchtfleisch
 
+import java.io.DataInputStream
 import java.io.EOFException
 import java.io.InputStream
 
@@ -41,6 +42,38 @@ 		if (b < 0) {
 			throw EOFException("while reading byte")
 		}
 		return b.toUByte()
+	}
+
+	fun readU16(): UShort {
+		var result = 0U
+		for (i in 0 until 2) {
+			result = result or (readU8().toUInt().shl(2U.shl(i).toInt()))
+		}
+		return result.toUShort()
+	}
+
+	fun readU32(): UInt {
+		var result = 0U
+		for (i in 0 until 4) {
+			result = result or (readU8().toUInt().shl(2U.shl(i).toInt()))
+		}
+		return result
+	}
+
+	fun readU64(): UShort {
+		var result = 0U
+		for (i in 0 until 8) {
+			result = result or (readU8().toUInt().shl(2U.shl(i).toInt()))
+		}
+		return result.toUShort()
+	}
+
+	fun readFloat32(): Float {
+		return DataInputStream(stream).readFloat()
+	}
+
+	fun readFloat64(): Double {
+		return DataInputStream(stream).readDouble()
 	}
 
 	fun readData(length: UByte): ByteArray {




diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 4a5f76c9c20ed397738fa3d24da0f99c491f63cc..7f7d3e77bd7b60502b44ff3b2124ab5ee5b11d6a 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -3,13 +3,24 @@  	xmlns:app="http://schemas.android.com/apk/res-auto"
 	android:id="@+id/container"
 	android:layout_width="match_parent"
-	android:layout_height="match_parent"
-	android:fitsSystemWindows="true">
+	android:layout_height="match_parent">
 
 	<androidx.coordinatorlayout.widget.CoordinatorLayout
 		android:layout_width="match_parent"
 		android:layout_height="match_parent">
 
+		<com.google.android.material.appbar.AppBarLayout
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content"
+			android:fitsSystemWindows="true">
+
+			<com.google.android.material.appbar.MaterialToolbar
+				android:id="@+id/topAppBar"
+				android:layout_width="match_parent"
+				android:layout_height="?attr/actionBarSize"
+				app:title="" />
+		</com.google.android.material.appbar.AppBarLayout>
+
 		<androidx.constraintlayout.widget.ConstraintLayout
 			android:layout_width="match_parent"
 			android:layout_height="match_parent">
@@ -19,7 +30,6 @@ 				android:id="@+id/nav_host_fragment_activity_main"
 				android:name="androidx.navigation.fragment.NavHostFragment"
 				android:layout_width="match_parent"
 				android:layout_height="0dp"
-				android:background="?attr/colorSurfaceVariant"
 				app:defaultNavHost="true"
 				app:layout_constraintBottom_toTopOf="@+id/bottom_navigation"
 				app:layout_constraintEnd_toEndOf="parent"
@@ -29,12 +39,9 @@ 				app:navGraph="@navigation/front_navigation" />
 
 			<com.google.android.material.bottomnavigation.BottomNavigationView
 				android:id="@+id/bottom_navigation"
-				style="@style/Theme.Bimba.BottomNavigationHome"
 				android:layout_width="match_parent"
 				android:layout_height="wrap_content"
 				android:layout_gravity="bottom"
-				android:background="?attr/colorSurfaceVariant"
-				app:elevation="0dp"
 				app:layout_constraintBottom_toBottomOf="parent"
 				app:layout_constraintEnd_toEndOf="parent"
 				app:layout_constraintStart_toStartOf="parent"




diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 56a9aa247c61445bc3140065c58bd1e84a79433a..675e138c356b890370f573bc063ca633a057d41c 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -5,7 +5,7 @@ 	xmlns:tools="http://schemas.android.com/tools"
 	android:layout_width="match_parent"
 	android:layout_height="match_parent"
 	android:tag="@string/title_home"
-	tools:context=".ui.home.HomeFragment">
+	tools:context=".dashboard.ui.home.HomeFragment">
 
 	<com.mancj.materialsearchbar.MaterialSearchBar
 		android:id="@+id/search_bar"




diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml
index 74641967c4e169cbca457bc48e5908d06af70dda..619f8762a446d4a9644c88b56e08a217d00f7021 100644
--- a/app/src/main/res/layout/fragment_map.xml
+++ b/app/src/main/res/layout/fragment_map.xml
@@ -4,7 +4,7 @@ 	xmlns:app="http://schemas.android.com/apk/res-auto"
 	xmlns:tools="http://schemas.android.com/tools"
 	android:layout_width="match_parent"
 	android:layout_height="match_parent"
-	tools:context=".ui.map.MapFragment">
+	tools:context=".dashboard.ui.map.MapFragment">
 
 	<TextView
 		android:id="@+id/text_notifications"




diff --git a/app/src/main/res/layout/fragment_voyage.xml b/app/src/main/res/layout/fragment_voyage.xml
index 552c359b898a7818990b8fd4ea6923eae8281c63..693d09e63f0b540012e227ccea8a0e423536bc04 100644
--- a/app/src/main/res/layout/fragment_voyage.xml
+++ b/app/src/main/res/layout/fragment_voyage.xml
@@ -4,7 +4,7 @@ 	xmlns:app="http://schemas.android.com/apk/res-auto"
 	xmlns:tools="http://schemas.android.com/tools"
 	android:layout_width="match_parent"
 	android:layout_height="match_parent"
-	tools:context=".ui.voyage.VoyageFragment">
+	tools:context=".dashboard.ui.voyage.VoyageFragment">
 
 	<TextView
 		android:id="@+id/text_dashboard"




diff --git a/app/src/main/res/navigation/front_navigation.xml b/app/src/main/res/navigation/front_navigation.xml
index 6b50b81c3dfbb3fdbcc18789ece45ed9cc4a5afb..dc19c6dec415f9646646d2413ec7d19cf1d015d9 100644
--- a/app/src/main/res/navigation/front_navigation.xml
+++ b/app/src/main/res/navigation/front_navigation.xml
@@ -7,19 +7,19 @@ 	app:startDestination="@+id/navigation_home">
 
 	<fragment
 		android:id="@+id/navigation_home"
-		android:name="ml.adamsprogs.bimba.ui.home.HomeFragment"
+		android:name="ml.adamsprogs.bimba.dashboard.ui.home.HomeFragment"
 		android:label="@string/title_home"
 		tools:layout="@layout/fragment_home" />
 
 	<fragment
 		android:id="@+id/navigation_map"
-		android:name="ml.adamsprogs.bimba.ui.map.MapFragment"
+		android:name="ml.adamsprogs.bimba.dashboard.ui.map.MapFragment"
 		android:label="@string/title_map"
 		tools:layout="@layout/fragment_map" />
 
 	<fragment
 		android:id="@+id/navigation_voyage"
-		android:name="ml.adamsprogs.bimba.ui.voyage.VoyageFragment"
+		android:name="ml.adamsprogs.bimba.dashboard.ui.voyage.VoyageFragment"
 		android:label="@string/title_voyage"
 		tools:layout="@layout/fragment_voyage" />
 </navigation>
\ No newline at end of file




diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9709dbbc1bbf18b1a4bab9aa575086a2e772ebee..f97ef3c2999011ce6ec1fb2f90423320f52b6444 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -6,4 +6,5 @@ 	Voyage
 	<string name="searchbar_menu_item_gps">search by GPS</string>
 	<string name="home_fab_description">GPS icon</string>
 	<string name="search_placeholder">Search stops and lines</string>
+	<string name="title_activity_results">Results</string>
 </resources>
\ No newline at end of file




diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 5332ac581520f04157c890c6d5af752e20eaaf38..1081689f25ee509ba58eaf887a6f8e114bc3aba5 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,4 +1,4 @@
-<resources>
+<resources xmlns:tools="http://schemas.android.com/tools">
 
 	<style name="Theme.Bimba" parent="Theme.Material3.Light.NoActionBar">
 		<item name="android:fontFamily">@font/railway</item>
@@ -28,7 +28,10 @@ 		@color/md_theme_light_outline
 		<item name="colorOnSurfaceInverse">@color/md_theme_light_inverseOnSurface</item>
 		<item name="colorSurfaceInverse">@color/md_theme_light_inverseSurface</item>
 		<item name="colorPrimaryInverse">@color/md_theme_light_inversePrimary</item>
-		<item name="statusBarBackground">@color/md_theme_light_surfaceVariant</item>
+
+		<item name="statusBarBackground">@android:color/transparent</item>
+		<item name="android:statusBarColor">@android:color/transparent</item>
+		<item name="android:enforceStatusBarContrast" tools:targetApi="q">false</item>
 		<item name="lightStatusBar">true</item>
 	</style>
 
@@ -36,18 +39,26 @@ 	
 		<attr name="lightStatusBar" format="boolean" />
 	</declare-styleable>
 
-	<style name="Theme.Bimba.BottomNavigationHome" parent="Widget.Material3.BottomNavigationView">
-		<item name="materialThemeOverlay">@style/ThemeOverlay.App.BottomNavigationView</item>
+	<style name="Theme.Bimba.SearchBar" parent="MaterialSearchBarLight">
+		<item name="mt_searchBarColor">@color/md_theme_light_surfaceVariant</item>
+		<item name="mt_textColor">@color/md_theme_light_onSurfaceVariant</item>
+		<item name="mt_placeholderColor">@color/md_theme_light_onSurfaceVariant
+		</item> <!-- todo grey out -->
+		<item name="mt_backIconTint">@color/md_theme_light_onSurfaceVariant</item>
+		<item name="mt_navIconTint">@color/md_theme_light_onSurfaceVariant</item>
+		<item name="mt_searchIconTint">@color/md_theme_light_onSurfaceVariant</item>
+		<item name="mt_menuIconTint">@color/md_theme_light_onSurfaceVariant</item>
+		<item name="mt_clearIconTint">@color/md_theme_light_onSurfaceVariant</item>
 	</style>
 
-	<style name="ThemeOverlay.App.BottomNavigationView" parent="">
-		<item name="colorSurface">@color/md_theme_light_surface</item>
-		<item name="colorOnSurfaceVariant">@color/md_theme_light_onSurfaceVariant</item>
+	<style name="Theme.Bimba.SearchResult.Title" parent="Theme.Bimba">
+		<item name="android:textColor">@color/md_theme_light_onSurfaceVariant</item>
+		<item name="android:textSize">16sp</item>
 	</style>
 
-	<style name="Theme.Bimba.SearchBar" parent="MaterialSearchBarLight">
-		<item name="mt_searchBarColor">@color/md_theme_light_surface</item>
-		<item name="mt_textColor">@color/md_theme_light_onSurface</item>
-		<item name="mt_placeholderColor">@color/md_theme_light_onSurface</item> <!-- todo grey out -->
+	<style name="Theme.Bimba.SearchResult.Description" parent="Theme.Bimba">
+		<item name="android:textColor">@color/md_theme_light_onSurfaceVariant
+		</item> <!-- todo grey out -->
+		<item name="android:textSize">9sp</item>
 	</style>
 </resources>
\ No newline at end of file




diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
index d13d41607cf84742d49707dfbad0c1eab0f5b2ed..4d90afca85cd7032c4dd5c0c74b619a01f11385d 100644
--- a/app/src/main/res/values-night/themes.xml
+++ b/app/src/main/res/values-night/themes.xml
@@ -1,4 +1,4 @@
-<resources>
+<resources xmlns:tools="http://schemas.android.com/tools">
 
 	<style name="Theme.Bimba" parent="Theme.Material3.Dark.NoActionBar">
 		<item name="android:fontFamily">@font/railway</item>
@@ -28,7 +28,10 @@ 		@color/md_theme_dark_outline
 		<item name="colorOnSurfaceInverse">@color/md_theme_dark_inverseOnSurface</item>
 		<item name="colorSurfaceInverse">@color/md_theme_dark_inverseSurface</item>
 		<item name="colorPrimaryInverse">@color/md_theme_dark_inversePrimary</item>
-		<item name="statusBarBackground">@color/md_theme_dark_surfaceVariant</item>
+
+		<item name="statusBarBackground">@android:color/transparent</item>
+		<item name="android:statusBarColor">@android:color/transparent</item>
+		<item name="android:enforceStatusBarContrast" tools:targetApi="q">false</item>
 		<item name="lightStatusBar">false</item>
 	</style>
 
@@ -36,18 +39,24 @@ 	
 		<attr name="lightStatusBar" format="boolean" />
 	</declare-styleable>
 
-	<style name="Theme.Bimba.BottomNavigationHome" parent="Widget.Material3.BottomNavigationView">
-		<item name="materialThemeOverlay">@style/ThemeOverlay.App.BottomNavigationView</item>
+	<style name="Theme.Bimba.SearchBar" parent="MaterialSearchBarLight">
+		<item name="mt_searchBarColor">@color/md_theme_dark_surfaceVariant</item>
+		<item name="mt_textColor">@color/md_theme_dark_onSurfaceVariant</item>
+		<item name="mt_placeholderColor">@color/md_theme_dark_onSurfaceVariant</item> <!-- todo grey out -->
+		<item name="mt_backIconTint">@color/md_theme_dark_onSurfaceVariant</item>
+		<item name="mt_navIconTint">@color/md_theme_dark_onSurfaceVariant</item>
+		<item name="mt_searchIconTint">@color/md_theme_dark_onSurfaceVariant</item>
+		<item name="mt_menuIconTint">@color/md_theme_dark_onSurfaceVariant</item>
+		<item name="mt_clearIconTint">@color/md_theme_dark_onSurfaceVariant</item>
 	</style>
 
-	<style name="ThemeOverlay.App.BottomNavigationView" parent="">
-		<item name="colorSurface">@color/md_theme_dark_surface</item>
-		<item name="colorOnSurfaceVariant">@color/md_theme_dark_onSurfaceVariant</item>
+	<style name="Theme.Bimba.SearchResult.Title" parent="Theme.Bimba">
+		<item name="android:textColor">@color/md_theme_dark_onSurfaceVariant</item>
+		<item name="android:textSize">16sp</item>
 	</style>
 
-	<style name="Theme.Bimba.SearchBar" parent="MaterialSearchBarLight">
-		<item name="mt_searchBarColor">@color/md_theme_dark_surface</item>
-		<item name="mt_textColor">@color/md_theme_dark_onSurface</item>
-		<item name="mt_placeholderColor">@color/md_theme_dark_onSurface</item> <!-- todo grey out -->
+	<style name="Theme.Bimba.SearchResult.Description" parent="Theme.Bimba">
+		<item name="android:textColor">@color/md_theme_dark_onSurfaceVariant</item> <!-- todo grey out -->
+		<item name="android:textSize">9sp</item>
 	</style>
 </resources>
\ No newline at end of file




diff --git a/build.gradle b/build.gradle
index 7565e1c021f5cfdfd7e0b5c751720cfb9f9f89d7..64f119e33344ef7caf3fa99959245374a5436294 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules.
 plugins {
     id 'com.android.application' version '7.2.2' apply false
     id 'com.android.library' version '7.2.2' apply false
-    id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
+    id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
 }
 
 task clean(type: Delete) {