mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-06 21:40:20 +00:00
TrackListActivity -> TrackListFragment.
This commit is contained in:
parent
a9428954ed
commit
4d9bef4aa8
@ -11,26 +11,12 @@ import io.casey.musikcube.remote.ui.albums.fragment.AlbumBrowseFragment
|
||||
import io.casey.musikcube.remote.ui.shared.activity.FragmentActivityWithTransport
|
||||
import io.casey.musikcube.remote.ui.shared.extension.EXTRA_ACTIVITY_TITLE
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.BaseFragment
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.DataProviderMixin
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.ItemContextMenuMixin
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.PlaybackMixin
|
||||
import io.casey.musikcube.remote.util.Strings
|
||||
|
||||
class AlbumBrowseActivity : FragmentActivityWithTransport() {
|
||||
private lateinit var playback: PlaybackMixin
|
||||
private lateinit var data: DataProviderMixin
|
||||
|
||||
private val albums
|
||||
get() = content as AlbumBrowseFragment
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
component.inject(this)
|
||||
data = mixin(DataProviderMixin())
|
||||
playback = mixin(PlaybackMixin())
|
||||
mixin(ItemContextMenuMixin(this))
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean = albums.createOptionsMenu(menu)
|
||||
override fun setFilter(filter: String) = albums.setFilter(filter)
|
||||
override fun onTransportChanged() = albums.notifyTransportChanged()
|
||||
|
@ -53,7 +53,7 @@ class AlbumBrowseFragment: BaseFragment(), Filterable, TitleProvider {
|
||||
adapter = AlbumBrowseAdapter(eventListener, playback, prefs)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
inflater.inflate(R.layout.recycler_view_fragment, container, false).apply {
|
||||
val recyclerView = findViewById<FastScrollRecyclerView>(R.id.recycler_view)
|
||||
setupDefaultRecyclerView(recyclerView, adapter)
|
||||
|
@ -7,28 +7,28 @@ import android.support.v4.app.FragmentPagerAdapter
|
||||
import io.casey.musikcube.remote.ui.albums.fragment.AlbumBrowseFragment
|
||||
import io.casey.musikcube.remote.ui.category.constant.NavigationType
|
||||
import io.casey.musikcube.remote.ui.category.fragment.CategoryBrowseFragment
|
||||
import io.casey.musikcube.remote.ui.tracks.fragment.TrackListFragment
|
||||
|
||||
class BrowseFragmentAdapter(private val context: Context, fm: FragmentManager): FragmentPagerAdapter(fm) {
|
||||
override fun getItem(index: Int): Fragment {
|
||||
if (index == 0) {
|
||||
return AlbumBrowseFragment.create()
|
||||
}
|
||||
else if (index == 1) {
|
||||
return CategoryBrowseFragment.create(
|
||||
override fun getItem(index: Int): Fragment =
|
||||
when (index) {
|
||||
0 -> AlbumBrowseFragment.create()
|
||||
1 -> CategoryBrowseFragment.create(
|
||||
CategoryBrowseFragment.arguments(context, "artist"))
|
||||
2 -> TrackListFragment.create()
|
||||
else -> CategoryBrowseFragment.create(
|
||||
CategoryBrowseFragment.arguments("playlists", NavigationType.Tracks))
|
||||
}
|
||||
return CategoryBrowseFragment.create(
|
||||
CategoryBrowseFragment.arguments("playlists", NavigationType.Tracks))
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? =
|
||||
when (position) {
|
||||
0 -> "albums"
|
||||
1 -> "artists"
|
||||
2 -> "songs"
|
||||
else -> "playlists"
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
return 3
|
||||
return 4
|
||||
}
|
||||
}
|
@ -2,289 +2,49 @@ package io.casey.musikcube.remote.ui.tracks.activity
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
|
||||
import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.service.websocket.Messages
|
||||
import io.casey.musikcube.remote.service.websocket.model.IDataProvider
|
||||
import io.casey.musikcube.remote.service.websocket.model.ITrack
|
||||
import io.casey.musikcube.remote.service.websocket.model.ITrackListQueryFactory
|
||||
import io.casey.musikcube.remote.ui.home.activity.MainActivity
|
||||
import io.casey.musikcube.remote.ui.shared.activity.BaseActivity
|
||||
import io.casey.musikcube.remote.ui.shared.activity.Filterable
|
||||
import io.casey.musikcube.remote.ui.shared.extension.*
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.TransportFragment
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.DataProviderMixin
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.ItemContextMenuMixin
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.PlaybackMixin
|
||||
import io.casey.musikcube.remote.ui.shared.model.DefaultSlidingWindow
|
||||
import io.casey.musikcube.remote.ui.shared.model.ITrackListSlidingWindow
|
||||
import io.casey.musikcube.remote.ui.shared.view.EmptyListView
|
||||
import io.casey.musikcube.remote.ui.shared.view.EmptyListView.Capability
|
||||
import io.casey.musikcube.remote.ui.tracks.adapter.TrackListAdapter
|
||||
import io.casey.musikcube.remote.ui.shared.activity.FragmentActivityWithTransport
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.BaseFragment
|
||||
import io.casey.musikcube.remote.ui.tracks.constant.Track
|
||||
import io.casey.musikcube.remote.util.Debouncer
|
||||
import io.casey.musikcube.remote.util.Strings
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import io.casey.musikcube.remote.ui.tracks.fragment.TrackListFragment
|
||||
|
||||
class TrackListActivity : BaseActivity(), Filterable {
|
||||
private lateinit var tracks: DefaultSlidingWindow
|
||||
private lateinit var emptyView: EmptyListView
|
||||
private lateinit var transport: TransportFragment
|
||||
private lateinit var adapter: TrackListAdapter
|
||||
class TrackListActivity : FragmentActivityWithTransport(), Filterable {
|
||||
private val tracks
|
||||
get() = content as TrackListFragment
|
||||
|
||||
private lateinit var data: DataProviderMixin
|
||||
private lateinit var playback: PlaybackMixin
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean =
|
||||
tracks.createOptionsMenu(menu)
|
||||
|
||||
private var categoryType: String = ""
|
||||
private var categoryId: Long = 0
|
||||
private var categoryValue: String = ""
|
||||
private var lastFilter = ""
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
tracks.optionsItemSelected(item)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
component.inject(this)
|
||||
data = mixin(DataProviderMixin())
|
||||
playback = mixin(PlaybackMixin())
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) =
|
||||
tracks.activityResult(requestCode, resultCode, data)
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
override fun createContentFragment(): BaseFragment = TrackListFragment.create(intent)
|
||||
|
||||
val intent = intent
|
||||
categoryType = intent.getStringExtra(Track.Extra.CATEGORY_TYPE) ?: ""
|
||||
categoryId = intent.getLongExtra(Track.Extra.SELECTED_ID, 0)
|
||||
categoryValue = intent.getStringExtra(Track.Extra.CATEGORY_VALUE) ?: ""
|
||||
val titleId = intent.getIntExtra(Track.Extra.TITLE_ID, R.string.songs_title)
|
||||
override val contentFragmentTag: String = TrackListFragment.TAG
|
||||
|
||||
mixin(ItemContextMenuMixin(this, menuListener))
|
||||
|
||||
setContentView(R.layout.recycler_view_activity)
|
||||
|
||||
setTitleFromIntent(titleId)
|
||||
enableUpNavigation()
|
||||
|
||||
val queryFactory = createCategoryQueryFactory(categoryType, categoryId)
|
||||
val recyclerView = findViewById<FastScrollRecyclerView>(R.id.recycler_view)
|
||||
|
||||
tracks = DefaultSlidingWindow(recyclerView, data.provider, queryFactory)
|
||||
adapter = TrackListAdapter(tracks, eventListener, playback, prefs)
|
||||
|
||||
setupDefaultRecyclerView(recyclerView, adapter)
|
||||
|
||||
emptyView = findViewById(R.id.empty_list_view)
|
||||
|
||||
emptyView.let {
|
||||
it.capability = if (isOfflineTracks) Capability.OfflineOk else Capability.OnlineOnly
|
||||
it.emptyMessage = emptyMessage
|
||||
it.alternateView = recyclerView
|
||||
}
|
||||
|
||||
tracks.setOnMetadataLoadedListener(slidingWindowListener)
|
||||
|
||||
transport = addTransportFragment {
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
if (Messages.Category.PLAYLISTS == categoryType) {
|
||||
menuInflater.inflate(R.menu.view_playlist_menu, menu)
|
||||
}
|
||||
else {
|
||||
initSearchMenu(menu, this)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == R.id.action_edit) {
|
||||
startActivityForResult(EditPlaylistActivity.getStartIntent(
|
||||
this, categoryValue, categoryId), Track.RequestCode.EDIT_PLAYLIST)
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == Track.RequestCode.EDIT_PLAYLIST && resultCode == RESULT_OK && data != null) {
|
||||
val playlistName = data.getStringExtra(EditPlaylistActivity.EXTRA_PLAYLIST_NAME) ?: ""
|
||||
val playlistId = data.getLongExtra(EditPlaylistActivity.EXTRA_PLAYLIST_ID, -1L)
|
||||
|
||||
if (categoryType != Messages.Category.PLAYLISTS || playlistId != this.categoryId) {
|
||||
showSnackbar(
|
||||
getString(R.string.playlist_edit_save_success, playlistName),
|
||||
buttonText = getString(R.string.button_view),
|
||||
buttonCb = {
|
||||
startActivity(TrackListActivity.getStartIntent(
|
||||
this@TrackListActivity, Messages.Category.PLAYLISTS, playlistId, playlistName))
|
||||
})
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
tracks.pause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
tracks.resume() /* needs to happen before */
|
||||
super.onResume()
|
||||
initObservers()
|
||||
requeryIfViewingOfflineCache()
|
||||
}
|
||||
|
||||
override fun setFilter(filter: String) {
|
||||
lastFilter = filter
|
||||
filterDebouncer.call()
|
||||
}
|
||||
|
||||
private val eventListener = object: TrackListAdapter.EventListener {
|
||||
override fun onItemClick(view: View, track: ITrack, position: Int) {
|
||||
if (isValidCategory(categoryType, categoryId)) {
|
||||
playback.service.play(categoryType, categoryId, position, lastFilter)
|
||||
}
|
||||
else {
|
||||
playback.service.playAll(position, lastFilter)
|
||||
}
|
||||
|
||||
startActivity(MainActivity.getStartIntent(this@TrackListActivity))
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onActionItemClick(view: View, track: ITrack, position: Int) {
|
||||
val mixin = mixin(ItemContextMenuMixin::class.java)!!
|
||||
if (categoryType == Messages.Category.PLAYLISTS) {
|
||||
mixin.showForPlaylistTrack(track, position, categoryId, categoryValue, view)
|
||||
}
|
||||
else {
|
||||
mixin.showForTrack(track, view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initObservers() {
|
||||
disposables.add(data.provider.observeState().subscribeBy(
|
||||
onNext = { states ->
|
||||
val shouldRequery =
|
||||
states.first === IDataProvider.State.Connected ||
|
||||
(states.first === IDataProvider.State.Disconnected && isOfflineTracks)
|
||||
|
||||
if (shouldRequery) {
|
||||
filterDebouncer.cancel()
|
||||
tracks.requery()
|
||||
}
|
||||
else {
|
||||
emptyView.update(states.first, adapter.itemCount)
|
||||
}
|
||||
},
|
||||
onError = {
|
||||
}))
|
||||
}
|
||||
|
||||
private val filterDebouncer = object : Debouncer<String>(350) {
|
||||
override fun onDebounced(last: String?) {
|
||||
if (!paused) {
|
||||
tracks.requery()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val emptyMessage: String
|
||||
get() {
|
||||
if (isOfflineTracks) {
|
||||
return getString(R.string.empty_no_offline_tracks_message)
|
||||
}
|
||||
|
||||
return getString(R.string.empty_no_items_format, getString(R.string.browse_type_tracks))
|
||||
}
|
||||
|
||||
private val isOfflineTracks: Boolean
|
||||
get() = Messages.Category.OFFLINE == categoryType
|
||||
|
||||
private fun requeryIfViewingOfflineCache() {
|
||||
if (isOfflineTracks) {
|
||||
tracks.requery()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCategoryQueryFactory(categoryType: String?, categoryId: Long): ITrackListQueryFactory {
|
||||
if (isValidCategory(categoryType, categoryId)) {
|
||||
/* tracks for a specified category (album, artists, genres, etc */
|
||||
return object : ITrackListQueryFactory {
|
||||
override fun count(): Observable<Int> =
|
||||
data.provider.getTrackCountByCategory(categoryType ?: "", categoryId, lastFilter)
|
||||
|
||||
override fun page(offset: Int, limit: Int): Observable<List<ITrack>> =
|
||||
data.provider.getTracksByCategory(categoryType ?: "", categoryId, limit, offset, lastFilter)
|
||||
|
||||
override fun offline(): Boolean =
|
||||
Messages.Category.OFFLINE == categoryType
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* all tracks */
|
||||
return object : ITrackListQueryFactory {
|
||||
override fun count(): Observable<Int> =
|
||||
data.provider.getTrackCount(lastFilter)
|
||||
|
||||
override fun page(offset: Int, limit: Int): Observable<List<ITrack>> =
|
||||
data.provider.getTracks(limit, offset, lastFilter)
|
||||
|
||||
override fun offline(): Boolean =
|
||||
Messages.Category.OFFLINE == categoryType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val slidingWindowListener = object : ITrackListSlidingWindow.OnMetadataLoadedListener {
|
||||
override fun onReloaded(count: Int) =
|
||||
emptyView.update(data.provider.state, count)
|
||||
|
||||
override fun onMetadataLoaded(offset: Int, count: Int) {}
|
||||
}
|
||||
|
||||
private val menuListener: ItemContextMenuMixin.EventListener?
|
||||
get() {
|
||||
if (categoryType == Messages.Category.PLAYLISTS) {
|
||||
return object: ItemContextMenuMixin.EventListener () {
|
||||
override fun onPlaylistUpdated(id: Long, name: String) {
|
||||
tracks.requery()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
override fun onTransportChanged() = tracks.notifyTransportChanged()
|
||||
|
||||
companion object {
|
||||
fun getStartIntent(context: Context, type: String, id: Long): Intent =
|
||||
getStartIntent(context, type, id, "")
|
||||
|
||||
fun getOfflineStartIntent(context: Context): Intent =
|
||||
getStartIntent(context, Messages.Category.OFFLINE, 0).apply {
|
||||
putExtra(Track.Extra.TITLE_ID, R.string.offline_tracks_title)
|
||||
}
|
||||
|
||||
fun getStartIntent(context: Context, type: String, id: Long, categoryValue: String): Intent =
|
||||
fun getStartIntent(context: Context,
|
||||
type: String = "",
|
||||
id: Long = 0,
|
||||
categoryValue: String = ""): Intent =
|
||||
Intent(context, TrackListActivity::class.java).apply {
|
||||
putExtra(Track.Extra.CATEGORY_TYPE, type)
|
||||
putExtra(Track.Extra.SELECTED_ID, id)
|
||||
putExtra(Track.Extra.CATEGORY_VALUE, categoryValue)
|
||||
|
||||
if (Strings.notEmpty(categoryValue)) {
|
||||
putExtra(
|
||||
EXTRA_ACTIVITY_TITLE,
|
||||
context.getString(R.string.songs_from_category, categoryValue))
|
||||
}
|
||||
putExtra(
|
||||
Track.Extra.FRAGMENT_ARGUMENTS,
|
||||
TrackListFragment.arguments(context, type, id, categoryValue))
|
||||
}
|
||||
|
||||
fun getStartIntent(context: Context): Intent =
|
||||
Intent(context, TrackListActivity::class.java)
|
||||
|
||||
private fun isValidCategory(categoryType: String?, categoryId: Long): Boolean =
|
||||
categoryType != null && categoryType.isNotEmpty() && categoryId != -1L
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ object Track {
|
||||
const val SELECTED_ID = "extra_selected_id"
|
||||
const val TITLE_ID = "extra_title_id"
|
||||
const val CATEGORY_VALUE = "extra_category_value"
|
||||
const val FRAGMENT_ARGUMENTS = "extra_fragment_arguments"
|
||||
}
|
||||
|
||||
object RequestCode {
|
||||
|
@ -1,11 +1,297 @@
|
||||
package io.casey.musikcube.remote.ui.tracks.fragment
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.view.*
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
|
||||
import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.service.websocket.Messages
|
||||
import io.casey.musikcube.remote.service.websocket.model.IDataProvider
|
||||
import io.casey.musikcube.remote.service.websocket.model.ITrack
|
||||
import io.casey.musikcube.remote.service.websocket.model.ITrackListQueryFactory
|
||||
import io.casey.musikcube.remote.ui.home.activity.MainActivity
|
||||
import io.casey.musikcube.remote.ui.shared.activity.Filterable
|
||||
import io.casey.musikcube.remote.ui.shared.activity.TitleProvider
|
||||
import io.casey.musikcube.remote.ui.shared.extension.EXTRA_ACTIVITY_TITLE
|
||||
import io.casey.musikcube.remote.ui.shared.extension.initSearchMenu
|
||||
import io.casey.musikcube.remote.ui.shared.extension.setupDefaultRecyclerView
|
||||
import io.casey.musikcube.remote.ui.shared.extension.showSnackbar
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.BaseFragment
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.DataProviderMixin
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.ItemContextMenuMixin
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.PlaybackMixin
|
||||
import io.casey.musikcube.remote.ui.shared.model.DefaultSlidingWindow
|
||||
import io.casey.musikcube.remote.ui.shared.model.ITrackListSlidingWindow
|
||||
import io.casey.musikcube.remote.ui.shared.view.EmptyListView
|
||||
import io.casey.musikcube.remote.ui.tracks.activity.EditPlaylistActivity
|
||||
import io.casey.musikcube.remote.ui.tracks.activity.TrackListActivity
|
||||
import io.casey.musikcube.remote.ui.tracks.adapter.TrackListAdapter
|
||||
import io.casey.musikcube.remote.ui.tracks.constant.Track
|
||||
import io.casey.musikcube.remote.util.Debouncer
|
||||
import io.casey.musikcube.remote.util.Strings
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class TrackListFragment: BaseFragment(), Filterable, TitleProvider {
|
||||
private lateinit var tracks: DefaultSlidingWindow
|
||||
private lateinit var emptyView: EmptyListView
|
||||
private lateinit var adapter: TrackListAdapter
|
||||
private lateinit var queryFactory: ITrackListQueryFactory
|
||||
|
||||
private lateinit var data: DataProviderMixin
|
||||
private lateinit var playback: PlaybackMixin
|
||||
|
||||
private var categoryType: String = ""
|
||||
private var categoryId: Long = 0
|
||||
private var titleId = R.string.songs_title
|
||||
private var categoryValue: String = ""
|
||||
private var lastFilter = ""
|
||||
|
||||
class TrackListFragment: BaseFragment() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
component.inject(this)
|
||||
data = mixin(DataProviderMixin())
|
||||
playback = mixin(PlaybackMixin())
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mixin(ItemContextMenuMixin(appCompatActivity, menuListener))
|
||||
|
||||
(arguments as Bundle).apply {
|
||||
categoryType = getString(Track.Extra.CATEGORY_TYPE, "")
|
||||
categoryId = getLong(Track.Extra.SELECTED_ID, 0)
|
||||
categoryValue = getString(Track.Extra.CATEGORY_VALUE, "")
|
||||
titleId = getInt(Track.Extra.TITLE_ID, titleId)
|
||||
}
|
||||
|
||||
queryFactory = createCategoryQueryFactory(categoryType, categoryId)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
tracks.pause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
tracks.resume() /* needs to happen first */
|
||||
super.onResume()
|
||||
initObservers()
|
||||
requeryIfViewingOfflineCache()
|
||||
}
|
||||
|
||||
private fun initObservers() =
|
||||
disposables.add(data.provider.observeState().subscribeBy(
|
||||
onNext = { states ->
|
||||
val shouldRequery =
|
||||
states.first === IDataProvider.State.Connected ||
|
||||
(states.first === IDataProvider.State.Disconnected && isOfflineTracks)
|
||||
|
||||
if (shouldRequery) {
|
||||
filterDebouncer.cancel()
|
||||
tracks.requery()
|
||||
}
|
||||
else {
|
||||
emptyView.update(states.first, adapter.itemCount)
|
||||
}
|
||||
},
|
||||
onError = {
|
||||
}))
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
inflater.inflate(R.layout.recycler_view_fragment, container, false).apply {
|
||||
val recyclerView = findViewById<FastScrollRecyclerView>(R.id.recycler_view)
|
||||
|
||||
tracks = DefaultSlidingWindow(recyclerView, data.provider, queryFactory)
|
||||
adapter = TrackListAdapter(tracks, eventListener, playback, prefs)
|
||||
|
||||
setupDefaultRecyclerView(recyclerView, adapter)
|
||||
|
||||
emptyView = findViewById(R.id.empty_list_view)
|
||||
|
||||
emptyView.let {
|
||||
it.capability = if (isOfflineTracks) EmptyListView.Capability.OfflineOk else EmptyListView.Capability.OnlineOnly
|
||||
it.emptyMessage = emptyMessage
|
||||
it.alternateView = recyclerView
|
||||
}
|
||||
|
||||
tracks.setOnMetadataLoadedListener(slidingWindowListener)
|
||||
}
|
||||
|
||||
override val title: String
|
||||
get() = getString(titleId)
|
||||
|
||||
override fun setFilter(filter: String) {
|
||||
lastFilter = filter
|
||||
filterDebouncer.call()
|
||||
}
|
||||
|
||||
fun createOptionsMenu(menu: Menu): Boolean {
|
||||
when (Messages.Category.PLAYLISTS == categoryType) {
|
||||
true -> appCompatActivity.menuInflater.inflate(R.menu.view_playlist_menu, menu)
|
||||
false -> initSearchMenu(menu, this)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun optionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == R.id.action_edit) {
|
||||
startActivityForResult(EditPlaylistActivity.getStartIntent(
|
||||
appCompatActivity, categoryValue, categoryId), Track.RequestCode.EDIT_PLAYLIST)
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
fun activityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == Track.RequestCode.EDIT_PLAYLIST && resultCode == AppCompatActivity.RESULT_OK && data != null) {
|
||||
val playlistName = data.getStringExtra(EditPlaylistActivity.EXTRA_PLAYLIST_NAME) ?: ""
|
||||
val playlistId = data.getLongExtra(EditPlaylistActivity.EXTRA_PLAYLIST_ID, -1L)
|
||||
|
||||
if (categoryType != Messages.Category.PLAYLISTS || playlistId != this.categoryId) {
|
||||
showSnackbar(
|
||||
appCompatActivity.findViewById(android.R.id.content),
|
||||
getString(R.string.playlist_edit_save_success, playlistName),
|
||||
buttonText = getString(R.string.button_view),
|
||||
buttonCb = {
|
||||
startActivity(TrackListActivity.getStartIntent(
|
||||
appCompatActivity, Messages.Category.PLAYLISTS, playlistId, playlistName))
|
||||
})
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
fun notifyTransportChanged() =
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
private val filterDebouncer = object : Debouncer<String>(350) {
|
||||
override fun onDebounced(last: String?) {
|
||||
if (!paused) {
|
||||
tracks.requery()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val emptyMessage: String
|
||||
get() {
|
||||
if (isOfflineTracks) {
|
||||
return getString(R.string.empty_no_offline_tracks_message)
|
||||
}
|
||||
|
||||
return getString(R.string.empty_no_items_format, getString(R.string.browse_type_tracks))
|
||||
}
|
||||
|
||||
private val isOfflineTracks: Boolean
|
||||
get() = Messages.Category.OFFLINE == categoryType
|
||||
|
||||
private fun requeryIfViewingOfflineCache() {
|
||||
if (isOfflineTracks) {
|
||||
tracks.requery()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCategoryQueryFactory(categoryType: String?, categoryId: Long): ITrackListQueryFactory {
|
||||
if (isValidCategory(categoryType, categoryId)) {
|
||||
/* tracks for a specified category (album, artists, genres, etc */
|
||||
return object : ITrackListQueryFactory {
|
||||
override fun count(): Observable<Int> =
|
||||
data.provider.getTrackCountByCategory(categoryType ?: "", categoryId, lastFilter)
|
||||
|
||||
override fun page(offset: Int, limit: Int): Observable<List<ITrack>> =
|
||||
data.provider.getTracksByCategory(categoryType ?: "", categoryId, limit, offset, lastFilter)
|
||||
|
||||
override fun offline(): Boolean =
|
||||
Messages.Category.OFFLINE == categoryType
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* all tracks */
|
||||
return object : ITrackListQueryFactory {
|
||||
override fun count(): Observable<Int> =
|
||||
data.provider.getTrackCount(lastFilter)
|
||||
|
||||
override fun page(offset: Int, limit: Int): Observable<List<ITrack>> =
|
||||
data.provider.getTracks(limit, offset, lastFilter)
|
||||
|
||||
override fun offline(): Boolean =
|
||||
Messages.Category.OFFLINE == categoryType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val slidingWindowListener = object : ITrackListSlidingWindow.OnMetadataLoadedListener {
|
||||
override fun onReloaded(count: Int) =
|
||||
emptyView.update(data.provider.state, count)
|
||||
|
||||
override fun onMetadataLoaded(offset: Int, count: Int) {}
|
||||
}
|
||||
|
||||
private val menuListener: ItemContextMenuMixin.EventListener?
|
||||
get() {
|
||||
if (categoryType == Messages.Category.PLAYLISTS) {
|
||||
return object: ItemContextMenuMixin.EventListener () {
|
||||
override fun onPlaylistUpdated(id: Long, name: String) {
|
||||
tracks.requery()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private val eventListener = object: TrackListAdapter.EventListener {
|
||||
override fun onItemClick(view: View, track: ITrack, position: Int) {
|
||||
if (isValidCategory(categoryType, categoryId)) {
|
||||
playback.service.play(categoryType, categoryId, position, lastFilter)
|
||||
}
|
||||
else {
|
||||
playback.service.playAll(position, lastFilter)
|
||||
}
|
||||
|
||||
startActivity(MainActivity.getStartIntent(appCompatActivity))
|
||||
appCompatActivity.finish() /* TODO: hmmm? */
|
||||
}
|
||||
|
||||
override fun onActionItemClick(view: View, track: ITrack, position: Int) {
|
||||
val mixin = mixin(ItemContextMenuMixin::class.java)!!
|
||||
if (categoryType == Messages.Category.PLAYLISTS) {
|
||||
mixin.showForPlaylistTrack(track, position, categoryId, categoryValue, view)
|
||||
}
|
||||
else {
|
||||
mixin.showForTrack(track, view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "TrackListFragment"
|
||||
|
||||
fun arguments(context: Context,
|
||||
type: String = "",
|
||||
id: Long = 0,
|
||||
categoryValue: String = ""): Bundle = Bundle().apply {
|
||||
putString(Track.Extra.CATEGORY_TYPE, type)
|
||||
putLong(Track.Extra.SELECTED_ID, id)
|
||||
putString(Track.Extra.CATEGORY_VALUE, categoryValue)
|
||||
if (Strings.notEmpty(categoryValue)) {
|
||||
putString(
|
||||
EXTRA_ACTIVITY_TITLE,
|
||||
context.getString(R.string.songs_from_category, categoryValue))
|
||||
}
|
||||
}
|
||||
|
||||
fun create(intent: Intent?): TrackListFragment {
|
||||
return create(intent?.extras?.getBundle(Track.Extra.FRAGMENT_ARGUMENTS) ?: Bundle())
|
||||
}
|
||||
|
||||
fun create(arguments: Bundle = Bundle()): TrackListFragment {
|
||||
return TrackListFragment().apply {
|
||||
this.arguments = arguments
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValidCategory(categoryType: String?, categoryId: Long): Boolean =
|
||||
categoryType != null && categoryType.isNotEmpty() && categoryId != -1L
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user