[Android] Create a repeatable scheduler action and use it for the widgets

Nicolas Pomepuy git at videolan.org
Tue Jul 25 14:57:29 UTC 2023


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Thu Jul 20 13:55:46 2023 +0200| [20b2ac286ade554af6e0ec19a7c58876273dcc61] | committer: Duncan McNamara

Create a repeatable scheduler action and use it for the widgets

> https://code.videolan.org/videolan/vlc-android/commit/20b2ac286ade554af6e0ec19a7c58876273dcc61
---

 .../vlc/gui/dialogs/WidgetExplanationDialog.kt     | 41 ++++++++++++----------
 .../videolan/vlc/util/LifecycleAwareScheduler.kt   | 17 +++++++++
 2 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/application/vlc-android/src/org/videolan/vlc/gui/dialogs/WidgetExplanationDialog.kt b/application/vlc-android/src/org/videolan/vlc/gui/dialogs/WidgetExplanationDialog.kt
index 96aad7a8e9..f74859bfb4 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/dialogs/WidgetExplanationDialog.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/dialogs/WidgetExplanationDialog.kt
@@ -36,7 +36,6 @@ import android.view.animation.DecelerateInterpolator
 import androidx.annotation.DrawableRes
 import androidx.core.animation.doOnEnd
 import androidx.core.content.ContextCompat
-import androidx.lifecycle.lifecycleScope
 import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
 import org.videolan.tools.coerceInOrDefault
 import org.videolan.tools.dp
@@ -44,19 +43,20 @@ import org.videolan.tools.setGone
 import org.videolan.tools.setVisible
 import org.videolan.vlc.R
 import org.videolan.vlc.databinding.DialogWidgetExplanationBinding
-import java.util.Timer
-import java.util.TimerTask
-import kotlin.concurrent.scheduleAtFixedRate
+import org.videolan.vlc.util.LifecycleAwareScheduler
+import org.videolan.vlc.util.SchedulerCallback
 
 
-class WidgetExplanationDialog : VLCBottomSheetDialogFragment() {
+private const val ACTION_REFRESH = "refresh"
+
+class WidgetExplanationDialog : VLCBottomSheetDialogFragment(), SchedulerCallback  {
     override fun getDefaultState(): Int = STATE_EXPANDED
 
     override fun needToManageOrientation(): Boolean = true
 
-    private lateinit var timer: TimerTask
     private lateinit var resizeAnimation: AnimatorSet
     internal lateinit var binding: DialogWidgetExplanationBinding
+    lateinit var scheduler: LifecycleAwareScheduler
 
     private val sizeDrawables = listOf(R.drawable.vlc_widget_mini, R.drawable.vlc_widget_micro, R.drawable.vlc_widget_pill, R.drawable.vlc_widget_macro)
     var currentDrawable = R.drawable.vlc_widget_macro
@@ -65,6 +65,10 @@ class WidgetExplanationDialog : VLCBottomSheetDialogFragment() {
 
     override fun initialFocusedView(): View = binding.title
 
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        scheduler =  LifecycleAwareScheduler(this)
+    }
 
     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
         binding = DialogWidgetExplanationBinding.inflate(layoutInflater, container, false)
@@ -73,13 +77,7 @@ class WidgetExplanationDialog : VLCBottomSheetDialogFragment() {
 
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
-        timer = Timer().scheduleAtFixedRate(0, 2000) {
-            lifecycleScope.launchWhenStarted {
-                val nextIndex = (sizeDrawables.indexOf(currentDrawable) + 1).coerceInOrDefault(0, sizeDrawables.size - 1, 0)
-                currentDrawable = sizeDrawables[nextIndex]
-                displaySizeImage(currentDrawable)
-            }
-        }
+        scheduler.scheduleAtFixedRate(ACTION_REFRESH, 2000)
 
         val sizeDrawbles = listOf(R.drawable.vlc_widget_mini, R.drawable.vlc_widget_micro, R.drawable.vlc_widget_pill, R.drawable.vlc_widget_macro)
         displaySizeImage(sizeDrawbles[0])
@@ -90,7 +88,7 @@ class WidgetExplanationDialog : VLCBottomSheetDialogFragment() {
                     binding.step2.setVisible()
                     binding.step3.setGone()
                     animateLongTap()
-                    timer.cancel()
+                    scheduler.cancelAction(ACTION_REFRESH)
                 }
                 2 -> {
                     binding.step1.setGone()
@@ -106,6 +104,16 @@ class WidgetExplanationDialog : VLCBottomSheetDialogFragment() {
         }
     }
 
+    override fun onTaskTriggered(id: String, data: Bundle) {
+        when (id) {
+            ACTION_REFRESH -> {
+                val nextIndex = (sizeDrawables.indexOf(currentDrawable) + 1).coerceInOrDefault(0, sizeDrawables.size - 1, 0)
+                currentDrawable = sizeDrawables[nextIndex]
+                displaySizeImage(currentDrawable)
+            }
+        }
+    }
+
     /**
      * Display a new image in the UI showing the different widget sizes
      *
@@ -115,11 +123,6 @@ class WidgetExplanationDialog : VLCBottomSheetDialogFragment() {
         binding.widgetSizes.setImageDrawable(ContextCompat.getDrawable(requireActivity(), drawable))
     }
 
-    override fun dismiss() {
-        timer.cancel()
-        super.dismiss()
-    }
-
     /**
      * Animate the view showing how to resize a widget
      *
diff --git a/application/vlc-android/src/org/videolan/vlc/util/LifecycleAwareScheduler.kt b/application/vlc-android/src/org/videolan/vlc/util/LifecycleAwareScheduler.kt
index 06549cde6f..4c07060afb 100644
--- a/application/vlc-android/src/org/videolan/vlc/util/LifecycleAwareScheduler.kt
+++ b/application/vlc-android/src/org/videolan/vlc/util/LifecycleAwareScheduler.kt
@@ -105,6 +105,23 @@ class LifecycleAwareScheduler(private val callback: SchedulerCallback) : Default
         timer.schedule(timeTasks[id], delay)
     }
 
+    /**
+     * Schedule an action to be called every [interval]ms.
+     * Can be called in any thread
+     *
+     * @param id the action id
+     * @param interval the interval between each action trigger
+     * @param data the data to be passed
+     */
+    fun scheduleAtFixedRate(id: String, interval: Long, data:Bundle = Bundle()) {
+        callback.lifecycle.addObserver(this at LifecycleAwareScheduler)
+        if (timeTasks.keys.contains(id)) cancelAction(id)
+        timeTasks[id] = timerTask {
+            callback.lifecycleScope.launch(Dispatchers.Main) { callback.onTaskTriggered(id, data) }
+        }
+        timer.scheduleAtFixedRate(timeTasks[id], 0, interval)
+    }
+
     /**
      * Cancel an existing action
      *



More information about the Android mailing list