Commit 6c2ea139 authored by Geoffrey Métais's avatar Geoffrey Métais

Split providers from viewmodels

parent 89b5646f
......@@ -85,10 +85,10 @@ class PlaylistFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshListene
if (position == playlistAdapter.getItemCount() - 1) {
return 1
}
if (viewModel.isFirstInSection(position + 1)) {
if (viewModel.provider.isFirstInSection(position + 1)) {
//calculate how many cell it must take
val firstSection = viewModel.getPositionForSection(position)
val firstSection = viewModel.provider.getPositionForSection(position)
val nbItems = position - firstSection
if (BuildConfig.DEBUG)
Log.d("SongsBrowserFragment", "Position: " + position + " nb items: " + nbItems + " span: " + nbItems % nbColumns)
......@@ -109,7 +109,7 @@ class PlaylistFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshListene
playlists.layoutManager = gridLayoutManager
playlists.adapter = playlistAdapter
playlists.addItemDecoration(RecyclerSectionItemGridDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), spacing, true, nbColumns, viewModel))
playlists.addItemDecoration(RecyclerSectionItemGridDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), spacing, true, nbColumns, viewModel.provider))
fastScroller = view.rootView.findViewById(R.id.songs_fast_scroller) as FastScroller
fastScroller.attachToCoordinator(view.rootView.findViewById(R.id.appbar) as AppBarLayout, view.rootView.findViewById(R.id.coordinator) as CoordinatorLayout, view.rootView.findViewById(R.id.fab) as FloatingActionButton)
}
......@@ -124,7 +124,7 @@ class PlaylistFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshListene
launch { binding.swipeLayout.isRefreshing = loading == true }
})
fastScroller.setRecyclerView(getCurrentRV(), viewModel)
fastScroller.setRecyclerView(getCurrentRV(), viewModel.provider)
}
......
......@@ -114,8 +114,8 @@ class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefres
songsAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_MEDIA, this)
adapters = arrayOf<AudioBrowserAdapter>(albumsAdapter, songsAdapter)
albumsList.addItemDecoration(RecyclerSectionItemDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), true, albumModel))
songsList.addItemDecoration(RecyclerSectionItemDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), true, tracksModel))
albumsList.addItemDecoration(RecyclerSectionItemDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), true, albumModel.provider))
songsList.addItemDecoration(RecyclerSectionItemDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), true, tracksModel.provider))
songsList.adapter = songsAdapter
albumsList.adapter = albumsAdapter
......@@ -181,7 +181,7 @@ class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefres
val albums = albumModel.pagedList.value
if (Util.isListEmpty(albums) && !viewModel.isFiltering())
viewPager!!.currentItem = 1
fastScroller.setRecyclerView(getCurrentRV(), viewModel)
fastScroller.setRecyclerView(getCurrentRV(), viewModel.provider)
}
}
......@@ -210,12 +210,12 @@ class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefres
override fun onTabReselected(tab: TabLayout.Tab) {
lists[tab.position].smoothScrollToPosition(0)
fastScroller.setRecyclerView(lists[tab.position], audioModels[tab.position])
fastScroller.setRecyclerView(lists[tab.position], audioModels[tab.position].provider)
}
override fun onTabSelected(tab: TabLayout.Tab) {
super.onTabSelected(tab)
fastScroller.setRecyclerView(lists[tab.position], audioModels[tab.position])
fastScroller.setRecyclerView(lists[tab.position], audioModels[tab.position].provider)
}
override fun getCurrentRV(): RecyclerView {
......
......@@ -137,7 +137,7 @@ class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshLis
list.adapter = adapters[i]
if (positions != null) list.scrollToPosition(positions[i])
list.addOnScrollListener(scrollListener)
list.addItemDecoration(RecyclerSectionItemDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), true, models[i]))
list.addItemDecoration(RecyclerSectionItemDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), true, models[i].provider))
}
viewPager!!.setOnTouchListener(mSwipeFilter)
swipeRefreshLayout?.setOnRefreshListener(this)
......@@ -243,7 +243,7 @@ class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshLis
override fun onTabSelected(tab: TabLayout.Tab) {
super.onTabSelected(tab)
fastScroller.setRecyclerView(lists[tab.position]!!, models[tab.position])
fastScroller.setRecyclerView(lists[tab.position]!!, models[tab.position].provider)
settings.edit().putInt(KEY_AUDIO_CURRENT_TAB, tab.position).apply()
val loading = viewModel.loading.value
if (loading == null || !loading)
......@@ -292,7 +292,7 @@ class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshLis
if (getCurrentAdapter() != null && adapter === getCurrentAdapter()) {
swipeRefreshLayout?.isEnabled = (getCurrentRV().layoutManager as LinearLayoutManager).findFirstVisibleItemPosition() <= 0
updateEmptyView()
fastScroller.setRecyclerView(getCurrentRV(), viewModel)
fastScroller.setRecyclerView(getCurrentRV(), viewModel.provider)
} else
setFabPlayShuffleAllVisibility()
}
......
......@@ -201,10 +201,10 @@ class MediaBrowserTvFragment : Fragment(), BrowserFragmentInterface, IEventsHand
if (position == adapter.itemCount - 1) {
return 1
}
if (viewModel.isFirstInSection(position + 1)) {
if (viewModel.provider.isFirstInSection(position + 1)) {
//calculate how many cell it must take
val firstSection = viewModel.getPositionForSection(position)
val firstSection = viewModel.provider.getPositionForSection(position)
val nbItems = position - firstSection
if (BuildConfig.DEBUG)
Log.d("SongsBrowserFragment", "Position: " + position + " nb items: " + nbItems + " span: " + nbItems % nbColumns)
......@@ -219,7 +219,7 @@ class MediaBrowserTvFragment : Fragment(), BrowserFragmentInterface, IEventsHand
adapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_MEDIA, this, itemSize).apply { setTV(true) }
list.addItemDecoration(RecyclerSectionItemGridDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_tv_height), spacing, true, nbColumns, viewModel))
list.addItemDecoration(RecyclerSectionItemGridDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_tv_height), spacing, true, nbColumns, viewModel.provider))
//header list
headerListContainer.visibility = View.GONE
......@@ -336,7 +336,7 @@ class MediaBrowserTvFragment : Fragment(), BrowserFragmentInterface, IEventsHand
override fun onHeaderSelected(header: String) {
hideHeaderSelectionScreen()
val positionForSectionByName = viewModel.getPositionForSectionByName(header)
val positionForSectionByName = viewModel.provider.getPositionForSectionByName(header)
if (list.getChildAt(positionForSectionByName) == null) {
adapter.focusNext = positionForSectionByName
} else {
......
......@@ -51,9 +51,9 @@ import kotlinx.coroutines.channels.actor
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.vlc.BuildConfig
import org.videolan.vlc.R
import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
import org.videolan.vlc.util.WeakHandler
import org.videolan.vlc.viewmodels.paged.HeadersIndex
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import java.util.concurrent.atomic.AtomicBoolean
private const val TAG = "FastScroller"
......@@ -82,7 +82,7 @@ class FastScroller : LinearLayout, CoroutineScope, Observer<HeadersIndex> {
private val scrollListener = ScrollListener()
private lateinit var recyclerView: RecyclerView
private lateinit var layoutManager: LinearLayoutManager
private lateinit var model: MLPagedModel<out MediaLibraryItem>
private lateinit var provider: MedialibraryProvider<out MediaLibraryItem>
private lateinit var handle: ImageView
private lateinit var bubble: TextView
private lateinit var coordinatorLayout: CoordinatorLayout
......@@ -227,15 +227,15 @@ class FastScroller : LinearLayout, CoroutineScope, Observer<HeadersIndex> {
/**
* Sets the [recyclerView] it will be attached to
*/
fun setRecyclerView(recyclerView: RecyclerView, model: MLPagedModel<out MediaLibraryItem>) {
fun setRecyclerView(recyclerView: RecyclerView, provider: MedialibraryProvider<out MediaLibraryItem>) {
this.recyclerView = recyclerView
this.layoutManager = recyclerView.layoutManager as LinearLayoutManager
this.recyclerView.removeOnScrollListener(scrollListener)
visibility = View.INVISIBLE
itemCount = recyclerView.adapter!!.itemCount
if (this::model.isInitialized) this.model.liveHeaders.removeObserver(this)
this.model = model
model.liveHeaders.observeForever(this)
if (this::provider.isInitialized) this.provider.liveHeaders.removeObserver(this)
this.provider = provider
provider.liveHeaders.observeForever(this)
recyclerView.addOnScrollListener(scrollListener)
showBubble = (recyclerView.adapter as SeparatedAdapter).hasSections()
}
......@@ -352,8 +352,8 @@ class FastScroller : LinearLayout, CoroutineScope, Observer<HeadersIndex> {
//ItemDecoration has to be taken into account so we add 1 for the sticky header
val position = layoutManager.findFirstVisibleItemPosition() + 1
if (BuildConfig.DEBUG) Log.d(TAG, "findFirstVisibleItemPosition $position")
val pos = model.getPositionForSection(position)
val sectionforPosition = model.getSectionforPosition(pos)
val pos = provider.getPositionForSection(position)
val sectionforPosition = provider.getSectionforPosition(pos)
sb.append(' ')
.append(sectionforPosition)
.append(' ')
......
......@@ -8,11 +8,11 @@ import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import org.videolan.vlc.R
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
private const val TAG = "RecyclerSectionItemDecoration"
class RecyclerSectionItemDecoration(private val headerOffset: Int, private val sticky: Boolean, private val model: MLPagedModel<*>) : RecyclerView.ItemDecoration() {
class RecyclerSectionItemDecoration(private val headerOffset: Int, private val sticky: Boolean, private val provider: MedialibraryProvider<*>) : RecyclerView.ItemDecoration() {
private lateinit var headerView: View
private lateinit var header: TextView
......@@ -21,7 +21,7 @@ class RecyclerSectionItemDecoration(private val headerOffset: Int, private val s
super.getItemOffsets(outRect, view, parent, state)
val pos = parent.getChildAdapterPosition(view)
if (model.isFirstInSection(pos)) {
if (provider.isFirstInSection(pos)) {
outRect.top = headerOffset
}
}
......@@ -43,10 +43,10 @@ class RecyclerSectionItemDecoration(private val headerOffset: Int, private val s
val previousChild = parent.getChildAt(0)
if (sticky && previousChild != null) {
val position = parent.getChildAdapterPosition(previousChild)
val sectionPosition = model.getPositionForSection(position)
val sectionPosition = provider.getPositionForSection(position)
previousSectionPosition = sectionPosition
val title = model.getSectionforPosition(sectionPosition)
val title = provider.getSectionforPosition(sectionPosition)
header.text = title
drawHeader(c, parent.getChildAt(0), headerView)
}
......@@ -60,9 +60,9 @@ class RecyclerSectionItemDecoration(private val headerOffset: Int, private val s
continue
}
val title = model.getSectionforPosition(position)
val title = provider.getSectionforPosition(position)
header.text = title
if (model.isFirstInSection(position)) {
if (provider.isFirstInSection(position)) {
drawHeader(c, child, headerView)
drawnPositions.add(i)
}
......
......@@ -10,12 +10,12 @@ import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import org.videolan.vlc.BuildConfig
import org.videolan.vlc.R
import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
import org.videolan.vlc.util.AndroidDevices
import org.videolan.vlc.viewmodels.paged.MLPagedModel
private const val TAG = "RecyclerSectionItemDecoration"
class RecyclerSectionItemGridDecoration(private val headerOffset: Int, private val space: Int, private val sticky: Boolean, private val nbColumns: Int, private val model: MLPagedModel<*>) : RecyclerView.ItemDecoration() {
class RecyclerSectionItemGridDecoration(private val headerOffset: Int, private val space: Int, private val sticky: Boolean, private val nbColumns: Int, private val provider: MedialibraryProvider<*>) : RecyclerView.ItemDecoration() {
private lateinit var headerView: View
private lateinit var header: TextView
......@@ -30,8 +30,8 @@ class RecyclerSectionItemGridDecoration(private val headerOffset: Int, private v
val pos = parent.getChildAdapterPosition(view)
for (i in 0..(nbColumns - 1)) {
if ((pos - i) >= 0 && model.isFirstInSection(pos - i)) {
for (i in 0 until nbColumns) {
if ((pos - i) >= 0 && provider.isFirstInSection(pos - i)) {
outRect.top = headerOffset + space
}
}
......@@ -56,10 +56,10 @@ class RecyclerSectionItemGridDecoration(private val headerOffset: Int, private v
val previousChild = parent.getChildAt(0)
if (sticky && previousChild != null) {
val position = parent.getChildAdapterPosition(previousChild)
val sectionPosition = model.getPositionForSection(position)
val sectionPosition = provider.getPositionForSection(position)
previousSectionPosition = sectionPosition
val title = model.getSectionforPosition(sectionPosition)
val title = provider.getSectionforPosition(sectionPosition)
header.text = title
fixLayoutSize(headerView, parent)
drawHeader(c, parent.getChildAt(0), headerView)
......@@ -74,9 +74,9 @@ class RecyclerSectionItemGridDecoration(private val headerOffset: Int, private v
continue
}
val title = model.getSectionforPosition(position)
val title = provider.getSectionforPosition(position)
header.text = title
if (model.isFirstInSection(position)) {
if (provider.isFirstInSection(position)) {
fixLayoutSize(headerView, parent)
drawHeader(c, child, headerView)
drawnPositions.add(i)
......
......@@ -40,7 +40,6 @@ import org.videolan.vlc.viewmodels.paged.HeadersIndex
import org.videolan.vlc.viewmodels.paged.MLPagedModel
@ExperimentalCoroutinesApi
abstract class MedialibraryProvider<T : MediaLibraryItem>(val context: Context, val scope: MLPagedModel<T>) {
protected val medialibrary = Medialibrary.getInstance()
val loading = MutableLiveData<Boolean>().apply { value = false }
......@@ -81,6 +80,8 @@ abstract class MedialibraryProvider<T : MediaLibraryItem>(val context: Context,
return true
}
fun isEmpty() = pagedList.value.isNullOrEmpty()
fun completeHeaders(list: Array<T>, startposition: Int) {
for ((position, item) in list.withIndex()) {
val previous = when {
......
......@@ -21,10 +21,8 @@
package org.videolan.vlc.viewmodels.paged
import android.content.Context
import androidx.annotation.MainThread
import androidx.collection.SparseArrayCompat
import androidx.lifecycle.LiveData
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
......@@ -37,7 +35,6 @@ import org.videolan.vlc.viewmodels.SortableModel
typealias HeadersIndex = SparseArrayCompat<String>
@Suppress("LeakingThis")
@ExperimentalCoroutinesApi
abstract class MLPagedModel<T : MediaLibraryItem>(context: Context) : SortableModel(context), Medialibrary.OnMedialibraryReadyListener, Medialibrary.OnDeviceChangeListener {
protected val medialibrary = Medialibrary.getInstance()
abstract val provider : MedialibraryProvider<T>
......@@ -107,25 +104,10 @@ abstract class MLPagedModel<T : MediaLibraryItem>(context: Context) : SortableMo
}
}
fun isEmpty() = pagedList.value.isNullOrEmpty()
fun isEmpty() = provider.isEmpty()
override fun refresh() {
if (this::restoreJob.isInitialized && restoreJob.isActive) restoreJob.cancel()
launch { provider.refresh() }
}
@MainThread
fun getSectionforPosition(position: Int) = provider.getSectionforPosition(position)
@MainThread
fun isFirstInSection(position: Int) = provider.isFirstInSection(position)
@MainThread
fun getPositionForSection(position: Int) = provider.getPositionForSection(position)
@MainThread
fun getPositionForSectionByName(header: String) = provider.getPositionForSectionByName(header)
@MainThread
fun getHeaderForPostion(position: Int) = provider.getHeaderForPostion(position)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment