mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-29 19:20:28 +00:00
Merge pull request #246 from clangen/clangen/android_ui_2
Second batch of experimental Android UI refactors
This commit is contained in:
commit
83cb366c3a
@ -138,7 +138,7 @@ void CategoryTrackListQuery::RegularQuery(musik::core::db::Connection &db) {
|
||||
std::string limitAndOffset = this->GetLimitAndOffset();
|
||||
|
||||
if (this->filter.size()) {
|
||||
trackFilter = " AND " + category::CATEGORY_TRACKLIST_FILTER;
|
||||
trackFilter = category::CATEGORY_TRACKLIST_FILTER;
|
||||
args.push_back(category::StringArgument(this->filter));
|
||||
args.push_back(category::StringArgument(this->filter));
|
||||
args.push_back(category::StringArgument(this->filter));
|
||||
|
@ -9,11 +9,11 @@ import io.casey.musikcube.remote.service.websocket.model.ICategoryValue
|
||||
import io.casey.musikcube.remote.ui.albums.constant.Album
|
||||
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.constant.Shared
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.BaseFragment
|
||||
import io.casey.musikcube.remote.util.Strings
|
||||
|
||||
class AlbumBrowseActivity : FragmentActivityWithTransport() {
|
||||
class AlbumBrowseActivity: FragmentActivityWithTransport() {
|
||||
private val albums
|
||||
get() = content as AlbumBrowseFragment
|
||||
|
||||
@ -25,6 +25,7 @@ class AlbumBrowseActivity : FragmentActivityWithTransport() {
|
||||
override fun createContentFragment(): BaseFragment =
|
||||
(intent.extras ?: Bundle()).run {
|
||||
AlbumBrowseFragment.create(
|
||||
applicationContext,
|
||||
getString(Album.Extra.CATEGORY_NAME, ""),
|
||||
getLong(Album.Extra.CATEGORY_ID, -1))
|
||||
}
|
||||
@ -42,7 +43,7 @@ class AlbumBrowseActivity : FragmentActivityWithTransport() {
|
||||
fun getStartIntent(context: Context, categoryName: String, categoryId: Long, categoryValue: String): Intent =
|
||||
getStartIntent(context, categoryName, categoryId).apply {
|
||||
if (Strings.notEmpty(categoryValue)) {
|
||||
putExtra(EXTRA_ACTIVITY_TITLE, context.getString(R.string.albums_by_title, categoryValue))
|
||||
putExtra(Shared.Extra.TITLE_OVERRIDE, context.getString(R.string.albums_by_title, categoryValue))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package io.casey.musikcube.remote.ui.albums.fragment
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
@ -15,14 +17,15 @@ import io.casey.musikcube.remote.ui.albums.constant.Album
|
||||
import io.casey.musikcube.remote.ui.shared.activity.IFilterable
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITitleProvider
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITransportObserver
|
||||
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.constant.Shared
|
||||
import io.casey.musikcube.remote.ui.shared.extension.*
|
||||
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.ui.tracks.fragment.TrackListFragment
|
||||
import io.casey.musikcube.remote.util.Debouncer
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
|
||||
@ -36,7 +39,7 @@ class AlbumBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITranspo
|
||||
private lateinit var emptyView: EmptyListView
|
||||
|
||||
override val title: String
|
||||
get() = app.getString(R.string.albums_title)
|
||||
get() = getTitleOverride(app.getString(R.string.albums_title))
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
component.inject(this)
|
||||
@ -55,7 +58,9 @@ class AlbumBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITranspo
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
inflater.inflate(R.layout.recycler_view_fragment, container, false).apply {
|
||||
inflater.inflate(this.getLayoutId(), container, false).apply {
|
||||
ViewCompat.setElevation(this, extras.elevation)
|
||||
|
||||
val recyclerView = findViewById<FastScrollRecyclerView>(R.id.recycler_view)
|
||||
setupDefaultRecyclerView(recyclerView, adapter)
|
||||
|
||||
@ -63,6 +68,8 @@ class AlbumBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITranspo
|
||||
emptyView.capability = EmptyListView.Capability.OnlineOnly
|
||||
emptyView.emptyMessage = getString(R.string.empty_no_items_format, getString(R.string.browse_type_albums))
|
||||
emptyView.alternateView = recyclerView
|
||||
|
||||
initToolbarIfNecessary(appCompatActivity, this)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@ -113,9 +120,28 @@ class AlbumBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITranspo
|
||||
}
|
||||
|
||||
private val eventListener = object: AlbumBrowseAdapter.EventListener {
|
||||
override fun onItemClicked(album: IAlbum) =
|
||||
startActivity(TrackListActivity.getStartIntent(
|
||||
appCompatActivity, Metadata.Category.ALBUM, album.id, album.value))
|
||||
override fun onItemClicked(album: IAlbum) {
|
||||
when (pushContainerId > 0) {
|
||||
true ->
|
||||
pushWithToolbar(
|
||||
pushContainerId,
|
||||
"TracksForAlbum($album.id)",
|
||||
TrackListFragment.create(
|
||||
TrackListFragment.arguments(
|
||||
appCompatActivity,
|
||||
Metadata.Category.ALBUM,
|
||||
album.id,
|
||||
album.value))
|
||||
.pushTo(pushContainerId))
|
||||
false ->
|
||||
startActivity(
|
||||
TrackListActivity.getStartIntent(
|
||||
appCompatActivity,
|
||||
Metadata.Category.ALBUM,
|
||||
album.id,
|
||||
album.value))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActionClicked(view: View, album: IAlbum) {
|
||||
mixin(ItemContextMenuMixin::class.java)?.showForCategory(album, view)
|
||||
@ -124,11 +150,19 @@ class AlbumBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITranspo
|
||||
|
||||
companion object {
|
||||
const val TAG = "AlbumBrowseFragment"
|
||||
fun create(categoryName: String = "", categoryId: Long = -1L): AlbumBrowseFragment =
|
||||
fun create(context: Context,
|
||||
categoryName: String = "",
|
||||
categoryId: Long = -1L,
|
||||
categoryValue: String = ""): AlbumBrowseFragment =
|
||||
AlbumBrowseFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(Album.Extra.CATEGORY_NAME, categoryName)
|
||||
putLong(Album.Extra.CATEGORY_ID, categoryId)
|
||||
if (categoryValue.isNotBlank()) {
|
||||
putString(
|
||||
Shared.Extra.TITLE_OVERRIDE,
|
||||
context.getString(R.string.albums_by_title, categoryValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,108 +3,68 @@ package io.casey.musikcube.remote.ui.browse.activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.FloatingActionButton
|
||||
import android.support.design.widget.TabLayout
|
||||
import android.support.v4.view.ViewPager
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.ui.browse.adapter.BrowseFragmentAdapter
|
||||
import io.casey.musikcube.remote.ui.browse.constant.Browse
|
||||
import io.casey.musikcube.remote.ui.browse.fragment.BrowseFragment
|
||||
import io.casey.musikcube.remote.ui.shared.activity.BaseActivity
|
||||
import io.casey.musikcube.remote.ui.shared.activity.IFabConsumer
|
||||
import io.casey.musikcube.remote.ui.shared.activity.IFilterable
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITransportObserver
|
||||
import io.casey.musikcube.remote.ui.shared.extension.enableUpNavigation
|
||||
import io.casey.musikcube.remote.ui.shared.extension.findFragment
|
||||
import io.casey.musikcube.remote.ui.shared.extension.initSearchMenu
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.TransportFragment
|
||||
|
||||
class BrowseActivity: BaseActivity(), IFilterable {
|
||||
private lateinit var transport: TransportFragment
|
||||
private lateinit var pager: ViewPager
|
||||
private lateinit var tabs: TabLayout
|
||||
private lateinit var fab: FloatingActionButton
|
||||
private lateinit var adapter: BrowseFragmentAdapter
|
||||
|
||||
class BrowseActivity: BaseActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContentView(R.layout.browse_activity)
|
||||
|
||||
adapter = BrowseFragmentAdapter(this, supportFragmentManager)
|
||||
|
||||
pager = findViewById(R.id.view_pager)
|
||||
pager.adapter = adapter
|
||||
pager.currentItem = adapter.indexOf(extras.getString(EXTRA_INITIAL_CATEGORY_TYPE))
|
||||
|
||||
tabs = findViewById(R.id.tab_layout)
|
||||
tabs.setupWithViewPager(pager)
|
||||
|
||||
fab = findViewById(R.id.fab)
|
||||
fab.setOnClickListener {
|
||||
(adapter.fragmentAt(pager.currentItem) as? IFabConsumer)?.onFabPress(fab)
|
||||
if (savedInstanceState == null) {
|
||||
createFragments()
|
||||
}
|
||||
|
||||
when (savedInstanceState == null) {
|
||||
true -> createFragments()
|
||||
else -> restoreFragments()
|
||||
}
|
||||
|
||||
transport.modelChangedListener = {
|
||||
adapter.onTransportChanged()
|
||||
}
|
||||
|
||||
pager.addOnPageChangeListener(object: ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
}
|
||||
|
||||
override fun onPageScrolled(pos: Int, offset: Float, offsetPixels: Int) {
|
||||
}
|
||||
|
||||
override fun onPageSelected(pos: Int) {
|
||||
adapter.fragmentAt(pos)?.let {
|
||||
when (it is IFabConsumer) {
|
||||
true -> {
|
||||
when (it.fabVisible) {
|
||||
true -> fab.show()
|
||||
false -> fab.hide()
|
||||
}
|
||||
}
|
||||
false -> fab.hide()
|
||||
}
|
||||
findFragment<TransportFragment>(TransportFragment.TAG).modelChangedListener = {
|
||||
supportFragmentManager.fragments.forEach {
|
||||
if (it is ITransportObserver) {
|
||||
it.onTransportChanged()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
enableUpNavigation()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
return initSearchMenu(menu, this)
|
||||
}
|
||||
|
||||
override fun setFilter(filter: String) {
|
||||
adapter.filter = filter
|
||||
override fun onBackPressed() {
|
||||
when {
|
||||
supportFragmentManager.backStackEntryCount > 0 -> {
|
||||
supportFragmentManager.popBackStack()
|
||||
}
|
||||
else -> {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFragments() {
|
||||
transport = TransportFragment.create()
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.add(R.id.transport_container, transport, TransportFragment.TAG)
|
||||
.add(
|
||||
R.id.content_container,
|
||||
BrowseFragment.create(extras),
|
||||
BrowseFragment.TAG)
|
||||
.add(
|
||||
R.id.transport_container,
|
||||
TransportFragment.create(),
|
||||
TransportFragment.TAG)
|
||||
.commit()
|
||||
}
|
||||
|
||||
private fun restoreFragments() {
|
||||
transport = findFragment(TransportFragment.TAG)
|
||||
supportFragmentManager.executePendingTransactions()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val EXTRA_INITIAL_CATEGORY_TYPE = "extra_initial_category_type"
|
||||
|
||||
fun getStartIntent(context: Context,
|
||||
initialCategoryType: String = ""): Intent =
|
||||
Intent(context, BrowseActivity::class.java).apply {
|
||||
putExtra(EXTRA_INITIAL_CATEGORY_TYPE, initialCategoryType)
|
||||
putExtra(Browse.Extras.INITIAL_CATEGORY_TYPE, initialCategoryType)
|
||||
}
|
||||
}
|
||||
}
|
@ -13,8 +13,12 @@ import io.casey.musikcube.remote.ui.shared.activity.IFilterable
|
||||
import io.casey.musikcube.remote.ui.tracks.fragment.TrackListFragment
|
||||
import io.casey.musikcube.remote.service.playback.impl.remote.Metadata
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITransportObserver
|
||||
import io.casey.musikcube.remote.ui.shared.extension.pushTo
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.BaseFragment
|
||||
|
||||
class BrowseFragmentAdapter(private val context: Context, fm: FragmentManager): FragmentPagerAdapter(fm) {
|
||||
class BrowseFragmentAdapter(private val context: Context,
|
||||
fm: FragmentManager,
|
||||
private val containerId: Int = -1): FragmentPagerAdapter(fm) {
|
||||
private val fragments = mutableMapOf<Int, Fragment>()
|
||||
|
||||
var filter = ""
|
||||
@ -25,6 +29,8 @@ class BrowseFragmentAdapter(private val context: Context, fm: FragmentManager):
|
||||
}
|
||||
}
|
||||
|
||||
var onFragmentInstantiated: ((Int) -> Unit?)? = null
|
||||
|
||||
fun onTransportChanged() =
|
||||
fragments.forEach {
|
||||
(it.value as? ITransportObserver)?.onTransportChanged()
|
||||
@ -41,15 +47,17 @@ class BrowseFragmentAdapter(private val context: Context, fm: FragmentManager):
|
||||
else -> 0
|
||||
}
|
||||
|
||||
override fun getItem(index: Int): Fragment =
|
||||
when (index) {
|
||||
override fun getItem(index: Int): Fragment {
|
||||
val fragment: BaseFragment = when (index) {
|
||||
0 -> CategoryBrowseFragment.create(
|
||||
CategoryBrowseFragment.arguments(context, Metadata.Category.ALBUM_ARTIST))
|
||||
1 -> AlbumBrowseFragment.create()
|
||||
1 -> AlbumBrowseFragment.create(context)
|
||||
2 -> TrackListFragment.create()
|
||||
else -> CategoryBrowseFragment.create(
|
||||
CategoryBrowseFragment.arguments(Metadata.Category.PLAYLISTS, NavigationType.Tracks))
|
||||
}
|
||||
return fragment.pushTo(this.containerId)
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? =
|
||||
context.getString(when (position) {
|
||||
@ -67,6 +75,7 @@ class BrowseFragmentAdapter(private val context: Context, fm: FragmentManager):
|
||||
val result = super.instantiateItem(container, position)
|
||||
fragments[position] = result as Fragment
|
||||
(result as? IFilterable)?.setFilter(filter)
|
||||
onFragmentInstantiated?.invoke(position)
|
||||
return result
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package io.casey.musikcube.remote.ui.browse.constant
|
||||
|
||||
object Browse {
|
||||
object Extras {
|
||||
const val INITIAL_CATEGORY_TYPE = "extra_initial_category_type"
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package io.casey.musikcube.remote.ui.browse.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.FloatingActionButton
|
||||
import android.support.design.widget.TabLayout
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.support.v4.view.ViewPager
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.ui.browse.adapter.BrowseFragmentAdapter
|
||||
import io.casey.musikcube.remote.ui.browse.constant.Browse
|
||||
import io.casey.musikcube.remote.ui.shared.activity.IFabConsumer
|
||||
import io.casey.musikcube.remote.ui.shared.activity.IFilterable
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITitleProvider
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITransportObserver
|
||||
import io.casey.musikcube.remote.ui.shared.extension.initToolbarIfNecessary
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.BaseFragment
|
||||
|
||||
class BrowseFragment: BaseFragment(), ITransportObserver, IFilterable, ITitleProvider {
|
||||
private lateinit var adapter: BrowseFragmentAdapter
|
||||
|
||||
override val title: String
|
||||
get() = getString(R.string.app_name)
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
|
||||
inflater.inflate(R.layout.browse_fragment, container, false).apply {
|
||||
val fab = findViewById<FloatingActionButton>(R.id.fab)
|
||||
val pager = findViewById<ViewPager>(R.id.view_pager)
|
||||
val tabs = findViewById<TabLayout>(R.id.tab_layout)
|
||||
|
||||
val showFabIfNecessary = { pos: Int ->
|
||||
adapter.fragmentAt(pos)?.let {
|
||||
when (it is IFabConsumer) {
|
||||
true -> {
|
||||
when (it.fabVisible) {
|
||||
true -> fab.show()
|
||||
false -> fab.hide()
|
||||
}
|
||||
}
|
||||
false -> fab.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fab.setOnClickListener {
|
||||
(adapter.fragmentAt(pager.currentItem) as? IFabConsumer)?.onFabPress(fab)
|
||||
}
|
||||
|
||||
adapter = BrowseFragmentAdapter(appCompatActivity, childFragmentManager, R.id.content_container)
|
||||
|
||||
adapter.onFragmentInstantiated = { pos ->
|
||||
if (pos == pager.currentItem) {
|
||||
showFabIfNecessary(pos)
|
||||
}
|
||||
}
|
||||
|
||||
pager.adapter = adapter
|
||||
pager.currentItem = adapter.indexOf(extras.getString(Browse.Extras.INITIAL_CATEGORY_TYPE))
|
||||
|
||||
tabs.setupWithViewPager(pager)
|
||||
|
||||
pager.addOnPageChangeListener(object: ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
}
|
||||
|
||||
override fun onPageScrolled(pos: Int, offset: Float, offsetPixels: Int) {
|
||||
}
|
||||
|
||||
override fun onPageSelected(pos: Int) {
|
||||
showFabIfNecessary(pos)
|
||||
}
|
||||
})
|
||||
|
||||
initToolbarIfNecessary(appCompatActivity, this)
|
||||
|
||||
showFabIfNecessary(pager.currentItem)
|
||||
}
|
||||
|
||||
override fun onTransportChanged() =
|
||||
adapter.onTransportChanged()
|
||||
|
||||
override fun setFilter(filter: String) {
|
||||
adapter.filter = filter
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "BrowseFragment"
|
||||
|
||||
fun create(extras: Bundle): BrowseFragment =
|
||||
BrowseFragment().apply { arguments = extras }
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.FloatingActionButton
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
@ -15,6 +16,7 @@ import io.casey.musikcube.remote.service.playback.impl.remote.Metadata
|
||||
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.albums.fragment.AlbumBrowseFragment
|
||||
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
|
||||
@ -22,36 +24,45 @@ import io.casey.musikcube.remote.ui.shared.activity.IFabConsumer
|
||||
import io.casey.musikcube.remote.ui.shared.activity.IFilterable
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITitleProvider
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITransportObserver
|
||||
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.constant.Shared
|
||||
import io.casey.musikcube.remote.ui.shared.extension.*
|
||||
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.ui.tracks.fragment.TrackListFragment
|
||||
import io.casey.musikcube.remote.util.Debouncer
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
|
||||
class CategoryBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITransportObserver, IFabConsumer {
|
||||
private lateinit var adapter: CategoryBrowseAdapter
|
||||
private var navigationType: NavigationType = NavigationType.Albums
|
||||
private var lastFilter: String? = null
|
||||
private var category: String = ""
|
||||
private 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
|
||||
|
||||
private val navigationType: NavigationType
|
||||
get() = NavigationType.get(extras.getInt(
|
||||
Category.Extra.NAVIGATION_TYPE, NavigationType.Albums.ordinal))
|
||||
|
||||
private val category
|
||||
get() = extras.getString(Category.Extra.CATEGORY, "")
|
||||
|
||||
private val predicateType: String
|
||||
get() = extras.getString(Category.Extra.PREDICATE_TYPE, "")
|
||||
|
||||
private val predicateId: Long
|
||||
get() = extras.getLong(Category.Extra.PREDICATE_ID, -1L)
|
||||
|
||||
override val title: String
|
||||
get() {
|
||||
Category.NAME_TO_TITLE[category]?.let {
|
||||
return getString(it)
|
||||
return getTitleOverride(getString(it))
|
||||
}
|
||||
return Category.toDisplayString(app, category)
|
||||
return getTitleOverride(Category.toDisplayString(app, category))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -62,18 +73,13 @@ class CategoryBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITran
|
||||
playback = mixin(PlaybackMixin())
|
||||
mixin(ItemContextMenuMixin(appCompatActivity, contextMenuListener, this))
|
||||
|
||||
extras.run {
|
||||
category = getString(Category.Extra.CATEGORY, category)
|
||||
predicateType = getString(Category.Extra.PREDICATE_TYPE, predicateType)
|
||||
predicateId = getLong(Category.Extra.PREDICATE_ID, predicateId)
|
||||
navigationType = NavigationType.get(getInt(Category.Extra.NAVIGATION_TYPE, navigationType.ordinal))
|
||||
}
|
||||
|
||||
adapter = CategoryBrowseAdapter(adapterListener, playback, navigationType, category, prefs)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
|
||||
inflater.inflate(R.layout.recycler_view_fragment, container, false).apply {
|
||||
inflater.inflate(this.getLayoutId(), container, false).apply {
|
||||
ViewCompat.setElevation(this, extras.elevation)
|
||||
|
||||
this@CategoryBrowseFragment.rootView = this
|
||||
|
||||
val recyclerView = findViewById<FastScrollRecyclerView>(R.id.recycler_view)
|
||||
@ -84,6 +90,7 @@ class CategoryBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITran
|
||||
emptyView.alternateView = recyclerView
|
||||
|
||||
setupDefaultRecyclerView(recyclerView, adapter)
|
||||
initToolbarIfNecessary(appCompatActivity, this)
|
||||
}
|
||||
|
||||
override fun onFabPress(fab: FloatingActionButton) {
|
||||
@ -188,10 +195,33 @@ class CategoryBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITran
|
||||
}
|
||||
|
||||
private fun navigateToAlbums(entry: ICategoryValue) =
|
||||
startActivity(AlbumBrowseActivity.getStartIntent(appCompatActivity, category, entry))
|
||||
when (pushContainerId > 0) {
|
||||
true ->
|
||||
this.pushWithToolbar(
|
||||
pushContainerId,
|
||||
"AlbumsBy($entry.value)",
|
||||
AlbumBrowseFragment
|
||||
.create(app, entry.type, entry.id, entry.value)
|
||||
.pushTo(pushContainerId))
|
||||
false ->
|
||||
startActivity(AlbumBrowseActivity
|
||||
.getStartIntent(appCompatActivity, category, entry))
|
||||
|
||||
}
|
||||
|
||||
private fun navigateToTracks(entry: ICategoryValue) =
|
||||
startActivity(TrackListActivity.getStartIntent(appCompatActivity, category, entry.id, entry.value))
|
||||
when (this.pushContainerId > 0) {
|
||||
true ->
|
||||
this.pushWithToolbar(
|
||||
this.pushContainerId,
|
||||
"TracksBy($entry.value)",
|
||||
TrackListFragment.create(TrackListFragment
|
||||
.arguments(appCompatActivity, entry.type, entry.id))
|
||||
.pushTo(pushContainerId))
|
||||
false ->
|
||||
startActivity(TrackListActivity.getStartIntent(
|
||||
appCompatActivity, category, entry.id, entry.value))
|
||||
}
|
||||
|
||||
private fun navigateToSelect(id: Long, name: String) =
|
||||
appCompatActivity.run {
|
||||
@ -231,7 +261,7 @@ class CategoryBrowseFragment: BaseFragment(), IFilterable, ITitleProvider, ITran
|
||||
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))
|
||||
else -> putString(Shared.Extra.TITLE_OVERRIDE, context.getString(format, predicateValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,9 @@ package io.casey.musikcube.remote.ui.shared.activity
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.FloatingActionButton
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.ui.shared.extension.enableUpNavigation
|
||||
import io.casey.musikcube.remote.ui.shared.extension.findFragment
|
||||
import io.casey.musikcube.remote.ui.shared.extension.setTitleFromIntent
|
||||
import io.casey.musikcube.remote.ui.shared.extension.*
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.BaseFragment
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.TransportFragment
|
||||
|
||||
@ -49,15 +48,32 @@ abstract class FragmentActivityWithTransport: BaseActivity(), IFilterable {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(content as? ITitleProvider)?.run {
|
||||
setTitleFromIntent(this.title)
|
||||
if (!content.hasToolbar) {
|
||||
(content as? ITitleProvider)?.run {
|
||||
setTitleFromIntent(this.title)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean =
|
||||
(content as? IMenuProvider)?.run {
|
||||
return this.createOptionsMenu(menu)
|
||||
} ?: false
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
if (!content.hasToolbar) {
|
||||
(content as? IMenuProvider)?.run {
|
||||
return this.createOptionsMenu(menu)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (!content.hasToolbar) {
|
||||
(content as? IMenuProvider)?.run {
|
||||
if (this.optionsItemSelected(item)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun setFilter(filter: String) =
|
||||
(content as? IFilterable)?.run {
|
||||
@ -73,6 +89,8 @@ abstract class FragmentActivityWithTransport: BaseActivity(), IFilterable {
|
||||
|
||||
private fun createFragments() {
|
||||
content = createContentFragment()
|
||||
.withToolbar()
|
||||
.withTitleOverride(this)
|
||||
transport = TransportFragment.create()
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
|
@ -1,7 +1,9 @@
|
||||
package io.casey.musikcube.remote.ui.shared.activity
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
|
||||
interface IMenuProvider {
|
||||
fun createOptionsMenu(menu: Menu): Boolean
|
||||
fun optionsItemSelected(menuItem: MenuItem): Boolean
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package io.casey.musikcube.remote.ui.shared.constant
|
||||
|
||||
object Shared {
|
||||
object Extra {
|
||||
const val TITLE_OVERRIDE = "extra_title_override"
|
||||
const val WITH_TOOLBAR = "extra_with_toolbar"
|
||||
const val PUSH_CONTAINER_ID = "extra_push_container_id"
|
||||
const val ELEVATION = "extra_elevation"
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package io.casey.musikcube.remote.ui.shared.extension
|
||||
import android.app.SearchManager
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v4.app.Fragment
|
||||
@ -23,14 +24,47 @@ 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.IFilterable
|
||||
import io.casey.musikcube.remote.ui.shared.activity.IMenuProvider
|
||||
import io.casey.musikcube.remote.ui.shared.constant.Shared
|
||||
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
|
||||
|
||||
const val EXTRA_ACTIVITY_TITLE = "extra_title"
|
||||
/*
|
||||
*
|
||||
* SharedPreferences
|
||||
*
|
||||
*/
|
||||
|
||||
fun SharedPreferences.getString(key: String): String? =
|
||||
when (!this.contains(key)) {
|
||||
true -> null
|
||||
else -> this.getString(key, "")
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Toolbar
|
||||
*
|
||||
*/
|
||||
|
||||
fun Toolbar.initSearchMenu(activity: AppCompatActivity, filterable: IFilterable?): Boolean =
|
||||
activity.initSearchMenu(this.menu, filterable)
|
||||
|
||||
fun Toolbar.setTitleFromIntent(defaultTitle: String) {
|
||||
val extras = (context as? AppCompatActivity)?.intent?.extras ?: Bundle()
|
||||
val title = extras.getString(Shared.Extra.TITLE_OVERRIDE)
|
||||
this.title = if (Strings.notEmpty(title)) title else defaultTitle
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* AppCompatActivity
|
||||
*
|
||||
*/
|
||||
|
||||
fun AppCompatActivity.setupDefaultRecyclerView(
|
||||
recyclerView: RecyclerView, adapter: RecyclerView.Adapter<*>)
|
||||
recyclerView: RecyclerView, adapter: RecyclerView.Adapter<*>)
|
||||
{
|
||||
val layoutManager = LinearLayoutManager(this)
|
||||
val dividerItemDecoration = DividerItemDecoration(this, layoutManager.orientation)
|
||||
@ -39,23 +73,6 @@ 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)
|
||||
|
||||
fun View.getColorCompat(resourceId: Int): Int =
|
||||
ContextCompat.getColor(context, resourceId)
|
||||
|
||||
fun Fragment.getColorCompat(resourceId: Int): Int =
|
||||
ContextCompat.getColor(activity!!, resourceId)
|
||||
|
||||
fun AppCompatActivity.getColorCompat(resourceId: Int): Int =
|
||||
ContextCompat.getColor(this, resourceId)
|
||||
|
||||
val AppCompatActivity.toolbar: Toolbar?
|
||||
get() = findViewById(R.id.toolbar)
|
||||
@ -74,9 +91,9 @@ fun AppCompatActivity.addTransportFragment(
|
||||
val fragment = TransportFragment.create()
|
||||
|
||||
this.supportFragmentManager
|
||||
.beginTransaction()
|
||||
.add(R.id.transport_container, fragment, TransportFragment.TAG)
|
||||
.commit()
|
||||
.beginTransaction()
|
||||
.add(R.id.transport_container, fragment, TransportFragment.TAG)
|
||||
.commit()
|
||||
|
||||
fragment.modelChangedListener = listener
|
||||
return fragment
|
||||
@ -86,10 +103,10 @@ fun AppCompatActivity.addTransportFragment(
|
||||
}
|
||||
|
||||
fun AppCompatActivity.setTitleFromIntent(defaultId: Int) =
|
||||
this.setTitleFromIntent(getString(defaultId))
|
||||
this.setTitleFromIntent(getString(defaultId))
|
||||
|
||||
fun AppCompatActivity.setTitleFromIntent(defaultTitle: String) {
|
||||
val title = this.intent.getStringExtra(EXTRA_ACTIVITY_TITLE)
|
||||
val title = this.intent.getStringExtra(Shared.Extra.TITLE_OVERRIDE)
|
||||
this.title = if (Strings.notEmpty(title)) title else defaultTitle
|
||||
}
|
||||
|
||||
@ -126,56 +143,144 @@ fun AppCompatActivity.initSearchMenu(menu: Menu, filterable: IFilterable?): Bool
|
||||
return true
|
||||
}
|
||||
|
||||
fun Fragment.initSearchMenu(menu: Menu, filterable: IFilterable?): Boolean =
|
||||
(activity as AppCompatActivity).initSearchMenu(menu, filterable)
|
||||
|
||||
fun CheckBox.setCheckWithoutEvent(checked: Boolean,
|
||||
listener: (CompoundButton, Boolean) -> Unit) {
|
||||
this.setOnCheckedChangeListener(null)
|
||||
this.isChecked = checked
|
||||
this.setOnCheckedChangeListener(listener)
|
||||
}
|
||||
|
||||
fun EditText.setTextAndMoveCursorToEnd(text: String) {
|
||||
this.setText(text)
|
||||
this.setSelection(this.text.length)
|
||||
}
|
||||
|
||||
fun View.setVisible(visible: Boolean) {
|
||||
this.visibility = if (visible) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
fun AppCompatActivity.dpToPx(dp: Float): Float = dp * this.resources.displayMetrics.density
|
||||
|
||||
fun showKeyboard(context: Context) {
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY)
|
||||
}
|
||||
|
||||
fun hideKeyboard(context: Context, view: View) {
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
}
|
||||
|
||||
fun AppCompatActivity.showKeyboard() = showKeyboard(this)
|
||||
|
||||
fun AppCompatActivity.hideKeyboard(view: View? = null) {
|
||||
val v = view ?: this.findViewById(android.R.id.content)
|
||||
hideKeyboard(this, v)
|
||||
}
|
||||
|
||||
fun DialogFragment.showKeyboard() = showKeyboard(activity!!)
|
||||
|
||||
fun DialogFragment.hideKeyboard() =
|
||||
hideKeyboard(activity!!, activity!!.findViewById(android.R.id.content))
|
||||
|
||||
fun AppCompatActivity.dialogVisible(tag: String): Boolean =
|
||||
this.supportFragmentManager.findFragmentByTag(tag) != null
|
||||
this.supportFragmentManager.findFragmentByTag(tag) != null
|
||||
|
||||
fun AppCompatActivity.showDialog(dialog: DialogFragment, tag: String) {
|
||||
dialog.show(this.supportFragmentManager, tag)
|
||||
}
|
||||
|
||||
fun AppCompatActivity.slideNextUp() = overridePendingTransition(R.anim.slide_up, R.anim.stay_put)
|
||||
|
||||
fun AppCompatActivity.slideThisDown() = overridePendingTransition(R.anim.stay_put, R.anim.slide_down)
|
||||
|
||||
fun AppCompatActivity.slideNextLeft() = overridePendingTransition(R.anim.slide_left, R.anim.slide_left_bg)
|
||||
|
||||
fun AppCompatActivity.slideThisRight() = overridePendingTransition(R.anim.slide_right_bg, R.anim.slide_right)
|
||||
|
||||
inline fun <reified T> AppCompatActivity.findFragment(tag: String): T {
|
||||
return this.supportFragmentManager.find(tag)
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Bundle
|
||||
*
|
||||
*/
|
||||
|
||||
fun Bundle.withElevation(fm: FragmentManager): Bundle {
|
||||
this.putFloat(Shared.Extra.ELEVATION, (fm.backStackEntryCount + 1) * 16.0f)
|
||||
return this
|
||||
}
|
||||
|
||||
val Bundle.elevation: Float
|
||||
get() = this.getFloat(Shared.Extra.ELEVATION, 0.0f)
|
||||
|
||||
/*
|
||||
*
|
||||
* BaseFragment
|
||||
*
|
||||
*/
|
||||
|
||||
val BaseFragment.pushContainerId: Int
|
||||
get() = this.extras.getInt(Shared.Extra.PUSH_CONTAINER_ID, -1)
|
||||
|
||||
inline fun <reified T: BaseFragment> T.pushTo(containerId: Int): T {
|
||||
if (containerId > 0) {
|
||||
this.extras.putInt(Shared.Extra.PUSH_CONTAINER_ID, containerId)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <reified T: BaseFragment> T.pushTo(other: BaseFragment): T {
|
||||
this.pushTo(other.pushContainerId)
|
||||
return this
|
||||
}
|
||||
|
||||
fun BaseFragment.pushWithToolbar(containerId: Int, backstackId: String, fragment: BaseFragment) {
|
||||
appCompatActivity.supportFragmentManager
|
||||
.beginTransaction()
|
||||
.setCustomAnimations(
|
||||
R.anim.slide_left, R.anim.slide_left_bg,
|
||||
R.anim.slide_right_bg, R.anim.slide_right)
|
||||
.replace(
|
||||
containerId,
|
||||
fragment
|
||||
.withToolbar()
|
||||
.addElevation(appCompatActivity.supportFragmentManager))
|
||||
.addToBackStack(backstackId)
|
||||
.commit()
|
||||
}
|
||||
|
||||
inline fun <reified T: BaseFragment> T.withToolbar(): T {
|
||||
this.arguments?.putBoolean(Shared.Extra.WITH_TOOLBAR, true)
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <reified T: BaseFragment> T.withTitleOverride(activity: AppCompatActivity): T {
|
||||
activity.intent?.getStringExtra(Shared.Extra.TITLE_OVERRIDE)?.let {
|
||||
if (it.isNotEmpty()) {
|
||||
this.extras.putString(Shared.Extra.TITLE_OVERRIDE, it)
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun BaseFragment.initSearchMenu(menu: Menu, filterable: IFilterable?): Boolean =
|
||||
(activity as AppCompatActivity).initSearchMenu(menu, filterable)
|
||||
|
||||
fun BaseFragment.initToolbarIfNecessary(activity: AppCompatActivity, view: View, searchMenu: Boolean = true) {
|
||||
view.findViewById<Toolbar>(R.id.toolbar)?.let {
|
||||
it.navigationIcon = appCompatActivity.getDrawable(R.drawable.ic_back)
|
||||
it.setNavigationOnClickListener {
|
||||
appCompatActivity.onBackPressed()
|
||||
}
|
||||
if (searchMenu) {
|
||||
it.initSearchMenu(activity, this as? IFilterable)
|
||||
}
|
||||
if (this is IMenuProvider) {
|
||||
this.createOptionsMenu(it.menu)
|
||||
it.setOnMenuItemClickListener {
|
||||
menuItem -> this.optionsItemSelected(menuItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseFragment.getLayoutId(): Int =
|
||||
when (this.extras.getBoolean(Shared.Extra.WITH_TOOLBAR)) {
|
||||
true -> R.layout.recycler_view_with_empty_state_and_toolbar_and_fab
|
||||
else -> R.layout.recycler_view_with_empty_state
|
||||
}
|
||||
|
||||
inline fun <reified T: BaseFragment> T.addElevation(fm: FragmentManager): T {
|
||||
this.extras.withElevation(fm)
|
||||
return this
|
||||
}
|
||||
|
||||
fun BaseFragment.setupDefaultRecyclerView(
|
||||
recyclerView: RecyclerView, adapter: RecyclerView.Adapter<*>)
|
||||
{
|
||||
this.appCompatActivity.setupDefaultRecyclerView(recyclerView, adapter)
|
||||
}
|
||||
|
||||
fun BaseFragment.getTitleOverride(defaultId: Int): String =
|
||||
this.getTitleOverride(getString(defaultId))
|
||||
|
||||
fun BaseFragment.getTitleOverride(defaultTitle: String): String {
|
||||
val title = this.extras.getString(Shared.Extra.TITLE_OVERRIDE) ?: ""
|
||||
return if (Strings.notEmpty(title)) title else defaultTitle
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Snackbar
|
||||
*
|
||||
*/
|
||||
|
||||
fun showSnackbar(view: View, text: String, bgColor: Int, fgColor: Int, buttonText: String? = null, buttonCb: ((View) -> Unit)? = null) {
|
||||
val sb = Snackbar.make(view, text, Snackbar.LENGTH_LONG)
|
||||
|
||||
@ -213,24 +318,89 @@ fun AppCompatActivity.showSnackbar(stringId: Int, buttonText: String? = null, bu
|
||||
showSnackbar(this.findViewById<View>(android.R.id.content), stringId, buttonText, buttonCb)
|
||||
|
||||
fun AppCompatActivity.showSnackbar(stringId: String, buttonText: String? = null, buttonCb: ((View) -> Unit)? = null) =
|
||||
showSnackbar(this.findViewById<View>(android.R.id.content), stringId, buttonText, buttonCb)
|
||||
showSnackbar(this.findViewById<View>(android.R.id.content), stringId, buttonText, buttonCb)
|
||||
|
||||
fun AppCompatActivity.showSnackbar(viewId: Int, stringId: Int, buttonText: String? = null, buttonCb: ((View) -> Unit)? = null) =
|
||||
showSnackbar(this.findViewById<View>(viewId), stringId, buttonText, buttonCb)
|
||||
|
||||
fun fallback(input: String?, fallback: String): String =
|
||||
if (input.isNullOrEmpty()) fallback else input
|
||||
/*
|
||||
*
|
||||
* View 1-offs
|
||||
*
|
||||
*/
|
||||
|
||||
fun fallback(input: String?, fallback: Int): String =
|
||||
if (input.isNullOrEmpty()) Application.instance.getString(fallback) else input
|
||||
fun CheckBox.setCheckWithoutEvent(checked: Boolean,
|
||||
listener: (CompoundButton, Boolean) -> Unit) {
|
||||
this.setOnCheckedChangeListener(null)
|
||||
this.isChecked = checked
|
||||
this.setOnCheckedChangeListener(listener)
|
||||
}
|
||||
|
||||
fun AppCompatActivity.slideNextUp() = overridePendingTransition(R.anim.slide_up, R.anim.stay_put)
|
||||
fun EditText.setTextAndMoveCursorToEnd(text: String) {
|
||||
this.setText(text)
|
||||
this.setSelection(this.text.length)
|
||||
}
|
||||
|
||||
fun AppCompatActivity.slideThisDown() = overridePendingTransition(R.anim.stay_put, R.anim.slide_down)
|
||||
fun View.setVisible(visible: Boolean) {
|
||||
this.visibility = if (visible) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
fun AppCompatActivity.slideNextLeft() = overridePendingTransition(R.anim.slide_left, R.anim.slide_left_bg)
|
||||
inline fun <reified T> FragmentManager.find(tag: String): T {
|
||||
return findFragmentByTag(tag) as T
|
||||
}
|
||||
|
||||
fun AppCompatActivity.slideThisRight() = overridePendingTransition(R.anim.slide_right_bg, R.anim.slide_right)
|
||||
/*
|
||||
*
|
||||
* Colors
|
||||
*
|
||||
*/
|
||||
|
||||
fun RecyclerView.ViewHolder.getColorCompat(resourceId: Int): Int =
|
||||
ContextCompat.getColor(itemView.context, resourceId)
|
||||
|
||||
fun View.getColorCompat(resourceId: Int): Int =
|
||||
ContextCompat.getColor(context, resourceId)
|
||||
|
||||
fun Fragment.getColorCompat(resourceId: Int): Int =
|
||||
ContextCompat.getColor(activity!!, resourceId)
|
||||
|
||||
fun AppCompatActivity.getColorCompat(resourceId: Int): Int =
|
||||
ContextCompat.getColor(this, resourceId)
|
||||
|
||||
/*
|
||||
*
|
||||
* Keyboard
|
||||
*
|
||||
*/
|
||||
|
||||
fun showKeyboard(context: Context) {
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY)
|
||||
}
|
||||
|
||||
fun hideKeyboard(context: Context, view: View) {
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
}
|
||||
|
||||
fun AppCompatActivity.showKeyboard() = showKeyboard(this)
|
||||
|
||||
fun AppCompatActivity.hideKeyboard(view: View? = null) {
|
||||
val v = view ?: this.findViewById(android.R.id.content)
|
||||
hideKeyboard(this, v)
|
||||
}
|
||||
|
||||
fun DialogFragment.showKeyboard() =
|
||||
showKeyboard(activity!!)
|
||||
|
||||
fun DialogFragment.hideKeyboard() =
|
||||
hideKeyboard(activity!!, activity!!.findViewById(android.R.id.content))
|
||||
|
||||
/*
|
||||
*
|
||||
* misc
|
||||
*
|
||||
*/
|
||||
|
||||
fun <T1: Any, T2: Any, R: Any> letMany(p1: T1?, p2: T2?, block: (T1, T2) -> R?): R? {
|
||||
return if (p1 != null && p2 != null) block(p1, p2) else null
|
||||
@ -249,8 +419,8 @@ fun <T1: Any, T2: Any, T3: Any, T4: Any, T5: Any, R: Any> letMany(p1: T1?, p2: T
|
||||
|
||||
fun titleEllipsizeMode(prefs: SharedPreferences): TextUtils.TruncateAt {
|
||||
val modeIndex = prefs.getInt(
|
||||
Prefs.Key.TITLE_ELLIPSIS_MODE_INDEX,
|
||||
Prefs.Default.TITLE_ELLIPSIS_SIZE_INDEX)
|
||||
Prefs.Key.TITLE_ELLIPSIS_MODE_INDEX,
|
||||
Prefs.Default.TITLE_ELLIPSIS_SIZE_INDEX)
|
||||
|
||||
return when(modeIndex) {
|
||||
0 -> TextUtils.TruncateAt.START
|
||||
@ -259,16 +429,8 @@ fun titleEllipsizeMode(prefs: SharedPreferences): TextUtils.TruncateAt {
|
||||
}
|
||||
}
|
||||
|
||||
fun SharedPreferences.getString(key: String): String? =
|
||||
when (!this.contains(key)) {
|
||||
true -> null
|
||||
else -> this.getString(key, "")
|
||||
}
|
||||
fun fallback(input: String?, fallback: String): String =
|
||||
if (input.isNullOrEmpty()) fallback else input
|
||||
|
||||
inline fun <reified T> FragmentManager.find(tag: String): T {
|
||||
return findFragmentByTag(tag) as T
|
||||
}
|
||||
|
||||
inline fun <reified T> AppCompatActivity.findFragment(tag: String): T {
|
||||
return this.supportFragmentManager.find(tag)
|
||||
}
|
||||
fun fallback(input: String?, fallback: Int): String =
|
||||
if (input.isNullOrEmpty()) Application.instance.getString(fallback) else input
|
||||
|
@ -7,6 +7,8 @@ import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.view.animation.Animation
|
||||
import io.casey.musikcube.remote.Application
|
||||
import io.casey.musikcube.remote.framework.IMixin
|
||||
import io.casey.musikcube.remote.framework.MixinSet
|
||||
@ -14,8 +16,15 @@ 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.activity.ITitleProvider
|
||||
import io.casey.musikcube.remote.ui.shared.extension.setTitleFromIntent
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.ViewModelMixin
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import android.view.animation.AlphaAnimation
|
||||
import android.view.animation.AnimationUtils
|
||||
import io.casey.musikcube.remote.R
|
||||
import java.lang.Exception
|
||||
|
||||
|
||||
open class BaseFragment: Fragment(), ViewModel.Provider {
|
||||
private val mixins = MixinSet()
|
||||
@ -51,6 +60,9 @@ open class BaseFragment: Fragment(), ViewModel.Provider {
|
||||
super.onResume()
|
||||
paused = false
|
||||
mixins.onResume()
|
||||
if (this is ITitleProvider) {
|
||||
toolbar?.setTitleFromIntent(title)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
@ -81,17 +93,69 @@ open class BaseFragment: Fragment(), ViewModel.Provider {
|
||||
mixins.onDestroy()
|
||||
}
|
||||
|
||||
/* https://stackoverflow.com/a/23276145 */
|
||||
override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
|
||||
val parent = parentFragment
|
||||
|
||||
/* only apply for childFragmentManager transitions */
|
||||
return when (!enter && parent != null && parent.isRemoving) {
|
||||
true -> {
|
||||
/* this is a workaround for the bug where child fragments disappear when
|
||||
the parent is removed (as all children are first removed from the parent)
|
||||
See https://code.google.com/p/android/issues/detail?id=55228 */
|
||||
val doNothingAnim = AlphaAnimation(1f, 1f)
|
||||
doNothingAnim.duration = getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION)
|
||||
doNothingAnim
|
||||
}
|
||||
false -> {
|
||||
super.onCreateAnimation(transit, enter, nextAnim)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T: ViewModel<*>> createViewModel(): T? = null
|
||||
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)
|
||||
|
||||
protected val extras: Bundle
|
||||
get() = arguments ?: Bundle()
|
||||
val hasToolbar: Boolean
|
||||
get() = this.toolbar != null
|
||||
|
||||
val toolbar: Toolbar?
|
||||
get() = this.view?.findViewById(R.id.toolbar)
|
||||
|
||||
val extras: Bundle
|
||||
get() {
|
||||
if (arguments == null) {
|
||||
arguments = Bundle()
|
||||
}
|
||||
return arguments!!
|
||||
}
|
||||
|
||||
val appCompatActivity: AppCompatActivity
|
||||
get() = activity as AppCompatActivity
|
||||
|
||||
val app: Application
|
||||
get() = Application.instance
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_CHILD_ANIMATION_DURATION = 250L
|
||||
|
||||
private fun getNextAnimationDuration(fragment: Fragment, defValue: Long): Long =
|
||||
try {
|
||||
/* attempt to get the resource ID of the next animation that
|
||||
will be applied to the given fragment. */
|
||||
val nextAnimField = Fragment::class.java.getDeclaredField("mNextAnim")
|
||||
nextAnimField.isAccessible = true
|
||||
val nextAnimResource = nextAnimField.getInt(fragment)
|
||||
val nextAnim = AnimationUtils.loadAnimation(fragment.activity, nextAnimResource)
|
||||
when (nextAnim == null) {
|
||||
true -> defValue
|
||||
false -> nextAnim.duration
|
||||
}
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
defValue
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ class TransportFragment: BaseFragment() {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
|
||||
{
|
||||
this.rootView = inflater.inflate(R.layout.fragment_transport, container, false)
|
||||
this.rootView = inflater.inflate(R.layout.transport_fragment, container, false)
|
||||
bindEventHandlers()
|
||||
rebindUi()
|
||||
return this.rootView
|
||||
|
@ -7,12 +7,11 @@ import android.view.MenuItem
|
||||
import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.service.playback.impl.remote.Metadata
|
||||
import io.casey.musikcube.remote.ui.shared.activity.FragmentActivityWithTransport
|
||||
import io.casey.musikcube.remote.ui.shared.activity.IFilterable
|
||||
import io.casey.musikcube.remote.ui.shared.fragment.BaseFragment
|
||||
import io.casey.musikcube.remote.ui.tracks.constant.Track
|
||||
import io.casey.musikcube.remote.ui.tracks.fragment.TrackListFragment
|
||||
|
||||
class TrackListActivity : FragmentActivityWithTransport(), IFilterable {
|
||||
class TrackListActivity: FragmentActivityWithTransport() {
|
||||
private val tracks
|
||||
get() = content as TrackListFragment
|
||||
|
||||
|
@ -3,6 +3,7 @@ package io.casey.musikcube.remote.ui.tracks.fragment
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.view.*
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
|
||||
@ -13,12 +14,11 @@ 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.IFilterable
|
||||
import io.casey.musikcube.remote.ui.shared.activity.IMenuProvider
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITitleProvider
|
||||
import io.casey.musikcube.remote.ui.shared.activity.ITransportObserver
|
||||
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.constant.Shared
|
||||
import io.casey.musikcube.remote.ui.shared.extension.*
|
||||
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
|
||||
@ -35,7 +35,7 @@ import io.casey.musikcube.remote.util.Strings
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
|
||||
class TrackListFragment: BaseFragment(), IFilterable, ITitleProvider, ITransportObserver {
|
||||
class TrackListFragment: BaseFragment(), IFilterable, ITitleProvider, ITransportObserver, IMenuProvider {
|
||||
private lateinit var tracks: DefaultSlidingWindow
|
||||
private lateinit var emptyView: EmptyListView
|
||||
private lateinit var adapter: TrackListAdapter
|
||||
@ -100,13 +100,16 @@ class TrackListFragment: BaseFragment(), IFilterable, ITitleProvider, ITransport
|
||||
}))
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
inflater.inflate(R.layout.recycler_view_fragment, container, false).apply {
|
||||
inflater.inflate(this.getLayoutId(), container, false).apply {
|
||||
ViewCompat.setElevation(this, extras.elevation)
|
||||
|
||||
val recyclerView = findViewById<FastScrollRecyclerView>(R.id.recycler_view)
|
||||
|
||||
tracks = DefaultSlidingWindow(recyclerView, data.provider, queryFactory)
|
||||
adapter = TrackListAdapter(tracks, eventListener, playback, prefs)
|
||||
|
||||
setupDefaultRecyclerView(recyclerView, adapter)
|
||||
initToolbarIfNecessary(appCompatActivity, this, searchMenu = false)
|
||||
|
||||
emptyView = findViewById(R.id.empty_list_view)
|
||||
|
||||
@ -119,37 +122,7 @@ class TrackListFragment: BaseFragment(), IFilterable, ITitleProvider, ITransport
|
||||
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 (Metadata.Category.PLAYLISTS == categoryType) {
|
||||
true -> appCompatActivity.menuInflater.inflate(R.menu.view_playlist_menu, menu)
|
||||
false -> initSearchMenu(menu, this)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun optionsItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId == R.id.action_edit) {
|
||||
true -> {
|
||||
appCompatActivity.startActivityForResult(
|
||||
EditPlaylistActivity.getStartIntent(
|
||||
appCompatActivity,
|
||||
categoryValue,
|
||||
categoryId),
|
||||
Track.RequestCode.EDIT_PLAYLIST)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
fun activityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
override fun onActivityResult(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)
|
||||
@ -168,6 +141,36 @@ class TrackListFragment: BaseFragment(), IFilterable, ITitleProvider, ITransport
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override val title: String
|
||||
get() = getTitleOverride(getString(titleId))
|
||||
|
||||
override fun setFilter(filter: String) {
|
||||
lastFilter = filter
|
||||
filterDebouncer.call()
|
||||
}
|
||||
|
||||
override fun createOptionsMenu(menu: Menu): Boolean {
|
||||
when (Metadata.Category.PLAYLISTS == categoryType) {
|
||||
true -> appCompatActivity.menuInflater.inflate(R.menu.view_playlist_menu, menu)
|
||||
false -> initSearchMenu(menu, this)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun optionsItemSelected(menuItem: MenuItem): Boolean =
|
||||
when (menuItem.itemId == R.id.action_edit) {
|
||||
true -> {
|
||||
appCompatActivity.startActivityForResult(
|
||||
EditPlaylistActivity.getStartIntent(
|
||||
appCompatActivity,
|
||||
categoryValue,
|
||||
categoryId),
|
||||
Track.RequestCode.EDIT_PLAYLIST)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun onTransportChanged() {
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
@ -283,7 +286,7 @@ class TrackListFragment: BaseFragment(), IFilterable, ITitleProvider, ITransport
|
||||
putString(Track.Extra.CATEGORY_VALUE, categoryValue)
|
||||
if (Strings.notEmpty(categoryValue)) {
|
||||
putString(
|
||||
EXTRA_ACTIVITY_TITLE,
|
||||
Shared.Extra.TITLE_OVERRIDE,
|
||||
context.getString(R.string.songs_from_category, categoryValue))
|
||||
}
|
||||
}
|
||||
|
5
src/musikdroid/app/src/main/res/drawable-v21/ic_back.xml
Normal file
5
src/musikdroid/app/src/main/res/drawable-v21/ic_back.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorControlNormal" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
||||
</vector>
|
@ -1,58 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
<FrameLayout
|
||||
android:id="@+id/content_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap" />
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/color_primary" />
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/fab_padding"
|
||||
android:src="@drawable/ic_fab_add"
|
||||
android:scaleType="center"
|
||||
android:elevation="6dp"
|
||||
android:visibility="gone"
|
||||
app:layout_anchor="@id/view_pager"
|
||||
app:layout_anchorGravity="bottom|right"
|
||||
app:backgroundTint="@color/color_primary"
|
||||
app:fabSize="mini"
|
||||
app:rippleColor="?colorAccent"/>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
android:layout_weight="1.0" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/transport_container"
|
||||
|
49
src/musikdroid/app/src/main/res/layout/browse_fragment.xml
Normal file
49
src/musikdroid/app/src/main/res/layout/browse_fragment.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap" />
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/color_primary" />
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/fab_padding"
|
||||
android:src="@drawable/ic_fab_add"
|
||||
android:scaleType="center"
|
||||
android:elevation="6dp"
|
||||
android:visibility="gone"
|
||||
app:layout_anchor="@id/view_pager"
|
||||
app:layout_anchorGravity="bottom|right"
|
||||
app:backgroundTint="@color/color_primary"
|
||||
app:fabSize="mini"
|
||||
app:rippleColor="?colorAccent"/>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
@ -23,6 +23,7 @@
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<io.casey.musikcube.remote.ui.shared.view.EmptyListView
|
||||
style="@style/EmptyView"
|
||||
android:id="@+id/empty_list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -1,40 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_weight="1"
|
||||
<FrameLayout
|
||||
android:id="@+id/content_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp">
|
||||
|
||||
<include layout="@layout/toolbar" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/content_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/fab_padding"
|
||||
android:src="@drawable/ic_fab_add"
|
||||
android:scaleType="center"
|
||||
android:elevation="6dp"
|
||||
android:visibility="gone"
|
||||
app:layout_anchor="@id/content_container"
|
||||
app:layout_anchorGravity="bottom|right"
|
||||
app:backgroundTint="@color/color_primary"
|
||||
app:fabSize="mini"
|
||||
app:rippleColor="?colorAccent"/>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/transport_container"
|
||||
|
@ -3,7 +3,8 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/theme_background" >
|
||||
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_weight="1"
|
||||
@ -23,6 +24,7 @@
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<io.casey.musikcube.remote.ui.shared.view.EmptyListView
|
||||
style="@style/EmptyView"
|
||||
android:id="@+id/empty_list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@ -30,20 +32,9 @@
|
||||
android:visibility="invisible"/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/fab"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/fab_padding"
|
||||
android:src="@drawable/ic_fab_add"
|
||||
android:scaleType="center"
|
||||
android:elevation="6dp"
|
||||
android:visibility="gone"
|
||||
app:layout_anchor="@id/recycler_view"
|
||||
app:layout_anchorGravity="bottom|right"
|
||||
app:backgroundTint="@color/color_primary"
|
||||
app:fabSize="mini"
|
||||
app:rippleColor="?colorAccent"/>
|
||||
app:layout_anchor="@id/recycler_view" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
|
@ -3,18 +3,18 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/theme_background"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
|
||||
style="@style/RecyclerView"
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:fastScrollAutoHide="true"
|
||||
app:fastScrollAutoHideDelay="1500"
|
||||
app:fastScrollThumbInactiveColor="@color/color_primary_dark"
|
||||
app:fastScrollThumbColor="@color/color_accent" />
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<io.casey.musikcube.remote.ui.shared.view.EmptyListView
|
||||
style="@style/EmptyView"
|
||||
android:id="@+id/empty_list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/theme_background" >
|
||||
|
||||
<include layout="@layout/toolbar" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/content_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
|
||||
style="@style/RecyclerView"
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<io.casey.musikcube.remote.ui.shared.view.EmptyListView
|
||||
style="@style/EmptyView"
|
||||
android:id="@+id/empty_list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/FAB"
|
||||
android:id="@+id/fab"
|
||||
app:layout_anchor="@id/content_container" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
@ -46,7 +46,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<android.support.v4.widget.Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="2dp"/>
|
||||
@ -88,5 +87,4 @@
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
@ -87,4 +87,30 @@
|
||||
<item name="android:shadowRadius">3</item>
|
||||
</style>
|
||||
|
||||
<style name="FAB">
|
||||
<item name="android:layout_gravity">bottom|right</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_margin">@dimen/fab_padding</item>
|
||||
<item name="android:src">@drawable/ic_fab_add</item>
|
||||
<item name="android:scaleType">center</item>
|
||||
<item name="android:elevation">6dp</item>
|
||||
<item name="android:visibility">gone</item>
|
||||
<item name="layout_anchorGravity">bottom|right</item>
|
||||
<item name="backgroundTint">@color/color_primary</item>
|
||||
<item name="fabSize">mini</item>
|
||||
<item name="rippleColor">?colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="RecyclerView">
|
||||
<item name="fastScrollAutoHide">true</item>
|
||||
<item name="fastScrollAutoHideDelay">1500</item>
|
||||
<item name="fastScrollThumbInactiveColor">@color/color_primary_dark</item>
|
||||
<item name="fastScrollThumbColor">@color/color_accent</item>
|
||||
</style>
|
||||
|
||||
<style name="EmptyView">
|
||||
<item name="android:background">@color/theme_background</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user