Bimba.git

commit 2ea93be4b5fe6ed3da031df8d6051377a2a33b2f

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

add content descriptions

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


diff --git a/app/src/androidTest/java/xyz/apiote/bimba/czwek/units/TGMKtTest.kt b/app/src/androidTest/java/xyz/apiote/bimba/czwek/units/TGMKtTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8699c205595e80d6dca7922994585004ad8f3a31
--- /dev/null
+++ b/app/src/androidTest/java/xyz/apiote/bimba/czwek/units/TGMKtTest.kt
@@ -0,0 +1,55 @@
+package xyz.apiote.bimba.czwek.units
+
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Test
+
+class TGMKtTest {
+	@Test
+	fun toDozenalString0(){
+		val i = 0
+		val context = InstrumentationRegistry.getInstrumentation().targetContext
+		assert(i.toDozenalString(context) == "zero") { "got ${i.toDozenalString(context)}, wanted zero" }
+	}
+
+	@Test
+	fun toDozenalString1(){
+		val i = 1
+		val context = InstrumentationRegistry.getInstrumentation().targetContext
+		assert(i.toDozenalString(context) == "one") { "got ${i.toDozenalString(context)}, wanted one" }
+	}
+
+	@Test
+	fun toDozenalString10(){
+		val i = 12
+		val context = InstrumentationRegistry.getInstrumentation().targetContext
+		assert(i.toDozenalString(context) == "one zen") { "got ${i.toDozenalString(context)}, wanted one zen" }
+	}
+
+	@Test
+	fun toDozenalString100(){
+		val i = 144
+		val context = InstrumentationRegistry.getInstrumentation().targetContext
+		assert(i.toDozenalString(context) == "one duna") { "got ${i.toDozenalString(context)}, wanted one duna" }
+	}
+
+	@Test
+	fun toDozenalString23(){
+		val i = 27
+		val context = InstrumentationRegistry.getInstrumentation().targetContext
+		assert(i.toDozenalString(context) == "two zen three") { "got ${i.toDozenalString(context)}, wanted two zen three" }
+	}
+
+	@Test
+	fun toDozenalString234(){
+		val i = 328
+		val context = InstrumentationRegistry.getInstrumentation().targetContext
+		assert(i.toDozenalString(context) == "two duna three zen four") { "got ${i.toDozenalString(context)}, wanted two duna three zen four" }
+	}
+
+	@Test
+	fun toDozenalString204(){
+		val i = 292
+		val context = InstrumentationRegistry.getInstrumentation().targetContext
+		assert(i.toDozenalString(context) == "two duna four") { "got ${i.toDozenalString(context)}, wanted two duna four" }
+	}
+}
\ No newline at end of file




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Departure.kt b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Departure.kt
index 7f09c54a9d644a3a21748a6996d655eb78912e24..b3459fda1568096322caab7e16e7dace0d9b87a6 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/repo/Departure.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/repo/Departure.kt
@@ -17,6 +17,7 @@ import xyz.apiote.bimba.czwek.api.DepartureV4
 import xyz.apiote.bimba.czwek.api.Time
 import xyz.apiote.bimba.czwek.api.UnknownResourceVersionException
 import xyz.apiote.bimba.czwek.units.Second
+import xyz.apiote.bimba.czwek.units.TGM
 import xyz.apiote.bimba.czwek.units.UnitSystem
 import java.time.Instant
 import java.time.ZoneId
@@ -157,7 +158,6 @@ 		d.boarding,
 		d.alerts.map { Alert(it) }
 	)
 
-	// TODO content description
 	fun statusText(context: Context?, showAsTime: Boolean, at: ZonedDateTime? = null): String {
 		val now = at ?: Instant.now().atZone(ZoneId.systemDefault())
 		val departureTime = ZonedDateTime.of(
@@ -172,7 +172,7 @@ 		if (departureTime.isBefore(now) && r < 3u) {
 			r = 0u
 		}
 		return when (r) {
-			0u -> if (context != null && UnitSystem.getSelected(context).base == 12) {
+			0u -> if (context != null && UnitSystem.getSelected(context) is TGM) {
 				val us = UnitSystem.getSelected(context)
 				us.toString(
 					context,




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/settings/SettingsActivity.kt b/app/src/main/java/xyz/apiote/bimba/czwek/settings/SettingsActivity.kt
index 9b5fc9f9d366eacf9d9bcbeee9f5dc7e38268986..f19dc985278de5999659136c1a28c19a9a3999a5 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/settings/SettingsActivity.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/settings/SettingsActivity.kt
@@ -2,7 +2,6 @@ package xyz.apiote.bimba.czwek.settings
 
 import android.content.Context
 import android.os.Bundle
-import android.util.Log
 import android.view.View
 import android.view.ViewGroup
 import androidx.activity.enableEdgeToEdge
@@ -47,6 +46,7 @@ 		ViewCompat.setOnApplyWindowInsetsListener(root) { v, windowInsets ->
 			val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
 			v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
 				topMargin = insets.top
+				// TODO bottom, left, right, camera
 			}
 			windowInsets
 		}
@@ -67,12 +67,11 @@ 				true
 			}
 
 			if (isWorkScheduled(requireContext(), "download_cities")) {
-				findPreference<Preference>("download_cities_list")?.isEnabled = false // TODO more reliable
+				findPreference<Preference>("download_cities_list")?.isEnabled = false
 			}
 
 			val citiesLastUpdate = PreferenceManager.getDefaultSharedPreferences(requireContext())
 				.getLong("cities_last_update", -1)
-			Log.i("geocoding", "$citiesLastUpdate")
 			if (citiesLastUpdate > 0) {
 				// TODO localise
 				val lastUpdateTime =




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/units/TGM.kt b/app/src/main/java/xyz/apiote/bimba/czwek/units/TGM.kt
index 43ed82ee09dbd47a231fc6a11a0587253c695858..01f12e34c0563df7314db784694ddec0110c9c0e 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/units/TGM.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/units/TGM.kt
@@ -38,7 +38,11 @@ 		} else {
 			Pair(tims / base.toDouble().pow(2).toInt(), "²")
 		}
 		return if (base == 10) {
-			context.getString(res, NumberFormat.getInstance().apply { maximumFractionDigits = 2 }.format(abs(t)), m)
+			context.getString(
+				res,
+				NumberFormat.getInstance().apply { maximumFractionDigits = 2 }.format(abs(t)),
+				m
+			)
 		} else {
 			context.getString(
 				res,
@@ -48,8 +52,31 @@ 			)
 		}
 	}
 
-	override fun contentDescription(context: Context, base: Int): String =
-		context.resources.getQuantityString(R.plurals.time_in_tm_cd, tims.toInt(), tims)
+	override fun contentDescription(context: Context, base: Int): String {
+		return if (base == 10) {
+			context.resources.getQuantityString(
+				R.plurals.time_in_tm_cd,
+				tims.toInt(),
+				tims.toInt()
+			)
+		} else {
+			if (tims > base.toDouble().pow(4)) {
+				val t = tims / base.toDouble().pow(4)
+				context.resources.getQuantityString(
+					R.plurals.time_in_4gf_12_cd,
+					t.toInt(),
+					t.toInt().toDozenalString(context)
+				)
+			} else {
+				val t = tims / base.toDouble().pow(2)
+				context.resources.getQuantityString(
+					R.plurals.time_in_2gf_12_cd,
+					t.toInt(),
+					t.toInt().toDozenalString(context)
+				)
+			}
+		}
+	}
 }
 
 class Grafut(val grafut: Double) : DistanceUnit {
@@ -65,7 +92,11 @@ 			Pair(grafut, "")
 		}
 
 		return if (base == 10) {
-			context.getString(R.string.distance_in_gf, NumberFormat.getInstance().apply { maximumFractionDigits = 2 }.format(g), m)
+			context.getString(
+				R.string.distance_in_gf,
+				NumberFormat.getInstance().apply { maximumFractionDigits = 2 }.format(g),
+				m
+			)
 		} else {
 			context.getString(
 				R.string.distance_in_gf,
@@ -76,10 +107,29 @@ 		}
 	}
 
 	override fun contentDescription(context: Context, base: Int): String {
-		// TODO
-		return ""
+		return if (base == 10) {
+			context.resources.getQuantityString(
+				R.plurals.distance_in_gf_cd,
+				grafut.toInt(),
+				grafut.toInt()
+			)
+		} else {
+			if (grafut > base.toDouble().pow(3)) {
+				val g = grafut / base.toDouble().pow(3)
+				context.resources.getQuantityString(
+					R.plurals.distance_in_3gf_12_cd,
+					g.toInt(),
+					g.toInt().toDozenalString(context)
+				)
+			} else {
+				context.resources.getQuantityString(
+					R.plurals.distance_in_gf_12_cd,
+					grafut.toInt(),
+					grafut.toInt().toDozenalString(context)
+				)
+			}
+		}
 	}
-
 }
 
 class Vlos(val vlos: Double) : SpeedUnit {
@@ -87,8 +137,19 @@ 	constructor(other: SpeedUnit) : this(other.mps() / 1.703133986928105)
 
 	override fun mps(): Double = vlos * 1.703133986928105
 	override fun contentDescription(context: Context, base: Int): String {
-		// TODO
-		return ""
+		return if (base == 10) {
+			context.resources.getQuantityString(
+				R.plurals.speed_in_vl_cd,
+				vlos.toInt(),
+				vlos.toInt()
+			)
+		} else {
+			context.resources.getQuantityString(
+				R.plurals.speed_in_vl_12_cd,
+				vlos.toInt(),
+				vlos.toInt().toDozenalString(context)
+			)
+		}
 	}
 
 	override fun toString(context: Context, base: Int): String {
@@ -107,11 +168,34 @@ 	result += x.toInt().toString(radix)
 	var frac = (x - x.toInt())
 	var digits = 0
 	while (frac > 0 && digits < precision) {
-		if (digits == 0) result += if (radix == 12) "·" else "."  // TODO separator based on locale
+		if (digits == 0) result += if (radix == 12) "·" else NumberFormat.getInstance().apply { maximumFractionDigits = 1 }.format(0.5).replace(Regex("[0-9]"), "")
 		frac *= radix
 		result += frac.toInt().toString(radix)
 		frac -= frac.toInt()
 		digits++
 	}
 	return result.lowercase().replace("a", "↊").replace("b", "↋")
+}
+
+fun Int.toDozenalString(context: Context): String {
+	if (this == 0) {
+		return context.resources.getStringArray(R.array.dozenal_digits)[0]
+	}
+	val r = StringBuilder()
+	var n = this
+	val digits = context.resources.getStringArray(R.array.dozenal_digits)
+	val multipliers = context.resources.getStringArray(R.array.dozenal_multipliers)
+	var i = 0
+	while (n > 0) {
+		val u = n % 12
+		if (u != 0) {
+			r.insert(0, " ")
+			r.insert(0, multipliers[i])
+			r.insert(0, " ")
+			r.insert(0, digits[u])
+		}
+		n /= 12
+		i++
+	}
+	return r.toString().trim()
 }
\ No newline at end of file




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/units/imperial.kt b/app/src/main/java/xyz/apiote/bimba/czwek/units/imperial.kt
index 842cc216d883112519b85fb77638d0ccf126fef7..f06ce367fd44750b68a9f8eb3e1a60835d232898 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/units/imperial.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/units/imperial.kt
@@ -32,7 +32,7 @@ 		)
 
 	override fun contentDescription(context: Context, base: Int): String =
 		context.resources.getQuantityString(
-			R.plurals.speed_in_mi_per_h_cd, miph.toInt(), miph
+			R.plurals.speed_in_mi_per_h_cd, miph.toInt(), miph.toInt()
 		)
 }
 




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/units/metric.kt b/app/src/main/java/xyz/apiote/bimba/czwek/units/metric.kt
index aed10d7ef19c109c30c28b1747ad597758e1d978..2f410632b40b89c76a02ad9d6e1f33097c15970e 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/units/metric.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/units/metric.kt
@@ -105,5 +105,5 @@ 			NumberFormat.getInstance().apply { maximumFractionDigits = 2 }.format(kmph)
 		)
 
 	override fun contentDescription(context: Context, base: Int): String =
-		context.resources.getQuantityString(R.plurals.speed_in_km_per_h_cd, kmph.toInt(), kmph)
+		context.resources.getQuantityString(R.plurals.speed_in_km_per_h_cd, kmph.toInt(), kmph.toInt())
 }
\ No newline at end of file




diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 5769aed0a30f247b1dd5735e17b142d669ee65ad..3b5e70a97a94517eebe0bf7f8d1b7273fd45f931 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -16,4 +16,34 @@ 		customary
 		<item>tgm10</item>
 		<item>tgm12</item>
 	</string-array>
+
+	<string-array name="dozenal_digits">
+		<item>@string/zero</item>
+		<item>@string/one</item>
+		<item>@string/two</item>
+		<item>@string/three</item>
+		<item>@string/four</item>
+		<item>@string/five</item>
+		<item>@string/six</item>
+		<item>@string/seven</item>
+		<item>@string/eight</item>
+		<item>@string/nine</item>
+		<item>@string/ten</item>
+		<item>@string/elv</item>
+	</string-array>
+
+	<string-array name="dozenal_multipliers">
+		<item/>
+		<item>@string/zen</item>
+		<item>@string/duna</item>
+		<item>@string/trin</item>
+		<item>@string/quedra</item>
+		<item>@string/quen</item>
+		<item>@string/hes</item>
+		<item>@string/sev</item>
+		<item>@string/ak</item>
+		<item>@string/neen</item>
+		<item>@string/dex</item>
+		<item>@string/lef</item>
+	</string-array>
 </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 46b385efeb43d4d3eedd555983a0cc5383a1fe59..c10a98efd6d9ee4670759780dc335da46334639f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -60,6 +60,14 @@ 	
 		<item quantity="one">%1$d grafut</item>
 		<item quantity="other">%1$d grafuts</item>
 	</plurals>
+	<plurals name="distance_in_3gf_12_cd">
+		<item quantity="one">%1$s trinagrafut</item>
+		<item quantity="other">%1$s trinagrafuts</item>
+	</plurals>
+	<plurals name="distance_in_gf_12_cd">
+		<item quantity="one">%1$s grafut</item>
+		<item quantity="other">%1$s grafuts</item>
+	</plurals>
 	<string name="time_in_s">%1$s s</string>
 	<plurals name="time_in_s_cd">
 		<item quantity="one">%1$d second</item>
@@ -71,6 +79,14 @@ 	
 		<item quantity="one">%1$d tim</item>
 		<item quantity="other">%1$d tims</item>
 	</plurals>
+	<plurals name="time_in_4gf_12_cd">
+		<item quantity="one">%1$s quedratim</item>
+		<item quantity="other">%1$s quedratims</item>
+	</plurals>
+	<plurals name="time_in_2gf_12_cd">
+		<item quantity="one">%1$s dunatim</item>
+		<item quantity="other">%1$s dunatims</item>
+	</plurals>
 	<string name="speed_in_km_per_h">%1$s km/h</string>
 	<string name="speed_in_m_per_s">%1$s m/s</string>
 	<string name="speed_in_mi_per_h">%1$s mph</string>
@@ -88,6 +104,10 @@ 		%1$d mile per hour
 		<item quantity="other">%1$d mile per hour</item>
 	</plurals>
 	<plurals name="speed_in_vl_cd">
+		<item quantity="one">%1$d vlos</item>
+		<item quantity="other">%1$d vlos</item>
+	</plurals>
+	<plurals name="speed_in_vl_12_cd">
 		<item quantity="one">%1$s vlos</item>
 		<item quantity="other">%1$s vlos</item>
 	</plurals>
@@ -218,4 +238,27 @@ 	Updating geocoding data
 	<string name="downloading_cities_list">downloading cities list</string>
 	<string name="finished_updating_geocoding_data">Finished updating geocoding data</string>
 	<string name="updating_geocoding_data_failed">Updating geocoding data failed</string>
+	<string name="zero">zero</string>
+	<string name="one">one</string>
+	<string name="two">two</string>
+	<string name="three">three</string>
+	<string name="four">four</string>
+	<string name="five">five</string>
+	<string name="six">six</string>
+	<string name="seven">seven</string>
+	<string name="eight">eight</string>
+	<string name="nine">nine</string>
+	<string name="ten">ten</string>
+	<string name="elv">elv</string>
+	<string name="zen">zen</string>
+	<string name="duna">duna</string>
+	<string name="quedra">quedra</string>
+	<string name="trin">trin</string>
+	<string name="quen">quen</string>
+	<string name="hes">hes</string>
+	<string name="sev">sev</string>
+	<string name="ak">ak</string>
+	<string name="neen">neen</string>
+	<string name="dex">dex</string>
+	<string name="lef">lef</string>
 </resources>




diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml
index 18e2503d6acdce2bab05798cdcad32efdfc5d108..ab4959ff16b28aba10d9e4f2e244473c76f04fe2 100644
--- a/app/src/main/res/xml/root_preferences.xml
+++ b/app/src/main/res/xml/root_preferences.xml
@@ -1,4 +1,5 @@
 <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
+	<PreferenceCategory app:title="Units">
 	<ListPreference
 		app:defaultValue="default"
 		app:entries="@array/unit_entries"
@@ -7,6 +8,7 @@ 		app:icon="@drawable/units"
 		app:key="unit_system"
 		app:title="@string/units_title"
 		app:useSimpleSummaryProvider="true" />
+	</PreferenceCategory>
 
 	<PreferenceCategory app:title="Geocoding">
 		<SwitchPreferenceCompat