search: add selection
Add selection to the search view.
This commit is contained in:
parent
3d03194878
commit
8aeb6d092e
6 changed files with 149 additions and 100 deletions
|
@ -59,6 +59,7 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.MainNavigationAction
|
import org.oxycblt.auxio.ui.MainNavigationAction
|
||||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||||
import org.oxycblt.auxio.ui.fragment.ViewBindingFragment
|
import org.oxycblt.auxio.ui.fragment.ViewBindingFragment
|
||||||
|
import org.oxycblt.auxio.ui.selection.SelectionToolbarOverlay
|
||||||
import org.oxycblt.auxio.ui.selection.SelectionViewModel
|
import org.oxycblt.auxio.ui.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.util.*
|
import org.oxycblt.auxio.util.*
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ import org.oxycblt.auxio.util.*
|
||||||
* respective item.
|
* respective item.
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*/
|
*/
|
||||||
class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuItemClickListener {
|
class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuItemClickListener, SelectionToolbarOverlay.Callback {
|
||||||
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
|
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
|
||||||
private val homeModel: HomeViewModel by androidActivityViewModels()
|
private val homeModel: HomeViewModel by androidActivityViewModels()
|
||||||
private val musicModel: MusicViewModel by activityViewModels()
|
private val musicModel: MusicViewModel by activityViewModels()
|
||||||
|
@ -114,9 +115,7 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.homeToolbarOverlay.registerListeners(
|
binding.homeToolbarOverlay.callback = this
|
||||||
onExit = { selectionModel.consume() }, onMenuItemClick = this)
|
|
||||||
|
|
||||||
binding.homeToolbar.setOnMenuItemClickListener(this@HomeFragment)
|
binding.homeToolbar.setOnMenuItemClickListener(this@HomeFragment)
|
||||||
|
|
||||||
updateTabConfiguration()
|
updateTabConfiguration()
|
||||||
|
@ -174,14 +173,12 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
|
||||||
|
|
||||||
override fun onDestroyBinding(binding: FragmentHomeBinding) {
|
override fun onDestroyBinding(binding: FragmentHomeBinding) {
|
||||||
super.onDestroyBinding(binding)
|
super.onDestroyBinding(binding)
|
||||||
binding.homeToolbarOverlay.unregisterListeners()
|
binding.homeToolbarOverlay.callback = null
|
||||||
binding.homeToolbar.setOnMenuItemClickListener(null)
|
binding.homeToolbar.setOnMenuItemClickListener(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
// HOME
|
|
||||||
|
|
||||||
R.id.action_search -> {
|
R.id.action_search -> {
|
||||||
logD("Navigating to search")
|
logD("Navigating to search")
|
||||||
// Reset selection (navigating to another selectable screen)
|
// Reset selection (navigating to another selectable screen)
|
||||||
|
@ -210,16 +207,6 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
|
||||||
.withAscending(item.isChecked))
|
.withAscending(item.isChecked))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SELECTION
|
|
||||||
|
|
||||||
R.id.action_play_next_selection -> {
|
|
||||||
playbackModel.playNext(selectionModel.consume())
|
|
||||||
requireContext().showToast(R.string.lng_queue_added)
|
|
||||||
}
|
|
||||||
R.id.action_queue_add_selection -> {
|
|
||||||
playbackModel.addToQueue(selectionModel.consume())
|
|
||||||
requireContext().showToast(R.string.lng_queue_added)
|
|
||||||
}
|
|
||||||
else -> {
|
else -> {
|
||||||
// Sorting option was selected, mark it as selected and update the mode
|
// Sorting option was selected, mark it as selected and update the mode
|
||||||
item.isChecked = true
|
item.isChecked = true
|
||||||
|
@ -230,9 +217,24 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always handling an item
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onClearSelection() {
|
||||||
|
selectionModel.consume()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPlaySelectionNext() {
|
||||||
|
playbackModel.playNext(selectionModel.consume())
|
||||||
|
requireContext().showToast(R.string.lng_queue_added)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAddSelectionToQueue() {
|
||||||
|
playbackModel.addToQueue(selectionModel.consume())
|
||||||
|
requireContext().showToast(R.string.lng_queue_added)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateCurrentTab(tab: MusicMode) {
|
private fun updateCurrentTab(tab: MusicMode) {
|
||||||
// Make sure that we update the scrolling view and allowed menu items whenever
|
// Make sure that we update the scrolling view and allowed menu items whenever
|
||||||
// the tab changes.
|
// the tab changes.
|
||||||
|
@ -453,9 +455,9 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
|
||||||
* https://al-e-shevelev.medium.com/how-to-reduce-scroll-sensitivity-of-viewpager2-widget-87797ad02414
|
* https://al-e-shevelev.medium.com/how-to-reduce-scroll-sensitivity-of-viewpager2-widget-87797ad02414
|
||||||
*/
|
*/
|
||||||
private fun ViewPager2.reduceSensitivity(by: Int) {
|
private fun ViewPager2.reduceSensitivity(by: Int) {
|
||||||
val recycler = VIEW_PAGER_RECYCLER_FIELD.get(this@reduceSensitivity)
|
val recycler = VP_RECYCLER_FIELD.get(this@reduceSensitivity)
|
||||||
val slop = VIEW_PAGER_TOUCH_SLOP_FIELD.get(recycler) as Int
|
val slop = RV_TOUCH_SLOP_FIELD.get(recycler) as Int
|
||||||
VIEW_PAGER_TOUCH_SLOP_FIELD.set(recycler, slop * by)
|
RV_TOUCH_SLOP_FIELD.set(recycler, slop * by)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Forces the view to recreate all fragments contained within it. */
|
/** Forces the view to recreate all fragments contained within it. */
|
||||||
|
@ -480,9 +482,9 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val VIEW_PAGER_RECYCLER_FIELD: Field by
|
private val VP_RECYCLER_FIELD: Field by
|
||||||
lazyReflectedField(ViewPager2::class, "mRecyclerView")
|
lazyReflectedField(ViewPager2::class, "mRecyclerView")
|
||||||
private val VIEW_PAGER_TOUCH_SLOP_FIELD: Field by
|
private val RV_TOUCH_SLOP_FIELD: Field by
|
||||||
lazyReflectedField(RecyclerView::class, "mTouchSlop")
|
lazyReflectedField(RecyclerView::class, "mTouchSlop")
|
||||||
private const val KEY_LAST_TRANSITION_AXIS =
|
private const val KEY_LAST_TRANSITION_AXIS =
|
||||||
BuildConfig.APPLICATION_ID + ".key.LAST_TRANSITION_AXIS"
|
BuildConfig.APPLICATION_ID + ".key.LAST_TRANSITION_AXIS"
|
||||||
|
|
|
@ -24,20 +24,10 @@ import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.ui.recycler.AlbumViewHolder
|
import org.oxycblt.auxio.ui.recycler.*
|
||||||
import org.oxycblt.auxio.ui.recycler.ArtistViewHolder
|
|
||||||
import org.oxycblt.auxio.ui.recycler.AuxioRecyclerView
|
|
||||||
import org.oxycblt.auxio.ui.recycler.GenreViewHolder
|
|
||||||
import org.oxycblt.auxio.ui.recycler.Header
|
|
||||||
import org.oxycblt.auxio.ui.recycler.HeaderViewHolder
|
|
||||||
import org.oxycblt.auxio.ui.recycler.Item
|
|
||||||
import org.oxycblt.auxio.ui.recycler.MenuItemListener
|
|
||||||
import org.oxycblt.auxio.ui.recycler.PlayingIndicatorAdapter
|
|
||||||
import org.oxycblt.auxio.ui.recycler.SimpleItemCallback
|
|
||||||
import org.oxycblt.auxio.ui.recycler.SongViewHolder
|
|
||||||
|
|
||||||
class SearchAdapter(private val listener: MenuItemListener) :
|
class SearchAdapter(private val listener: MenuItemListener) :
|
||||||
PlayingIndicatorAdapter<RecyclerView.ViewHolder>(), AuxioRecyclerView.SpanSizeLookup {
|
SelectionIndicatorAdapter<RecyclerView.ViewHolder>(), AuxioRecyclerView.SpanSizeLookup {
|
||||||
private val differ = AsyncListDiffer(this, DIFFER)
|
private val differ = AsyncListDiffer(this, DIFFER)
|
||||||
|
|
||||||
override fun getItemCount() = differ.currentList.size
|
override fun getItemCount() = differ.currentList.size
|
||||||
|
|
|
@ -27,6 +27,7 @@ import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.postDelayed
|
import androidx.core.view.postDelayed
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
|
@ -42,22 +43,21 @@ import org.oxycblt.auxio.settings.Settings
|
||||||
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
import org.oxycblt.auxio.ui.fragment.MenuFragment
|
||||||
import org.oxycblt.auxio.ui.recycler.Item
|
import org.oxycblt.auxio.ui.recycler.Item
|
||||||
import org.oxycblt.auxio.ui.recycler.MenuItemListener
|
import org.oxycblt.auxio.ui.recycler.MenuItemListener
|
||||||
import org.oxycblt.auxio.util.androidViewModels
|
import org.oxycblt.auxio.ui.selection.SelectionToolbarOverlay
|
||||||
import org.oxycblt.auxio.util.collect
|
import org.oxycblt.auxio.ui.selection.SelectionViewModel
|
||||||
import org.oxycblt.auxio.util.collectImmediately
|
import org.oxycblt.auxio.util.*
|
||||||
import org.oxycblt.auxio.util.context
|
|
||||||
import org.oxycblt.auxio.util.getSystemServiceCompat
|
|
||||||
import org.oxycblt.auxio.util.logW
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [Fragment] that allows for the searching of the entire music library.
|
* A [Fragment] that allows for the searching of the entire music library.
|
||||||
|
* FIXME: Keyboard logic is really wonky
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*/
|
*/
|
||||||
class SearchFragment :
|
class SearchFragment :
|
||||||
MenuFragment<FragmentSearchBinding>(), MenuItemListener, Toolbar.OnMenuItemClickListener {
|
MenuFragment<FragmentSearchBinding>(), MenuItemListener, Toolbar.OnMenuItemClickListener, SelectionToolbarOverlay.Callback {
|
||||||
|
|
||||||
// SearchViewModel is only scoped to this Fragment
|
// SearchViewModel is only scoped to this Fragment
|
||||||
private val searchModel: SearchViewModel by androidViewModels()
|
private val searchModel: SearchViewModel by androidViewModels()
|
||||||
|
private val selectionModel: SelectionViewModel by activityViewModels()
|
||||||
|
|
||||||
private val searchAdapter = SearchAdapter(this)
|
private val searchAdapter = SearchAdapter(this)
|
||||||
private val settings: Settings by lifecycleObject { binding -> Settings(binding.context) }
|
private val settings: Settings by lifecycleObject { binding -> Settings(binding.context) }
|
||||||
|
@ -78,6 +78,8 @@ class SearchFragment :
|
||||||
override fun onCreateBinding(inflater: LayoutInflater) = FragmentSearchBinding.inflate(inflater)
|
override fun onCreateBinding(inflater: LayoutInflater) = FragmentSearchBinding.inflate(inflater)
|
||||||
|
|
||||||
override fun onBindingCreated(binding: FragmentSearchBinding, savedInstanceState: Bundle?) {
|
override fun onBindingCreated(binding: FragmentSearchBinding, savedInstanceState: Bundle?) {
|
||||||
|
binding.searchToolbarOverlay.callback = this
|
||||||
|
|
||||||
binding.searchToolbar.apply {
|
binding.searchToolbar.apply {
|
||||||
val itemIdToSelect =
|
val itemIdToSelect =
|
||||||
when (searchModel.filterMode) {
|
when (searchModel.filterMode) {
|
||||||
|
@ -91,7 +93,12 @@ class SearchFragment :
|
||||||
menu.findItem(itemIdToSelect).isChecked = true
|
menu.findItem(itemIdToSelect).isChecked = true
|
||||||
|
|
||||||
setNavigationOnClickListener {
|
setNavigationOnClickListener {
|
||||||
|
// Reset selection (navigating to another selectable screen)
|
||||||
|
selectionModel.consume()
|
||||||
|
|
||||||
|
// Drop keyboard as it's no longer needed
|
||||||
imm.hide()
|
imm.hide()
|
||||||
|
|
||||||
findNavController().navigateUp()
|
findNavController().navigateUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,40 +128,61 @@ class SearchFragment :
|
||||||
collectImmediately(
|
collectImmediately(
|
||||||
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::handlePlayback)
|
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::handlePlayback)
|
||||||
collect(navModel.exploreNavigationItem, ::handleNavigation)
|
collect(navModel.exploreNavigationItem, ::handleNavigation)
|
||||||
|
collectImmediately(selectionModel.selected, ::handleSelection)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyBinding(binding: FragmentSearchBinding) {
|
override fun onDestroyBinding(binding: FragmentSearchBinding) {
|
||||||
|
binding.searchToolbarOverlay.callback = null
|
||||||
binding.searchToolbar.setOnMenuItemClickListener(null)
|
binding.searchToolbar.setOnMenuItemClickListener(null)
|
||||||
binding.searchRecycler.adapter = null
|
binding.searchRecycler.adapter = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
if (item.itemId != R.id.submenu_filtering) {
|
||||||
R.id.submenu_filtering -> {}
|
searchModel.updateFilterModeWithId(item.itemId)
|
||||||
else -> {
|
item.isChecked = true
|
||||||
if (item.itemId != R.id.submenu_filtering) {
|
|
||||||
searchModel.updateFilterModeWithId(item.itemId)
|
|
||||||
item.isChecked = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onClearSelection() {
|
||||||
|
selectionModel.consume()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPlaySelectionNext() {
|
||||||
|
playbackModel.playNext(selectionModel.consume())
|
||||||
|
requireContext().showToast(R.string.lng_queue_added)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAddSelectionToQueue() {
|
||||||
|
playbackModel.addToQueue(selectionModel.consume())
|
||||||
|
requireContext().showToast(R.string.lng_queue_added)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onItemClick(item: Item) {
|
override fun onItemClick(item: Item) {
|
||||||
when (item) {
|
check(item is Music) { "Unexpected datatype ${item::class.simpleName}"}
|
||||||
is Song ->
|
if (selectionModel.selected.value.isEmpty()) {
|
||||||
when (settings.libPlaybackMode) {
|
when (item) {
|
||||||
MusicMode.SONGS -> playbackModel.playFromAll(item)
|
is Song ->
|
||||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
when (settings.libPlaybackMode) {
|
||||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
MusicMode.SONGS -> playbackModel.playFromAll(item)
|
||||||
else -> error("Unexpected playback mode: ${settings.libPlaybackMode}")
|
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||||
}
|
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||||
is MusicParent -> navModel.exploreNavigateTo(item)
|
else -> error("Unexpected playback mode: ${settings.libPlaybackMode}")
|
||||||
|
}
|
||||||
|
is MusicParent -> navModel.exploreNavigateTo(item)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selectionModel.select(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSelect(item: Item) {
|
||||||
|
check(item is Music) { "Unexpected datatype ${item::class.simpleName}"}
|
||||||
|
selectionModel.select(item)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onOpenMenu(item: Item, anchor: View) {
|
override fun onOpenMenu(item: Item, anchor: View) {
|
||||||
when (item) {
|
when (item) {
|
||||||
is Song -> musicMenu(anchor, R.menu.menu_song_actions, item)
|
is Song -> musicMenu(anchor, R.menu.menu_song_actions, item)
|
||||||
|
@ -193,9 +221,20 @@ class SearchFragment :
|
||||||
else -> return
|
else -> return
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Reset selection (navigating to another selectable screen)
|
||||||
|
selectionModel.consume()
|
||||||
|
|
||||||
|
// Drop keyboard as it's no longer needed
|
||||||
imm.hide()
|
imm.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleSelection(selected: List<Music>) {
|
||||||
|
searchAdapter.updateSelection(selected)
|
||||||
|
if (requireBinding().searchToolbarOverlay.updateSelectionAmount(selected.size) && selected.isNotEmpty()) {
|
||||||
|
imm.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun InputMethodManager.hide() {
|
private fun InputMethodManager.hide() {
|
||||||
hideSoftInputFromWindow(requireView().windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
|
hideSoftInputFromWindow(requireView().windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.oxycblt.auxio.ui.selection
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.view.MenuItem
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.annotation.AttrRes
|
import androidx.annotation.AttrRes
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
@ -37,11 +38,29 @@ class SelectionToolbarOverlay
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
|
constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) :
|
||||||
FrameLayout(context, attrs, defStyleAttr) {
|
FrameLayout(context, attrs, defStyleAttr) {
|
||||||
|
var callback: Callback? = null
|
||||||
|
|
||||||
private lateinit var innerToolbar: MaterialToolbar
|
private lateinit var innerToolbar: MaterialToolbar
|
||||||
private val selectionToolbar =
|
private val selectionToolbar =
|
||||||
MaterialToolbar(context).apply {
|
MaterialToolbar(context).apply {
|
||||||
inflateMenu(R.menu.menu_selection_actions)
|
|
||||||
setNavigationIcon(R.drawable.ic_close_24)
|
setNavigationIcon(R.drawable.ic_close_24)
|
||||||
|
setNavigationOnClickListener {
|
||||||
|
callback?.onClearSelection()
|
||||||
|
}
|
||||||
|
|
||||||
|
inflateMenu(R.menu.menu_selection_actions)
|
||||||
|
setOnMenuItemClickListener {
|
||||||
|
when (it.itemId) {
|
||||||
|
R.id.action_play_next -> {
|
||||||
|
callback?.onPlaySelectionNext()
|
||||||
|
}
|
||||||
|
R.id.action_queue_add -> {
|
||||||
|
callback?.onAddSelectionToQueue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var fadeThroughAnimator: ValueAnimator? = null
|
private var fadeThroughAnimator: ValueAnimator? = null
|
||||||
|
@ -56,23 +75,9 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
addView(selectionToolbar)
|
addView(selectionToolbar)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add listeners for the selection toolbar. */
|
override fun onDetachedFromWindow() {
|
||||||
fun registerListeners(
|
super.onDetachedFromWindow()
|
||||||
onExit: OnClickListener,
|
callback = null
|
||||||
onMenuItemClick: Toolbar.OnMenuItemClickListener
|
|
||||||
) {
|
|
||||||
selectionToolbar.apply {
|
|
||||||
setNavigationOnClickListener(onExit)
|
|
||||||
setOnMenuItemClickListener(onMenuItemClick)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Unregister listeners for this instance. */
|
|
||||||
fun unregisterListeners() {
|
|
||||||
selectionToolbar.apply {
|
|
||||||
setNavigationOnClickListener(null)
|
|
||||||
setOnMenuItemClickListener(null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -146,4 +151,10 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
||||||
isInvisible = innerAlpha == 1f
|
isInvisible = innerAlpha == 1f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onClearSelection()
|
||||||
|
fun onPlaySelectionNext()
|
||||||
|
fun onAddSelectionToQueue()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,37 +12,44 @@
|
||||||
app:liftOnScroll="true"
|
app:liftOnScroll="true"
|
||||||
app:liftOnScrollTargetViewId="@id/search_recycler">
|
app:liftOnScrollTargetViewId="@id/search_recycler">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<org.oxycblt.auxio.ui.selection.SelectionToolbarOverlay
|
||||||
android:id="@+id/search_toolbar"
|
android:id="@+id/search_toolbar_overlay"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
app:menu="@menu/menu_search"
|
|
||||||
app:navigationIcon="@drawable/ic_back_24">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/search_toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:endIconContentDescription="@string/desc_clear_search"
|
app:menu="@menu/menu_search"
|
||||||
app:endIconDrawable="@drawable/ic_close_24"
|
app:navigationIcon="@drawable/ic_back_24">
|
||||||
app:endIconMode="clear_text"
|
|
||||||
app:endIconTint="?attr/colorControlNormal"
|
|
||||||
app:errorEnabled="false"
|
|
||||||
app:hintEnabled="false">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/search_edit_text"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@android:color/transparent"
|
app:endIconContentDescription="@string/desc_clear_search"
|
||||||
android:hint="@string/lng_search_library"
|
app:endIconDrawable="@drawable/ic_close_24"
|
||||||
android:imeOptions="actionSearch|flagNoExtractUi"
|
app:endIconMode="clear_text"
|
||||||
android:inputType="textFilter"
|
app:endIconTint="?attr/colorControlNormal"
|
||||||
android:paddingStart="@dimen/spacing_tiny"
|
app:errorEnabled="false"
|
||||||
android:paddingEnd="0dp" />
|
app:hintEnabled="false">
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/search_edit_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:hint="@string/lng_search_library"
|
||||||
|
android:imeOptions="actionSearch|flagNoExtractUi"
|
||||||
|
android:inputType="textFilter"
|
||||||
|
android:paddingStart="@dimen/spacing_tiny"
|
||||||
|
android:paddingEnd="0dp" />
|
||||||
|
|
||||||
</com.google.android.material.appbar.MaterialToolbar>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.MaterialToolbar>
|
||||||
|
|
||||||
|
</org.oxycblt.auxio.ui.selection.SelectionToolbarOverlay>
|
||||||
|
|
||||||
</org.oxycblt.auxio.ui.AuxioAppBarLayout>
|
</org.oxycblt.auxio.ui.AuxioAppBarLayout>
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_play_next_selection"
|
android:id="@+id/action_play_next"
|
||||||
android:title="@string/lbl_play_next"
|
android:title="@string/lbl_play_next"
|
||||||
android:icon="@drawable/ic_play_next"
|
android:icon="@drawable/ic_play_next"
|
||||||
app:showAsAction="ifRoom"/>
|
app:showAsAction="ifRoom"/>
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_queue_add_selection"
|
android:id="@+id/action_queue_add"
|
||||||
android:icon="@drawable/ic_play_next"
|
android:icon="@drawable/ic_play_next"
|
||||||
android:title="@string/lbl_queue_add"
|
android:title="@string/lbl_queue_add"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
Loading…
Reference in a new issue