[Android] Fix TV browser focus when navigating with the breadcrumb
Nicolas Pomepuy
git at videolan.org
Thu Sep 7 12:56:28 UTC 2023
vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Tue Sep 5 11:54:29 2023 +0200| [a4672c1d592e295a10084a6deec4971065361ffa] | committer: Duncan McNamara
Fix TV browser focus when navigating with the breadcrumb
> https://code.videolan.org/videolan/vlc-android/commit/a4672c1d592e295a10084a6deec4971065361ffa
---
.../television/ui/browser/FileBrowserTvFragment.kt | 44 +++++++++++++++++++++-
.../viewmodels/browser/PathOperationDelegate.kt | 15 ++++++++
2 files changed, 57 insertions(+), 2 deletions(-)
diff --git a/application/television/src/main/java/org/videolan/television/ui/browser/FileBrowserTvFragment.kt b/application/television/src/main/java/org/videolan/television/ui/browser/FileBrowserTvFragment.kt
index ee5cdc1030..8f1d689dc2 100644
--- a/application/television/src/main/java/org/videolan/television/ui/browser/FileBrowserTvFragment.kt
+++ b/application/television/src/main/java/org/videolan/television/ui/browser/FileBrowserTvFragment.kt
@@ -44,12 +44,18 @@ import org.videolan.vlc.util.DialogDelegate
import org.videolan.vlc.util.FileUtils
import org.videolan.vlc.util.IDialogManager
import org.videolan.vlc.util.isSchemeSupported
-import org.videolan.vlc.viewmodels.browser.*
+import org.videolan.vlc.util.onAnyChange
+import org.videolan.vlc.viewmodels.browser.BrowserModel
+import org.videolan.vlc.viewmodels.browser.IPathOperationDelegate
+import org.videolan.vlc.viewmodels.browser.TYPE_FILE
+import org.videolan.vlc.viewmodels.browser.TYPE_NETWORK
+import org.videolan.vlc.viewmodels.browser.getBrowserModel
private const val TAG = "FileBrowserTvFragment"
class FileBrowserTvFragment : BaseBrowserTvFragment<MediaLibraryItem>(), PathAdapterListener, IDialogManager {
+ private lateinit var dataObserver: RecyclerView.AdapterDataObserver
private var favExists: Boolean = false
private var isRootLevel = false
private lateinit var browserFavRepository: BrowserFavRepository
@@ -68,7 +74,35 @@ class FileBrowserTvFragment : BaseBrowserTvFragment<MediaLibraryItem>(), PathAda
override fun getColumnNumber() = resources.getInteger(R.integer.tv_songs_col_count)
override fun provideAdapter(eventsHandler: IEventsHandler<MediaLibraryItem>, itemSize: Int): TvItemAdapter {
- return FileTvItemAdapter(this, itemSize, isRootLevel && getCategory() == TYPE_NETWORK)
+ val fileTvItemAdapter = FileTvItemAdapter(this, itemSize, isRootLevel && getCategory() == TYPE_NETWORK)
+ // restore the position from the source when navigating from Arian
+ dataObserver = fileTvItemAdapter.onAnyChange {
+ val source = (viewModel as IPathOperationDelegate).getSource()
+ val selectedIndex = if (source != null) {
+ if (fileTvItemAdapter.dataset.contains(source)) {
+ //the source has been found because we are on its direct parent
+ fileTvItemAdapter.dataset.indexOf(source)
+ } else {
+ // we look for the item included in the source path to find what item to focus
+ var index: Int? = null
+ fileTvItemAdapter.dataset.forEach {
+ if ((source as? MediaWrapper)?.uri?.toString()?.startsWith(it.uri.toString()) == true) {
+ index = fileTvItemAdapter.dataset.indexOf(it)
+ }
+ }
+ index
+ }
+ } else null
+ if (selectedIndex != null) {
+ val lm = binding.list.layoutManager as LinearLayoutManager
+ lm.scrollToPosition(selectedIndex)
+ lm.getChildAt(selectedIndex)?.let {
+ it.requestFocus()
+ (viewModel as IPathOperationDelegate).consumeSource()
+ }
+ }
+ }
+ return fileTvItemAdapter
}
override fun getDisplayPrefId() = "display_tv_file_${getCategory()}"
@@ -183,6 +217,7 @@ class FileBrowserTvFragment : BaseBrowserTvFragment<MediaLibraryItem>(), PathAda
if (supportFragmentManager.backStackEntryCount == 0) browse(MLServiceLocator.getAbstractMediaWrapper(tag.toUri()), false)
else {
(viewModel as IPathOperationDelegate).setDestination(MLServiceLocator.getAbstractMediaWrapper(tag.toUri()))
+ (viewModel as IPathOperationDelegate).setSource(currentItem)
supportFragmentManager.popBackStack()
}
}
@@ -231,6 +266,11 @@ class FileBrowserTvFragment : BaseBrowserTvFragment<MediaLibraryItem>(), PathAda
(viewModel as BrowserModel).stop()
}
+ override fun onDestroy() {
+ super.onDestroy()
+ if (::dataObserver.isInitialized) (adapter as FileTvItemAdapter).unregisterAdapterDataObserver(dataObserver)
+ }
+
override fun getCategory() = (viewModel as BrowserModel).type
override fun onClick(v: View, position: Int, item: MediaLibraryItem) {
diff --git a/application/vlc-android/src/org/videolan/vlc/viewmodels/browser/PathOperationDelegate.kt b/application/vlc-android/src/org/videolan/vlc/viewmodels/browser/PathOperationDelegate.kt
index c0ef12b647..0f18af537a 100644
--- a/application/vlc-android/src/org/videolan/vlc/viewmodels/browser/PathOperationDelegate.kt
+++ b/application/vlc-android/src/org/videolan/vlc/viewmodels/browser/PathOperationDelegate.kt
@@ -4,6 +4,7 @@ import android.net.Uri
import android.util.Base64
import androidx.collection.SimpleArrayMap
import org.videolan.medialibrary.interfaces.media.MediaWrapper
+import org.videolan.medialibrary.media.MediaLibraryItem
interface IPathOperationDelegate {
@@ -14,6 +15,9 @@ interface IPathOperationDelegate {
fun retrieveSafePath(encoded: String): String
fun setDestination(media: MediaWrapper?)
fun getAndRemoveDestination(): MediaWrapper?
+ fun setSource(currentItem: MediaLibraryItem?)
+ fun getSource(): MediaLibraryItem?
+ fun consumeSource()
}
class PathOperationDelegate : IPathOperationDelegate {
@@ -21,15 +25,26 @@ class PathOperationDelegate : IPathOperationDelegate {
privateDestination = media
}
+ override fun setSource(currentItem: MediaLibraryItem?) {
+ privateSource = currentItem
+ }
+
override fun getAndRemoveDestination(): MediaWrapper? {
val destination = privateDestination
privateDestination = null
return destination
}
+ override fun consumeSource() {
+ privateSource = null
+ }
+
+ override fun getSource() = privateSource
+
companion object {
val storages = SimpleArrayMap<String, String>()
private var privateDestination: MediaWrapper? = null
+ private var privateSource: MediaLibraryItem? = null
}
More information about the Android
mailing list