Bimba.git

commit 2a5a688e8c497e0c81247b6405b2c8ab318d0f9b

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

use countdown to update departures and show time to update

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


diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/departures/DeparturesActivity.kt b/app/src/main/java/xyz/apiote/bimba/czwek/departures/DeparturesActivity.kt
index 3ace64fd176fe6079d89e6ecd848ed72e9a42ec6..9f2d3cc6b79c738b200b899fecf49c16b69710e5 100644
--- a/app/src/main/java/xyz/apiote/bimba/czwek/departures/DeparturesActivity.kt
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/departures/DeparturesActivity.kt
@@ -12,6 +12,7 @@ import android.net.NetworkCapabilities
 import android.net.NetworkRequest
 import android.os.Build
 import android.os.Bundle
+import android.os.CountDownTimer
 import android.os.Handler
 import android.os.Looper
 import android.text.format.DateUtils
@@ -29,12 +30,14 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.timepicker.MaterialTimePicker
 import com.google.android.material.timepicker.TimeFormat
-import kotlinx.coroutines.Runnable
 import xyz.apiote.bimba.czwek.R
 import xyz.apiote.bimba.czwek.api.Error
 import xyz.apiote.bimba.czwek.databinding.ActivityDeparturesBinding
 import xyz.apiote.bimba.czwek.repo.Departure
 import xyz.apiote.bimba.czwek.repo.Stop
+import xyz.apiote.bimba.czwek.units.Millisecond
+import xyz.apiote.bimba.czwek.units.Second
+import xyz.apiote.bimba.czwek.units.Tim
 import java.time.Instant
 import java.time.LocalDate
 import java.time.LocalTime
@@ -48,7 +51,6 @@
 	private lateinit var adapter: BimbaDeparturesAdapter
 
 	private val handler = Handler(Looper.getMainLooper())
-	private var runnable = Runnable {}
 
 	private var openBottomSheet: DepartureBottomSheet? = null
 	private lateinit var snackbar: Snackbar
@@ -68,6 +70,18 @@ 	private val linesFilterTemporary = mutableMapOf()
 	private var startTime: LocalTime = LocalTime.MIN
 	private var endTime: LocalTime = LocalTime.MAX
 	private var alertDescriptions: String = ""
+
+	// TODO [elizabeth] millisInFuture from header Cache-Control max-age
+	private val countdown = object : CountDownTimer(Millisecond(Second(30)).millis, Millisecond(Tim(1)).millis) {
+		override fun onTick(millisUntilFinished: Long) {
+			val timsUntillFinished = Tim(Millisecond(millisUntilFinished))
+			binding.departuresUpdatesProgress.progress = timsUntillFinished.tims
+		}
+
+		override fun onFinish() {
+			getDepartures()
+		}
+	}
 
 	override fun onCreate(savedInstanceState: Bundle?) {
 		super.onCreate(savedInstanceState)
@@ -284,13 +298,12 @@ 	}
 
 	override fun onPause() {
 		super.onPause()
-		handler.removeCallbacks(runnable)
+		countdown.cancel()
 	}
 
 	override fun onStop() {
 		super.onStop()
-		handler.removeCallbacks(runnable)
-		handler.removeCallbacksAndMessages(null)
+		countdown.cancel()
 	}
 
 	private fun getName(): String {
@@ -309,6 +322,7 @@ 		}
 	}
 
 	fun getDepartures(force: Boolean = false) {
+		binding.departuresUpdatesProgress.isIndeterminate = true
 		if (force) {
 			showLoading()
 		} else {
@@ -316,9 +330,6 @@ 			adapter.refreshItems()
 			setupSnackbar()
 		}
 		viewModel.getDepartures(this, date, force)
-		handler.removeCallbacks(runnable)
-		runnable = Runnable { getDepartures() }
-		handler.postDelayed(runnable, 30 * 1000)
 	}
 
 	private fun setupSnackbar() {
@@ -343,6 +354,7 @@
 	private fun showError(error: Error) {
 		binding.departuresProgress.visibility = View.GONE
 		binding.departuresRecycler.visibility = View.GONE
+		binding.departuresUpdatesProgress.visibility = View.GONE
 		binding.errorImage.visibility = View.VISIBLE
 		binding.errorText.visibility = View.VISIBLE
 
@@ -361,11 +373,21 @@ 		binding.departuresProgress.visibility = View.VISIBLE
 		binding.departuresRecycler.visibility = View.GONE
 		binding.errorImage.visibility = View.GONE
 		binding.errorText.visibility = View.GONE
+		binding.departuresUpdatesProgress.visibility = View.GONE
 	}
 
 	private fun updateItems(departures: List<Departure>, stop: Stop) {
 		setupSnackbar()
 		binding.departuresProgress.visibility = View.GONE
+		// TODO [elizabeth] max, progress from header Cache-Control max-age
+		binding.departuresUpdatesProgress.apply {
+			visibility = View.VISIBLE
+			isIndeterminate = false
+			max = Tim(Second(30)).tims
+			progress = Tim(Second(30)).tims
+		}
+		countdown.cancel()
+		countdown.start()
 		adapter.update(departures, date != null, true)
 		binding.collapsingLayout.apply {
 			title = stop.name




diff --git a/app/src/main/java/xyz/apiote/bimba/czwek/units/Time.kt b/app/src/main/java/xyz/apiote/bimba/czwek/units/Time.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9456eae31f27301d561789f4e07ca44dd9519bef
--- /dev/null
+++ b/app/src/main/java/xyz/apiote/bimba/czwek/units/Time.kt
@@ -0,0 +1,17 @@
+package xyz.apiote.bimba.czwek.units
+
+interface TimeUnit
+
+data class Second(val secs: Long) {
+	constructor(t: Tim) : this(t.tims.toLong() * 25 / 144)
+}
+
+data class Millisecond(val millis: Long) {
+	constructor(t: Tim) : this(t.tims.toLong() * 25 * 1000 / 144)
+	constructor(s: Second) : this(s.secs * 1000)
+}
+
+data class Tim(val tims: Int) {
+	constructor(s: Second) : this((s.secs * 144 / 25).toInt())
+	constructor(m: Millisecond) : this((m.millis * 144 / 25 / 1000).toInt())
+}
\ No newline at end of file




diff --git a/app/src/main/res/layout/activity_departures.xml b/app/src/main/res/layout/activity_departures.xml
index 4744dc352f27edaf2b35495e8d89e7775388ef95..c5c97475c1c6fd8e75e36117e95b5c5d0de71570 100644
--- a/app/src/main/res/layout/activity_departures.xml
+++ b/app/src/main/res/layout/activity_departures.xml
@@ -143,4 +143,15 @@ 		
 
 	</com.google.android.material.appbar.AppBarLayout>
 
+	<com.google.android.material.progressindicator.LinearProgressIndicator
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:id="@+id/departures_updates_progress"
+		app:layout_anchor="@id/app_bar_layout"
+		app:layout_anchorGravity="bottom"
+		android:visibility="gone"
+		android:indeterminate="true"
+		android:layout_marginEnd="4dp"
+		android:layout_marginStart="4dp" />
+
 </androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file