ui: split off selection from home

Split off selection functionality from the home fragment to a new
selection viewmodel.

It's going to be used elsewhere, so may as well.
This commit is contained in:
Alexander Capehart 2022-12-15 13:59:40 -07:00
parent f1ae870eea
commit 761dab9239
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
14 changed files with 42 additions and 30 deletions

View file

@ -59,7 +59,7 @@ abstract class DetailAdapter<L : DetailAdapter.Listener>(
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) =
throw IllegalStateException()
throw NotImplementedError()
override fun onBindViewHolder(
holder: RecyclerView.ViewHolder,

View file

@ -60,10 +60,6 @@ class HomeViewModel(application: Application) :
val genres: StateFlow<List<Genre>>
get() = _genres
private val _selected = MutableStateFlow(listOf<Music>())
val selected: StateFlow<List<Music>>
get() = _selected
var tabs: List<MusicMode> = visibleTabs
private set
@ -88,19 +84,6 @@ class HomeViewModel(application: Application) :
musicStore.addCallback(this)
}
/** Select a music item. */
fun select(item: Music) {
val items = _selected.value.toMutableList()
if (items.remove(item)) {
logD("Unselecting item $item")
_selected.value = items
} else {
logD("Selecting item $item")
items.add(item)
_selected.value = items
}
}
/** Update the current tab based off of the new ViewPager position. */
fun updateCurrentTab(pos: Int) {
logD("Updating current tab to ${tabs[pos]}")

View file

@ -56,7 +56,7 @@ class AlbumListFragment : HomeListFragment<Album>() {
}
collectImmediately(homeModel.albums, homeAdapter::replaceList)
collectImmediately(homeModel.selected, homeAdapter::updateSelection)
collectImmediately(selectionModel.selected, homeAdapter::updateSelection)
collectImmediately(playbackModel.parent, playbackModel.isPlaying, ::handleParent)
}

View file

@ -52,7 +52,7 @@ class ArtistListFragment : HomeListFragment<Artist>() {
}
collectImmediately(homeModel.artists, homeAdapter::replaceList)
collectImmediately(homeModel.selected, homeAdapter::updateSelection)
collectImmediately(selectionModel.selected, homeAdapter::updateSelection)
collectImmediately(playbackModel.parent, playbackModel.isPlaying, ::handleParent)
}

View file

@ -51,7 +51,7 @@ class GenreListFragment : HomeListFragment<Genre>() {
}
collectImmediately(homeModel.genres, homeAdapter::replaceList)
collectImmediately(homeModel.selected, homeAdapter::updateSelection)
collectImmediately(selectionModel.selected, homeAdapter::updateSelection)
collectImmediately(playbackModel.parent, playbackModel.isPlaying, ::handlePlayback)
}

View file

@ -20,9 +20,11 @@ package org.oxycblt.auxio.home.list
import android.os.Bundle
import android.view.LayoutInflater
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.ui.SelectionViewModel
import org.oxycblt.auxio.ui.fastscroll.FastScrollRecyclerView
import org.oxycblt.auxio.ui.fragment.MenuFragment
import org.oxycblt.auxio.ui.recycler.Item
@ -39,6 +41,7 @@ abstract class HomeListFragment<T : Item> :
FastScrollRecyclerView.PopupProvider,
FastScrollRecyclerView.OnFastScrollListener {
protected val homeModel: HomeViewModel by androidActivityViewModels()
protected val selectionModel: SelectionViewModel by activityViewModels()
override fun onCreateBinding(inflater: LayoutInflater) =
FragmentHomeListBinding.inflate(inflater)
@ -69,7 +72,7 @@ abstract class HomeListFragment<T : Item> :
override fun onItemClick(item: Item) {
check(item is Music) { "Unexpected datatype: ${item::class.java}" }
if (homeModel.selected.value.isEmpty()) {
if (selectionModel.selected.value.isEmpty()) {
onItemClick(item)
} else {
onSelect(item)
@ -78,6 +81,6 @@ abstract class HomeListFragment<T : Item> :
override fun onSelect(item: Item) {
check(item is Music) { "Unexpected datatype: ${item::class.java}" }
homeModel.select(item)
selectionModel.select(item)
}
}

View file

@ -59,7 +59,7 @@ class SongListFragment : HomeListFragment<Song>() {
}
collectImmediately(homeModel.songs, homeAdapter::replaceList)
collectImmediately(homeModel.selected, homeAdapter::updateSelection)
collectImmediately(selectionModel.selected, homeAdapter::updateSelection)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::handlePlayback)
}

View file

@ -0,0 +1,26 @@
package org.oxycblt.auxio.ui
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.util.logD
class SelectionViewModel : ViewModel() {
private val _selected = MutableStateFlow(listOf<Music>())
val selected: StateFlow<List<Music>>
get() = _selected
/** Select a music item. */
fun select(item: Music) {
val items = _selected.value.toMutableList()
if (items.remove(item)) {
logD("Unselecting item $item")
_selected.value = items
} else {
logD("Selecting item $item")
items.add(item)
_selected.value = items
}
}
}

View file

@ -65,7 +65,7 @@
style="@style/Widget.Auxio.Button.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_mid_medium"
android:layout_marginEnd="@dimen/spacing_small"
android:text="@string/lbl_play"
app:layout_constraintEnd_toStartOf="@+id/detail_shuffle_button"

View file

@ -79,7 +79,7 @@
style="@style/Widget.Auxio.Button.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_mid_medium"
android:layout_marginEnd="@dimen/spacing_small"
android:text="@string/lbl_play"
app:layout_constraintEnd_toStartOf="@+id/detail_shuffle_button"

View file

@ -79,7 +79,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_mid_medium"
android:layout_marginEnd="@dimen/spacing_small"
android:text="@string/lbl_play"
app:layout_constraintBottom_toBottomOf="@+id/detail_cover"

View file

@ -75,7 +75,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_mid_medium"
android:layout_marginEnd="@dimen/spacing_small"
android:text="@string/lbl_play"
app:layout_constraintBottom_toBottomOf="@+id/detail_cover"

View file

@ -68,7 +68,7 @@
style="@style/Widget.Auxio.Button.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_medium"
android:layout_marginTop="@dimen/spacing_mid_medium"
android:layout_marginEnd="@dimen/spacing_small"
android:text="@string/lbl_play"
app:layout_constraintEnd_toStartOf="@+id/detail_shuffle_button"