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