Bimba.git

commit bbd76f12f6f280a36bcac0f9e79ca3bad6ac3fa4

Author: Adam Evyčędo <git@apiote.xyz>

Merge branch 'develop' into translations

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


diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 4c4f412fafbcd7a61baecb8ed4e14734b604c450..dc0f5b9eb21edba214763393e9c2cceab452b741 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -14,13 +14,20 @@
 * Travel planning
 * Offline timetable
 
-== [3.9.0] – 2025-02-08
+== [3.9.0] – 2025-03-20
 
 === Added
 
 * Travel planning based on Transitous
 
-== [3.6.1] – 2024-09-04
+== [3.8.0] – 2025-01-21
+
+=== Changed
+
+* separated arrivals and departures
+* switched to Transitous MOTIS 2 API
+
+== [3.7.0] – 2024-10-15
 
 === Fixed
 




diff --git a/README.adoc b/README.adoc
index 911bd206a8b9b12526d94e40597541b17bee5bb3..6cd20de2687c56df5400b6bf4d67f1292242809f 100644
--- a/README.adoc
+++ b/README.adoc
@@ -4,7 +4,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later
 
 = Bimba
 Adam Evyčędo <me@apiote.xyz>
-v3.9.0-rc.1 2025-02-08
+v3.9.0 2025-03-20
 :toc:
 
 Bimba is a FLOSS public transport passenger companion; a timetable in your pocket.




diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4296d6b0b56cab349d2e2378c061b90ff60f354b..d90eca0fb8ff6df7c0b393332b505265bbc33119 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -27,8 +27,8 @@ 	defaultConfig {
 		applicationId = "xyz.apiote.bimba.czwek"
 		minSdk = 21
 		targetSdk = 35
-		versionCode = 35
-		versionName = "3.9.0-rc.1"
+		versionCode = 37
+		versionName = "3.9.0"
 
 		testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
 		resourceConfigurations += listOf("en", "de", "en-rGB", "en-rUS", "et", "fr", "it", "pl", "ru", "ta")




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/home/Favourites.kt b/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/home/Favourites.kt
index 11c0a85d49513a4f0720a5ca7a1854bc429b73c9..c27191404e8cd4f2f33328c2a95f636f0140dbe7 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/home/Favourites.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/home/Favourites.kt
@@ -57,9 +57,9 @@ 				return false
 			}
 
 			val favouritesSame = oldFav.feedName == newFav.feedName &&
-					oldFav.stopName == newFav.stopName &&
-					oldFav.sequence == newFav.sequence &&
-					oldFav.lines == newFav.lines
+				oldFav.stopName == newFav.stopName &&
+				oldFav.sequence == newFav.sequence &&
+				oldFav.lines == newFav.lines
 
 			if (!favouritesSame) {
 				return false
@@ -74,13 +74,13 @@ 				return false
 			}
 
 			return oldDeparture!!.get().id == newDeparture!!.get().id &&
-					oldDeparture!!.get().vehicle.Line == newDeparture!!.get().vehicle.Line &&
-					oldDeparture!!.get().vehicle.Headsign == newDeparture!!.get().vehicle.Headsign &&
-					oldDeparture!!.get().statusText(
-						context,
-						false,
-						lastUpdate
-					) == newDeparture!!.get().statusText(context, false)
+				oldDeparture!!.get().vehicle.Line == newDeparture!!.get().vehicle.Line &&
+				oldDeparture!!.get().vehicle.Headsign == newDeparture!!.get().vehicle.Headsign &&
+				oldDeparture!!.get().statusText(
+					context,
+					false,
+					lastUpdate
+				) == newDeparture!!.get().statusText(context, false)
 		}
 	}
 
@@ -192,13 +192,19 @@ 				holder.stopHeadline.text = favourite.stopName
 				holder.lineIcon.setImageDrawable(vehicle.Line.icon(context))
 				holder.lineIcon.contentDescription = vehicle.Line.kind.name
 				holder.lineName.text = vehicle.Line.name
-				holder.headsign.text =
+				holder.headsign.text = if (vehicle.Headsign.isNotBlank()) {
 					context.getString(R.string.departure_headsign, vehicle.Headsign)
-				holder.headsign.contentDescription =
+				} else {
+					""
+				}
+				holder.headsign.contentDescription = if (vehicle.Headsign.isNotBlank()) {
 					context.getString(
 						R.string.departure_headsign_content_description,
 						vehicle.Headsign
 					)
+				} else {
+					""
+				}
 
 				with(event.get()) {
 					if (arrivalTime == departureTime) {




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/departures/Departures.kt b/app/src/main/java/xyz/apiote/bimba/czwek/departures/Departures.kt
index a5d676e2b8392b6aca5f6efb899b86d44fff2a97..1224b2da60591ee9e657cfe67ca6b50130f8ee06 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/departures/Departures.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/departures/Departures.kt
@@ -72,13 +72,19 @@ 			}
 			holder?.lineIcon?.setImageDrawable(event.vehicle.Line.icon(context!!))
 			holder?.lineIcon?.contentDescription = event.vehicle.Line.kind.name
 			holder?.lineName?.text = event.vehicle.Line.name
-			holder?.headsign?.text =
+			holder?.headsign?.text = if (event.vehicle.Headsign.isNotBlank()) {
 				context?.getString(R.string.departure_headsign, event.vehicle.Headsign)
-			holder?.headsign?.contentDescription =
+			} else {
+				""
+			}
+			holder?.headsign?.contentDescription = if (event.vehicle.Headsign.isNotBlank()) {
 				context?.getString(
 					R.string.departure_headsign_content_description,
 					event.vehicle.Headsign
 				)
+			} else {
+				""
+			}
 
 			when {
 				event.isRealtime -> {
@@ -118,14 +124,14 @@
 			val statusTexts = event.statusText(context, showAsTime)
 			if (event.arrivalTime == event.departureTime) {
 				if (!event.exact) {
-					holder?.arrivalStatus?.apply{
+					holder?.arrivalStatus?.apply {
 						visibility = View.VISIBLE
 						text = context?.getString(R.string.approximately)
 					}
 				} else {
 					holder?.arrivalStatus?.visibility = View.INVISIBLE
 				}
-				holder?.arrivalTime?.apply{
+				holder?.arrivalTime?.apply {
 					text = statusTexts.second
 					visibility = View.VISIBLE
 				}
@@ -247,15 +253,15 @@ 			val oldDeparture = oldDepartures[oldItemPosition]
 			val newDeparture = newDepartures[newItemPosition]
 			return if (oldDeparture.event != null && newDeparture.event != null) {
 				!oldDeparture.event.terminusArrival &&
-						oldDeparture.event.terminusArrival == newDeparture.event.terminusArrival &&
-						oldDeparture.event.exact == newDeparture.event.exact &&
-						oldDeparture.event.vehicle.Line == newDeparture.event.vehicle.Line &&
-						oldDeparture.event.vehicle.Headsign == newDeparture.event.vehicle.Headsign &&
-						oldDeparture.event.statusText(
-							context,
-							false,
-							lastUpdate
-						) == newDeparture.event.statusText(context, false) && !showAsTimeChanged
+					oldDeparture.event.terminusArrival == newDeparture.event.terminusArrival &&
+					oldDeparture.event.exact == newDeparture.event.exact &&
+					oldDeparture.event.vehicle.Line == newDeparture.event.vehicle.Line &&
+					oldDeparture.event.vehicle.Headsign == newDeparture.event.vehicle.Headsign &&
+					oldDeparture.event.statusText(
+						context,
+						false,
+						lastUpdate
+					) == newDeparture.event.statusText(context, false) && !showAsTimeChanged
 			} else if (oldDeparture.alert.isNotEmpty() && newDeparture.alert.isEmpty()) {
 				oldDeparture.alert == newDeparture.alert
 			} else {
@@ -449,16 +455,30 @@ 				}
 			}
 
 			findViewById<TextView>(R.id.line).apply {
-				contentDescription = getString(
-					R.string.vehicle_headsign_content_description,
-					event.vehicle.Line.name,
-					event.vehicle.Headsign
-				)
-				text = getString(
-					R.string.vehicle_headsign,
-					event.vehicle.Line.name,
-					event.vehicle.Headsign
-				)
+				contentDescription = if (event.vehicle.Headsign.isNotBlank()) {
+					getString(
+						R.string.vehicle_headsign_content_description,
+						event.vehicle.Line.name,
+						event.vehicle.Headsign
+					)
+				} else {
+					getString(
+						R.string.vehicle_headsign_content_description_no_headsign,
+						event.vehicle.Line.name,
+					)
+				}
+				text = if (event.vehicle.Headsign.isNotBlank()) {
+					getString(
+						R.string.vehicle_headsign,
+						event.vehicle.Line.name,
+						event.vehicle.Headsign
+					)
+				} else {
+					getString(
+						R.string.vehicle_headsign_no_headsign,
+						event.vehicle.Line.name,
+					)
+				}
 			}
 
 
@@ -619,7 +639,7 @@ 			content.apply {
 				findViewById<MapView>(R.id.map).let { map ->
 					map.setTileSource(TileSourceFactory.MAPNIK)
 					if (((context?.resources?.configuration?.uiMode ?: UI_MODE_NIGHT_UNDEFINED)
-								and UI_MODE_NIGHT_MASK) == UI_MODE_NIGHT_YES
+							and UI_MODE_NIGHT_MASK) == UI_MODE_NIGHT_YES
 					) {
 						map.overlayManager.tilesOverlay.setColorFilter(TilesOverlay.INVERT_COLORS)
 					}




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt
index 2f4d18ccb8bbebd0cd076fefb7d802efd9acc97e..89a8b4a501c929a45a80ccd85edd53cb5c602caa 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/Journeys.kt
@@ -107,7 +107,11 @@ 						it.intermediateStops.size + 1,
 						it.intermediateStops.size + 1
 					)
 
-					context.getString(R.string.journey_stops_headsign, stops, headsign)
+					if (headsign.isBlank()) {
+						stops
+					} else {
+						context.getString(R.string.journey_stops_headsign, stops, headsign)
+					}
 				}
 
 				val legDestination = legView.findViewById<TextView>(R.id.leg_destination)




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysActivity.kt b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysActivity.kt
index ad9c1ea0427a21dabd5fbd54f144587e85f027dd..403e016bc952f86da3be5f1fc0a6dacf39a16ecc 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysActivity.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/journeys/JourneysActivity.kt
@@ -11,6 +11,8 @@ import android.content.res.Configuration.UI_MODE_NIGHT_MASK
 import android.content.res.Configuration.UI_MODE_NIGHT_UNDEFINED
 import android.content.res.Configuration.UI_MODE_NIGHT_YES
 import android.graphics.DashPathEffect
+import android.graphics.Paint.Cap
+import android.graphics.Paint.Join
 import android.os.Build
 import android.os.Bundle
 import android.view.View
@@ -150,6 +152,8 @@ 							GeoPoint(it.latitude, it.longitude)
 						}
 						val contrastShape = Polyline()
 						val contrastPaint = contrastShape.outlinePaint
+						contrastPaint.strokeCap = Cap.ROUND
+						contrastPaint.strokeJoin = Join.ROUND
 						contrastPaint.color =
 							Colour.getThemeColour(com.google.android.material.R.attr.colorOnBackground, this)
 						contrastPaint.strokeWidth = contrastPaint.strokeWidth * 1.5f
@@ -159,8 +163,10 @@
 						val shape = Polyline()
 						val paint = shape.outlinePaint
 						paint.color = leg.start.vehicle.Line.colour.toInt()
+						paint.strokeCap = Cap.ROUND
+						paint.strokeJoin = Join.ROUND
 						if (leg.start.vehicle.Line.kind.isActive()) {
-							paint.setPathEffect(DashPathEffect(floatArrayOf(10f, 10f), 0f))
+							paint.pathEffect = DashPathEffect(floatArrayOf(10f, 10f), 0f)
 							paint.color = Colour.getThemeColour(
 								com.google.android.material.R.attr.colorSurfaceContainer, this
 							)




diff --git a/app/src/main/res/layout/journey_leg.xml b/app/src/main/res/layout/journey_leg.xml
index 72d8f2d222507dbde33fb613c7c7f37e9e888818..f7079cff9258751dd2d8b3d04b631293c8d39dc6 100644
--- a/app/src/main/res/layout/journey_leg.xml
+++ b/app/src/main/res/layout/journey_leg.xml
@@ -1,65 +1,83 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
 SPDX-FileCopyrightText: Adam Evyčędo
 
 SPDX-License-Identifier: GPL-3.0-or-later
 -->
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-	android:layout_width="wrap_content"
+	xmlns:app="http://schemas.android.com/apk/res-auto"
+	xmlns:tool="http://schemas.android.com/tools"
+	android:layout_width="match_parent"
 	android:layout_height="wrap_content"
-	xmlns:app="http://schemas.android.com/apk/res-auto"
 	android:paddingStart="8dp"
+	android:paddingTop="8dp"
 	android:paddingEnd="8dp"
-	android:paddingTop="16dp"
-	android:paddingBottom="16dp"
-	xmlns:tool="http://schemas.android.com/tools">
-	<ImageView
-		android:id="@+id/leg_origin_image"
-		android:layout_width="wrap_content"
+	android:paddingBottom="8dp">
+
+	<androidx.constraintlayout.widget.ConstraintLayout
+		android:id="@+id/leg_origin_box"
+		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
-		android:src="@drawable/origin"
-		android:contentDescription="@string/beginning_of_journey_s_leg"
+		android:paddingBottom="8dp"
+		android:paddingTop="8dp"
 		app:layout_constraintStart_toStartOf="parent"
-		app:layout_constraintTop_toTopOf="parent" />
+		app:layout_constraintTop_toTopOf="parent">
 
-	<com.google.android.material.textview.MaterialTextView
-		android:id="@+id/leg_origin"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_marginStart="8dp"
-		android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
-		app:layout_constraintBottom_toBottomOf="@+id/leg_origin_image"
-		app:layout_constraintStart_toEndOf="@+id/leg_origin_image"
-		app:layout_constraintTop_toTopOf="@+id/leg_origin_image"
-		tool:text="Polna" />
+		<ImageView
+			android:id="@+id/leg_origin_image"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:contentDescription="@string/beginning_of_journey_s_leg"
+			android:src="@drawable/origin"
+			app:layout_constraintBottom_toBottomOf="@+id/leg_origin"
+			app:layout_constraintStart_toStartOf="parent"
+			app:layout_constraintTop_toTopOf="@+id/leg_origin" />
 
-	<com.google.android.material.textview.MaterialTextView
-		android:id="@+id/leg_origin_time"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_marginStart="8dp"
-		android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
-		app:layout_constraintBottom_toBottomOf="@+id/leg_origin"
-		app:layout_constraintStart_toEndOf="@+id/leg_origin"
-		app:layout_constraintTop_toTopOf="@+id/leg_origin"
-		tool:text="11:25" />
+		<com.google.android.material.textview.MaterialTextView
+			android:id="@+id/leg_origin"
+			android:layout_width="0dp"
+			android:layout_height="wrap_content"
+			android:layout_marginStart="8dp"
+			android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
+			app:layout_constraintBottom_toBottomOf="parent"
+			app:layout_constraintEnd_toStartOf="@+id/leg_origin_time"
+			app:layout_constraintStart_toEndOf="@+id/leg_origin_image"
+			app:layout_constraintTop_toTopOf="parent"
+			tool:text="Polna" />
 
+		<com.google.android.material.textview.MaterialTextView
+			android:id="@+id/leg_origin_time"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
+			app:layout_constraintBottom_toBottomOf="@+id/leg_origin"
+			app:layout_constraintEnd_toEndOf="parent"
+			app:layout_constraintTop_toTopOf="@+id/leg_origin"
+			tool:text="11:25" />
+	</androidx.constraintlayout.widget.ConstraintLayout>
+
+	<androidx.constraintlayout.widget.ConstraintLayout
+		android:id="@+id/leg_mode_box"
+		android:paddingBottom="8dp"
+		android:paddingTop="8dp"
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		app:layout_constraintStart_toStartOf="parent"
+		app:layout_constraintTop_toBottomOf="@id/leg_origin_box">
 	<ImageView
 		android:id="@+id/leg_mode_image"
 		android:layout_width="wrap_content"
 		android:layout_height="wrap_content"
-		android:layout_marginTop="8dp"
 		android:src="@drawable/bike"
 		app:layout_constraintStart_toStartOf="parent"
-		app:layout_constraintTop_toBottomOf="@+id/leg_origin_image"
-        tool:ignore="ContentDescription" />
+		app:layout_constraintTop_toTopOf="parent"
+		tool:ignore="ContentDescription" />
 
 	<com.google.android.material.textview.MaterialTextView
 		android:id="@+id/leg_line"
 		android:layout_width="wrap_content"
 		android:layout_height="wrap_content"
-		android:paddingEnd="8dp"
 		android:paddingStart="8dp"
+		android:paddingEnd="8dp"
 		android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
 		app:layout_constraintBottom_toBottomOf="@+id/leg_mode_image"
 		app:layout_constraintStart_toEndOf="@+id/leg_mode_image"
@@ -68,45 +86,57 @@ 		tool:text="610" />
 
 	<com.google.android.material.textview.MaterialTextView
 		android:id="@+id/leg_distance"
-		android:layout_width="wrap_content"
+		android:layout_width="0dp"
 		android:layout_height="wrap_content"
 		android:layout_marginStart="8dp"
 		android:textAppearance="@style/TextAppearance.Material3.LabelSmall"
 		app:layout_constraintBottom_toBottomOf="@+id/leg_line"
+		app:layout_constraintEnd_toEndOf="parent"
 		app:layout_constraintStart_toEndOf="@+id/leg_line"
 		app:layout_constraintTop_toTopOf="@+id/leg_line"
 		tool:text="12 stops" />
+	</androidx.constraintlayout.widget.ConstraintLayout>
 
-	<ImageView
-		android:id="@+id/leg_destination_image"
-		android:layout_width="wrap_content"
+	<androidx.constraintlayout.widget.ConstraintLayout
+		android:paddingBottom="8dp"
+		android:paddingTop="8dp"
+		android:id="@+id/leg_destination_box"
+		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
-		android:layout_marginTop="8dp"
-		android:src="@drawable/destination"
-		android:contentDescription="@string/end_of_journey_s_leg"
 		app:layout_constraintStart_toStartOf="parent"
-		app:layout_constraintTop_toBottomOf="@+id/leg_mode_image" />
+		app:layout_constraintTop_toBottomOf="@id/leg_mode_box">
 
-	<com.google.android.material.textview.MaterialTextView
-		android:id="@+id/leg_destination"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:layout_marginStart="8dp"
-		android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
-		app:layout_constraintBottom_toBottomOf="@+id/leg_destination_image"
-		app:layout_constraintStart_toEndOf="@+id/leg_destination_image"
-		app:layout_constraintTop_toTopOf="@+id/leg_destination_image"
-		tool:text="Dębiec" />
+		<ImageView
+			android:id="@+id/leg_destination_image"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:contentDescription="@string/end_of_journey_s_leg"
+			android:src="@drawable/destination"
+			app:layout_constraintBottom_toBottomOf="@+id/leg_destination"
+			app:layout_constraintStart_toStartOf="parent"
+			app:layout_constraintTop_toTopOf="@+id/leg_destination" />
+
+		<com.google.android.material.textview.MaterialTextView
+			android:id="@+id/leg_destination"
+			android:layout_width="0dp"
+			android:layout_height="wrap_content"
+			android:layout_marginStart="8dp"
+			android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
+			app:layout_constraintBottom_toBottomOf="parent"
+			app:layout_constraintEnd_toStartOf="@+id/leg_destination_time"
+			app:layout_constraintStart_toEndOf="@+id/leg_destination_image"
+			app:layout_constraintTop_toTopOf="parent"
+			tool:text="Bardzo dluga nazwa przystanku na którym należy wysiąść" />
 
 	<com.google.android.material.textview.MaterialTextView
 		android:id="@+id/leg_destination_time"
 		android:layout_width="wrap_content"
 		android:layout_height="wrap_content"
-		android:layout_marginStart="8dp"
 		android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
 		app:layout_constraintBottom_toBottomOf="@+id/leg_destination"
-		app:layout_constraintStart_toEndOf="@+id/leg_destination"
+		app:layout_constraintEnd_toEndOf="parent"
 		app:layout_constraintTop_toTopOf="@+id/leg_destination"
 		tool:text="11:30" />
+	</androidx.constraintlayout.widget.ConstraintLayout>
 
 </androidx.constraintlayout.widget.ConstraintLayout>
\ 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 dce39381bead6ef1b66c86ce7bd003eaeb3d90e6..7647b07af4ed343e2846c4ce3d5125b969b48aba 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -30,6 +30,7 @@ 	Cannot obtain current location
 	<string name="no_departures">No departures</string>
 	<string name="waiting_position">waiting for position</string>
 	<string name="vehicle_headsign"><annotation decoration="apply"><annotation arg="0">%1$s</annotation></annotation> » <annotation arg="1">%2$s</annotation></string>
+	<string name="vehicle_headsign_no_headsign">line <annotation decoration="apply"><annotation arg="0">%1$s</annotation></annotation></string>
 	<string name="distance_in_m">%1$s m</string>
 	<plurals name="distance_in_m_cd">
 		<item quantity="one">%1$d metre</item>
@@ -74,11 +75,11 @@ 	
 		<item quantity="one">%1$d second</item>
 		<item quantity="other">%1$d seconds</item>
 	</plurals>
-	<string name="time_in_tm">%1$s %2$sTm</string>
+	<string name="time_in_tm">in %1$s %2$sTm</string>
 	<string name="time_in_tm_past">%1$s %2$sTm ago</string>
 	<plurals name="time_in_tm_cd">
-		<item quantity="one">%1$d tim</item>
-		<item quantity="other">%1$d tims</item>
+		<item quantity="one">in %1$d tim</item>
+		<item quantity="other">in %1$d tims</item>
 	</plurals>
 	<plurals name="time_in_4tm_12_cd">
 		<item quantity="one">%1$s quedratim</item>
@@ -187,6 +188,7 @@ 	Stop on demand in zone %1$s
 	<string name="stop_stub_on_demand">Stop on demand</string>
 	<string name="stop_stub_in_zone">Stop in zone %1$s</string>
 	<string name="vehicle_headsign_content_description">%1$s towards %2$s</string>
+	<string name="vehicle_headsign_content_description_no_headsign">line %1$s</string>
 	<string name="departure_headsign">» %1$s</string>
 	<string name="credits">Font yellowcircle8 (https://git.apiote.xyz/yellowcircle8.git) based on Railway Sans © Greg Fleming, OFL-1.1 https://github.com/davelab6/Railway-Sans\n\n Mastodon icon (https://github.com/mastodon/joinmastodon) © Mastodon contributors, AGPL-3.0-or-later\n\n Bimba logo created by https://github.com/tebriz159\n\n Material icons © Google, Apache-2.0\n\n Map data © OpenStreetMap contributors (https://www.openstreetmap.org/copyright), ODbL-1.0\n\n Cities list used for geocoding short plus codes © Geonames (https://geonames.org), CC BY\n\n Matrix logo ™/® Matrix.org</string>
 	<string name="title_about">About</string>
@@ -294,7 +296,6 @@ 	arrival
 	<string name="departure_approximate">approx. dep.</string>
 	<string name="departure">departure</string>
 	<string name="approximately">approximately</string>
-	<string name="origin_input_hint">Origin</string>
 	<string name="destination_input_hint">Destination</string>
 	<string name="depart_after">Depart after</string>
 	<string name="arrive_by">Arrive by</string>
@@ -311,10 +312,11 @@ 		%1$d stops
 	</plurals>
 	<string name="use_as_origin">use as origin</string>
 	<string name="use_as_destination">use as destination</string>
-	<string name="here">here</string>
 	<string name="no_journeys_found">No journeys found</string>
 	<string name="title_select_date_journey">Select date of the journey</string>
 	<string name="title_select_time_journey">Select journey time</string>
 	<string name="other_options">Other options</string>
 	<string name="journey_stops_headsign">%1$s (» %2$s)</string>
+	<string name="origin_input_hint">Origin</string>
+	<string name="here">here</string>
 </resources>




diff --git a/app/src/main/res/values-en-rGB/strings.xml b/app/src/main/res/values-en-rGB/strings.xml
index 68ccb1a0918d8af2192cc15c04dec08e8931ab6d..0439f88d8155b6d4e6a196da0a663ec31eb810cd 100644
--- a/app/src/main/res/values-en-rGB/strings.xml
+++ b/app/src/main/res/values-en-rGB/strings.xml
@@ -28,6 +28,7 @@ 	Cannot obtain current location
 	<string name="no_departures">No departures</string>
 	<string name="waiting_position">waiting for position</string>
 	<string name="vehicle_headsign"><annotation decoration="apply"><annotation arg="0">%1$s</annotation></annotation> » <annotation arg="1">%2$s</annotation></string>
+	<string name="vehicle_headsign_no_headsign">line <annotation decoration="apply"><annotation arg="0">%1$s</annotation></annotation></string>
 	<string name="distance_in_m">%1$s m</string>
 	<plurals name="distance_in_m_cd">
 		<item quantity="one">%1$d metre</item>
@@ -72,7 +73,7 @@ 	
 		<item quantity="one">%1$d second</item>
 		<item quantity="other">%1$d seconds</item>
 	</plurals>
-	<string name="time_in_tm">%1$s %2$sTm</string>
+	<string name="time_in_tm">in %1$s %2$sTm</string>
 	<string name="time_in_tm_past">%1$s %2$sTm ago</string>
 	<plurals name="time_in_tm_cd">
 		<item quantity="one">%1$d tim</item>
@@ -129,6 +130,7 @@ 	towards %1$s
 	<string name="departure_momentarily">momentarily</string>
 	<string name="departure_departed">departed</string>
 	<string name="departure_now">now</string>
+	<string name="time">%1$02d:%2$02d</string>
 	<string name="at_time">at %1$02d:%2$02d</string>
 	<string name="about_time">about %1$02d:%2$02d</string>
 	<string name="at_time_realtime">at %1$02d:%2$02d:%3$02d</string>
@@ -184,6 +186,7 @@ 	Stop on demand in zone %1$s
 	<string name="stop_stub_on_demand">Stop on demand</string>
 	<string name="stop_stub_in_zone">Stop in zone %1$s</string>
 	<string name="vehicle_headsign_content_description">%1$s towards %2$s</string>
+	<string name="vehicle_headsign_content_description_no_headsign">line %1$s</string>
 	<string name="departure_headsign">» %1$s</string>
 	<string name="credits">Font yellowcircle8 (https://git.apiote.xyz/yellowcircle8.git) based on Railway Sans © Greg Fleming, OFL-1.1 https://github.com/davelab6/Railway-Sans\n\n Mastodon icon (https://github.com/mastodon/joinmastodon) © Mastodon contributors, AGPL-3.0-or-later\n\n Bimba logo created by https://github.com/tebriz159\n\n Material icons © Google, Apache-2.0\n\n Map data © OpenStreetMap contributors (https://www.openstreetmap.org/copyright), ODbL-1.0\n\n Cities list used for geocoding short plus codes © Geonames (https://geonames.org), CC BY\n\n Matrix logo ™/® Matrix.org</string>
 	<string name="title_about">About</string>
@@ -291,9 +294,23 @@ 	arrival
 	<string name="departure_approximate">approx. dep.</string>
 	<string name="departure">departure</string>
 	<string name="approximately">approximately</string>
+	<string name="destination_input_hint">Destination</string>
 	<string name="depart_after">Depart after</string>
+	<string name="no_journeys_found">No journeys found</string>
 	<string name="title_select_date_journey">Select date of the journey</string>
 	<string name="title_select_time_journey">Select journey time</string>
 	<string name="other_options">Other options</string>
 	<string name="journey_stops_headsign">%1$s (» %2$s)</string>
+	<string name="origin_input_hint">Origin</string>
+	<string name="arrive_by">Arrive by</string>
+	<string name="today">Today</string>
+	<string name="now">Now</string>
+	<string name="wheelchair_accessible">Wheelchair accessible</string>
+	<string name="bike_transport">Bike transport</string>
+	<string name="go">Go</string>
+	<string name="beginning_of_journey_s_leg">beginning of journey’s leg</string>
+	<string name="end_of_journey_s_leg">end of journey’s leg</string>
+	<string name="use_as_origin">use as origin</string>
+	<string name="use_as_destination">use as destination</string>
+	<string name="here">here</string>
 </resources>




diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml
index d4bc4fbef1a1e5295bf9e0618e391ab104cdd960..3b80001be91904e0c223070fd8bb031f75a20534 100644
--- a/app/src/main/res/values-en-rUS/strings.xml
+++ b/app/src/main/res/values-en-rUS/strings.xml
@@ -27,6 +27,7 @@ 	Cannot obtain current location
 	<string name="no_departures">No departures</string>
 	<string name="waiting_position">waiting for position</string>
 	<string name="vehicle_headsign"><annotation decoration="apply"><annotation arg="0">%1$s</annotation></annotation> » <annotation arg="1">%2$s</annotation></string>
+	<string name="vehicle_headsign_no_headsign">line <annotation decoration="apply"><annotation arg="0">%1$s</annotation></annotation></string>
 	<string name="distance_in_m">%1$s m</string>
 	<plurals name="distance_in_m_cd">
 		<item quantity="one">%1$d meter</item>
@@ -42,7 +43,7 @@ 	
 		<item quantity="one">%1$d second</item>
 		<item quantity="other">%1$d seconds</item>
 	</plurals>
-	<string name="time_in_tm">%1$s %2$sTm</string>
+	<string name="time_in_tm">in %1$s %2$sTm</string>
 	<string name="time_in_tm_past">%1$s %2$sTm ago</string>
 	<plurals name="time_in_tm_cd">
 		<item quantity="one">%1$d tim</item>
@@ -86,6 +87,7 @@ 	towards %1$s
 	<string name="departure_momentarily">momentarily</string>
 	<string name="departure_departed">departed</string>
 	<string name="departure_now">now</string>
+	<string name="time">%1$02d:%2$02d</string>
 	<string name="at_time">at %1$02d:%2$02d</string>
 	<string name="about_time">about %1$02d:%2$02d</string>
 	<string name="at_time_realtime">at %1$02d:%2$02d:%3$02d</string>
@@ -140,6 +142,7 @@ 	Stop on demand in zone %1$s
 	<string name="stop_stub_on_demand">Stop on demand</string>
 	<string name="stop_stub_in_zone">Stop in zone %1$s</string>
 	<string name="vehicle_headsign_content_description">%1$s towards %2$s</string>
+	<string name="vehicle_headsign_content_description_no_headsign">line %1$s</string>
 	<string name="departure_headsign">» %1$s</string>
 	<string name="credits">Font yellowcircle8 (https://git.apiote.xyz/yellowcircle8.git) based on Railway Sans © Greg Fleming, OFL-1.1 https://github.com/davelab6/Railway-Sans\n\n Mastodon icon (https://github.com/mastodon/joinmastodon) © Mastodon contributors, AGPL-3.0-or-later\n\n Bimba logo created by https://github.com/tebriz159\n\n Material icons © Google, Apache-2.0\n\n Map data © OpenStreetMap contributors (https://www.openstreetmap.org/copyright), ODbL-1.0\n\n Cities list used for geocoding short plus codes © Geonames (https://geonames.org), CC BY\n\n Matrix logo ™/® Matrix.org</string>
 	<string name="title_about">About</string>
@@ -289,9 +292,23 @@ 	arrival
 	<string name="departure_approximate">approx. dep.</string>
 	<string name="departure">departure</string>
 	<string name="approximately">approximately</string>
+	<string name="destination_input_hint">Destination</string>
 	<string name="depart_after">Depart after</string>
+	<string name="no_journeys_found">No journeys found</string>
 	<string name="title_select_date_journey">Select date of the journey</string>
 	<string name="title_select_time_journey">Select journey time</string>
 	<string name="other_options">Other options</string>
 	<string name="journey_stops_headsign">%1$s (» %2$s)</string>
+	<string name="origin_input_hint">Origin</string>
+	<string name="arrive_by">Arrive by</string>
+	<string name="today">Today</string>
+	<string name="now">Now</string>
+	<string name="wheelchair_accessible">Wheelchair accessible</string>
+	<string name="bike_transport">Bike transport</string>
+	<string name="go">Go</string>
+	<string name="beginning_of_journey_s_leg">beginning of journey’s leg</string>
+	<string name="end_of_journey_s_leg">end of journey’s leg</string>
+	<string name="use_as_origin">use as origin</string>
+	<string name="use_as_destination">use as destination</string>
+	<string name="here">here</string>
 </resources>
\ No newline at end of file




diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 993cd3c1fbcab934b48b9321084bcd857bf444a5..7d65807e96868f83a2bba74fc3d5644c3d976bd1 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -42,6 +42,7 @@     zatłoczony
     <string name="occupancy_full">pełny</string>
     <string name="occupancy_wont_let">nie wpuszcza</string>
     <string name="no_map_app">Brak aplikacji map</string>
+    <string name="vehicle_headsign_content_description_no_headsign">linia %1$s</string>
     <string name="departure_headsign">» %1$s</string>
     <string name="departure_headsign_content_description">w kierunku przystanku %1$s</string>
     <string name="departure_momentarily">za moment</string>
@@ -125,7 +126,8 @@     Wybierz końcowy czas
     <string name="more">Więcej</string>
     <string name="alert_header">Komunikaty</string>
     <string name="map_attribution"><![CDATA[© kontrubutorzy <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>]]></string>
-    <string name="distance_in_m">%1$s m</string>
+	<string name="vehicle_headsign_no_headsign">linia <annotation decoration="apply"><annotation arg="0">%1$s</annotation></annotation></string>
+	<string name="distance_in_m">%1$s m</string>
     <string name="distance_in_km">%1$s km</string>
     <string name="distance_in_two_units_cd">%1$s i %2$s</string>
     <string name="distance_in_yd">%1$s yd</string>
@@ -133,7 +135,7 @@     %1$s ft
     <string name="distance_in_mi">%1$s mi</string>
     <string name="distance_in_gf">%1$s %2$sGf</string>
     <string name="time_in_s">%1$s s</string>
-    <string name="time_in_tm">%1$s %2$sTm</string>
+    <string name="time_in_tm">za %1$s %2$sTm</string>
     <string name="time_in_tm_past">%1$s %2$sTm temu</string>
     <string name="speed_in_m_per_s">%1$s m/s</string>
     <string name="speed_in_mi_per_h">%1$s mph</string>




diff --git a/metadata/en-US/changelogs/36.txt b/metadata/en-US/changelogs/36.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5d9b90e518374aa4790e7770deb1656621d7c0a9
--- /dev/null
+++ b/metadata/en-US/changelogs/36.txt
@@ -0,0 +1,2 @@
+* added travel planning based on Transitous
+* added translations by Arkadiusz, ArnaudDvs, Jonah Brüchert, Kemal Oktay Aktoğan, Priit Jõerüüt, Xapitonov, தமிழ்நேரம்




diff --git a/metadata/en-US/changelogs/37.txt b/metadata/en-US/changelogs/37.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1150b2df6f52588c9d9b25367715740cd7efabf1
--- /dev/null
+++ b/metadata/en-US/changelogs/37.txt
@@ -0,0 +1,3 @@
+* added travel planning based on Transitous
+* hid unavailable headsigns from Transitous
+* added translations by Arkadiusz, ArnaudDvs, Jonah Brüchert, Kemal Oktay Aktoğan, Priit Jõerüüt, Xapitonov, தமிழ்நேரம்




diff --git a/metadata/pl-PL/changelogs/37.txt b/metadata/pl-PL/changelogs/37.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7b35996efd76352891f8fe0313ba3c7babc9e7a1
--- /dev/null
+++ b/metadata/pl-PL/changelogs/37.txt
@@ -0,0 +1,3 @@
+* dodano planowanie trasy za pomocą Transitous
+* schowano niedostępne przystanki końcowe z Transitous
+* dodano tłumaczenia od: Arkadiusz, ArnaudDvs, Jonah Brüchert, Kemal Oktay Aktoğan, Priit Jõerüüt, Xapitonov, தமிழ்நேரம்