mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-29 19:20:28 +00:00
More untested refactors.
This commit is contained in:
parent
dbab36feed
commit
04f5f2e645
@ -4,6 +4,7 @@ import dagger.Component
|
||||
import io.casey.musikcube.remote.ui.albums.activity.AlbumBrowseActivity
|
||||
import io.casey.musikcube.remote.ui.category.activity.AllCategoriesActivity
|
||||
import io.casey.musikcube.remote.ui.category.activity.CategoryBrowseActivity
|
||||
import io.casey.musikcube.remote.ui.category.fragment.CategoryBrowseFragment
|
||||
import io.casey.musikcube.remote.ui.home.activity.MainActivity
|
||||
import io.casey.musikcube.remote.ui.home.view.MainMetadataView
|
||||
import io.casey.musikcube.remote.ui.playqueue.activity.PlayQueueActivity
|
||||
@ -12,6 +13,7 @@ import io.casey.musikcube.remote.ui.settings.activity.RemoteEqActivity
|
||||
import io.casey.musikcube.remote.ui.settings.activity.RemoteSettingsActivity
|
||||
import io.casey.musikcube.remote.ui.settings.activity.SettingsActivity
|
||||
import io.casey.musikcube.remote.ui.shared.activity.BaseActivity
|
||||
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.view.EmptyListView
|
||||
@ -32,6 +34,9 @@ interface ViewComponent {
|
||||
fun inject(activity: SettingsActivity)
|
||||
fun inject(activity: TrackListActivity)
|
||||
|
||||
fun inject(fragment: BaseFragment)
|
||||
fun inject(fragment: CategoryBrowseFragment)
|
||||
|
||||
fun inject(view: EmptyListView)
|
||||
fun inject(view: MainMetadataView)
|
||||
|
||||
|
@ -0,0 +1,219 @@
|
||||
package io.casey.musikcube.remote.ui.category.fragment
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
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.ICategoryValue
|
||||
import io.casey.musikcube.remote.service.websocket.model.IDataProvider
|
||||
import io.casey.musikcube.remote.ui.albums.activity.AlbumBrowseActivity
|
||||
import io.casey.musikcube.remote.ui.category.adapter.CategoryBrowseAdapter
|
||||
import io.casey.musikcube.remote.ui.category.constant.Category
|
||||
import io.casey.musikcube.remote.ui.category.constant.NavigationType
|
||||
import io.casey.musikcube.remote.ui.shared.activity.Filterable
|
||||
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.setFabVisible
|
||||
import io.casey.musikcube.remote.ui.shared.extension.setupDefaultRecyclerView
|
||||
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.view.EmptyListView
|
||||
import io.casey.musikcube.remote.ui.tracks.activity.TrackListActivity
|
||||
import io.casey.musikcube.remote.util.Debouncer
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class CategoryBrowseFragment: BaseFragment(), Filterable {
|
||||
private lateinit var adapter: CategoryBrowseAdapter
|
||||
private var navigationType: NavigationType = NavigationType.Tracks
|
||||
private var lastFilter: String? = null
|
||||
private lateinit var category: String
|
||||
private lateinit var predicateType: String
|
||||
private var predicateId: Long = -1
|
||||
private lateinit var rootView: View
|
||||
private lateinit var emptyView: EmptyListView
|
||||
private lateinit var data: DataProviderMixin
|
||||
private lateinit var playback: PlaybackMixin
|
||||
|
||||
val title: String
|
||||
get() {
|
||||
Category.NAME_TO_TITLE[category]?.let {
|
||||
return getString(it)
|
||||
}
|
||||
return Category.toDisplayString(app, category)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
component.inject(this)
|
||||
data = mixin(DataProviderMixin())
|
||||
playback = mixin(PlaybackMixin())
|
||||
mixin(ItemContextMenuMixin(appCompatActivity, contextMenuListener))
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val args = arguments as Bundle
|
||||
category = args.getString(Category.Extra.CATEGORY, "")
|
||||
predicateType = args.getString(Category.Extra.PREDICATE_TYPE, "")
|
||||
predicateId = args.getLong(Category.Extra.PREDICATE_ID, -1)
|
||||
navigationType = NavigationType.get(args.getInt(Category.Extra.NAVIGATION_TYPE, NavigationType.Albums.ordinal))
|
||||
adapter = CategoryBrowseAdapter(adapterListener, playback, navigationType, category, prefs)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
rootView = inflater.inflate(R.layout.recycler_view_activity, container, false)
|
||||
|
||||
rootView.apply {
|
||||
val recyclerView = findViewById<FastScrollRecyclerView>(R.id.recycler_view)
|
||||
val fab = findViewById<View>(R.id.fab)
|
||||
val fabVisible = (category == Messages.Category.PLAYLISTS)
|
||||
|
||||
emptyView = findViewById(R.id.empty_list_view)
|
||||
emptyView.capability = EmptyListView.Capability.OnlineOnly
|
||||
emptyView.emptyMessage = getString(R.string.empty_no_items_format, categoryTypeString)
|
||||
emptyView.alternateView = recyclerView
|
||||
|
||||
findViewById<View>(R.id.fab).setOnClickListener {
|
||||
if (category == Messages.Category.PLAYLISTS) {
|
||||
mixin(ItemContextMenuMixin::class.java)?.createPlaylist()
|
||||
}
|
||||
}
|
||||
|
||||
setupDefaultRecyclerView(recyclerView, adapter)
|
||||
setFabVisible(fabVisible, fab, recyclerView)
|
||||
}
|
||||
|
||||
return rootView
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
initObservers()
|
||||
}
|
||||
|
||||
override fun setFilter(filter: String) {
|
||||
this.lastFilter = filter
|
||||
this.filterDebouncer.call()
|
||||
}
|
||||
|
||||
fun createOptionsMenu(menu: Menu): Boolean {
|
||||
when (Messages.Category.PLAYLISTS == category) {
|
||||
true -> menu.clear()
|
||||
else -> initSearchMenu(menu, this)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun initObservers() {
|
||||
disposables.add(data.provider.observeState().subscribeBy(
|
||||
onNext = { states ->
|
||||
when (states.first) {
|
||||
IDataProvider.State.Connected -> {
|
||||
filterDebouncer.cancel()
|
||||
requery()
|
||||
}
|
||||
IDataProvider.State.Disconnected -> {
|
||||
emptyView.update(states.first, adapter.itemCount)
|
||||
}
|
||||
else -> { }
|
||||
}
|
||||
},
|
||||
onError = {
|
||||
}))
|
||||
}
|
||||
|
||||
private val categoryTypeString: String
|
||||
get() {
|
||||
Category.NAME_TO_EMPTY_TYPE[category]?.let {
|
||||
return getString(it)
|
||||
}
|
||||
return Category.toDisplayString(app, category)
|
||||
}
|
||||
|
||||
private fun requery() {
|
||||
@Suppress("UNUSED")
|
||||
data.provider
|
||||
.getCategoryValues(category, predicateType, predicateId, lastFilter ?: "")
|
||||
.subscribeBy(
|
||||
onNext = { values -> adapter.setModel(values) },
|
||||
onError = { },
|
||||
onComplete = { emptyView.update(data.provider.state, adapter.itemCount)})
|
||||
}
|
||||
|
||||
private val filterDebouncer = object : Debouncer<String>(350) {
|
||||
override fun onDebounced(last: String?) {
|
||||
if (!paused) {
|
||||
requery()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val contextMenuListener = object: ItemContextMenuMixin.EventListener() {
|
||||
override fun onPlaylistDeleted(id: Long, name: String) = requery()
|
||||
|
||||
override fun onPlaylistUpdated(id: Long, name: String) = requery()
|
||||
|
||||
override fun onPlaylistCreated(id: Long, name: String) =
|
||||
if (navigationType == NavigationType.Select) navigateToSelect(id, name) else requery()
|
||||
}
|
||||
|
||||
private val adapterListener = object: CategoryBrowseAdapter.EventListener {
|
||||
override fun onItemClicked(value: ICategoryValue) {
|
||||
when (navigationType) {
|
||||
NavigationType.Albums -> navigateToAlbums(value)
|
||||
NavigationType.Tracks -> navigateToTracks(value)
|
||||
NavigationType.Select -> navigateToSelect(value.id, value.value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActionClicked(view: View, value: ICategoryValue) {
|
||||
mixin(ItemContextMenuMixin::class.java)?.showForCategory(value, view)
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToAlbums(entry: ICategoryValue) =
|
||||
startActivity(AlbumBrowseActivity.getStartIntent(appCompatActivity, category, entry))
|
||||
|
||||
private fun navigateToTracks(entry: ICategoryValue) =
|
||||
startActivity(TrackListActivity.getStartIntent(appCompatActivity, category, entry.id, entry.value))
|
||||
|
||||
private fun navigateToSelect(id: Long, name: String) =
|
||||
appCompatActivity.run {
|
||||
setResult(Activity.RESULT_OK, Intent().apply {
|
||||
putExtra(Category.Extra.CATEGORY, category)
|
||||
putExtra(Category.Extra.ID, id)
|
||||
putExtra(Category.Extra.NAME, name)
|
||||
})
|
||||
finish()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(context: Context,
|
||||
category: String,
|
||||
predicateType: String = "",
|
||||
predicateId: Long = -1,
|
||||
predicateValue: String = ""): CategoryBrowseFragment =
|
||||
CategoryBrowseFragment().apply {
|
||||
this.arguments = Bundle().apply {
|
||||
putString(Category.Extra.CATEGORY, category)
|
||||
putString(Category.Extra.PREDICATE_TYPE, predicateType)
|
||||
putLong(Category.Extra.PREDICATE_ID, predicateId)
|
||||
if (predicateValue.isNotBlank() && Category.NAME_TO_RELATED_TITLE.containsKey(category)) {
|
||||
val format = Category.NAME_TO_RELATED_TITLE[category]
|
||||
when (format) {
|
||||
null -> throw IllegalArgumentException("unknown category $category")
|
||||
else -> putString(EXTRA_ACTIVITY_TITLE, context.getString(format, predicateValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,8 @@ abstract class BaseActivity : AppCompatActivity(), ViewModel.Provider, Runner.Ta
|
||||
}
|
||||
|
||||
protected var disposables = CompositeDisposable()
|
||||
private set
|
||||
|
||||
protected lateinit var prefs: SharedPreferences
|
||||
private var paused = false
|
||||
private val mixins = MixinSet()
|
||||
|
@ -25,6 +25,7 @@ import io.casey.musikcube.remote.Application
|
||||
import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.ui.settings.constants.Prefs
|
||||
import io.casey.musikcube.remote.ui.shared.activity.Filterable
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.BaseFragment
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.TransportFragment
|
||||
import io.casey.musikcube.remote.util.Strings
|
||||
|
||||
@ -40,6 +41,12 @@ fun AppCompatActivity.setupDefaultRecyclerView(
|
||||
recyclerView.addItemDecoration(dividerItemDecoration)
|
||||
}
|
||||
|
||||
fun BaseFragment.setupDefaultRecyclerView(
|
||||
recyclerView: RecyclerView, adapter: RecyclerView.Adapter<*>)
|
||||
{
|
||||
this.appCompatActivity.setupDefaultRecyclerView(recyclerView, adapter)
|
||||
}
|
||||
|
||||
fun RecyclerView.ViewHolder.getColorCompat(resourceId: Int): Int =
|
||||
ContextCompat.getColor(itemView.context, resourceId)
|
||||
|
||||
@ -100,6 +107,10 @@ fun AppCompatActivity.setFabVisible(visible: Boolean, fab: View, recycler: Recyc
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseFragment.setFabVisible(visible: Boolean, fab: View, recyclerView: RecyclerView) {
|
||||
this.appCompatActivity.setFabVisible(visible, fab, recyclerView)
|
||||
}
|
||||
|
||||
fun AppCompatActivity.initSearchMenu(menu: Menu, filterable: Filterable?) {
|
||||
this.menuInflater.inflate(R.menu.search_menu, menu)
|
||||
|
||||
@ -131,6 +142,10 @@ fun AppCompatActivity.initSearchMenu(menu: Menu, filterable: Filterable?) {
|
||||
searchView.setIconifiedByDefault(true)
|
||||
}
|
||||
|
||||
fun Fragment.initSearchMenu(menu: Menu, filterable: Filterable?) {
|
||||
(activity as AppCompatActivity).initSearchMenu(menu, filterable)
|
||||
}
|
||||
|
||||
fun CheckBox.setCheckWithoutEvent(checked: Boolean,
|
||||
listener: (CompoundButton, Boolean) -> Unit) {
|
||||
this.setOnCheckedChangeListener(null)
|
||||
|
@ -1,19 +1,40 @@
|
||||
package io.casey.musikcube.remote.ui.shared.fragment
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.ComposePathEffect
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import io.casey.musikcube.remote.Application
|
||||
import io.casey.musikcube.remote.framework.IMixin
|
||||
import io.casey.musikcube.remote.framework.MixinSet
|
||||
import io.casey.musikcube.remote.framework.ViewModel
|
||||
import io.casey.musikcube.remote.injection.DaggerViewComponent
|
||||
import io.casey.musikcube.remote.injection.ViewComponent
|
||||
import io.casey.musikcube.remote.ui.settings.constants.Prefs
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.ViewModelMixin
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
open class BaseFragment: Fragment(), ViewModel.Provider {
|
||||
private val mixins = MixinSet()
|
||||
protected lateinit var prefs: SharedPreferences
|
||||
protected val component: ViewComponent =
|
||||
DaggerViewComponent.builder()
|
||||
.appComponent(Application.appComponent)
|
||||
.build()
|
||||
|
||||
protected var paused = true
|
||||
private set
|
||||
|
||||
protected var disposables = CompositeDisposable()
|
||||
private set
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
mixins.onCreate(savedInstanceState ?: Bundle())
|
||||
prefs = Application.instance.getSharedPreferences(Prefs.NAME, Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
@ -23,11 +44,15 @@ open class BaseFragment: Fragment(), ViewModel.Provider {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
paused = false
|
||||
mixins.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
disposables.dispose()
|
||||
disposables = CompositeDisposable()
|
||||
paused = true
|
||||
mixins.onPause()
|
||||
}
|
||||
|
||||
@ -55,4 +80,10 @@ open class BaseFragment: Fragment(), ViewModel.Provider {
|
||||
protected fun <T: ViewModel<*>> getViewModel(): T? = mixin(ViewModelMixin::class.java)?.get<T>() as T
|
||||
protected fun <T: IMixin> mixin(mixin: T): T = mixins.add(mixin)
|
||||
protected fun <T: IMixin> mixin(cls: Class<out T>): T? = mixins.get(cls)
|
||||
|
||||
val appCompatActivity: AppCompatActivity
|
||||
get() = activity as AppCompatActivity
|
||||
|
||||
val app: Application
|
||||
get() = Application.instance
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user