music: rename mode -> type

Rename MusicMode to MusicType.

The original naming was always a bit clunky given that it referred to
both settings and data configuration. I feel that "Type" is probably
better overall.
This commit is contained in:
Alexander Capehart 2023-07-11 12:08:51 -06:00
parent 3908400418
commit 4275fdbcf0
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
20 changed files with 185 additions and 184 deletions

View file

@ -62,7 +62,7 @@ import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.IndexingProgress
import org.oxycblt.auxio.music.IndexingState
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.NoAudioPermissionException
import org.oxycblt.auxio.music.NoMusicException
@ -173,7 +173,7 @@ class HomeFragment :
// --- VIEWMODEL SETUP ---
collect(homeModel.recreateTabs.flow, ::handleRecreate)
collectImmediately(homeModel.currentTabMode, ::updateCurrentTab)
collectImmediately(homeModel.currentTabType, ::updateCurrentTab)
collectImmediately(homeModel.songsList, homeModel.isFastScrolling, ::updateFab)
collect(listModel.menu.flow, ::handleMenu)
collectImmediately(listModel.selected, ::updateSelection)
@ -245,7 +245,7 @@ class HomeFragment :
item.isChecked = true
homeModel.setSortForCurrentTab(
homeModel
.getSortForTab(homeModel.currentTabMode.value)
.getSortForTab(homeModel.currentTabType.value)
.withDirection(Sort.Direction.ASCENDING))
true
}
@ -254,7 +254,7 @@ class HomeFragment :
item.isChecked = true
homeModel.setSortForCurrentTab(
homeModel
.getSortForTab(homeModel.currentTabMode.value)
.getSortForTab(homeModel.currentTabType.value)
.withDirection(Sort.Direction.DESCENDING))
true
}
@ -265,7 +265,7 @@ class HomeFragment :
logD("Updating sort mode")
item.isChecked = true
homeModel.setSortForCurrentTab(
homeModel.getSortForTab(homeModel.currentTabMode.value).withMode(newMode))
homeModel.getSortForTab(homeModel.currentTabType.value).withMode(newMode))
true
} else {
logW("Unexpected menu item selected")
@ -277,10 +277,10 @@ class HomeFragment :
private fun setupPager(binding: FragmentHomeBinding) {
binding.homePager.adapter =
HomePagerAdapter(homeModel.currentTabModes, childFragmentManager, viewLifecycleOwner)
HomePagerAdapter(homeModel.currentTabTypes, childFragmentManager, viewLifecycleOwner)
val toolbarParams = binding.homeToolbar.layoutParams as AppBarLayout.LayoutParams
if (homeModel.currentTabModes.size == 1) {
if (homeModel.currentTabTypes.size == 1) {
// A single tab makes the tab layout redundant, hide it and disable the collapsing
// behavior.
logD("Single tab shown, disabling TabLayout")
@ -298,22 +298,22 @@ class HomeFragment :
TabLayoutMediator(
binding.homeTabs,
binding.homePager,
AdaptiveTabStrategy(requireContext(), homeModel.currentTabModes))
AdaptiveTabStrategy(requireContext(), homeModel.currentTabTypes))
.attach()
}
private fun updateCurrentTab(tabMode: MusicMode) {
private fun updateCurrentTab(tabType: MusicType) {
val binding = requireBinding()
// Update the sort options to align with those allowed by the tab
val isVisible: (Int) -> Boolean =
when (tabMode) {
when (tabType) {
// Disallow sorting by count for songs
MusicMode.SONGS -> {
MusicType.SONGS -> {
logD("Using song-specific menu options")
({ id -> id != R.id.option_sort_count })
}
// Disallow sorting by album for albums
MusicMode.ALBUMS -> {
MusicType.ALBUMS -> {
logD("Using album-specific menu options")
({ id -> id != R.id.option_sort_album })
}
@ -332,7 +332,7 @@ class HomeFragment :
val sortMenu =
unlikelyToBeNull(binding.homeNormalToolbar.menu.findItem(R.id.submenu_sorting).subMenu)
val toHighlight = homeModel.getSortForTab(tabMode)
val toHighlight = homeModel.getSortForTab(tabType)
for (option in sortMenu) {
val isCurrentMode = option.itemId == toHighlight.mode.itemId
@ -364,15 +364,15 @@ class HomeFragment :
// scrolling state. This prevents the lift state from being confused as one
// goes between different tabs.
binding.homeAppbar.liftOnScrollTargetViewId =
when (tabMode) {
MusicMode.SONGS -> R.id.home_song_recycler
MusicMode.ALBUMS -> R.id.home_album_recycler
MusicMode.ARTISTS -> R.id.home_artist_recycler
MusicMode.GENRES -> R.id.home_genre_recycler
MusicMode.PLAYLISTS -> R.id.home_playlist_recycler
when (tabType) {
MusicType.SONGS -> R.id.home_song_recycler
MusicType.ALBUMS -> R.id.home_album_recycler
MusicType.ARTISTS -> R.id.home_artist_recycler
MusicType.GENRES -> R.id.home_genre_recycler
MusicType.PLAYLISTS -> R.id.home_playlist_recycler
}
if (tabMode != MusicMode.PLAYLISTS) {
if (tabType != MusicType.PLAYLISTS) {
logD("Flipping to shuffle button")
binding.homeFab.flipTo(R.drawable.ic_shuffle_off_24, R.string.desc_shuffle_all) {
playbackModel.shuffleAll()
@ -632,18 +632,18 @@ class HomeFragment :
* [FragmentStateAdapter].
*/
private class HomePagerAdapter(
private val tabs: List<MusicMode>,
private val tabs: List<MusicType>,
fragmentManager: FragmentManager,
lifecycleOwner: LifecycleOwner
) : FragmentStateAdapter(fragmentManager, lifecycleOwner.lifecycle) {
override fun getItemCount() = tabs.size
override fun createFragment(position: Int): Fragment =
when (tabs[position]) {
MusicMode.SONGS -> SongListFragment()
MusicMode.ALBUMS -> AlbumListFragment()
MusicMode.ARTISTS -> ArtistListFragment()
MusicMode.GENRES -> GenreListFragment()
MusicMode.PLAYLISTS -> PlaylistListFragment()
MusicType.SONGS -> SongListFragment()
MusicType.ALBUMS -> AlbumListFragment()
MusicType.ARTISTS -> ArtistListFragment()
MusicType.GENRES -> GenreListFragment()
MusicType.PLAYLISTS -> PlaylistListFragment()
}
}

View file

@ -24,7 +24,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import org.oxycblt.auxio.R
import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.settings.Settings
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.unlikelyToBeNull
@ -75,9 +75,9 @@ class HomeSettingsImpl @Inject constructor(@ApplicationContext context: Context)
logD("Old tabs: $oldTabs")
// The playlist tab is now parsed, but it needs to be made visible.
val playlistIndex = oldTabs.indexOfFirst { it.mode == MusicMode.PLAYLISTS }
val playlistIndex = oldTabs.indexOfFirst { it.type == MusicType.PLAYLISTS }
check(playlistIndex > -1) // This should exist, otherwise we are in big trouble
oldTabs[playlistIndex] = Tab.Visible(MusicMode.PLAYLISTS)
oldTabs[playlistIndex] = Tab.Visible(MusicType.PLAYLISTS)
logD("New tabs: $oldTabs")
sharedPreferences.edit {

View file

@ -29,9 +29,9 @@ import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaySong
@ -108,15 +108,15 @@ constructor(
get() = playbackSettings.playInListWith
/**
* A list of [MusicMode] corresponding to the current [Tab] configuration, excluding invisible
* A list of [MusicType] corresponding to the current [Tab] configuration, excluding invisible
* [Tab]s.
*/
var currentTabModes = makeTabModes()
var currentTabTypes = makeTabTypes()
private set
private val _currentTabMode = MutableStateFlow(currentTabModes[0])
/** The [MusicMode] of the currently shown [Tab]. */
val currentTabMode: StateFlow<MusicMode> = _currentTabMode
private val _currentTabType = MutableStateFlow(currentTabTypes[0])
/** The [MusicType] of the currently shown [Tab]. */
val currentTabType: StateFlow<MusicType> = _currentTabType
private val _shouldRecreate = MutableEvent<Unit>()
/**
@ -177,8 +177,8 @@ constructor(
override fun onTabsChanged() {
// Tabs changed, update the current tabs and set up a re-create event.
currentTabModes = makeTabModes()
logD("Updating tabs: ${currentTabMode.value}")
currentTabTypes = makeTabTypes()
logD("Updating tabs: ${currentTabType.value}")
_shouldRecreate.put(Unit)
}
@ -192,16 +192,16 @@ constructor(
/**
* Get the preferred [Sort] for a given [Tab].
*
* @param tabMode The [MusicMode] of the [Tab] desired.
* @param tabType The [MusicType] of the [Tab] desired.
* @return The [Sort] preferred for that [Tab]
*/
fun getSortForTab(tabMode: MusicMode) =
when (tabMode) {
MusicMode.SONGS -> musicSettings.songSort
MusicMode.ALBUMS -> musicSettings.albumSort
MusicMode.ARTISTS -> musicSettings.artistSort
MusicMode.GENRES -> musicSettings.genreSort
MusicMode.PLAYLISTS -> musicSettings.playlistSort
fun getSortForTab(tabType: MusicType) =
when (tabType) {
MusicType.SONGS -> musicSettings.songSort
MusicType.ALBUMS -> musicSettings.albumSort
MusicType.ARTISTS -> musicSettings.artistSort
MusicType.GENRES -> musicSettings.genreSort
MusicType.PLAYLISTS -> musicSettings.playlistSort
}
/**
@ -211,33 +211,33 @@ constructor(
*/
fun setSortForCurrentTab(sort: Sort) {
// Can simply re-sort the current list of items without having to access the library.
when (val mode = _currentTabMode.value) {
MusicMode.SONGS -> {
logD("Updating song [$mode] sort mode to $sort")
when (val type = _currentTabType.value) {
MusicType.SONGS -> {
logD("Updating song [$type] sort mode to $sort")
musicSettings.songSort = sort
_songsInstructions.put(UpdateInstructions.Replace(0))
_songsList.value = sort.songs(_songsList.value)
}
MusicMode.ALBUMS -> {
logD("Updating album [$mode] sort mode to $sort")
MusicType.ALBUMS -> {
logD("Updating album [$type] sort mode to $sort")
musicSettings.albumSort = sort
_albumsInstructions.put(UpdateInstructions.Replace(0))
_albumsLists.value = sort.albums(_albumsLists.value)
}
MusicMode.ARTISTS -> {
logD("Updating artist [$mode] sort mode to $sort")
MusicType.ARTISTS -> {
logD("Updating artist [$type] sort mode to $sort")
musicSettings.artistSort = sort
_artistsInstructions.put(UpdateInstructions.Replace(0))
_artistsList.value = sort.artists(_artistsList.value)
}
MusicMode.GENRES -> {
logD("Updating genre [$mode] sort mode to $sort")
MusicType.GENRES -> {
logD("Updating genre [$type] sort mode to $sort")
musicSettings.genreSort = sort
_genresInstructions.put(UpdateInstructions.Replace(0))
_genresList.value = sort.genres(_genresList.value)
}
MusicMode.PLAYLISTS -> {
logD("Updating playlist [$mode] sort mode to $sort")
MusicType.PLAYLISTS -> {
logD("Updating playlist [$type] sort mode to $sort")
musicSettings.playlistSort = sort
_playlistsInstructions.put(UpdateInstructions.Replace(0))
_playlistsList.value = sort.playlists(_playlistsList.value)
@ -246,13 +246,13 @@ constructor(
}
/**
* Update [currentTabMode] to reflect a new ViewPager2 position
* Update [currentTabType] to reflect a new ViewPager2 position
*
* @param pagerPos The new position of the ViewPager2 instance.
*/
fun synchronizeTabPosition(pagerPos: Int) {
logD("Updating current tab to ${currentTabModes[pagerPos]}")
_currentTabMode.value = currentTabModes[pagerPos]
logD("Updating current tab to ${currentTabTypes[pagerPos]}")
_currentTabType.value = currentTabTypes[pagerPos]
}
/**
@ -266,11 +266,11 @@ constructor(
}
/**
* Create a list of [MusicMode]s representing a simpler version of the [Tab] configuration.
* Create a list of [MusicType]s representing a simpler version of the [Tab] configuration.
*
* @return A list of the [MusicMode]s for each visible [Tab] in the configuration, ordered in
* @return A list of the [MusicType]s for each visible [Tab] in the configuration, ordered in
* the same way as the configuration.
*/
private fun makeTabModes() =
homeSettings.homeTabs.filterIsInstance<Tab.Visible>().map { it.mode }
private fun makeTabTypes() =
homeSettings.homeTabs.filterIsInstance<Tab.Visible>().map { it.type }
}

View file

@ -39,8 +39,8 @@ import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.AlbumViewHolder
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
@ -99,7 +99,7 @@ class AlbumListFragment :
override fun getPopup(pos: Int): String? {
val album = homeModel.albumsList.value[pos]
// Change how we display the popup depending on the current sort mode.
return when (homeModel.getSortForTab(MusicMode.ALBUMS).mode) {
return when (homeModel.getSortForTab(MusicType.ALBUMS).mode) {
// By Name -> Use Name
is Sort.Mode.ByName -> album.name.thumb

View file

@ -37,8 +37,8 @@ import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.ArtistViewHolder
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
@ -94,7 +94,7 @@ class ArtistListFragment :
override fun getPopup(pos: Int): String? {
val artist = homeModel.artistsList.value[pos]
// Change how we display the popup depending on the current sort mode.
return when (homeModel.getSortForTab(MusicMode.ARTISTS).mode) {
return when (homeModel.getSortForTab(MusicType.ARTISTS).mode) {
// By Name -> Use Name
is Sort.Mode.ByName -> artist.name.thumb

View file

@ -37,8 +37,8 @@ import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.GenreViewHolder
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
@ -93,7 +93,7 @@ class GenreListFragment :
override fun getPopup(pos: Int): String? {
val genre = homeModel.genresList.value[pos]
// Change how we display the popup depending on the current sort mode.
return when (homeModel.getSortForTab(MusicMode.GENRES).mode) {
return when (homeModel.getSortForTab(MusicType.GENRES).mode) {
// By Name -> Use Name
is Sort.Mode.ByName -> genre.name.thumb

View file

@ -35,8 +35,8 @@ import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.PlaylistViewHolder
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
@ -91,7 +91,7 @@ class PlaylistListFragment :
override fun getPopup(pos: Int): String? {
val playlist = homeModel.playlistsList.value[pos]
// Change how we display the popup depending on the current sort mode.
return when (homeModel.getSortForTab(MusicMode.GENRES).mode) {
return when (homeModel.getSortForTab(MusicType.GENRES).mode) {
// By Name -> Use Name
is Sort.Mode.ByName -> playlist.name.thumb

View file

@ -37,8 +37,8 @@ import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.SongViewHolder
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
@ -98,7 +98,7 @@ class SongListFragment :
// Change how we display the popup depending on the current sort mode.
// Note: We don't use the more correct individual artist name here, as sorts are largely
// based off the names of the parent objects and not the child objects.
return when (homeModel.getSortForTab(MusicMode.SONGS).mode) {
return when (homeModel.getSortForTab(MusicType.SONGS).mode) {
// Name -> Use name
is Sort.Mode.ByName -> song.name.thumb

View file

@ -22,7 +22,7 @@ import android.content.Context
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicType
/**
* A [TabLayoutMediator.TabConfigurationStrategy] that uses larger/smaller tab configurations
@ -32,7 +32,7 @@ import org.oxycblt.auxio.music.MusicMode
* @param tabs Current tab configuration from settings
* @author Alexander Capehart (OxygenCobalt)
*/
class AdaptiveTabStrategy(context: Context, private val tabs: List<MusicMode>) :
class AdaptiveTabStrategy(context: Context, private val tabs: List<MusicType>) :
TabLayoutMediator.TabConfigurationStrategy {
private val width = context.resources.configuration.smallestScreenWidthDp
@ -41,23 +41,23 @@ class AdaptiveTabStrategy(context: Context, private val tabs: List<MusicMode>) :
val string: Int
when (tabs[position]) {
MusicMode.SONGS -> {
MusicType.SONGS -> {
icon = R.drawable.ic_song_24
string = R.string.lbl_songs
}
MusicMode.ALBUMS -> {
MusicType.ALBUMS -> {
icon = R.drawable.ic_album_24
string = R.string.lbl_albums
}
MusicMode.ARTISTS -> {
MusicType.ARTISTS -> {
icon = R.drawable.ic_artist_24
string = R.string.lbl_artists
}
MusicMode.GENRES -> {
MusicType.GENRES -> {
icon = R.drawable.ic_genre_24
string = R.string.lbl_genres
}
MusicMode.PLAYLISTS -> {
MusicType.PLAYLISTS -> {
icon = R.drawable.ic_playlist_24
string = R.string.lbl_playlists
}

View file

@ -18,30 +18,30 @@
package org.oxycblt.auxio.home.tabs
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.util.logE
import org.oxycblt.auxio.util.logW
/**
* A representation of a library tab suitable for configuration.
*
* @param mode The type of list in the home view this instance corresponds to.
* @param type The type of list in the home view this instance corresponds to.
* @author Alexander Capehart (OxygenCobalt)
*/
sealed class Tab(open val mode: MusicMode) {
sealed class Tab(open val type: MusicType) {
/**
* A visible tab. This will be visible in the home and tab configuration views.
*
* @param mode The type of list in the home view this instance corresponds to.
* @param type The type of list in the home view this instance corresponds to.
*/
data class Visible(override val mode: MusicMode) : Tab(mode)
data class Visible(override val type: MusicType) : Tab(type)
/**
* A visible tab. This will be visible in the tab configuration view, but not in the home view.
*
* @param mode The type of list in the home view this instance corresponds to.
* @param type The type of list in the home view this instance corresponds to.
*/
data class Invisible(override val mode: MusicMode) : Tab(mode)
data class Invisible(override val type: MusicType) : Tab(type)
companion object {
// Like other IO-bound datatypes in Auxio, tabs are stored in a binary format. However, tabs
@ -67,14 +67,14 @@ sealed class Tab(open val mode: MusicMode) {
*/
const val SEQUENCE_DEFAULT = 0b1000_1001_1010_1011_1100
/** Maps between the integer code in the tab sequence and it's [MusicMode]. */
/** Maps between the integer code in the tab sequence and it's [MusicType]. */
private val MODE_TABLE =
arrayOf(
MusicMode.SONGS,
MusicMode.ALBUMS,
MusicMode.ARTISTS,
MusicMode.GENRES,
MusicMode.PLAYLISTS)
MusicType.SONGS,
MusicType.ALBUMS,
MusicType.ARTISTS,
MusicType.GENRES,
MusicType.PLAYLISTS)
/**
* Convert an array of [Tab]s into it's integer representation.
@ -84,7 +84,7 @@ sealed class Tab(open val mode: MusicMode) {
*/
fun toIntCode(tabs: Array<Tab>): Int {
// Like when deserializing, make sure there are no duplicate tabs for whatever reason.
val distinct = tabs.distinctBy { it.mode }
val distinct = tabs.distinctBy { it.type }
if (tabs.size != distinct.size) {
logW(
"Tab sequences should not have duplicates [old: ${tabs.size} new: ${distinct.size}]")
@ -95,8 +95,8 @@ sealed class Tab(open val mode: MusicMode) {
for (tab in distinct) {
val bin =
when (tab) {
is Visible -> 1.shl(3) or MODE_TABLE.indexOf(tab.mode)
is Invisible -> MODE_TABLE.indexOf(tab.mode)
is Visible -> 1.shl(3) or MODE_TABLE.indexOf(tab.type)
is Invisible -> MODE_TABLE.indexOf(tab.type)
}
sequence = sequence or bin.shl(shift)
@ -131,7 +131,7 @@ sealed class Tab(open val mode: MusicMode) {
}
// Make sure there are no duplicate tabs
val distinct = tabs.distinctBy { it.mode }
val distinct = tabs.distinctBy { it.type }
if (tabs.size != distinct.size) {
logW(
"Tab sequences should not have duplicates [old: ${tabs.size} new: ${distinct.size}]")

View file

@ -26,7 +26,7 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.ItemTabBinding
import org.oxycblt.auxio.list.EditClickListListener
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.logD
@ -107,14 +107,14 @@ class TabViewHolder private constructor(private val binding: ItemTabBinding) :
fun bind(tab: Tab, listener: EditClickListListener<Tab>) {
listener.bind(tab, this, dragHandle = binding.tabDragHandle)
binding.tabCheckBox.apply {
// Update the CheckBox name to align with the mode
// Update the CheckBox name to align with the type
setText(
when (tab.mode) {
MusicMode.SONGS -> R.string.lbl_songs
MusicMode.ALBUMS -> R.string.lbl_albums
MusicMode.ARTISTS -> R.string.lbl_artists
MusicMode.GENRES -> R.string.lbl_genres
MusicMode.PLAYLISTS -> R.string.lbl_playlists
when (tab.type) {
MusicType.SONGS -> R.string.lbl_songs
MusicType.ALBUMS -> R.string.lbl_albums
MusicType.ARTISTS -> R.string.lbl_artists
MusicType.GENRES -> R.string.lbl_genres
MusicType.PLAYLISTS -> R.string.lbl_playlists
})
// Unlike in other adapters, we update the checked state alongside

View file

@ -91,13 +91,13 @@ class TabCustomizeDialog :
override fun onClick(item: Tab, viewHolder: RecyclerView.ViewHolder) {
// We will need the exact index of the tab to update on in order to
// notify the adapter of the change.
val index = tabAdapter.tabs.indexOfFirst { it.mode == item.mode }
val index = tabAdapter.tabs.indexOfFirst { it.type == item.type }
val old = tabAdapter.tabs[index]
val new =
when (old) {
// Invert the visibility of the tab
is Tab.Visible -> Tab.Invisible(old.mode)
is Tab.Invisible -> Tab.Visible(old.mode)
is Tab.Visible -> Tab.Invisible(old.type)
is Tab.Invisible -> Tab.Visible(old.type)
}
logD("Flipping tab visibility [from: $old to: $new]")
tabAdapter.setTab(index, new)

View file

@ -80,23 +80,23 @@ sealed interface Music : Item {
class UID
private constructor(
private val format: Format,
private val mode: MusicMode,
private val type: MusicType,
private val uuid: UUID
) : Parcelable {
// Cache the hashCode for HashMap efficiency.
@IgnoredOnParcel private var hashCode = format.hashCode()
init {
hashCode = 31 * hashCode + mode.hashCode()
hashCode = 31 * hashCode + type.hashCode()
hashCode = 31 * hashCode + uuid.hashCode()
}
override fun hashCode() = hashCode
override fun equals(other: Any?) =
other is UID && format == other.format && mode == other.mode && uuid == other.uuid
other is UID && format == other.format && type == other.type && uuid == other.uuid
override fun toString() = "${format.namespace}:${mode.intCode.toString(16)}-$uuid"
override fun toString() = "${format.namespace}:${type.intCode.toString(16)}-$uuid"
/**
* Internal marker of [Music.UID] format type.
@ -124,23 +124,23 @@ sealed interface Music : Item {
* Creates an Auxio-style [UID] of random composition. Used if there is no
* non-subjective, unlikely-to-change metadata of the music.
*
* @param mode The analogous [MusicMode] of the item that created this [UID].
* @param type The analogous [MusicType] of the item that created this [UID].
*/
fun auxio(mode: MusicMode): UID {
return UID(Format.AUXIO, mode, UUID.randomUUID())
fun auxio(type: MusicType): UID {
return UID(Format.AUXIO, type, UUID.randomUUID())
}
/**
* Creates an Auxio-style [UID] with a [UUID] composed of a hash of the non-subjective,
* unlikely-to-change metadata of the music.
*
* @param mode The analogous [MusicMode] of the item that created this [UID].
* @param type The analogous [MusicType] of the item that created this [UID].
* @param updates Block to update the [MessageDigest] hash with the metadata of the
* item. Make sure the metadata hashed semantically aligns with the format
* specification.
* @return A new auxio-style [UID].
*/
fun auxio(mode: MusicMode, updates: MessageDigest.() -> Unit): UID {
fun auxio(type: MusicType, updates: MessageDigest.() -> Unit): UID {
val digest =
MessageDigest.getInstance("SHA-256").run {
updates()
@ -170,19 +170,19 @@ sealed interface Music : Item {
.or(digest[13].toLong().and(0xFF).shl(16))
.or(digest[14].toLong().and(0xFF).shl(8))
.or(digest[15].toLong().and(0xFF)))
return UID(Format.AUXIO, mode, uuid)
return UID(Format.AUXIO, type, uuid)
}
/**
* Creates a MusicBrainz-style [UID] with a [UUID] derived from the MusicBrainz ID
* extracted from a file.
*
* @param mode The analogous [MusicMode] of the item that created this [UID].
* @param type The analogous [MusicType] of the item that created this [UID].
* @param mbid The analogous MusicBrainz ID for this item that was extracted from a
* file.
* @return A new MusicBrainz-style [UID].
*/
fun musicBrainz(mode: MusicMode, mbid: UUID) = UID(Format.MUSICBRAINZ, mode, mbid)
fun musicBrainz(type: MusicType, mbid: UUID) = UID(Format.MUSICBRAINZ, type, mbid)
/**
* Convert a [UID]'s string representation back into a concrete [UID] instance.
@ -210,10 +210,10 @@ sealed interface Music : Item {
return null
}
val mode =
MusicMode.fromIntCode(ids[0].toIntOrNull(16) ?: return null) ?: return null
val type =
MusicType.fromIntCode(ids[0].toIntOrNull(16) ?: return null) ?: return null
val uuid = ids[1].toUuidOrNull() ?: return null
return UID(format, mode, uuid)
return UID(format, type, uuid)
}
}
}

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2022 Auxio Project
* MusicMode.kt is part of Auxio.
* MusicType.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -21,20 +21,20 @@ package org.oxycblt.auxio.music
import org.oxycblt.auxio.IntegerTable
/**
* Represents a data configuration corresponding to a specific type of [Music],
* General configuration enum to control what kind of music is being worked with.
*
* @author Alexander Capehart (OxygenCobalt)
*/
enum class MusicMode {
/** Configure with respect to [Song] instances. */
enum class MusicType {
/** @see Song */
SONGS,
/** Configure with respect to [Album] instances. */
/** @see Album */
ALBUMS,
/** Configure with respect to [Artist] instances. */
/** @see Artist */
ARTISTS,
/** Configure with respect to [Genre] instances. */
/** @see Genre */
GENRES,
/** Configure with respect to [Playlist] instances. */
/** @see Playlist */
PLAYLISTS;
/**
@ -54,11 +54,11 @@ enum class MusicMode {
companion object {
/**
* Convert a [MusicMode] integer representation into an instance.
* Convert a [MusicType] integer representation into an instance.
*
* @param intCode An integer representation of a [MusicMode]
* @return The corresponding [MusicMode], or null if the [MusicMode] is invalid.
* @see MusicMode.intCode
* @param intCode An integer representation of a [MusicType]
* @return The corresponding [MusicType], or null if the [MusicType] is invalid.
* @see MusicType.intCode
*/
fun fromIntCode(intCode: Int) =
when (intCode) {

View file

@ -25,8 +25,8 @@ import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.fs.MimeType
import org.oxycblt.auxio.music.fs.Path
@ -54,8 +54,8 @@ import org.oxycblt.auxio.util.update
class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Song {
override val uid =
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
rawSong.musicBrainzId?.toUuidOrNull()?.let { Music.UID.musicBrainz(MusicMode.SONGS, it) }
?: Music.UID.auxio(MusicMode.SONGS) {
rawSong.musicBrainzId?.toUuidOrNull()?.let { Music.UID.musicBrainz(MusicType.SONGS, it) }
?: Music.UID.auxio(MusicType.SONGS) {
// Song UIDs are based on the raw data without parsing so that they remain
// consistent across music setting changes. Parents are not held up to the
// same standard since grouping is already inherently linked to settings.
@ -251,8 +251,8 @@ class AlbumImpl(
override val uid =
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
rawAlbum.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ALBUMS, it) }
?: Music.UID.auxio(MusicMode.ALBUMS) {
rawAlbum.musicBrainzId?.let { Music.UID.musicBrainz(MusicType.ALBUMS, it) }
?: Music.UID.auxio(MusicType.ALBUMS) {
// Hash based on only names despite the presence of a date to increase stability.
// I don't know if there is any situation where an artist will have two albums with
// the exact same name, but if there is, I would love to know.
@ -366,8 +366,8 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, musicSettings: MusicSetti
override val uid =
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
rawArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ARTISTS, it) }
?: Music.UID.auxio(MusicMode.ARTISTS) { update(rawArtist.name) }
rawArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicType.ARTISTS, it) }
?: Music.UID.auxio(MusicType.ARTISTS) { update(rawArtist.name) }
override val name =
rawArtist.name?.let { Name.Known.from(it, rawArtist.sortName, musicSettings) }
?: Name.Unknown(R.string.def_artist)
@ -461,7 +461,7 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, musicSettings: MusicSetti
class GenreImpl(grouping: Grouping<RawGenre, SongImpl>, musicSettings: MusicSettings) : Genre {
private val rawGenre = grouping.raw.inner
override val uid = Music.UID.auxio(MusicMode.GENRES) { update(rawGenre.name) }
override val uid = Music.UID.auxio(MusicType.GENRES) { update(rawGenre.name) }
override val name =
rawGenre.name?.let { Name.Known.from(it, rawGenre.name, musicSettings) }
?: Name.Unknown(R.string.def_genre)

View file

@ -19,8 +19,8 @@
package org.oxycblt.auxio.music.user
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.device.DeviceLibrary
@ -78,7 +78,7 @@ private constructor(
*/
fun from(name: String, songs: List<Song>, musicSettings: MusicSettings) =
PlaylistImpl(
Music.UID.auxio(MusicMode.PLAYLISTS),
Music.UID.auxio(MusicType.PLAYLISTS),
Name.Known.from(name, null, musicSettings),
songs)

View file

@ -23,7 +23,7 @@ import androidx.core.content.edit
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.settings.Settings
/**
@ -32,19 +32,21 @@ import org.oxycblt.auxio.settings.Settings
* @author Alexander Capehart (OxygenCobalt)
*/
interface SearchSettings : Settings<Nothing> {
/** The type of Music the search view is currently filtering to. */
var searchFilterMode: MusicMode?
/** The type of Music the search view is should filter to. */
var filterTo: MusicType?
}
class SearchSettingsImpl @Inject constructor(@ApplicationContext context: Context) :
Settings.Impl<Nothing>(context), SearchSettings {
override var searchFilterMode: MusicMode?
override var filterTo: MusicType?
get() =
MusicMode.fromIntCode(
sharedPreferences.getInt(getString(R.string.set_key_search_filter), Int.MIN_VALUE))
MusicType.fromIntCode(
sharedPreferences.getInt(
getString(R.string.set_key_search_filter_to), Int.MIN_VALUE))
set(value) {
sharedPreferences.edit {
putInt(getString(R.string.set_key_search_filter), value?.intCode ?: Int.MIN_VALUE)
putInt(
getString(R.string.set_key_search_filter_to), value?.intCode ?: Int.MIN_VALUE)
apply()
}
}

View file

@ -33,8 +33,8 @@ import org.oxycblt.auxio.list.BasicHeader
import org.oxycblt.auxio.list.Divider
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.device.DeviceLibrary
import org.oxycblt.auxio.music.user.UserLibrary
@ -117,12 +117,12 @@ constructor(
userLibrary: UserLibrary,
query: String
): List<Item> {
val filterMode = searchSettings.searchFilterMode
val filter = searchSettings.filterTo
val items =
if (filterMode == null) {
// A nulled filter mode means to not filter anything.
logD("No filter mode specified, using entire library")
if (filter == null) {
// A nulled filter type means to not filter anything.
logD("No filter specified, using entire library")
SearchEngine.Items(
deviceLibrary.songs,
deviceLibrary.albums,
@ -130,14 +130,13 @@ constructor(
deviceLibrary.genres,
userLibrary.playlists)
} else {
logD("Filter mode specified, filtering library")
logD("Filter specified, reducing library")
SearchEngine.Items(
songs = if (filterMode == MusicMode.SONGS) deviceLibrary.songs else null,
albums = if (filterMode == MusicMode.ALBUMS) deviceLibrary.albums else null,
artists = if (filterMode == MusicMode.ARTISTS) deviceLibrary.artists else null,
genres = if (filterMode == MusicMode.GENRES) deviceLibrary.genres else null,
playlists =
if (filterMode == MusicMode.PLAYLISTS) userLibrary.playlists else null)
songs = if (filter == MusicType.SONGS) deviceLibrary.songs else null,
albums = if (filter == MusicType.ALBUMS) deviceLibrary.albums else null,
artists = if (filter == MusicType.ARTISTS) deviceLibrary.artists else null,
genres = if (filter == MusicType.GENRES) deviceLibrary.genres else null,
playlists = if (filter == MusicType.PLAYLISTS) userLibrary.playlists else null)
}
val results = searchEngine.search(items, query)
@ -199,35 +198,35 @@ constructor(
*/
@IdRes
fun getFilterOptionId() =
when (searchSettings.searchFilterMode) {
MusicMode.SONGS -> R.id.option_filter_songs
MusicMode.ALBUMS -> R.id.option_filter_albums
MusicMode.ARTISTS -> R.id.option_filter_artists
MusicMode.GENRES -> R.id.option_filter_genres
MusicMode.PLAYLISTS -> R.id.option_filter_playlists
when (searchSettings.filterTo) {
MusicType.SONGS -> R.id.option_filter_songs
MusicType.ALBUMS -> R.id.option_filter_albums
MusicType.ARTISTS -> R.id.option_filter_artists
MusicType.GENRES -> R.id.option_filter_genres
MusicType.PLAYLISTS -> R.id.option_filter_playlists
// Null maps to filtering nothing.
null -> R.id.option_filter_all
}
/**
* Update the filter mode with the newly-selected filter option.
* Update the filter type with the newly-selected filter option.
*
* @return A menu item ID of the new filtering option selected.
*/
fun setFilterOptionId(@IdRes id: Int) {
val newFilterMode =
val newFilter =
when (id) {
R.id.option_filter_songs -> MusicMode.SONGS
R.id.option_filter_albums -> MusicMode.ALBUMS
R.id.option_filter_artists -> MusicMode.ARTISTS
R.id.option_filter_genres -> MusicMode.GENRES
R.id.option_filter_playlists -> MusicMode.PLAYLISTS
R.id.option_filter_songs -> MusicType.SONGS
R.id.option_filter_albums -> MusicType.ALBUMS
R.id.option_filter_artists -> MusicType.ARTISTS
R.id.option_filter_genres -> MusicType.GENRES
R.id.option_filter_playlists -> MusicType.PLAYLISTS
// Null maps to filtering nothing.
R.id.option_filter_all -> null
else -> error("Invalid option ID provided")
}
logD("Updating filter mode to $newFilterMode")
searchSettings.searchFilterMode = newFilterMode
logD("Updating filter type to $newFilter")
searchSettings.filterTo = newFilter
search(lastQuery)
}

View file

@ -42,7 +42,7 @@
<string name="set_key_bar_action" translatable="false">auxio_bar_action</string>
<string name="set_key_notif_action" translatable="false">auxio_notif_action</string>
<string name="set_key_search_filter" translatable="false">KEY_SEARCH_FILTER</string>
<string name="set_key_search_filter_to" translatable="false">KEY_SEARCH_FILTER</string>
<string name="set_key_songs_sort" translatable="false">auxio_songs_sort</string>
<string name="set_key_albums_sort" translatable="false">auxio_albums_sort</string>

View file

@ -24,9 +24,9 @@ import org.junit.Test
class MusicModeTest {
@Test
fun intCode() {
assertEquals(MusicMode.SONGS, MusicMode.fromIntCode(MusicMode.SONGS.intCode))
assertEquals(MusicMode.ALBUMS, MusicMode.fromIntCode(MusicMode.ALBUMS.intCode))
assertEquals(MusicMode.ARTISTS, MusicMode.fromIntCode(MusicMode.ARTISTS.intCode))
assertEquals(MusicMode.GENRES, MusicMode.fromIntCode(MusicMode.GENRES.intCode))
assertEquals(MusicType.SONGS, MusicType.fromIntCode(MusicType.SONGS.intCode))
assertEquals(MusicType.ALBUMS, MusicType.fromIntCode(MusicType.ALBUMS.intCode))
assertEquals(MusicType.ARTISTS, MusicType.fromIntCode(MusicType.ARTISTS.intCode))
assertEquals(MusicType.GENRES, MusicType.fromIntCode(MusicType.GENRES.intCode))
}
}