diff --git a/3imba.svg b/3imba.svg
index c50a215f7f5cf61a33bb8a381d247af1ab7eebc0..55d9af1cd0196dbde99fbb5c3272c388fdf9c2c1 100644
--- a/3imba.svg
+++ b/3imba.svg
@@ -3,7 +3,6 @@ xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
@@ -22,7 +21,6 @@ rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
diff --git a/app/build.gradle b/app/build.gradle
index f83613c9bb0a0fadee2f4a6202fe11327e3cae4d..17900722ec9d39dd0fec456fe6dd9ddf51c1d563 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -38,7 +38,7 @@ }
dependencies {
implementation 'androidx.core:core-ktx:1.9.0'
- implementation 'androidx.appcompat:appcompat:1.6.0'
+ implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
diff --git a/app/src/androidTest/java/ml/adamsprogs/bimba/ExampleInstrumentedTest.kt b/app/src/androidTest/java/ml/adamsprogs/bimba/ExampleInstrumentedTest.kt
deleted file mode 100644
index 12072519495305fc9bdc3e93cc96af9ed1cfafbe..0000000000000000000000000000000000000000
--- a/app/src/androidTest/java/ml/adamsprogs/bimba/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package ml.adamsprogs.bimba
-
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.ext.junit.runners.AndroidJUnit4
-
-import org.junit.Test
-import org.junit.runner.RunWith
-
-import org.junit.Assert.*
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("ml.adamsprogs.bimba", appContext.packageName)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7de0435db26c3d4d5babfa875d01e60bf4614892..6e86b57b4ced88504298a3b09380d33dd243e046 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,7 +7,6 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <!--suppress AndroidUnknownAttribute -->
<application
android:name=".Bimba"
android:allowBackup="true"
@@ -41,21 +40,16 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
- <!--suppress AndroidUnknownAttribute -->
<data android:scheme="http" />
- <!--suppress AndroidUnknownAttribute -->
<data android:scheme="https" />
- <!--suppress AndroidUnknownAttribute -->
<data android:host="www.peka.poznan.pl" />
- <!--suppress AndroidUnknownAttribute -->
- <data android:pathPrefix="/vm" /> <!-- todo(intents) test with ?przystanek=... -->
+ <data android:pathPrefix="/vm" />
</intent-filter>
</activity>
<activity
android:name=".search.ResultsActivity"
android:exported="false"
android:label="@string/title_activity_results" />
- <!--suppress AndroidUnknownAttribute -->
<activity
android:name=".dashboard.MainActivity"
android:exported="false"
diff --git a/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt b/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt
index 019ce0dc48a04d71befc67fc281b27a0be5db554..7f89c0ec8c12615e02ded718ef99a59e139cdfc8 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/api/Api.kt
@@ -12,6 +12,8 @@ import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
+// todo [3.1] constants
+
data class Server(val host: String, val token: String, val feeds: String) {
companion object {
fun get(context: Context): Server {
@@ -29,7 +31,6 @@ data class Result(val stream: InputStream?, val error: Error?)
data class Error(val statusCode: Int, val stringResource: Int, val imageResource: Int)
-@Suppress("BlockingMethodInNonBlockingContext")
suspend fun getFeeds(cm: ConnectivityManager, server: Server): Result {
return rawRequest(
URL("${hostWithScheme(server.host)}/api/"),
@@ -55,7 +56,12 @@ suspend fun locateItems(cm: ConnectivityManager, server: Server, near: Position): Result {
return request(server, "items", mapOf("near" to near.toString()), cm)
}
-suspend fun getLocatablesIn(cm: ConnectivityManager, server: Server, bl: Position, tr: Position): Result {
+suspend fun getLocatablesIn(
+ cm: ConnectivityManager,
+ server: Server,
+ bl: Position,
+ tr: Position
+): Result {
return request(server, "locatables", mapOf("lb" to bl.toString(), "rt" to tr.toString()), cm)
}
@@ -72,11 +78,9 @@ }
return request(server, "departures", params, cm)
}
-@Suppress("BlockingMethodInNonBlockingContext")
suspend fun rawRequest(url: URL, server: Server, cm: ConnectivityManager): Result {
- @Suppress("DEPRECATION") // fix_later(API_29, API_23) https://developer.android.com/reference/android/net/ConnectivityManager#getActiveNetwork()
+ @Suppress("DEPRECATION") // fixme later(API_29, API_23) https://developer.android.com/reference/android/net/ConnectivityManager#getActiveNetwork()
if (cm.activeNetworkInfo == null) {
- // todo check false-positives
return Result(null, Error(0, R.string.error_offline, R.drawable.error_net))
}
return withContext(Dispatchers.IO) {
@@ -91,10 +95,7 @@ val (string, image) = when (c.responseCode) {
400 -> Pair(R.string.error_400, R.drawable.error_app)
401 -> Pair(R.string.error_401, R.drawable.error_sec)
403 -> Pair(R.string.error_403, R.drawable.error_sec)
- 404 -> Pair(
- R.string.error_404,
- R.drawable.error_search
- ) // todo check if server returns 404
+ 404 -> Pair(R.string.error_404, R.drawable.error_search)
429 -> Pair(R.string.error_429, R.drawable.error_limit)
500 -> Pair(R.string.error_50x, R.drawable.error_server)
502 -> Pair(R.string.error_50x, R.drawable.error_server)
@@ -110,7 +111,6 @@ }
}
}
-@Suppress("BlockingMethodInNonBlockingContext")
suspend fun request(
server: Server,
resource: String,
@@ -118,7 +118,7 @@ params: Map,
cm: ConnectivityManager
): Result {
return withContext(Dispatchers.IO) {
- val url = URL(
+ val url = URL( // todo [3.1] scheme, host, path, constructed query
"${hostWithScheme(server.host)}/api/${server.feeds}/$resource${
params.map {
"${it.key}=${
diff --git a/app/src/main/java/ml/adamsprogs/bimba/api/Responses.kt b/app/src/main/java/ml/adamsprogs/bimba/api/Responses.kt
index ab40e38e878d814f8f80c812ff731b812883f8d1..d1b585e68275c8a693cf9c3e2f8be95594fd0c4b 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/api/Responses.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/api/Responses.kt
@@ -15,7 +15,7 @@ 1UL -> {
DeparturesSuccess.unmarshal(stream)
}
else -> {
- TODO("throw unknown tag")
+ TODO("[api-freeze] throw unknown tag")
}
}
}
@@ -61,7 +61,7 @@ 1UL -> {
ItemsSuccess.unmarshal(stream)
}
else -> {
- TODO("throw unknown tag")
+ TODO("[api-freeze] throw unknown tag")
}
}
}
@@ -83,7 +83,7 @@ 1UL -> {
items.add(Line.unmarshal(stream))
}
else -> {
- TODO("throw unknown tag")
+ TODO("[api-freeze] throw unknown tag")
}
}
}
@@ -104,7 +104,7 @@ 1UL -> {
FeedsSuccess.unmarshal(stream)
}
else -> {
- TODO("throw unknown tag")
+ TODO("[api-freeze] throw unknown tag")
}
}
}
@@ -145,7 +145,7 @@ 1UL -> {
LocatablesSuccess.unmarshal(stream)
}
else -> {
- TODO("throw unknown tag")
+ TODO("[api-freeze] throw unknown tag")
}
}
}
@@ -167,7 +167,7 @@ 1UL -> {
locatables.add(Vehicle.unmarshal(stream))
}
else -> {
- TODO("throw unknown tag")
+ TODO("[api-freeze] throw unknown tag")
}
}
}
diff --git a/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt b/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt
index d339afa3b5746d64e5e54d5f6bd7b349791bda5d..99a5abc5900a4e81e2955d885f3eb2ae76032a02 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/api/Structs.kt
@@ -5,6 +5,7 @@ import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
+import android.text.format.DateUtils
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.graphics.ColorUtils.HSLToColor
import androidx.core.graphics.drawable.toBitmap
@@ -13,6 +14,7 @@ import ml.adamsprogs.bimba.dpToPixel
import ml.adamsprogs.bimba.dpToPixelI
import xyz.apiote.fruchtfleisch.Reader
import java.io.InputStream
+import java.util.*
import java.util.zip.Adler32
import kotlin.math.abs
import kotlin.math.pow
@@ -188,6 +190,31 @@ }
override fun location(): Position = Position
+ fun congestion(context: Context): String {
+ return when (CongestionLevel.toUInt()) { // todo enum
+ 0u -> context.getString(R.string.congestion_unknown)
+ 1u -> context.getString(R.string.congestion_smooth)
+ 2u -> context.getString(R.string.congestion_stop_and_go)
+ 3u -> context.getString(R.string.congestion_congestion)
+ 4u -> context.getString(R.string.congestion_jams)
+ else -> TODO("throw invalid congestion")
+ }
+ }
+
+ fun occupancy(context: Context): String {
+ return when (OccupancyStatus.toUInt()) { // todo enum
+ 0u -> context.getString(R.string.occupancy_unknown)
+ 1u -> context.getString(R.string.occupancy_empty)
+ 2u -> context.getString(R.string.occupancy_many_seats)
+ 3u -> context.getString(R.string.occupancy_few_seats)
+ 4u -> context.getString(R.string.occupancy_standing_only)
+ 5u -> context.getString(R.string.occupancy_crowded)
+ 6u -> context.getString(R.string.occupancy_full)
+ 7u -> context.getString(R.string.occupancy_wont_let)
+ else -> TODO("throw invalid occupancy")
+ }
+ }
+
companion object {
fun unmarshal(stream: InputStream): Vehicle {
val reader = Reader(stream)
@@ -220,7 +247,7 @@ val reader = Reader(stream)
val colour = Colour.unmarshal(stream)
val type = reader.readUInt()
val name = reader.readString()
- return LineStub(name = name, colour = colour, type = LineType(type.toUInt()))
+ return LineStub(name = name, colour = colour, type = LineType.of(type.toUInt()))
}
}
@@ -240,6 +267,58 @@ val stopOrder: String,
val vehicle: Vehicle,
val boarding: UByte
) {
+
+ fun statusText(context: Context?): String {
+ val now = Calendar.getInstance()
+ val departureTime = Calendar.getInstance().apply {
+ set(Calendar.HOUR_OF_DAY, this@Departure.time.Hour.toInt())
+ set(Calendar.MINUTE, this@Departure.time.Minute.toInt())
+ set(Calendar.SECOND, this@Departure.time.Second.toInt())
+ set(
+ Calendar.ZONE_OFFSET,
+ TimeZone.getTimeZone(this@Departure.time.Zone).getOffset(now.timeInMillis)
+ )
+ roll(Calendar.DAY_OF_MONTH, this@Departure.time.DayOffset.toInt())
+ }
+ return when (status.toInt()) {
+ 0 -> DateUtils.getRelativeTimeSpanString(
+ departureTime.timeInMillis,
+ now.timeInMillis,
+ DateUtils.MINUTE_IN_MILLIS,
+ DateUtils.FORMAT_ABBREV_RELATIVE
+ )
+ .toString()
+ 1 -> context?.getString(R.string.departure_momentarily) ?: "momentarily"
+ 2 -> context?.getString(R.string.departure_now) ?: "now"
+ 3 -> context?.getString(R.string.departure_departed) ?: "departed"
+ else -> TODO("throw invalid")
+ }
+ }
+
+ fun timeString(context: Context): String {
+ return if (isRealtime) {
+ context.getString(
+ R.string.at_time_realtime,
+ time.Hour.toInt(),
+ time.Minute.toInt(),
+ time.Second.toInt()
+ )
+ } else {
+ context.getString(R.string.at_time, time.Hour.toInt(), time.Minute.toInt())
+ }
+ }
+
+ fun boardingText(context: Context): String {
+ // todo [3.x] probably should take into account (on|off)-boarding only, on demand
+ return when {
+ (boarding.and(0b1010u) != (0b0).toUByte()) -> context.getString(R.string.on_demand)
+ (boarding.and(0b0101u) == (0b0101).toUByte()) -> context.getString(R.string.no_boarding)
+ (boarding.and(0b0100u) == (0b0100).toUByte()) -> context.getString(R.string.on_boarding)
+ (boarding.and(0b0001u) == (0b0001).toUByte()) -> context.getString(R.string.off_boarding)
+ else -> context.getString(R.string.boarding)
+ }
+ }
+
companion object {
fun unmarshal(stream: InputStream): Departure {
val reader = Reader(stream)
@@ -307,10 +386,25 @@ result += "${chOpt.line} → ${chOpt.headsign}\n"
return result
}
- fun changeOptions(): String {
- return changeOptions.groupBy { it.line }
+ fun changeOptions(context: Context): Pair<String,String> {
+ return Pair(changeOptions.groupBy { it.line }
.map { Pair(it.key, it.value.joinToString { co -> co.headsign }) }
- .joinToString { "${it.first} » ${it.second}" }
+ .joinToString {
+ context.getString(
+ R.string.vehicle_headsign,
+ it.first,
+ it.second
+ )
+ },
+ changeOptions.groupBy { it.line }
+ .map { Pair(it.key, it.value.joinToString { co -> co.headsign }) }
+ .joinToString {
+ context.getString(
+ R.string.vehicle_headsign_content_description,
+ it.first,
+ it.second
+ )
+ })
}
companion object {
@@ -390,7 +484,7 @@ LineType.TRAM -> R.drawable.tram_black
LineType.UNKNOWN -> R.drawable.vehicle_black
}
val icon =
- AppCompatResources.getDrawable(context, iconID)?.mutate() // todo(code) move context out
+ AppCompatResources.getDrawable(context, iconID)?.mutate()
?.apply {
setTint(textColour(colour))
}?.toBitmap(dpToPixelI(19.2f / scale), dpToPixelI(19.2f / scale), Bitmap.Config.ARGB_8888)
@@ -437,15 +531,11 @@ val graphBack: LineGraph,
val name: String
) : Item, LineAbstract {
override fun toString(): String {
- return "$name ($type) [${textColour()}/$colour]\n→ [${headsignsThere.joinToString()}]\n→ [${headsignsBack.joinToString()}]\n"
+ return "$name ($type) [$colour]\n→ [${headsignsThere.joinToString()}]\n→ [${headsignsBack.joinToString()}]\n"
}
fun icon(context: Context, scale: Float = 1f): Bitmap {
return super.icon(context, type, colour, scale)
- }
-
- fun textColour(): Int {
- return super.textColour(colour)
}
companion object {
@@ -467,7 +557,7 @@ val graphThere = LineGraph.unmarshal(stream)
val graphBack = LineGraph.unmarshal(stream)
val name = reader.readString()
return Line(
- name = name, colour = colour, type = LineType(type.toUInt()),
+ name = name, colour = colour, type = LineType.of(type.toUInt()),
headsignsThere = headsignsThere, headsignsBack = headsignsBack, graphThere = graphThere,
graphBack = graphBack
)
@@ -476,14 +566,16 @@ }
}
enum class LineType {
- TRAM, BUS, UNKNOWN
-}
+ TRAM, BUS, UNKNOWN;
-fun LineType(type: UInt): LineType {
- return when (type) {
- 0U -> LineType.valueOf("TRAM")
- 3U -> LineType.valueOf("BUS")
- else -> LineType.valueOf("UNKNOWN")
+ companion object {
+ fun of(type: UInt): LineType {
+ return when (type) {
+ 0U -> valueOf("TRAM")
+ 3U -> valueOf("BUS")
+ else -> valueOf("UNKNOWN")
+ }
+ }
}
}
diff --git a/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt
index fd757e49612e6dd6e73f627dc48f909d4535e94c..676af3a60b6b9d8c5d09ea3ab0c679246f640f5d 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/dashboard/MainActivity.kt
@@ -85,7 +85,7 @@
@Suppress(
"OVERRIDE_DEPRECATION",
"DEPRECATION"
- ) // fix_later https://developer.android.com/reference/androidx/activity/OnBackPressedDispatcher
+ ) // fixme later https://developer.android.com/reference/androidx/activity/OnBackPressedDispatcher
override fun onBackPressed() {
if (binding.container.isDrawerOpen(binding.navigationDrawer)) {
binding.container.closeDrawer(binding.navigationDrawer)
@@ -102,7 +102,7 @@ binding.container.openDrawer(binding.navigationDrawer)
}
}
- fun onGpsClicked(fab: View, fragment: Fragment) {
+ fun onGpsClicked(fragment: Fragment) {
when (PackageManager.PERMISSION_GRANTED) {
ContextCompat.checkSelfPermission(
this,
@@ -139,7 +139,7 @@ }
startActivity(intent)
}
is Line -> {
- TODO("start line graph actvity")
+ TODO("[3.1] start line graph activity")
}
}
}
@@ -149,7 +149,7 @@ showResults(ResultsActivity.Mode.MODE_SEARCH, text.toString())
}
private fun showResults(mode: ResultsActivity.Mode, query: String = "") {
- /* todo(ux,low) animation
+ /* todo [3.1] (ux,low) animation
https://developer.android.com/guide/fragments/animate
https://github.com/raheemadamboev/fab-explosion-animation-app
*/
@@ -161,7 +161,8 @@ startActivity(intent)
}
private fun setNavbarIcons(f: Fragment) {
- binding.bottomNavigation.menu[2].setIcon(R.drawable.voyage_outline)
+ // todo [voyage-planning]
+ // binding.bottomNavigation.menu[2].setIcon(R.drawable.voyage_outline)
binding.bottomNavigation.menu[1].setIcon(R.drawable.home_outline)
binding.bottomNavigation.menu[0].setIcon(R.drawable.map_outline)
when (f) {
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
index 2470cf45ad7dc2c49c7bb1a634f08da1178f5487..d410a5a2a0735ee7203a81126953ea57b8e23be0 100644
--- 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
@@ -18,7 +18,7 @@ import ml.adamsprogs.bimba.dashboard.MainActivity
import ml.adamsprogs.bimba.api.Item
import ml.adamsprogs.bimba.databinding.FragmentHomeBinding
-// todo search: https://github.com/material-components/material-components-android/blob/master/docs/components/Search.md
+// todo [3.1] search: https://github.com/material-components/material-components-android/blob/master/docs/components/Search.md
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
@@ -78,15 +78,9 @@ })
binding.floatingActionButton.setOnClickListener {
binding.searchBar.clearSuggestions()
- (context as MainActivity).onGpsClicked(it, this)
+ (context as MainActivity).onGpsClicked(this)
}
- /* todo(ux,low) on searchbar focus && if != '' -> populate suggestions
- binding.searchBar.searchEditText.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
- Log.v("Focus", "$hasFocus")
- if(binding.searchBar.text != "" && hasFocus) {
- binding.searchBar.lastSuggestions = lastSuggestions
- }
- }*/
+ // todo [3.1] (ux,low) on searchbar focus && if != '' -> populate suggestions
return binding.root
}
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
index abaafb36ea21072a914aec949226368972bad7ea..1b3144477b7a8512448f37c5b962ed63b422b9b1 100644
--- 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
@@ -69,7 +69,7 @@ )
}
handler.postDelayed(
workRunnable,
- 1000
+ 750
) // todo(ux,low) make good time (probably between 500, 1000ms)
}
}
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
index a94ead33ad554857e69409f65813f9240ee46759..5146115ec74ba17dbb13cd2d2355f219d7d2cb7d 100644
--- 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
@@ -37,10 +37,8 @@ import org.osmdroid.views.overlay.TilesOverlay
import org.osmdroid.views.overlay.gestures.RotationGestureOverlay
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay
-import java.io.File
-
-// todo empty state on no network and long time on entry
+// todo empty state on no network
class MapFragment : Fragment() {
@@ -53,7 +51,7 @@
private val handler = Handler(Looper.getMainLooper())
private var workRunnable = Runnable {}
- private var snackbar: Snackbar? = null
+ private var snack: Snackbar? = null
@SuppressLint("ClickableViewAccessibility")
override fun onCreateView(
@@ -96,7 +94,7 @@ locationOverlay.setPersonAnchor(.5f, .5f)
}
binding.floatingActionButton.setOnClickListener {
- (context as MainActivity).onGpsClicked(it, this)
+ (context as MainActivity).onGpsClicked(this)
}
binding.map.addMapListener(object : MapListener {
@@ -118,7 +116,7 @@ return root
}
private fun onMapMove(): Boolean {
- snackbar?.dismiss()
+ snack?.dismiss()
return delayGetLocatables()
}
@@ -161,8 +159,9 @@ }
}
fun showLocation() {
- snackbar = Snackbar.make(binding.root, "waiting for position", Snackbar.LENGTH_INDEFINITE)
- snackbar!!.show()
+ snack =
+ Snackbar.make(binding.root, getString(R.string.waiting_position), Snackbar.LENGTH_INDEFINITE)
+ snack!!.show()
binding.floatingActionButton.hide()
binding.map.overlays.removeAll {
it is MyLocationNewOverlay
@@ -170,7 +169,7 @@ }
locationOverlay.enableFollowLocation()
binding.map.overlays.add(locationOverlay)
locationOverlay.runOnFirstFix {
- snackbar?.dismiss()
+ snack?.dismiss()
}
}
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
index def30777abd8ca73bb7e73a16581c5818d124dfb..0e92face1169bc1ed59c86d5299fe75638b4fd27 100644
--- 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
@@ -13,6 +13,7 @@ import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
+import androidx.constraintlayout.widget.Group
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -60,6 +61,95 @@ companion object {
const val TAG = "MapBottomSheet"
}
+ private fun showVehicle(content: View, vehicle: Vehicle) {
+ content.findViewById<Group>(R.id.stop_group).visibility = View.GONE
+ content.findViewById<Group>(R.id.vehicle_group).visibility = View.VISIBLE
+
+ context?.let { ctx ->
+ content.findViewById<TextView>(R.id.title).apply {
+ text = ctx.getString(R.string.vehicle_headsign, vehicle.Line.name, vehicle.Headsign)
+ contentDescription = ctx.getString(
+ R.string.vehicle_headsign_content_description,
+ vehicle.Line.name,
+ vehicle.Headsign
+ )
+ }
+ // todo units -- [3.1] settings or system-based
+ content.findViewById<TextView>(R.id.speed_text).text =
+ ctx.getString(R.string.speed_in_km_per_h, vehicle.Speed * 3.6)
+ content.findViewById<TextView>(R.id.congestion_text).text = vehicle.congestion(ctx)
+ content.findViewById<TextView>(R.id.occupancy_text).text = vehicle.occupancy(ctx)
+ content.findViewById<ImageView>(R.id.ac).visibility =
+ if (vehicle.getCapability(Vehicle.Capability.AC)) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+ content.findViewById<ImageView>(R.id.bike).visibility =
+ if (vehicle.getCapability(Vehicle.Capability.BIKE)) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+ content.findViewById<ImageView>(R.id.voice).visibility =
+ if (vehicle.getCapability(Vehicle.Capability.VOICE)) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+ content.findViewById<ImageView>(R.id.ticket).visibility =
+ if (vehicle.let {
+ it.getCapability(Vehicle.Capability.TICKET_DRIVER) || it.getCapability(Vehicle.Capability.TICKET_MACHINE)
+ }) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+ content.findViewById<ImageView>(R.id.usb).visibility =
+ if (vehicle.getCapability(Vehicle.Capability.USB_CHARGING)) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+ }
+ }
+
+ private fun showStop(content: View, stop: Stop) {
+ context?.let { ctx ->
+ content.findViewById<Group>(R.id.stop_group).visibility = View.VISIBLE
+ content.findViewById<Group>(R.id.vehicle_group).visibility = View.GONE
+ content.findViewById<TextView>(R.id.title).text =
+ context?.getString(R.string.stop_title, stop.name, stop.code)
+ content.findViewById<Button>(R.id.departures_button).setOnClickListener {
+ val intent = Intent(ctx, DeparturesActivity::class.java).apply {
+ putExtra("code", stop.code)
+ putExtra("name", stop.name)
+ }
+ startActivity(intent)
+ }
+ content.findViewById<Button>(R.id.navigation_button).setOnClickListener {
+ try {
+ startActivity(
+ Intent(
+ Intent.ACTION_VIEW,
+ Uri.parse("geo:${stop.location().latitude},${stop.location().longitude}")
+ )
+ )
+ } catch (_: ActivityNotFoundException) {
+ Toast.makeText(context, ctx.getString(R.string.no_map_app), Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ stop.changeOptions(ctx).let { changeOptions ->
+ content.findViewById<TextView>(R.id.change_options).apply {
+ text = changeOptions.first
+ contentDescription = changeOptions.second
+ }
+ }
+ }
+ }
+
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -69,111 +159,10 @@ val content = inflater.inflate(R.layout.map_bottom_sheet, container, false)
content.apply {
when (locatable) {
is Vehicle -> {
- findViewById<TextView>(R.id.title).apply {
- text = "${locatable.Line.name} » ${locatable.Headsign}"
- contentDescription = "${locatable.Line.name} towards ${locatable.Headsign}"
- }
- findViewById<TextView>(R.id.change_options).visibility = View.GONE
- findViewById<Button>(R.id.departures_button).visibility = View.GONE
- findViewById<Button>(R.id.navigation_button).visibility = View.GONE
- findViewById<TextView>(R.id.speed_text).apply {
- // todo units
- val speed = locatable.Speed * 1.703
- text = "%.3f Vl".format(speed)
- }
- findViewById<TextView>(R.id.congestion_text).apply {
- text = when (locatable.CongestionLevel.toUInt()) {
- 0u -> "unknown"
- 1u -> "smooth traffic"
- 2u -> "stop and go"
- 3u -> "congestion"
- 4u -> "severe jams"
- else -> TODO("throw invalid congestion")
- }
- }
- findViewById<TextView>(R.id.occupancy_text).apply {
- text = when (locatable.OccupancyStatus.toUInt()) {
- 0u -> "unknown"
- 1u -> "empty"
- 2u -> "many seats"
- 3u -> "few seats"
- 4u -> "standing only"
- 5u -> "crowded"
- 6u -> "full"
- 7u -> "won’t accept passengers" // todo shorten
- else -> TODO("throw invalid congestion")
- }
- }
-
- findViewById<ImageView>(R.id.ac).visibility =
- if (locatable.getCapability(Vehicle.Capability.AC)) {
- View.VISIBLE
- } else {
- View.GONE
- }
- findViewById<ImageView>(R.id.bike).visibility =
- if (locatable.getCapability(Vehicle.Capability.BIKE)) {
- View.VISIBLE
- } else {
- View.GONE
- }
- findViewById<ImageView>(R.id.voice).visibility =
- if (locatable.getCapability(Vehicle.Capability.VOICE)) {
- View.VISIBLE
- } else {
- View.GONE
- }
- findViewById<ImageView>(R.id.ticket).visibility =
- if (locatable.let {
- it.getCapability(Vehicle.Capability.TICKET_DRIVER) || it.getCapability(Vehicle.Capability.TICKET_MACHINE)
- }) {
- View.VISIBLE
- } else {
- View.GONE
- }
- findViewById<ImageView>(R.id.usb).visibility =
- if (locatable.getCapability(Vehicle.Capability.USB_CHARGING)) {
- View.VISIBLE
- } else {
- View.GONE
- }
+ showVehicle(this, locatable)
}
is Stop -> {
- findViewById<TextView>(R.id.title).text = "${locatable.name} [${locatable.code}]"
- findViewById<Button>(R.id.departures_button).setOnClickListener {
- val intent = Intent(context, DeparturesActivity::class.java).apply {
- putExtra("code", locatable.code)
- putExtra("name", locatable.name)
- }
- startActivity(intent)
- }
- findViewById<Button>(R.id.navigation_button).setOnClickListener {
- try {
- startActivity(
- Intent(
- Intent.ACTION_VIEW,
- Uri.parse("geo:${locatable.location().latitude},${locatable.location().longitude}")
- )
- )
- } catch (_: ActivityNotFoundException) {
- Toast.makeText(context, "No maps app installed", Toast.LENGTH_SHORT).show()
- }
- }
-
- findViewById<TextView>(R.id.change_options).text = locatable.changeOptions()
-
- findViewById<ImageView>(R.id.speed_icon).visibility = View.GONE
- findViewById<TextView>(R.id.speed_text).visibility = View.GONE
- findViewById<ImageView>(R.id.congestion_icon).visibility = View.GONE
- findViewById<TextView>(R.id.congestion_text).visibility = View.GONE
- findViewById<ImageView>(R.id.occupancy_icon).visibility = View.GONE
- findViewById<TextView>(R.id.occupancy_text).visibility = View.GONE
-
- findViewById<ImageView>(R.id.ac).visibility = View.GONE
- findViewById<ImageView>(R.id.bike).visibility = View.GONE
- findViewById<ImageView>(R.id.voice).visibility = View.GONE
- findViewById<ImageView>(R.id.ticket).visibility = View.GONE
- findViewById<ImageView>(R.id.usb).visibility = View.GONE
+ showStop(this, locatable)
}
}
}
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
index 5348f5356cbc3108ab63a8f2980936d1e7409d5b..0dd58b3469156839e197127f7dd1e7846d408da9 100644
--- 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
@@ -7,7 +7,7 @@
class VoyageViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
- value = "This is dashboard Fragment"
+ value = "This is voyage Fragment"
}
val text: LiveData<String> = _text
}
\ No newline at end of file
diff --git a/app/src/main/java/ml/adamsprogs/bimba/departures/Departures.kt b/app/src/main/java/ml/adamsprogs/bimba/departures/Departures.kt
index 339010367fda02c73372000294cbf17b334ac190..2fc1050efba838eb958e88b9a000baf5d517c6bd 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/departures/Departures.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/departures/Departures.kt
@@ -36,7 +36,6 @@ val lineName: TextView = itemView.findViewById(R.id.departure_line)
val headsign: TextView = itemView.findViewById(R.id.departure_headsign)
companion object {
- @SuppressLint("SetTextI18n")
fun bind(
departure: Departure,
holder: BimbaDepartureViewHolder?,
@@ -47,35 +46,13 @@ holder?.root?.setOnClickListener {
onClickListener(departure)
}
holder?.lineIcon?.setImageBitmap(departure.line.icon(context!!))
+ holder?.lineIcon?.contentDescription = departure.line.type.name
holder?.lineName?.text = departure.line.name
- holder?.headsign?.text = "» ${departure.headsign}" // todo >> is not a11y
- val now = Calendar.getInstance()
- val departureTime = Calendar.getInstance().apply {
- set(Calendar.HOUR_OF_DAY, departure.time.Hour.toInt())
- set(Calendar.MINUTE, departure.time.Minute.toInt())
- set(Calendar.SECOND, departure.time.Second.toInt())
- // todo zone
- roll(Calendar.DAY_OF_MONTH, departure.time.DayOffset.toInt())
- }
- var duration = departureTime.timeInMillis - now.timeInMillis
- val hours = duration / (60 * 60 * 1000)
- duration %= (60 * 60 * 1000)
- val minutes = duration / (60 * 1000)
- duration %= (60 * 1000)
- holder?.departureTime?.text = when (departure.status.toInt()) { // todo(i18n) plurals
- 0 -> {
- "in " +
- if (hours > 0) {
- "$hours h "
- } else {
- ""
- } + "$minutes min"
- }
- 1 -> "momentarily"
- 2 -> "now"
- 3 -> "departed"
- else -> ""
- }
+ holder?.headsign?.text = context?.getString(R.string.departure_headsign, departure.headsign)
+ holder?.headsign?.contentDescription =
+ context?.getString(R.string.departure_headsign_content_description, departure.headsign)
+
+ holder?.departureTime?.text = departure.statusText(context)
}
}
}
@@ -91,21 +68,23 @@
private var departuresPositions: MutableMap<String, Int> = HashMap()
init {
- departures = departures.map { // fixme (!!) does szczanieckiej not populate departure.vehicle.(line,headsign)?
- Departure(
- it.ID, it.line, it.headsign, it.time, it.status, it.isRealtime,
- it.stopOrder, Vehicle(
- it.vehicle.ID,
- it.vehicle.Position,
- it.vehicle.Capabilities,
- it.vehicle.Speed,
- it.line,
- it.headsign,
- it.vehicle.CongestionLevel,
- it.vehicle.OccupancyStatus
- ),
- it.boarding)
- }
+ departures =
+ departures.map { // fixme (!!) does szczanieckiej not populate departure.vehicle.(line,headsign)?
+ Departure(
+ it.ID, it.line, it.headsign, it.time, it.status, it.isRealtime,
+ it.stopOrder, Vehicle(
+ it.vehicle.ID,
+ it.vehicle.Position,
+ it.vehicle.Capabilities,
+ it.vehicle.Speed,
+ it.line,
+ it.headsign,
+ it.vehicle.CongestionLevel,
+ it.vehicle.OccupancyStatus
+ ),
+ it.boarding
+ )
+ }
departures.forEachIndexed { i, departure ->
departuresPositions[departure.ID] = i
}
@@ -131,21 +110,13 @@ departures[position]
}
}
+ @SuppressLint("NotifyDataSetChanged") // todo [3.1] DiffUtil
fun update(items: List<Departure>) {
val newPositions: MutableMap<String, Int> = HashMap()
items.forEachIndexed { i, departure ->
newPositions[departure.ID] = i
}
-// // fixme jumps
-// departures.minus(items.toSet()).forEach {
-// notifyItemRemoved(departuresPositions[it.ID]!!)
-// }
-// items.minus(departures.toSet()).forEach {
-// notifyItemInserted(newPositions[it.ID]!!)
-// }
-// items.intersect(departures.toSet()).forEach {
-// notifyItemChanged(newPositions[it.ID]!!)
-// }
+
departures = items.map { // fixme (!!)
Departure(
it.ID, it.line, it.headsign, it.time, it.status, it.isRealtime,
@@ -159,16 +130,17 @@ it.headsign,
it.vehicle.CongestionLevel,
it.vehicle.OccupancyStatus
),
- it.boarding)
+ it.boarding
+ )
}
departuresPositions = newPositions
notifyDataSetChanged()
}
}
-class ModalBottomSheet(private var departure: Departure) : BottomSheetDialogFragment() {
+class DepartureBottomSheet(private var departure: Departure) : BottomSheetDialogFragment() {
companion object {
- const val TAG = "ModalBottomSheet"
+ const val TAG = "DepartureBottomSheet"
}
private var cancelCallback: (() -> Unit)? = null
@@ -188,18 +160,12 @@ }
fun update(departure: Departure) {
this.departure = departure
- this.view?.let { setContent(it) }
+ this.view?.let { context?.let { ctx -> setContent(it, ctx) } }
}
- private fun setContent(view: View) {
- var timeText = "at ${departure.time.Hour.toString().padStart(2, '0')}:${
- departure.time.Minute.toString().padStart(2, '0')
- }"
- if (departure.isRealtime) {
- timeText += ":${departure.time.Second.toString().padStart(2, '0')}"
- }
+ private fun setContent(view: View, ctx: Context) {
view.apply {
- findViewById<TextView>(R.id.time).text = timeText
+ findViewById<TextView>(R.id.time).text = departure.timeString(ctx)
findViewById<ImageView>(R.id.rt_icon).apply {
visibility = if (departure.isRealtime) {
@@ -221,47 +187,20 @@ }
}
findViewById<TextView>(R.id.line).apply {
- contentDescription = "${departure.line.name} towards ${departure.headsign}"
- text = "${departure.line.name} » ${departure.headsign}"
+ contentDescription = getString(
+ R.string.vehicle_headsign_content_description,
+ departure.line.name,
+ departure.headsign
+ )
+ text = getString(R.string.vehicle_headsign, departure.line.name, departure.headsign)
}
- findViewById<TextView>(R.id.boarding_text).apply {
- text = if (departure.boarding.and(0b1010u) != (0b0).toUByte()) {
- "on demand"
- } else if (departure.boarding.and(0b0101u) != (0b0).toUByte()) {
- "no boarding"
- } else {
- "can board"
- }
- }
- findViewById<TextView>(R.id.speed_text).apply {
- // todo units
- val speed = departure.vehicle.Speed * 1.703
- text = "%.3f Vl".format(speed)
- }
- findViewById<TextView>(R.id.congestion_text).apply {
- text = when (departure.vehicle.CongestionLevel.toUInt()) {
- 0u -> "unknown"
- 1u -> "smooth traffic"
- 2u -> "stop and go"
- 3u -> "congestion"
- 4u -> "severe jams"
- else -> TODO("throw invalid congestion")
- }
- }
- findViewById<TextView>(R.id.occupancy_text).apply {
- text = when (departure.vehicle.OccupancyStatus.toUInt()) {
- 0u -> "unknown"
- 1u -> "empty"
- 2u -> "many seats"
- 3u -> "few seats"
- 4u -> "standing only"
- 5u -> "crowded"
- 6u -> "full"
- 7u -> "won’t accept passengers" // todo shorten
- else -> TODO("throw invalid congestion")
- }
- }
+ findViewById<TextView>(R.id.boarding_text).text = departure.boardingText(ctx)
+ // todo units -- [3.1] settings or system-based
+ findViewById<TextView>(R.id.speed_text).text =
+ getString(R.string.speed_in_km_per_h, departure.vehicle.Speed * 3.6)
+ findViewById<TextView>(R.id.congestion_text).text = departure.vehicle.congestion(ctx)
+ findViewById<TextView>(R.id.occupancy_text).text = departure.vehicle.occupancy(ctx)
findViewById<ImageView>(R.id.ac).visibility =
if (departure.vehicle.getCapability(Vehicle.Capability.AC)) {
@@ -300,7 +239,7 @@ if (departure.vehicle.Position.isZero()) {
map.visibility = View.GONE
return@let
}
- map.controller.apply {
+ map.controller.apply { // todo glide to centre, not jump
setZoom(19.0f.toDouble())
setCenter(
GeoPoint(
@@ -317,7 +256,7 @@ val marker = Marker(map).apply {
position =
GeoPoint(departure.vehicle.location().latitude, departure.vehicle.location().longitude)
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
- icon = context?.let { ctx -> departure.vehicle.icon(ctx, 2f) } // fixme colour?
+ icon = context?.let { ctx -> departure.vehicle.icon(ctx, 2f) }
setOnClickListener {}
}
map.overlays.add(marker)
@@ -334,25 +273,27 @@ savedInstanceState: Bundle?
): View {
val content = inflater.inflate(R.layout.departure_bottom_sheet, container, false)
- 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
- ) {
- map.overlayManager.tilesOverlay.setColorFilter(TilesOverlay.INVERT_COLORS)
+ context?.let { ctx ->
+ 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
+ ) {
+ map.overlayManager.tilesOverlay.setColorFilter(TilesOverlay.INVERT_COLORS)
+ }
+ map.zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
+ map.setOnTouchListener { _, _ -> true }
+ map.setMultiTouchControls(true)
+ map.overlays.add(RotationGestureOverlay(map).apply { isEnabled = true })
}
- map.zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
- map.setOnTouchListener { _, _ -> true}
- map.setMultiTouchControls(true)
- map.overlays.add(RotationGestureOverlay(map).apply { isEnabled = true })
- }
- setContent(this)
+ setContent(this, ctx)
- (dialog as BottomSheetDialog).behavior.peekHeight = dpToPixelI(180f)
+ (dialog as BottomSheetDialog).behavior.peekHeight = dpToPixelI(180f)
- return content
+ }
}
+ return content
}
}
\ 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
index e2f12209ee96239ba701d37c4356c5946d81fdb2..fc0fd313ada49db7f943750b2b9e73f83d342142 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/departures/DeparturesActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/departures/DeparturesActivity.kt
@@ -32,7 +32,7 @@
private val handler = Handler(Looper.getMainLooper())
private var runnable = Runnable {}
- private var openBottomSheet: ModalBottomSheet? = null
+ private var openBottomSheet: DepartureBottomSheet? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -48,8 +48,8 @@ }
binding.departuresRecycler.layoutManager = LinearLayoutManager(this)
adapter = BimbaDeparturesAdapter(layoutInflater, this, listOf()) {
- ModalBottomSheet(it).apply {
- show(supportFragmentManager, ModalBottomSheet.TAG)
+ DepartureBottomSheet(it).apply {
+ show(supportFragmentManager, DepartureBottomSheet.TAG)
openBottomSheet = this
setOnCancel { openBottomSheet = null }
}
@@ -151,7 +151,7 @@ binding.errorImage.visibility = View.GONE
binding.errorText.visibility = View.GONE
binding.departuresRecycler.visibility = View.VISIBLE
}
- // todo alerts
- // todo stop info
+ // todo [3.1] alerts
+ // todo [3.1] stop info
}
}
\ No newline at end of file
diff --git a/app/src/main/java/ml/adamsprogs/bimba/feeds/FeedChooserActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/feeds/FeedChooserActivity.kt
index ee75453e0014bd89d67b00c811ab49b736e6e910..7b31fa6a0eaff1d039aa770a45e1cca311315c06 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/feeds/FeedChooserActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/feeds/FeedChooserActivity.kt
@@ -24,6 +24,8 @@ import ml.adamsprogs.bimba.dashboard.MainActivity
import ml.adamsprogs.bimba.databinding.ActivityFeedChooserBinding
import java.io.InputStream
+// todo split into server+token -> dialog if token not given and (rate limited or access denied), [3.1] check .well-known -> feeds choosing
+
class FeedChooserActivity : AppCompatActivity() {
private var _binding: ActivityFeedChooserBinding? = null
@@ -69,7 +71,7 @@ private fun setUpRecycler() {
binding.resultsRecycler.layoutManager = LinearLayoutManager(this)
adapter = BimbaFeedInfoAdapter(layoutInflater, listOf(), this) {
Log.v("FeedInfo", "clicked: $it")
- // todo show bottom sheet
+ // todo show bottom sheet with attribution and info
}
binding.resultsRecycler.adapter = adapter
}
@@ -82,7 +84,7 @@ putString("server", host)
putString("token", token)
}
- binding.circularProgressIndicator.visibility = View.VISIBLE
+ binding.progress.visibility = View.VISIBLE
binding.resultsRecycler.visibility = View.GONE
binding.feedInfo.visibility = View.GONE
@@ -131,14 +133,10 @@ }
}
private fun updateItems(response: FeedsSuccess) {
- Log.v("items", "${response.adminContact} ${response.rateLimited}")
- response.feeds.forEach {
- Log.v("items", "$it")
- }
- binding.circularProgressIndicator.visibility = View.GONE
+ binding.progress.visibility = View.GONE
binding.resultsRecycler.visibility = View.VISIBLE
binding.feedInfo.visibility = View.VISIBLE
- binding.feedInfo.text = // todo(ui) table
+ binding.feedInfo.text = // todo(ui) remove after splitting
if (response.rateLimited) {
getString(R.string.server_info_rate_limited, response.adminContact)
} else {
diff --git a/app/src/main/java/ml/adamsprogs/bimba/feeds/FeedInfos.kt b/app/src/main/java/ml/adamsprogs/bimba/feeds/FeedInfos.kt
index 09707bfb08879bbb89bbc881b3e715bd43f2b275..34a1d1f84653bd4fdcc920d056a371d3f6d75842 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/feeds/FeedInfos.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/feeds/FeedInfos.kt
@@ -1,5 +1,6 @@
package ml.adamsprogs.bimba.feeds
-// git:fixup feeds
+
+import android.annotation.SuppressLint
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.view.LayoutInflater
@@ -14,7 +15,7 @@ import ml.adamsprogs.bimba.api.FeedInfo
class BimbaFeedInfoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
- val root: View = itemView.findViewById(R.id.feedinfo)
+ val root: View = itemView.findViewById(R.id.feed)
val switch: MaterialSwitch = itemView.findViewById(R.id.feed_switch)
val name: TextView = itemView.findViewById(R.id.feed_name)
@@ -69,6 +70,7 @@ }
override fun getItemCount(): Int = feeds.size
+ @SuppressLint("NotifyDataSetChanged") // todo [3.1] DiffUtil
fun update(items: List<FeedInfo>) {
feeds = items
notifyDataSetChanged()
diff --git a/app/src/main/java/ml/adamsprogs/bimba/search/Results.kt b/app/src/main/java/ml/adamsprogs/bimba/search/Results.kt
index 8758a66de867fce2a67bf3abb40ff6d45a7907eb..4ed01d22ce933369cfabbe52e0cb38c63df37c62 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/search/Results.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/search/Results.kt
@@ -2,7 +2,6 @@ package ml.adamsprogs.bimba.search
import android.annotation.SuppressLint
import android.content.Context
-import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -38,25 +37,37 @@ onClickListener(item)
}
}
- @SuppressLint("SetTextI18n")
- fun bindStop(stop: Stop, holder: BimbaViewHolder?, context: Context?) {
- holder?.icon?.setImageDrawable(stop.icon(context!!))
- holder?.title?.text = "${stop.name} [${stop.code}]"
- holder?.description?.text = stop.changeOptions()
+ private fun bindStop(stop: Stop, holder: BimbaViewHolder?, context: Context?) {
+ holder?.icon?.apply {
+ setImageDrawable(stop.icon(context!!))
+ contentDescription = context.getString(R.string.stop_content_description)
+ }
+ holder?.title?.text = context?.getString(R.string.stop_title, stop.name, stop.code)
+ context?.let {
+ stop.changeOptions(it).let { changeOptions ->
+ holder?.description?.apply {
+ text = changeOptions.first
+ contentDescription = changeOptions.second
+ }
+ }
+ }
}
- @SuppressLint("SetTextI18n")
- fun bindLine(line: Line, holder: BimbaViewHolder?, context: Context?) {
- val icon = line.icon(context!!)
+ private fun bindLine(line: Line, holder: BimbaViewHolder?, context: Context?) {
holder?.icon?.apply {
- setImageBitmap(icon)
+ setImageBitmap(line.icon(context!!))
+ contentDescription = line.type.name
colorFilter = null
- Log.v("Colour", "${line.name}: ${line.colour}, ${line.colour.toInt().toString(16)}")
- Log.v("Colour", "${line.name}: ${line.textColour()}, ${line.textColour().toString(16)}")
}
holder?.title?.text = line.name
- holder?.description?.text =
- "${line.headsignsThere.joinToString { it }} «» ${line.headsignsBack.joinToString { it }}"
+ holder?.description?.text = context?.getString(
+ R.string.line_headsigns,
+ line.headsignsThere.joinToString { it },
+ line.headsignsBack.joinToString { it })
+ holder?.description?.contentDescription = context?.getString(
+ R.string.line_headsigns_content_description,
+ line.headsignsThere.joinToString { it },
+ line.headsignsBack.joinToString { it })
}
}
}
@@ -98,6 +109,7 @@ }
override fun getItemCount(): Int = items.size
+ @SuppressLint("NotifyDataSetChanged") // todo [3.1] DiffUtil
fun update(items: List<Item>) {
this.items = items
notifyDataSetChanged()
diff --git a/app/src/main/java/ml/adamsprogs/bimba/search/ResultsActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/search/ResultsActivity.kt
index 3f188ad8b534f373ba15da1e7da6c8eeae58506f..3bc018c930bcffbcb66bd0c2ab98a2e6dff3ad34 100644
--- a/app/src/main/java/ml/adamsprogs/bimba/search/ResultsActivity.kt
+++ b/app/src/main/java/ml/adamsprogs/bimba/search/ResultsActivity.kt
@@ -1,6 +1,5 @@
package ml.adamsprogs.bimba.search
-import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.location.Location
@@ -53,7 +52,7 @@ }
startActivity(intent)
}
is Line -> {
- TODO("start line graph activity")
+ TODO("[3.1] start line graph activity")
}
}
}
@@ -62,33 +61,36 @@ setSupportActionBar(binding.topAppBar)
WindowCompat.setDecorFitsSystemWindows(window, false)
- @Suppress("DEPRECATION") // fix_later getSerializable in API>=33
+ @Suppress("DEPRECATION") // fixme later getSerializable in API>=33
when (intent.extras?.get("mode")) {
Mode.MODE_LOCATION -> {
- supportActionBar?.title = "Stops nearby"
+ supportActionBar?.title = getString(R.string.stops_nearby)
locate()
}
Mode.MODE_SEARCH -> {
val query = intent.extras?.getString("query")!!
- supportActionBar?.title = "Results for ‘$query’"
+ supportActionBar?.title = getString(R.string.results_for, query)
getItemsByQuery(Server.get(this), query)
}
}
}
- @SuppressLint("MissingPermission")
private fun locate() {
- val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
- locationManager.requestLocationUpdates(
- LocationManager.GPS_PROVIDER, 1000 * 60 * 10, 100f, this
- )
- handler.removeCallbacks(runnable)
- runnable = Runnable {
- showError(Error(0, R.string.error_gps, R.drawable.error_gps))
+ try {
+ val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
+ locationManager.requestLocationUpdates(
+ LocationManager.GPS_PROVIDER, 1000 * 60 * 10, 100f, this
+ )
+ handler.removeCallbacks(runnable)
+ runnable = Runnable {
+ showError(Error(0, R.string.error_gps, R.drawable.error_gps))
+ }
+ handler.postDelayed(runnable, 60 * 1000)
+ locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
+ ?.let { onLocationChanged(it) }
+ } catch (_: SecurityException) {
+ // this won’t happen because we don’t start this activity without location permission
}
- handler.postDelayed(runnable, 60 * 1000)
- locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
- ?.let { onLocationChanged(it) }
}
override fun onLocationChanged(location: Location) {
@@ -98,7 +100,7 @@ }
override fun onResume() {
super.onResume()
- @Suppress("DEPRECATION") // fix_later getSerializable in API>=33
+ @Suppress("DEPRECATION") // fixme later getSerializable in API>=33
if (intent.extras?.get("mode") == Mode.MODE_LOCATION) {
locate()
}
diff --git a/app/src/main/res/drawable/inari.xml b/app/src/main/res/drawable/inari.xml
index d07433c89483e8ed88dac67cd32206f96364f717..da25ef47d0c88263da2cc9acce30d60b253a96a3 100644
--- a/app/src/main/res/drawable/inari.xml
+++ b/app/src/main/res/drawable/inari.xml
@@ -1,4 +1,3 @@
-<!-- git:inari -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="66.982dp"
android:height="55.716dp"
diff --git a/app/src/main/res/layout/activity_departures.xml b/app/src/main/res/layout/activity_departures.xml
index 552d23dd735a7ccaefdba0088b845182b3d6fda6..e5aad3ed0e731d53aedb2311a3c1c30fe7f2b9cf 100644
--- a/app/src/main/res/layout/activity_departures.xml
+++ b/app/src/main/res/layout/activity_departures.xml
@@ -3,14 +3,15 @@ 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">
+ android:layout_height="match_parent"
+ android:paddingBottom="16dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/departures_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ProgressBar
+ <com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/departures_progress"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
@@ -21,7 +22,7 @@ app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
- android:id="@+id/errorImage"
+ android:id="@+id/error_image"
android:layout_width="92dp"
android:layout_height="92dp"
android:visibility="gone"
@@ -32,8 +33,8 @@ app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
tools:src="@drawable/error_net" />
- <TextView
- android:id="@+id/errorText"
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/error_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
@@ -44,7 +45,7 @@ android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/errorImage"
+ app:layout_constraintTop_toBottomOf="@+id/error_image"
tools:text="No connection" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -72,7 +73,6 @@
</com.google.android.material.appbar.AppBarLayout>
- <!-- todo padding bottom -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/departures_recycler"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/activity_feed_chooser.xml b/app/src/main/res/layout/activity_feed_chooser.xml
index 95a30db5071a769fd056dba5d8a314522377c934..8d8a85d5706a3ddc0ecc787289988d9ffc1ead1f 100644
--- a/app/src/main/res/layout/activity_feed_chooser.xml
+++ b/app/src/main/res/layout/activity_feed_chooser.xml
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- git:fixup feeds -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
@@ -14,7 +13,7 @@ android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
- android:hint="Bimba server"
+ android:hint="@string/bimba_server_address_hint"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
@@ -32,7 +31,7 @@ android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
- android:hint="Token"
+ android:hint="@string/bimba_server_token_hint"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/server_field">
@@ -48,7 +47,7 @@ android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
- android:text="Continue"
+ android:text="@string/bimba_server_continue_button"
app:layout_constraintEnd_toEndOf="@+id/token_field"
app:layout_constraintStart_toStartOf="@+id/token_field"
app:layout_constraintTop_toBottomOf="@+id/token_field" />
@@ -61,7 +60,7 @@ android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@+id/button" />
<com.google.android.material.progressindicator.CircularProgressIndicator
- android:id="@+id/circularProgressIndicator"
+ android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
@@ -71,7 +70,7 @@ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider" />
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/feed_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 3bb6106b6bf38245c81e0043df466024c1ecd71b..db6ee416fe2a78decde7397d7094bc2493116a1e 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -14,7 +14,7 @@ android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
- android:id="@+id/topAppBar"
+ android:id="@+id/top_app_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="" />
@@ -48,7 +48,7 @@ app:menu="@menu/bottom_nav_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
-
+ <!-- todo show feeds and go to chooser (settings) -->
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigation_drawer"
android:layout_width="wrap_content"
diff --git a/app/src/main/res/layout/activity_results.xml b/app/src/main/res/layout/activity_results.xml
index 544c223c2396559b92f1042c1f6832ab9cd69e43..e080acfa860e7e43c54143e0a930808dd9efa641 100644
--- a/app/src/main/res/layout/activity_results.xml
+++ b/app/src/main/res/layout/activity_results.xml
@@ -3,14 +3,15 @@ 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">
+ android:layout_height="match_parent"
+ android:paddingBottom="16dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/results_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ProgressBar
+ <com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/results_progress"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
@@ -21,7 +22,7 @@ app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
- android:id="@+id/errorImage"
+ android:id="@+id/error_image"
android:layout_width="92dp"
android:layout_height="92dp"
android:visibility="gone"
@@ -32,8 +33,8 @@ app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription"
tools:src="@drawable/error_net" />
- <TextView
- android:id="@+id/errorText"
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/error_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
@@ -44,7 +45,7 @@ android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/errorImage"
+ app:layout_constraintTop_toBottomOf="@+id/error_image"
tools:text="No connection" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -56,14 +57,13 @@ android:fitsSystemWindows="true"
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar
- android:id="@+id/topAppBar"
+ android:id="@+id/top_app_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/title_activity_results" />
</com.google.android.material.appbar.AppBarLayout>
- <!-- todo padding bottom -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/results_recycler"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/departure.xml b/app/src/main/res/layout/departure.xml
index de205dcb54a7edb9a2abaf46c1537bce6d9fcf62..429c5f76ca00a8df572208bce0977da615e9beb9 100644
--- a/app/src/main/res/layout/departure.xml
+++ b/app/src/main/res/layout/departure.xml
@@ -14,9 +14,10 @@ android:layout_marginStart="8dp"
app:layout_constraintBottom_toTopOf="@+id/departure_headsign"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/departure_time"
- tools:srcCompat="@drawable/bus_black" />
+ tools:srcCompat="@drawable/bus_black"
+ tools:ignore="ContentDescription" />
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/departure_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -25,9 +26,9 @@ android:layout_marginEnd="8dp"
android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
- tools:text="1h 56mins" />
+ tools:text="1hr" />
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/departure_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -38,7 +39,7 @@ app:layout_constraintStart_toEndOf="@+id/line_icon"
app:layout_constraintTop_toTopOf="parent"
tools:text="Metropolitan" />
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/departure_headsign"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/departure_bottom_sheet.xml b/app/src/main/res/layout/departure_bottom_sheet.xml
index 755eb3b3f9bfedc2389ccd89d2ef79966bbaa19d..0eb2ee87737e2abcc637c176d0f78a0fef6e1a8f 100644
--- a/app/src/main/res/layout/departure_bottom_sheet.xml
+++ b/app/src/main/res/layout/departure_bottom_sheet.xml
@@ -32,14 +32,14 @@ android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
android:visibility="gone"
app:layout_constraintBaseline_toBaselineOf="@+id/time"
app:layout_constraintStart_toEndOf="@+id/time"
- tool:text="(+2 mins)" />
+ tool:text="(+2 min)" />
<ImageView
android:id="@+id/rt_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="16dp"
- android:contentDescription="departure is realtime"
+ android:contentDescription="@string/realtime_content_description"
app:layout_constraintBottom_toBottomOf="@+id/time"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/time"
@@ -50,7 +50,7 @@ android:id="@+id/wheelchair_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="8dp"
- android:contentDescription="vehicle is wheelchair accessible"
+ android:contentDescription="@string/wheelchair_content_description"
app:layout_constraintStart_toEndOf="@id/rt_icon"
app:layout_constraintTop_toTopOf="@+id/rt_icon"
app:srcCompat="@drawable/wheelchair" />
@@ -66,10 +66,8 @@ android:textAlignment="center"
android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/time"
- tool:text="Metropolitan » Aleje Marcinkowskiego" />
+ app:layout_constraintTop_toBottomOf="@id/time" />
- <!--suppress AndroidUnknownAttribute -->
<ImageView
android:id="@+id/boarding_icon"
android:layout_width="16dp"
@@ -93,7 +91,6 @@ app:layout_constraintEnd_toEndOf="@id/middle"
app:layout_constraintTop_toTopOf="parent"
tool:text="on demand" />
- <!--suppress AndroidUnknownAttribute -->
<ImageView
android:id="@+id/speed_icon"
android:layout_width="16dp"
@@ -116,7 +113,6 @@ app:layout_constraintEnd_toStartOf="@+id/middle"
app:layout_constraintTop_toBottomOf="@id/boarding_text"
tool:text="10 Vl" />
- <!--suppress AndroidUnknownAttribute -->
<ImageView
android:id="@+id/congestion_icon"
android:layout_width="16dp"
@@ -141,7 +137,6 @@ app:layout_constraintStart_toEndOf="@id/congestion_icon"
app:layout_constraintTop_toTopOf="parent"
tool:text="smooth traffic" />
- <!--suppress AndroidUnknownAttribute -->
<ImageView
android:id="@+id/occupancy_icon"
android:layout_width="16dp"
@@ -193,7 +188,7 @@ android:id="@+id/ac"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="air condition"
+ android:contentDescription="@string/air_condition_content_description"
app:srcCompat="@drawable/ac"
tool:ignore="MissingConstraints" />
@@ -201,7 +196,7 @@ android:id="@+id/bike"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="bicycles allowed"
+ android:contentDescription="@string/bicycles_allowed_content_description"
app:srcCompat="@drawable/bike"
tool:ignore="MissingConstraints" />
@@ -209,7 +204,7 @@ android:id="@+id/voice"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="voice announcements"
+ android:contentDescription="@string/voice_announcements_content_description"
app:srcCompat="@drawable/voice"
tool:ignore="MissingConstraints" />
@@ -217,7 +212,7 @@ android:id="@+id/ticket"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="tickets sold"
+ android:contentDescription="@string/tickets_sold_content_description"
app:srcCompat="@drawable/ticket"
tool:ignore="MissingConstraints" />
@@ -225,7 +220,7 @@ android:id="@+id/usb"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="USB charging"
+ android:contentDescription="@string/usb_charging_content_description"
app:srcCompat="@drawable/usb"
tool:ignore="MissingConstraints" />
diff --git a/app/src/main/res/layout/feedinfo.xml b/app/src/main/res/layout/feedinfo.xml
index 4129ff7c6ffa1c1a9308dfc0872327e96d23ccee..26ed2b036981ea9db8718aa65d08cde15b330ffe 100644
--- a/app/src/main/res/layout/feedinfo.xml
+++ b/app/src/main/res/layout/feedinfo.xml
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- git:fixup feeds -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/feedinfo"
+ android:id="@+id/feed"
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/feed_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index be113fd08116a6888dee343876f422088b67fc2e..0b6fc8cd6f610ad649bae777ea281aa8f230a660 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -34,7 +34,7 @@ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<ImageView
- android:id="@+id/imageView2"
+ android:id="@+id/inari"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
@@ -46,6 +46,7 @@ android:src="@drawable/inari"
app:layout_constraintBottom_toTopOf="@+id/floating_action_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/search_bar" />
+ app:layout_constraintTop_toBottomOf="@+id/search_bar"
+ tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml
index 539858aa42b4041aea5db8e79b2f7c9f35b6aa96..84500fce485f296b22515dee3ce782aad7ef0efb 100644
--- a/app/src/main/res/layout/fragment_map.xml
+++ b/app/src/main/res/layout/fragment_map.xml
@@ -20,7 +20,7 @@ android:id="@+id/floating_action_button"
style="?attr/floatingActionButtonSmallStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="bottom|right"
+ android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription="@string/home_fab_description"
android:src="@drawable/gps_black" />
diff --git a/app/src/main/res/layout/fragment_voyage.xml b/app/src/main/res/layout/fragment_voyage.xml
index 693d09e63f0b540012e227ccea8a0e423536bc04..977deb77d46bbd2f91cfe3fa362b466366f6a400 100644
--- a/app/src/main/res/layout/fragment_voyage.xml
+++ b/app/src/main/res/layout/fragment_voyage.xml
@@ -6,7 +6,7 @@ android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".dashboard.ui.voyage.VoyageFragment">
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/text_dashboard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/map_bottom_sheet.xml b/app/src/main/res/layout/map_bottom_sheet.xml
index d7ab738d5571271bc41a5417c7eab8c6b41e6282..ee43994f8c22280a3fda028fd21149ee94138d3b 100644
--- a/app/src/main/res/layout/map_bottom_sheet.xml
+++ b/app/src/main/res/layout/map_bottom_sheet.xml
@@ -24,8 +24,13 @@ android:textAlignment="center"
android:textAppearance="@style/TextAppearance.Material3.HeadlineSmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tool:text="Aleje Marcinkowskiego [AMAR01]" />
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.constraintlayout.widget.Group
+ android:id="@+id/stop_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:constraint_referenced_ids="change_options,departures_button,navigation_button" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/change_options"
@@ -35,8 +40,7 @@ android:layout_margin="16dp"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/title"
- tool:text="610 » Górczyn, 215 » Rondo Kaponiera, 392 » Słowiańska" />
+ app:layout_constraintTop_toBottomOf="@+id/title" />
<Button
android:id="@+id/departures_button"
@@ -44,7 +48,7 @@ style="@style/Widget.Material3.Button.TextButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
- android:text="Show departures"
+ android:text="@string/show_departures"
app:icon="@drawable/departure"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -56,13 +60,18 @@ style="@style/Widget.Material3.Button.TextButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
- android:text="Open in maps app"
+ android:text="@string/open_in_maps_app"
app:icon="@drawable/open_outside"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/departures_button" />
- <!--suppress AndroidUnknownAttribute -->
+ <androidx.constraintlayout.widget.Group
+ android:id="@+id/vehicle_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:constraint_referenced_ids="speed_icon,speed_text,congestion_icon,congestion_text,occupancy_icon,occupancy_text,ac,bike,voice,ticket,usb" />
+
<ImageView
android:id="@+id/speed_icon"
android:layout_width="16dp"
@@ -85,7 +94,6 @@ app:layout_constraintEnd_toStartOf="@+id/middle"
app:layout_constraintTop_toBottomOf="@id/title"
tool:text="10 Vl" />
- <!--suppress AndroidUnknownAttribute -->
<ImageView
android:id="@+id/congestion_icon"
android:layout_width="16dp"
@@ -110,7 +118,6 @@ app:layout_constraintStart_toEndOf="@id/congestion_icon"
app:layout_constraintTop_toBottomOf="@id/title"
tool:text="smooth traffic" />
- <!--suppress AndroidUnknownAttribute -->
<ImageView
android:id="@+id/occupancy_icon"
android:layout_width="16dp"
@@ -161,7 +168,7 @@ android:id="@+id/ac"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="air condition"
+ android:contentDescription="@string/air_condition_content_description"
app:srcCompat="@drawable/ac"
tool:ignore="MissingConstraints" />
@@ -169,7 +176,7 @@ android:id="@+id/bike"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="bicycles allowed"
+ android:contentDescription="@string/bicycles_allowed_content_description"
app:srcCompat="@drawable/bike"
tool:ignore="MissingConstraints" />
@@ -177,7 +184,7 @@ android:id="@+id/voice"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="voice announcements"
+ android:contentDescription="@string/voice_announcements_content_description"
app:srcCompat="@drawable/voice"
tool:ignore="MissingConstraints" />
@@ -185,7 +192,7 @@ android:id="@+id/ticket"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="tickets sold"
+ android:contentDescription="@string/tickets_sold_content_description"
app:srcCompat="@drawable/ticket"
tool:ignore="MissingConstraints" />
@@ -193,7 +200,7 @@ android:id="@+id/usb"
android:layout_width="24dp"
android:layout_height="24dp"
- android:contentDescription="USB charging"
+ android:contentDescription="@string/usb_charging_content_description"
app:srcCompat="@drawable/usb"
tool:ignore="MissingConstraints" />
diff --git a/app/src/main/res/layout/result.xml b/app/src/main/res/layout/result.xml
index b0d9d514924029ec71102dede57e8e96b7e7317c..639d48dc3683b3d9ccc6de9b63e669fce00a6fd5 100644
--- a/app/src/main/res/layout/result.xml
+++ b/app/src/main/res/layout/result.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- git:sugg_result -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/suggestion"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -15,9 +15,10 @@ android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toTopOf="parent"
+ tools:ignore="ContentDescription" />
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/suggestion_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -30,7 +31,7 @@ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/suggestion_image"
app:layout_constraintTop_toTopOf="parent" />
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/suggestion_description"
style="@style/Theme.Bimba.SearchResult.Description"
android:layout_width="0dp"
diff --git a/app/src/main/res/layout/suggestion.xml b/app/src/main/res/layout/suggestion.xml
index 8aa8652229bde6d4f63e2b9c40da7c884b4f3bb5..7ad3e5ab507b2259036ec8cd4fc2ba2de2e0d8f4 100644
--- a/app/src/main/res/layout/suggestion.xml
+++ b/app/src/main/res/layout/suggestion.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/suggestion"
android:layout_width="match_parent"
android:layout_height="72dp">
@@ -14,9 +15,10 @@ android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toTopOf="parent"
+ tools:ignore="ContentDescription" />
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/suggestion_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -29,14 +31,14 @@ app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/suggestion_image"
app:layout_constraintTop_toTopOf="parent" />
- <TextView
+ <com.google.android.material.textview.MaterialTextView
android:id="@+id/suggestion_description"
style="@style/Theme.Bimba.SearchResult.Description"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
- android:maxLines="4"
android:ellipsize="end"
+ android:maxLines="4"
android:text=""
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml
index 51c38c91f6a9ef5d57eab41c7a6b49862b091dbc..3631e523fcafffa65395d79c36b61911ef55aeda 100644
--- a/app/src/main/res/menu/bottom_nav_menu.xml
+++ b/app/src/main/res/menu/bottom_nav_menu.xml
@@ -8,8 +8,9 @@ - android:id="@+id/navigation_home"
android:icon="@drawable/home_outline"
android:title="@string/title_home" />
+ <!-- todo [voyage planning]
<item
android:id="@+id/navigation_voyage"
android:icon="@drawable/voyage_outline"
- android:title="@string/title_voyage" />
+ android:title="@string/title_voyage" />-->
</menu>
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 8e2fb5b9fc056fc27c5dc40a72c0eb04a81babd1..d715893aa6f22b49f7237f704316c3c47ed9c19e 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -11,62 +11,67 @@ #FF000000
<color name="white">#FFFFFFFF</color>
<color name="seed">#54af39</color>
- <color name="md_theme_light_primary">#1A6D00</color>
- <color name="md_theme_light_onPrimary">#FFFFFF</color>
- <color name="md_theme_light_primaryContainer">#9AFA79</color>
- <color name="md_theme_light_onPrimaryContainer">#032100</color>
- <color name="md_theme_light_secondary">#6A5F00</color>
- <color name="md_theme_light_onSecondary">#FFFFFF</color>
- <color name="md_theme_light_secondaryContainer">#F9E447</color>
- <color name="md_theme_light_onSecondaryContainer">#201C00</color>
- <color name="md_theme_light_tertiary">#8C4F00</color>
- <color name="md_theme_light_onTertiary">#FFFFFF</color>
- <color name="md_theme_light_tertiaryContainer">#FFDCC0</color>
- <color name="md_theme_light_onTertiaryContainer">#2D1600</color>
+ <color name="md_theme_light_primary">#1A6D00</color> <!-- 40 -->
+ <color name="md_theme_light_onPrimary">#FFFFFF</color> <!-- 100 -->
+ <color name="md_theme_light_primaryContainer">#9AFA79</color> <!-- 90 -->
+ <color name="md_theme_light_onPrimaryContainer">#032100</color> <!-- 10 -->
+ <color name="md_theme_light_secondary">#6A5F00</color> <!-- 40 -->
+ <color name="md_theme_light_onSecondary">#FFFFFF</color> <!-- 100 -->
+ <color name="md_theme_light_secondaryContainer">#F9E447</color> <!-- 90 -->
+ <color name="md_theme_light_onSecondaryContainer">#201C00</color> <!-- 10 -->
+ <color name="md_theme_light_tertiary">#8C4F00</color> <!-- 40 -->
+ <color name="md_theme_light_onTertiary">#FFFFFF</color> <!-- 100 -->
+ <color name="md_theme_light_tertiaryContainer">#FFDCC0</color> <!-- 90 -->
+ <color name="md_theme_light_onTertiaryContainer">#2D1600</color> <!-- 10 -->
+
<color name="md_theme_light_error">#BA1A1A</color>
<color name="md_theme_light_errorContainer">#FFDAD6</color>
<color name="md_theme_light_onError">#FFFFFF</color>
<color name="md_theme_light_onErrorContainer">#410002</color>
- <color name="md_theme_light_background">#FCFCFF</color>
- <color name="md_theme_light_onBackground">#001D33</color>
- <color name="md_theme_light_surface">#FCFCFF</color>
- <color name="md_theme_light_onSurface">#001D33</color>
- <color name="md_theme_light_surfaceVariant">#DFE4D7</color>
- <color name="md_theme_light_onSurfaceVariant">#43483F</color>
- <color name="md_theme_light_outline">#73796E</color>
- <color name="md_theme_light_inverseOnSurface">#E8F2FF</color>
- <color name="md_theme_light_inverseSurface">#003353</color>
- <color name="md_theme_light_inversePrimary">#7FDC60</color>
- <color name="md_theme_light_shadow">#000000</color>
- <color name="md_theme_light_surfaceTint">#1A6D00</color>
- <color name="md_theme_light_surfaceTintColor">#1A6D00</color>
- <color name="md_theme_dark_primary">#7FDC60</color>
- <color name="md_theme_dark_onPrimary">#093900</color>
- <color name="md_theme_dark_primaryContainer">#115300</color>
- <color name="md_theme_dark_onPrimaryContainer">#9AFA79</color>
- <color name="md_theme_dark_secondary">#DCC82A</color>
- <color name="md_theme_dark_onSecondary">#373100</color>
- <color name="md_theme_dark_secondaryContainer">#504700</color>
- <color name="md_theme_dark_onSecondaryContainer">#F9E447</color>
- <color name="md_theme_dark_tertiary">#FFB875</color>
- <color name="md_theme_dark_onTertiary">#4B2800</color>
- <color name="md_theme_dark_tertiaryContainer">#6B3B00</color>
- <color name="md_theme_dark_onTertiaryContainer">#FFDCC0</color>
+
+ <color name="md_theme_light_background">#FCFCFF</color> <!-- primary 99 -->
+ <color name="md_theme_light_onBackground">#001D33</color> <!-- primary 10 -->
+ <color name="md_theme_light_surface">#FCFCFF</color> <!-- primary 99 -->
+ <color name="md_theme_light_onSurface">#001D33</color> <!-- primary 10 -->
+ <color name="md_theme_light_surfaceVariant">#DFE4D7</color> <!-- neutral 90 -->
+ <color name="md_theme_light_onSurfaceVariant">#43483F</color> <!-- neutral 30 -->
+ <color name="md_theme_light_outline">#73796E</color> <!-- neutral 50 -->
+ <color name="md_theme_light_inverseOnSurface">#E8F2FF</color> <!-- neutral 95 -->
+ <color name="md_theme_light_inverseSurface">#003353</color> <!-- neutral 20 -->
+ <color name="md_theme_light_inversePrimary">#7FDC60</color> <!-- 80 -->
+ <color name="md_theme_light_shadow">#000000</color> <!-- 0 -->
+ <color name="md_theme_light_surfaceTint">#1A6D00</color> <!-- primary 40 -->
+ <color name="md_theme_light_surfaceTintColor">#1A6D00</color> <!-- primary 40 -->
+
+ <color name="md_theme_dark_primary">#7FDC60</color> <!-- 80 -->
+ <color name="md_theme_dark_onPrimary">#093900</color> <!-- 20 -->
+ <color name="md_theme_dark_primaryContainer">#115300</color> <!-- 30 -->
+ <color name="md_theme_dark_onPrimaryContainer">#9AFA79</color> <!-- 90 -->
+ <color name="md_theme_dark_secondary">#DCC82A</color> <!-- 80 -->
+ <color name="md_theme_dark_onSecondary">#373100</color> <!-- 20 -->
+ <color name="md_theme_dark_secondaryContainer">#504700</color> <!-- 30 -->
+ <color name="md_theme_dark_onSecondaryContainer">#F9E447</color> <!-- 90 -->
+ <color name="md_theme_dark_tertiary">#FFB875</color> <!-- 80 -->
+ <color name="md_theme_dark_onTertiary">#4B2800</color> <!-- 20 -->
+ <color name="md_theme_dark_tertiaryContainer">#6B3B00</color> <!-- 30 -->
+ <color name="md_theme_dark_onTertiaryContainer">#FFDCC0</color> <!-- 90 -->
+
<color name="md_theme_dark_error">#FFB4AB</color>
<color name="md_theme_dark_errorContainer">#93000A</color>
<color name="md_theme_dark_onError">#690005</color>
<color name="md_theme_dark_onErrorContainer">#FFDAD6</color>
- <color name="md_theme_dark_background">#001D33</color>
- <color name="md_theme_dark_onBackground">#CEE5FF</color>
- <color name="md_theme_dark_surface">#001D33</color>
- <color name="md_theme_dark_onSurface">#CEE5FF</color>
- <color name="md_theme_dark_surfaceVariant">#43483F</color>
- <color name="md_theme_dark_onSurfaceVariant">#C3C8BC</color>
- <color name="md_theme_dark_outline">#8D9387</color>
- <color name="md_theme_dark_inverseOnSurface">#001D33</color>
- <color name="md_theme_dark_inverseSurface">#CEE5FF</color>
- <color name="md_theme_dark_inversePrimary">#1A6D00</color>
- <color name="md_theme_dark_shadow">#000000</color>
- <color name="md_theme_dark_surfaceTint">#7FDC60</color>
- <color name="md_theme_dark_surfaceTintColor">#7FDC60</color>
+
+ <color name="md_theme_dark_background">#001D33</color> <!-- primary 10 -->
+ <color name="md_theme_dark_onBackground">#CEE5FF</color> <!-- primary 90 -->
+ <color name="md_theme_dark_surface">#001D33</color> <!-- primary 10 -->
+ <color name="md_theme_dark_onSurface">#CEE5FF</color> <!-- primary 90 -->
+ <color name="md_theme_dark_surfaceVariant">#43483F</color> <!-- neutral 30 -->
+ <color name="md_theme_dark_onSurfaceVariant">#C3C8BC</color> <!-- -->
+ <color name="md_theme_dark_outline">#8D9387</color> <!-- unused -->
+ <color name="md_theme_dark_inverseOnSurface">#001D33</color> <!-- primary 10 -->
+ <color name="md_theme_dark_inverseSurface">#CEE5FF</color> <!-- primary 90 -->
+ <color name="md_theme_dark_inversePrimary">#1A6D00</color> <!-- primary 40 -->
+ <color name="md_theme_dark_shadow">#000000</color> <!-- 0 -->
+ <color name="md_theme_dark_surfaceTint">#7FDC60</color> <!-- primary 80 -->
+ <color name="md_theme_dark_surfaceTintColor">#7FDC60</color> <!-- primary 80 -->
</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
deleted file mode 100644
index b4b724d5d63243169442e9a7046072e5ba0f0fe7..0000000000000000000000000000000000000000
--- a/app/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<resources>
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
-</resources>
\ 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 51b4adeb82ec6ebadf9d62aada03881473d907d9..c20bcf31f1e57cb276fd5864b46b8265e8dcfe62 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -3,7 +3,6 @@ Bimba
<string name="title_home">Home</string>
<string name="title_map">Map</string>
<string name="title_voyage">Voyage</string>
- <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>
@@ -18,8 +17,62 @@ Not found
<string name="error_429">Rate limit exceeded. Try again later</string>
<string name="error_50x">There was an error on the sever. Try again later</string>
<string name="error_unknown">Unknown error happened</string>
- <string name="error_connecting">Error connecting to the server. Try again later</string>
- <string name="error_offline">You are offline. Connect to the Internet</string> <!-- send a bug report to bimba@git.apiote.xyz, details are: url=$URL, response=$response -->
+ <string name="error_connecting">Error connecting to the server. Try again later</string> <!-- send a bug report to bimba@git.apiote.xyz, details are: url=$URL, response=$response -->
+ <string name="error_offline">You are offline. Connect to the Internet</string>
<string name="error_gps">Cannot obtain location</string>
<string name="no_departures">No departures</string>
+ <string name="waiting_position">waiting for position</string>
+ <string name="vehicle_headsign">%s » %s</string>
+ <string name="vehicle_headsign_content_description">%s towards %s</string>
+ <string name="speed_in_km_per_h">%.3f km/h</string>
+ <string name="congestion_unknown">unknown</string>
+ <string name="congestion_smooth">smooth</string>
+ <string name="congestion_stop_and_go">stop and go</string>
+ <string name="congestion_congestion">congestion</string>
+ <string name="congestion_jams">jams</string>
+ <string name="occupancy_unknown">unknown</string>
+ <string name="occupancy_empty">empty</string>
+ <string name="occupancy_many_seats">many seats</string>
+ <string name="occupancy_few_seats">few seats</string>
+ <string name="occupancy_standing_only">standing only</string>
+ <string name="occupancy_crowded">crowded</string>
+ <string name="occupancy_full">full</string>
+ <string name="occupancy_wont_let">won’t let in</string>
+ <string name="stop_title">%s [%s]</string>
+ <string name="no_map_app">No maps app installed</string>
+ <string name="departure_headsign">» %s</string>
+ <string name="departure_headsign_content_description">towards %s</string>
+ <string name="departure_momentarily">momentarily</string>
+ <string name="departure_departed">departed</string>
+ <string name="departure_now">now</string>
+ <string name="at_time">at %02d:%02d</string>
+ <string name="at_time_realtime">at %02d:%02d:%02d</string>
+ <string name="on_demand">on demand</string>
+ <string name="no_boarding">no boarding</string>
+ <string name="on_boarding">on-boarding</string>
+ <string name="off_boarding">off-boarding</string>
+ <string name="boarding">can board</string>
+ <string name="line_headsigns">%s «» %s</string>
+ <string name="line_headsigns_content_description">between %s and %s</string>
+ <string name="stops_nearby">Stops nearby</string>
+ <string name="results_for">Results for ‘%s’</string>
+ <string name="bimba_server_address_hint">Bimba server</string>
+ <string name="bimba_server_token_hint">Token</string>
+ <string name="bimba_server_continue_button">Continue</string>
+ <string name="realtime_content_description">departure is realtime</string>
+ <string name="wheelchair_content_description">vehicle is wheelchair accessible</string>
+ <string name="air_condition_content_description">air conditioning</string>
+ <string name="bicycles_allowed_content_description">bicycles allowed</string>
+ <string name="voice_announcements_content_description">voice announcements</string>
+ <string name="tickets_sold_content_description">tickets sold on board</string>
+ <string name="usb_charging_content_description">USB charging</string>
+ <string name="show_departures">Show departures</string>
+ <string name="open_in_maps_app">Open in maps app</string>
+ <string name="stop_content_description">stop</string>
+ <string name="seatbelts_everyone">Seatbelts, everyone!</string>
+ <string name="onboarding_question">How would you like to start?</string>
+ <string name="onboarding_simple">Simple</string>
+ <string name="onboarding_simple_action">choose cities</string>
+ <string name="onboarding_advanced">Advanced</string>
+ <string name="onboarding_simple_advanced">choose server</string> <!-- taken from ‘Magic School Bus’. Should be translated like in the series -->
</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 73c4810b2d9228a96bd4c5f6f1dd592158a6ce91..20db7647bca1ddb8c20b84ce74f662156fcc0910 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -67,4 +67,6 @@ - @drawable/ic_launcher_foreground
<item name="windowSplashScreenIconBackgroundColor">@color/ic_launcher_background</item>
<item name="postSplashScreenTheme">@style/Theme.Bimba</item>
</style>
+
+ <style name="Theme.Bimba.Style" />
</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values-v21/themes.xml b/app/src/main/res/values-v21/themes.xml
deleted file mode 100644
index f0f3937ac135cf1b40e66084bb14ecdffcc63c2c..0000000000000000000000000000000000000000
--- a/app/src/main/res/values-v21/themes.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <style name="Theme.Bimba.Style" parent="Theme.Bimba" />
-</resources>
\ No newline at end of file
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
index e99ab9e207141de03020fa52a928f877f388d7ca..9157acd18cdf838751e15affe9aad8ea49f91b49 100644
--- a/app/src/main/res/xml/backup_rules.xml
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -6,8 +6,4 @@ Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
- <!--
- <include domain="sharedpref" path="."/>
- <exclude domain="sharedpref" path="device.xml"/>
--->
</full-backup-content>
\ No newline at end of file
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
index 14c561a1ce073d6d7c60d38c89e478b9fa2d1dea..dbd7d6cff871fd2450b0f9c01fc1143b79092776 100644
--- a/app/src/main/res/xml/data_extraction_rules.xml
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -5,7 +5,7 @@ for details.
-->
<data-extraction-rules>
<cloud-backup>
- <!-- TODO: Use <include> and <exclude> to control what is backed up.
+ <!-- Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
diff --git a/app/src/test/java/ml/adamsprogs/bimba/ExampleUnitTest.kt b/app/src/test/java/ml/adamsprogs/bimba/ExampleUnitTest.kt
deleted file mode 100644
index aafcc64544b83749246a78fd5e1db880484c226c..0000000000000000000000000000000000000000
--- a/app/src/test/java/ml/adamsprogs/bimba/ExampleUnitTest.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package ml.adamsprogs.bimba
-
-import org.junit.Test
-
-import org.junit.Assert.*
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleUnitTest {
- @Test
- fun addition_isCorrect() {
- assertEquals(4, 2 + 2)
- }
-}
\ No newline at end of file
diff --git a/inari.svg b/inari.svg
index 226773effee996e1bedf078c220e7cb88d8b9dc0..33ef0449f475b445414c384d7050c0c552173d37 100644
--- a/inari.svg
+++ b/inari.svg
@@ -11,8 +11,7 @@ inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
sodipodi:docname="drawing.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:svg="http://www.w3.org/2000/svg">
+ xmlns="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#505050"