Commit 9e11f0be authored by Geoffrey Métais's avatar Geoffrey Métais Committed by Geoffrey Métais

AlbumSongsViewModel

Refactor AudioAlbumsSongsFragment with a dedicated ViewModel, replacing
albums + tracks models
parent 41a92cfb
......@@ -42,6 +42,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.launch
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.medialibrary.media.MediaWrapper
import org.videolan.vlc.BuildConfig
import org.videolan.vlc.R
import org.videolan.vlc.databinding.PlaylistsFragmentBinding
......@@ -50,13 +51,16 @@ import org.videolan.vlc.gui.audio.AudioBrowserFragment
import org.videolan.vlc.gui.audio.BaseAudioBrowser
import org.videolan.vlc.gui.view.FastScroller
import org.videolan.vlc.gui.view.RecyclerSectionItemGridDecoration
import org.videolan.vlc.media.MediaUtils
import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
import org.videolan.vlc.reloadLibrary
import org.videolan.vlc.util.CTX_PLAY_ALL
import org.videolan.vlc.util.getScreenWidth
import org.videolan.vlc.viewmodels.paged.PagedPlaylistsModel
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
class PlaylistFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshListener {
class PlaylistFragment : BaseAudioBrowser<PagedPlaylistsModel>(), SwipeRefreshLayout.OnRefreshListener {
private lateinit var binding: PlaylistsFragmentBinding
private lateinit var playlists: RecyclerView
......@@ -143,6 +147,11 @@ class PlaylistFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshListene
} else super.onClick(v, position, item)
}
override fun onCtxAction(position: Int, option: Int) {
if (option == CTX_PLAY_ALL) MediaUtils.playAll(requireContext(), viewModel.provider as MedialibraryProvider<MediaWrapper>, position, false)
else super.onCtxAction(position, option)
}
override fun onRefresh() {
activity?.reloadLibrary()
......
......@@ -36,7 +36,6 @@ import androidx.paging.PagedList
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.viewpager.widget.ViewPager
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.tabs.TabLayout
......@@ -51,27 +50,28 @@ import org.videolan.vlc.gui.PlaylistActivity
import org.videolan.vlc.gui.view.FastScroller
import org.videolan.vlc.gui.view.RecyclerSectionItemDecoration
import org.videolan.vlc.media.MediaUtils
import org.videolan.vlc.util.CTX_PLAY_ALL
import org.videolan.vlc.util.Util
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import org.videolan.vlc.viewmodels.paged.PagedAlbumsModel
import org.videolan.vlc.viewmodels.paged.PagedTracksModel
import org.videolan.vlc.viewmodels.mobile.AlbumSongsViewModel
private const val TAG = "VLC/AudioAlbumsSongsFragment"
private const val MODE_ALBUM = 0
private const val MODE_SONG = 1
private const val MODE_TOTAL = 2 // Number of audio mProvider modes
/* All subclasses of Fragment must include a public empty constructor. */
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshListener {
class AudioAlbumsSongsFragment : BaseAudioBrowser<AlbumSongsViewModel>(), SwipeRefreshLayout.OnRefreshListener {
private var handler = Handler(Looper.getMainLooper())
private lateinit var albumModel: PagedAlbumsModel
private lateinit var tracksModel: PagedTracksModel
private lateinit var lists: Array<RecyclerView>
private lateinit var audioModels: Array<MLPagedModel<MediaLibraryItem>>
private lateinit var songsAdapter: AudioBrowserAdapter
private lateinit var albumsAdapter: AudioBrowserAdapter
private lateinit var fastScroller: FastScroller
private lateinit var item: MediaLibraryItem
override val hasTabs = true
/*
......@@ -85,18 +85,14 @@ class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefres
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
item = if (savedInstanceState != null)
val item = if (savedInstanceState != null)
savedInstanceState.getParcelable<Parcelable>(AudioBrowserFragment.TAG_ITEM) as MediaLibraryItem
else
arguments!!.getParcelable<Parcelable>(AudioBrowserFragment.TAG_ITEM) as MediaLibraryItem
albumModel = ViewModelProviders.of(this, PagedAlbumsModel.Factory(requireContext(), item)).get(PagedAlbumsModel::class.java)
tracksModel = ViewModelProviders.of(this, PagedTracksModel.Factory(requireContext(), item)).get(PagedTracksModel::class.java)
audioModels = arrayOf(albumModel as MLPagedModel<MediaLibraryItem>, tracksModel as MLPagedModel<MediaLibraryItem>)
viewModel = ViewModelProviders.of(requireActivity(), AlbumSongsViewModel.Factory(requireContext(), item)).get(AlbumSongsViewModel::class.java)
}
override fun getTitle(): String = item.title
override fun getTitle(): String = viewModel.parent.title
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.audio_albums_songs, container, false)
......@@ -112,33 +108,21 @@ class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefres
val titles = arrayOf(getString(R.string.albums), getString(R.string.songs))
albumsAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_ALBUM, this)
songsAdapter = AudioBrowserAdapter(MediaLibraryItem.TYPE_MEDIA, this)
adapters = arrayOf<AudioBrowserAdapter>(albumsAdapter, songsAdapter)
adapters = arrayOf(albumsAdapter, songsAdapter)
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))
albumsList.addItemDecoration(RecyclerSectionItemDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), true, viewModel.albumsProvider))
songsList.addItemDecoration(RecyclerSectionItemDecoration(resources.getDimensionPixelSize(R.dimen.recycler_section_header_height), true, viewModel.tracksProvider))
songsList.adapter = songsAdapter
albumsList.adapter = albumsAdapter
viewPager!!.offscreenPageLimit = MODE_TOTAL - 1
@Suppress("UNCHECKED_CAST")
viewPager!!.adapter = AudioPagerAdapter(lists as Array<View>, titles)
fastScroller = view.rootView.findViewById<View>(R.id.songs_fast_scroller) as FastScroller
fastScroller.attachToCoordinator(view.rootView.findViewById<View>(R.id.appbar) as AppBarLayout, view.rootView.findViewById<View>(R.id.coordinator) as CoordinatorLayout, view.rootView.findViewById<View>(R.id.fab) as FloatingActionButton)
viewPager!!.setOnTouchListener(swipeFilter)
viewModel = audioModels[viewPager!!.currentItem]
viewPager!!.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {
viewModel = audioModels[viewPager!!.currentItem]
}
})
swipeRefreshLayout = view.findViewById(R.id.swipeLayout)
swipeRefreshLayout!!.setOnRefreshListener(this)
......@@ -151,10 +135,11 @@ class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefres
}
fabPlay?.setImageResource(R.drawable.ic_fab_play)
albumModel.pagedList.observe(this, Observer { albums -> if (albums != null) albumsAdapter.submitList(albums as PagedList<MediaLibraryItem>) })
tracksModel.pagedList.observe(this, Observer { tracks ->
viewModel.albumsProvider.pagedList.observe(this, Observer { albums -> if (albums != null) albumsAdapter.submitList(albums as PagedList<MediaLibraryItem>) })
viewModel.tracksProvider.pagedList.observe(this, Observer { tracks ->
if (tracks != null) {
if (tracks.isEmpty() && !tracksModel.isFiltering()) {
@Suppress("UNCHECKED_CAST")
if (tracks.isEmpty() && !viewModel.isFiltering()) {
val activity = activity
activity?.finish()
} else
......@@ -163,14 +148,15 @@ class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefres
})
}
override fun getCurrentAdapter() = adapters[currentTab]
override fun onRefresh() {
(requireActivity() as ContentActivity).closeSearchView()
albumModel.refresh()
tracksModel.refresh()
viewModel.refresh()
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putParcelable(AudioBrowserFragment.TAG_ITEM, item)
outState.putParcelable(AudioBrowserFragment.TAG_ITEM, viewModel.parent)
super.onSaveInstanceState(outState)
}
......@@ -178,10 +164,9 @@ class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefres
super.onUpdateFinished(adapter)
handler.post {
swipeRefreshLayout?.isRefreshing = false
val albums = albumModel.pagedList.value
if (Util.isListEmpty(albums) && !viewModel.isFiltering())
viewPager!!.currentItem = 1
fastScroller.setRecyclerView(getCurrentRV(), viewModel.provider)
val albums = viewModel.albumsProvider.pagedList.value
if (Util.isListEmpty(albums) && !viewModel.isFiltering()) currentTab = 1
fastScroller.setRecyclerView(getCurrentRV(), viewModel.providers[currentTab])
}
}
......@@ -203,42 +188,32 @@ class AudioAlbumsSongsFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefres
MediaUtils.openMedia(v.context, item as MediaWrapper)
}
override fun onCtxAction(position: Int, option: Int) {
if (option == CTX_PLAY_ALL) MediaUtils.playAll(requireContext(), viewModel.tracksProvider, position, false)
else super.onCtxAction(position, option)
}
override fun onTabUnselected(tab: TabLayout.Tab) {
super.onTabUnselected(tab)
audioModels[tab.position].restore()
viewModel.restore()
}
override fun onTabReselected(tab: TabLayout.Tab) {
lists[tab.position].smoothScrollToPosition(0)
fastScroller.setRecyclerView(lists[tab.position], audioModels[tab.position].provider)
fastScroller.setRecyclerView(lists[tab.position], viewModel.providers[tab.position])
}
override fun onTabSelected(tab: TabLayout.Tab) {
super.onTabSelected(tab)
fastScroller.setRecyclerView(lists[tab.position], audioModels[tab.position].provider)
}
override fun getCurrentRV(): RecyclerView {
return lists[viewPager!!.currentItem]
fastScroller.setRecyclerView(lists[tab.position], viewModel.providers[tab.position])
}
override fun setFabPlayVisibility(enable: Boolean) {
super.setFabPlayVisibility(enable)
}
override fun getCurrentRV() = lists[currentTab]
override fun onFabPlayClick(view: View) {
if (viewPager!!.currentItem == 0)
MediaUtils.playAlbums(activity, albumModel.provider, 0, false)
if (currentTab == 0)
MediaUtils.playAlbums(activity, viewModel.albumsProvider, 0, false)
else
MediaUtils.playAll(view.context, tracksModel.provider, 0, false)
}
companion object {
private val TAG = "VLC/AudioAlbumsSongsFragment"
private val MODE_ALBUM = 0
private val MODE_SONG = 1
private val MODE_TOTAL = 2 // Number of audio mProvider modes
MediaUtils.playAll(view.context, viewModel.tracksProvider, 0, false)
}
}
......@@ -50,17 +50,15 @@ import org.videolan.vlc.gui.preferences.PreferencesActivity
import org.videolan.vlc.gui.view.FastScroller
import org.videolan.vlc.gui.view.RecyclerSectionItemDecoration
import org.videolan.vlc.media.MediaUtils
import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
import org.videolan.vlc.reloadLibrary
import org.videolan.vlc.util.KEY_ARTISTS_SHOW_ALL
import org.videolan.vlc.util.KEY_AUDIO_CURRENT_TAB
import org.videolan.vlc.util.Settings
import org.videolan.vlc.util.WeakHandler
import org.videolan.vlc.util.*
import org.videolan.vlc.viewmodels.paged.*
import java.util.*
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshListener {
class AudioBrowserFragment : BaseAudioBrowser<MLPagedModel<*>>(), SwipeRefreshLayout.OnRefreshListener {
private lateinit var songsAdapter: AudioBrowserAdapter
private lateinit var artistsAdapter: AudioBrowserAdapter
......@@ -127,7 +125,7 @@ class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshLis
viewPager!!.offscreenPageLimit = MODE_TOTAL - 1
viewPager!!.adapter = AudioPagerAdapter(lists as Array<View>, titles)
val tabPosition = settings.getInt(KEY_AUDIO_CURRENT_TAB, 0)
viewPager!!.currentItem = tabPosition
currentTab = tabPosition
val positions = savedInstanceState?.getIntegerArrayList(KEY_LISTS_POSITIONS)
for (i in 0 until MODE_TOTAL) {
val llm = LinearLayoutManager(activity)
......@@ -147,11 +145,11 @@ class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshLis
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {
viewModel = models[viewPager!!.currentItem]
viewModel = models[currentTab]
}
})
viewModel = models[viewPager!!.currentItem]
viewModel = models[currentTab]
}
override fun onSaveInstanceState(outState: Bundle) {
......@@ -190,7 +188,7 @@ class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshLis
if ((pass == 0) xor (current == i)) continue
models[i].pagedList.observe(this, Observer { items -> if (items != null) adapters[i].submitList(items) })
models[i].loading.observe(this, Observer { loading ->
if (loading == null || viewPager!!.currentItem != i) return@Observer
if (loading == null || currentTab != i) return@Observer
if (loading)
mHandler.sendEmptyMessageDelayed(SET_REFRESHING, 300)
else
......@@ -262,6 +260,11 @@ class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshLis
lists[tab.position]?.smoothScrollToPosition(0)
}
override fun onCtxAction(position: Int, option: Int) {
if (option == CTX_PLAY_ALL) MediaUtils.playAll(requireContext(), viewModel.provider as MedialibraryProvider<MediaWrapper>, position, false)
else super.onCtxAction(position, option)
}
override fun onClick(v: View, position: Int, item: MediaLibraryItem) {
if (actionMode != null) {
super.onClick(v, position, item)
......@@ -289,7 +292,7 @@ class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshLis
override fun onUpdateFinished(adapter: RecyclerView.Adapter<*>) {
super.onUpdateFinished(adapter)
if (getCurrentAdapter() != null && adapter === getCurrentAdapter()) {
if (adapter === getCurrentAdapter()) {
swipeRefreshLayout?.isEnabled = (getCurrentRV().layoutManager as LinearLayoutManager).findFirstVisibleItemPosition() <= 0
updateEmptyView()
fastScroller.setRecyclerView(getCurrentRV(), viewModel.provider)
......@@ -299,13 +302,9 @@ class AudioBrowserFragment : BaseAudioBrowser(), SwipeRefreshLayout.OnRefreshLis
override fun getCurrentRV(): RecyclerView {
return lists[viewPager!!.currentItem]!!
}
override fun getCurrentRV() = lists[currentTab]!!
override fun getCurrentAdapter(): AudioBrowserAdapter? {
return adapters[viewPager!!.currentItem]
}
override fun getCurrentAdapter() = adapters[currentTab]
private class AudioBrowserHandler internal constructor(owner: AudioBrowserFragment) : WeakHandler<AudioBrowserFragment>(owner) {
......
......@@ -48,14 +48,13 @@ import org.videolan.vlc.gui.helpers.UiTools
import org.videolan.vlc.interfaces.IEventsHandler
import org.videolan.vlc.media.MediaUtils
import org.videolan.vlc.media.PlaylistManager
import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
import org.videolan.vlc.util.*
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import org.videolan.vlc.viewmodels.SortableModel
import java.util.*
@ExperimentalCoroutinesApi
@ObsoleteCoroutinesApi
abstract class BaseAudioBrowser : MediaBrowserFragment<MLPagedModel<*>>(), IEventsHandler, CtxActionReceiver, ViewPager.OnPageChangeListener, TabLayout.OnTabSelectedListener {
abstract class BaseAudioBrowser<T : SortableModel> : MediaBrowserFragment<T>(), IEventsHandler, CtxActionReceiver, ViewPager.OnPageChangeListener, TabLayout.OnTabSelectedListener {
internal lateinit var adapters: Array<AudioBrowserAdapter>
......@@ -67,8 +66,12 @@ abstract class BaseAudioBrowser : MediaBrowserFragment<MLPagedModel<*>>(), IEven
protected abstract fun getCurrentRV(): RecyclerView
protected var adapter: AudioBrowserAdapter? = null
open fun getCurrentAdapter(): AudioBrowserAdapter? {
return adapter
open fun getCurrentAdapter() = adapter
protected var currentTab
get() = viewPager?.currentItem ?: 0
set(value) {
viewPager?.currentItem = value
}
private lateinit var layoutOnPageChangeListener: TabLayout.TabLayoutOnPageChangeListener
......@@ -248,17 +251,13 @@ abstract class BaseAudioBrowser : MediaBrowserFragment<MLPagedModel<*>>(), IEven
UiTools.updateSortTitles(this)
}
override fun onItemFocused(v: View, item: MediaLibraryItem) {
}
override fun onItemFocused(v: View, item: MediaLibraryItem) {}
override fun onCtxAction(position: Int, option: Int) {
val adapter = getCurrentAdapter()
if (position >= adapter?.itemCount ?: 0) return
val media = adapter?.getItem(position) ?: return
if (position >= getCurrentAdapter()?.itemCount ?: 0) return
val media = getCurrentAdapter()?.getItem(position) ?: return
when (option) {
CTX_PLAY -> MediaUtils.playTracks(requireActivity(), media, 0)
CTX_PLAY_ALL -> MediaUtils.playAll(requireContext(), viewModel.provider as MedialibraryProvider<MediaWrapper>, position, false)
CTX_INFORMATION -> showInfoDialog(media)
CTX_DELETE -> removeItem(media)
CTX_APPEND -> MediaUtils.appendMedia(requireActivity(), media.tracks)
......
......@@ -439,8 +439,7 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
override fun onCtxAction(position: Int, option: Int) {
if (adapter.getItem(position) !is MediaWrapper) return
val mw = adapter.getItem(position) as MediaWrapper
val mw = adapter.getItem(position) as? MediaWrapper ?: return
when (option) {
CTX_PLAY -> MediaUtils.openMedia(activity, mw)
CTX_PLAY_ALL -> {
......
......@@ -32,6 +32,7 @@ import android.view.View
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.launch
......@@ -130,7 +131,7 @@ open class FileBrowserFragment : BaseBrowserFragment() {
}
override fun onCtxAction(position: Int, option: Int) {
val mw = adapter.getItem(position) as MediaWrapper?
val mw = this.adapter.getItem(position) as MediaWrapper?
when (option) {
CTX_FAV_ADD -> browserFavRepository.addLocalFavItem(mw!!.uri, mw.title, mw.artworkURL)
else -> super.onCtxAction(position, option)
......
......@@ -131,7 +131,7 @@ class NetworkBrowserFragment : BaseBrowserFragment() {
}
override fun onCtxAction(position: Int, option: Int) {
val mw = adapter.getItem(position) as MediaWrapper
val mw = this.adapter.getItem(position) as MediaWrapper
when (option) {
CTX_FAV_ADD -> browserFavRepository.addNetworkFavItem(mw.uri, mw.title, mw.artworkURL)
CTX_FAV_EDIT -> showAddServerDialog(mw)
......
......@@ -169,18 +169,18 @@ class MRLPanelFragment : Fragment(), View.OnKeyListener, TextView.OnEditorAction
when (option) {
CTX_RENAME -> renameStream(position)
CTX_APPEND -> {
val media = viewModel.dataset.value.get(position) ?: return
val media = viewModel.dataset.value[position]
MediaUtils.appendMedia(requireContext(), media)
}
CTX_ADD_TO_PLAYLIST -> {
val media = viewModel.dataset.value.get(position) ?: return
val media = viewModel.dataset.value[position]
UiTools.addToPlaylist(requireActivity(), media.tracks, SavePlaylistDialog.KEY_NEW_TRACKS)
}
}
}
private fun renameStream(position: Int) {
val media = viewModel.dataset.value.get(position) ?: return
val media = viewModel.dataset.value[position]
val edit = EditText(requireActivity())
AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.rename_media, media.title))
......
......@@ -26,11 +26,11 @@ import org.videolan.medialibrary.media.Album
import org.videolan.medialibrary.media.Artist
import org.videolan.medialibrary.media.Genre
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import org.videolan.vlc.viewmodels.SortableModel
@ExperimentalCoroutinesApi
class AlbumsProvider(val parent : MediaLibraryItem?, context: Context, scope: MLPagedModel<Album>) : MedialibraryProvider<Album>(context, scope) {
class AlbumsProvider(val parent : MediaLibraryItem?, context: Context, scope: SortableModel) : MedialibraryProvider<Album>(context, scope) {
override fun canSortByDuration() = true
override fun canSortByReleaseDate() = true
......
......@@ -23,11 +23,11 @@ package org.videolan.vlc.providers.medialibrary
import android.content.Context
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.videolan.medialibrary.media.Artist
import org.videolan.vlc.viewmodels.paged.PagedArtistsModel
import org.videolan.vlc.viewmodels.SortableModel
@ExperimentalCoroutinesApi
class ArtistsProvider(context: Context, scope: PagedArtistsModel, var showAll: Boolean) : MedialibraryProvider<Artist>(context, scope) {
class ArtistsProvider(context: Context, scope: SortableModel, var showAll: Boolean) : MedialibraryProvider<Artist>(context, scope) {
override fun getAll() : Array<Artist> = medialibrary.getArtists(showAll, scope.sort, scope.desc)
......
......@@ -23,11 +23,11 @@ package org.videolan.vlc.providers.medialibrary
import android.content.Context
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.videolan.medialibrary.media.Folder
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import org.videolan.vlc.viewmodels.SortableModel
@ExperimentalCoroutinesApi
class FoldersProvider(context: Context, scope: MLPagedModel<Folder>, val type: Int) : MedialibraryProvider<Folder>(context, scope) {
class FoldersProvider(context: Context, scope: SortableModel, val type: Int) : MedialibraryProvider<Folder>(context, scope) {
override fun getAll() : Array<Folder> = medialibrary.getFolders(type, scope.sort, scope.desc, getTotalCount(), 0)
override fun getTotalCount() = medialibrary.getFoldersCount(type)
......
......@@ -23,11 +23,11 @@ package org.videolan.vlc.providers.medialibrary
import android.content.Context
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.videolan.medialibrary.media.Genre
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import org.videolan.vlc.viewmodels.SortableModel
@ExperimentalCoroutinesApi
class GenresProvider(context: Context, scope: MLPagedModel<Genre>) : MedialibraryProvider<Genre>(context, scope) {
class GenresProvider(context: Context, scope: SortableModel) : MedialibraryProvider<Genre>(context, scope) {
override fun getAll() : Array<Genre> = medialibrary.getGenres(scope.sort, scope.desc)
......
......@@ -36,11 +36,11 @@ import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.vlc.util.MEDIALIBRARY_PAGE_SIZE
import org.videolan.vlc.util.ModelsHelper
import org.videolan.vlc.util.retry
import org.videolan.vlc.viewmodels.SortableModel
import org.videolan.vlc.viewmodels.paged.HeadersIndex
import org.videolan.vlc.viewmodels.paged.MLPagedModel
abstract class MedialibraryProvider<T : MediaLibraryItem>(val context: Context, val scope: MLPagedModel<T>) {
abstract class MedialibraryProvider<T : MediaLibraryItem>(val context: Context, val scope: SortableModel) {
protected val medialibrary = Medialibrary.getInstance()
val loading = MutableLiveData<Boolean>().apply { value = false }
private val headers = HeadersIndex()
......
......@@ -23,11 +23,11 @@ package org.videolan.vlc.providers.medialibrary
import android.content.Context
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.videolan.medialibrary.media.Playlist
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import org.videolan.vlc.viewmodels.SortableModel
@ExperimentalCoroutinesApi
class PlaylistsProvider(context: Context, scope: MLPagedModel<Playlist>) : MedialibraryProvider<Playlist>(context, scope) {
class PlaylistsProvider(context: Context, scope: SortableModel) : MedialibraryProvider<Playlist>(context, scope) {
override fun getAll() : Array<Playlist> = medialibrary.getPlaylists(scope.sort, scope.desc)
......
......@@ -23,11 +23,11 @@ package org.videolan.vlc.providers.medialibrary
import android.content.Context
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.videolan.medialibrary.media.*
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import org.videolan.vlc.viewmodels.SortableModel
@ExperimentalCoroutinesApi
class TracksProvider(val parent : MediaLibraryItem?, context: Context, scope: MLPagedModel<MediaWrapper>) : MedialibraryProvider<MediaWrapper>(context, scope) {
class TracksProvider(val parent : MediaLibraryItem?, context: Context, scope: SortableModel) : MedialibraryProvider<MediaWrapper>(context, scope) {
override fun canSortByDuration() = true
override fun canSortByAlbum() = parent !== null
......
......@@ -25,11 +25,11 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.videolan.medialibrary.media.Folder
import org.videolan.medialibrary.media.MediaWrapper
import org.videolan.vlc.media.getAll
import org.videolan.vlc.viewmodels.paged.MLPagedModel
import org.videolan.vlc.viewmodels.SortableModel
@ExperimentalCoroutinesApi
class VideosProvider(val folder : Folder?, context: Context, scope: MLPagedModel<MediaWrapper>) : MedialibraryProvider<MediaWrapper>(context, scope){
class VideosProvider(val folder : Folder?, context: Context, scope: SortableModel) : MedialibraryProvider<MediaWrapper>(context, scope){
override fun canSortByFileNameName() = true
override fun canSortByDuration() = true
......
......@@ -8,7 +8,7 @@ import org.videolan.vlc.util.canSortBy
abstract class SortableModel(protected val context: Context): ScopedModel(), RefreshModel {
protected open val sortKey = this.javaClass.simpleName!!
protected open val sortKey : String = this.javaClass.simpleName
var sort = Medialibrary.SORT_ALPHA
var desc = false
......
package org.videolan.vlc.viewmodels.mobile
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.videolan.medialibrary.Medialibrary
import org.videolan.medialibrary.media.Album
import org.videolan.medialibrary.media.Artist
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.vlc.providers.medialibrary.AlbumsProvider
import org.videolan.vlc.providers.medialibrary.TracksProvider
import org.videolan.vlc.util.EmptyMLCallbacks
@ExperimentalCoroutinesApi
class AlbumSongsViewModel(context: Context, val parent: MediaLibraryItem) : BaseAudioViewModel(context),
Medialibrary.MediaCb,
Medialibrary.ArtistsCb by EmptyMLCallbacks,
Medialibrary.AlbumsCb by EmptyMLCallbacks {
val albumsProvider = AlbumsProvider(parent, context, this)
val tracksProvider = TracksProvider(parent, context, this)
override val providers = arrayOf(albumsProvider, tracksProvider)
init {
when (parent) {
is Artist -> medialibrary.addArtistsCb(this@AlbumSongsViewModel)
is Album -> medialibrary.addAlbumsCb(this@AlbumSongsViewModel)
else -> medialibrary.addMediaCb(this@AlbumSongsViewModel)
}
if (medialibrary.isStarted) refresh()
}
override fun onMediaAdded() { refresh() }
override fun onMediaModified() { refresh() }
override fun onMediaDeleted() { refresh() }
override fun onArtistsModified() { refresh() }
override fun onAlbumsModified() { refresh() }
override fun onCleared() {
when (parent) {
is Artist -> medialibrary.removeArtistsCb(this)
is Album -> medialibrary.removeAlbumsCb(this)
else -> medialibrary.removeMediaCb(this)
}
super.onCleared()
}
class Factory(val context: Context, val parent: MediaLibraryItem): ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return AlbumSongsViewModel(context.applicationContext, parent) as T
}
}
}
\ No newline at end of file
package org.videolan.vlc.viewmodels.mobile
import android.content.Context
import org.videolan.medialibrary.Medialibrary
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.vlc.providers.medialibrary.MedialibraryProvider
import org.videolan.vlc.viewmodels.SortableModel
abstract class BaseAudioViewModel(context: Context) : SortableModel(context),
Medialibrary.OnMedialibraryReadyListener, Medialibrary.OnDeviceChangeListener {
val medialibrary = Medialibrary.getInstance().apply {
addOnMedialibraryReadyListener(this@BaseAudioViewModel)
addOnDeviceChangeListener(this@BaseAudioViewModel)
}
abstract val providers : Array<MedialibraryProvider<out MediaLibraryItem>>
override fun refresh() = providers.forEach { it.refresh() }
override fun restore() {
if (filterQuery !== null) filter(null)
}
override fun filter(query: String?) {
filterQuery = query
refresh()
}