Add sorting to LibraryFragment

Add basic sorting to LibraryFragment.
This commit is contained in:
OxygenCobalt 2020-09-28 15:10:14 -06:00
parent aad42b5201
commit 37c52d9e5c
17 changed files with 227 additions and 174 deletions

View file

@ -5,7 +5,6 @@ TODO:
/detail/ /detail/
- Add genre detail
- ? Implement Toolbar update functionality ? - ? Implement Toolbar update functionality ?
- ! Implement shared element transitions ! - ! Implement shared element transitions !
@ -24,11 +23,14 @@ TODO:
/library/ /library/
- ? Move into ViewPager ? - Re-add albums/genres into a single adapter
- Sorting - Add highlighting to the current sortmode
- Search - Search
- ? Show Artists, Albums, and Songs in search ?
- Exit functionality - Exit functionality
- ? Show Artists, Albums, and Songs in search ?
- ? Move into ViewPager ?
- ! Move Adapter functionality to ListAdapter!
To be added: To be added:
/prefs/ /prefs/

View file

@ -15,7 +15,6 @@ import org.oxycblt.auxio.databinding.FragmentAlbumDetailBinding
import org.oxycblt.auxio.detail.adapters.DetailSongAdapter import org.oxycblt.auxio.detail.adapters.DetailSongAdapter
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.SortMode
import org.oxycblt.auxio.theme.applyDivider import org.oxycblt.auxio.theme.applyDivider
import org.oxycblt.auxio.theme.toColor import org.oxycblt.auxio.theme.toColor
@ -65,7 +64,7 @@ class AlbumDetailFragment : Fragment() {
// If the album was shown directly from LibraryFragment, Then enable the ability to // If the album was shown directly from LibraryFragment, Then enable the ability to
// navigate upwards to the parent artist // navigate upwards to the parent artist
if (args.fromLibrary) { if (args.enableParentNav) {
detailModel.navToParent.observe(viewLifecycleOwner) { detailModel.navToParent.observe(viewLifecycleOwner) {
if (it) { if (it) {
findNavController().navigate( findNavController().navigate(
@ -89,14 +88,7 @@ class AlbumDetailFragment : Fragment() {
// Then update the sort mode of the album adapter. // Then update the sort mode of the album adapter.
songAdapter.submitList( songAdapter.submitList(
detailModel.currentAlbum.value!!.songs.sortedWith( mode.getSortedSongList(detailModel.currentAlbum.value!!.songs)
SortMode.songSortComparators.getOrDefault(
mode,
// If any invalid value is given, just default to the normal sort order.
compareByDescending { it.track }
)
)
) )
} }

View file

@ -16,7 +16,6 @@ import org.oxycblt.auxio.detail.adapters.DetailAlbumAdapter
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.SortMode
import org.oxycblt.auxio.theme.applyDivider import org.oxycblt.auxio.theme.applyDivider
import org.oxycblt.auxio.theme.toColor import org.oxycblt.auxio.theme.toColor
@ -72,14 +71,7 @@ class ArtistDetailFragment : Fragment() {
// Then update the sort mode of the album adapter. // Then update the sort mode of the album adapter.
albumAdapter.submitList( albumAdapter.submitList(
detailModel.currentArtist.value!!.albums.sortedWith( mode.getSortedAlbumList(detailModel.currentArtist.value!!.albums)
SortMode.albumSortComparators.getOrDefault(
mode,
// If any invalid value is given, just default to the normal sort order.
compareByDescending { it.year }
)
)
) )
} }

View file

@ -16,7 +16,6 @@ import org.oxycblt.auxio.detail.adapters.DetailArtistAdapter
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.SortMode
import org.oxycblt.auxio.theme.applyDivider import org.oxycblt.auxio.theme.applyDivider
import org.oxycblt.auxio.theme.toColor import org.oxycblt.auxio.theme.toColor
@ -70,14 +69,7 @@ class GenreDetailFragment : Fragment() {
// Then update the sort mode of the artist adapter. // Then update the sort mode of the artist adapter.
albumAdapter.submitList( albumAdapter.submitList(
detailModel.currentGenre.value!!.artists.sortedWith( mode.getSortedArtistList(detailModel.currentGenre.value!!.artists)
SortMode.artistSortComparators.getOrDefault(
mode,
// If any invalid value is given, just default to the normal sort order.
compareByDescending { it.name }
)
)
) )
} }

View file

@ -5,29 +5,24 @@ import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import org.oxycblt.auxio.MainFragmentDirections import org.oxycblt.auxio.MainFragmentDirections
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentLibraryBinding import org.oxycblt.auxio.databinding.FragmentLibraryBinding
import org.oxycblt.auxio.library.adapters.AlbumAdapter
import org.oxycblt.auxio.library.adapters.ArtistAdapter import org.oxycblt.auxio.library.adapters.ArtistAdapter
import org.oxycblt.auxio.library.adapters.GenreAdapter
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.theme.SHOW_ALBUMS
import org.oxycblt.auxio.theme.SHOW_ARTISTS
import org.oxycblt.auxio.theme.SHOW_GENRES
import org.oxycblt.auxio.theme.applyDivider import org.oxycblt.auxio.theme.applyDivider
class LibraryFragment : Fragment() { class LibraryFragment : Fragment() {
// FIXME: Temp value, remove when there are actual preferences
private val libraryMode = SHOW_ARTISTS
private val musicModel: MusicViewModel by activityViewModels() private val musicModel: MusicViewModel by activityViewModels()
private val libraryModel: LibraryViewModel by activityViewModels() private val libraryModel: LibraryViewModel by activityViewModels()
@ -38,34 +33,34 @@ class LibraryFragment : Fragment() {
): View? { ): View? {
val binding = FragmentLibraryBinding.inflate(inflater) val binding = FragmentLibraryBinding.inflate(inflater)
binding.libraryRecycler.adapter = when (libraryMode) { val artistAdapter = ArtistAdapter(
SHOW_ARTISTS -> ArtistAdapter( ClickListener { navToItem(it) }
musicModel.artists.value!!, )
ClickListener {
navToArtist(it)
}
)
SHOW_ALBUMS -> AlbumAdapter(
musicModel.albums.value!!,
ClickListener {
navToAlbum(it)
}
)
SHOW_GENRES -> GenreAdapter(
musicModel.genres.value!!,
ClickListener {
navToGenre(it)
}
)
else -> null
}
binding.libraryRecycler.adapter = artistAdapter
binding.libraryRecycler.applyDivider() binding.libraryRecycler.applyDivider()
binding.libraryRecycler.setHasFixedSize(true) binding.libraryRecycler.setHasFixedSize(true)
libraryModel.sortMode.observe(viewLifecycleOwner) { mode ->
binding.libraryToolbar.overflowIcon = ContextCompat.getDrawable(
requireContext(), mode.iconRes
)
artistAdapter.updateData(
mode.getSortedArtistList(
musicModel.artists.value!!
)
)
}
binding.libraryToolbar.setOnMenuItemClickListener {
libraryModel.updateSortMode(it)
true
}
binding.libraryToolbar.inflateMenu(R.menu.menu_library)
Log.d(this::class.simpleName, "Fragment created.") Log.d(this::class.simpleName, "Fragment created.")
return binding.root return binding.root
@ -77,39 +72,19 @@ class LibraryFragment : Fragment() {
libraryModel.isAlreadyNavigating = false libraryModel.isAlreadyNavigating = false
} }
private fun navToArtist(artist: Artist) { private fun navToItem(baseModel: BaseModel) {
// Dont navigate if an item has already been selected // Don't navigate if an item has already been selected
if (!libraryModel.isAlreadyNavigating) { if (!libraryModel.isAlreadyNavigating) {
libraryModel.isAlreadyNavigating = true libraryModel.isAlreadyNavigating = true
findNavController().navigate( findNavController().navigate(
MainFragmentDirections.actionShowArtist( when (baseModel) {
artist.id is Genre -> MainFragmentDirections.actionShowGenre(baseModel.id)
) is Artist -> MainFragmentDirections.actionShowArtist(baseModel.id)
) is Album -> MainFragmentDirections.actionShowAlbum(baseModel.id, true)
}
}
private fun navToAlbum(album: Album) { else -> return
if (!libraryModel.isAlreadyNavigating) { }
libraryModel.isAlreadyNavigating = true
findNavController().navigate(
MainFragmentDirections.actionShowAlbum(
album.id, true
)
)
}
}
private fun navToGenre(genre: Genre) {
if (!libraryModel.isAlreadyNavigating) {
libraryModel.isAlreadyNavigating = true
findNavController().navigate(
MainFragmentDirections.actionShowGenre(
genre.id
)
) )
} }
} }

View file

@ -1,7 +1,34 @@
package org.oxycblt.auxio.library package org.oxycblt.auxio.library
import android.view.MenuItem
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import org.oxycblt.auxio.R
import org.oxycblt.auxio.recycler.SortMode
import org.oxycblt.auxio.theme.SHOW_ARTISTS
class LibraryViewModel : ViewModel() { class LibraryViewModel : ViewModel() {
var isAlreadyNavigating = false var isAlreadyNavigating = false
// TODO: Move these to pref values when they're added
private val mShowMode = MutableLiveData(SHOW_ARTISTS)
val showMode: LiveData<Int> get() = mShowMode
private val mSortMode = MutableLiveData(SortMode.ALPHA_UP)
val sortMode: LiveData<SortMode> get() = mSortMode
fun updateSortMode(item: MenuItem) {
val mode = when (item.itemId) {
R.id.sort_none -> SortMode.NONE
R.id.sort_alpha_down -> SortMode.ALPHA_DOWN
R.id.sort_alpha_up -> SortMode.ALPHA_UP
else -> SortMode.NONE
}
if (mode != mSortMode.value) {
mSortMode.value = mode
}
}
} }

View file

@ -2,18 +2,16 @@ package org.oxycblt.auxio.library.adapters
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.ListAdapter
import org.oxycblt.auxio.databinding.ItemAlbumBinding import org.oxycblt.auxio.databinding.ItemAlbumBinding
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.recycler.BaseViewHolder import org.oxycblt.auxio.recycler.BaseViewHolder
import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.DiffCallback
class AlbumAdapter( class AlbumAdapter(
private val data: List<Album>,
private val listener: ClickListener<Album> private val listener: ClickListener<Album>
) : RecyclerView.Adapter<AlbumAdapter.ViewHolder>() { ) : ListAdapter<Album, AlbumAdapter.ViewHolder>(DiffCallback()) {
override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder( return ViewHolder(
@ -22,7 +20,7 @@ class AlbumAdapter(
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(data[position]) holder.bind(getItem(position))
} }
inner class ViewHolder( inner class ViewHolder(

View file

@ -9,10 +9,11 @@ import org.oxycblt.auxio.recycler.BaseViewHolder
import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.ClickListener
class ArtistAdapter( class ArtistAdapter(
private val data: List<Artist>,
private val listener: ClickListener<Artist> private val listener: ClickListener<Artist>
) : RecyclerView.Adapter<ArtistAdapter.ViewHolder>() { ) : RecyclerView.Adapter<ArtistAdapter.ViewHolder>() {
private var data = listOf<Artist>()
override fun getItemCount(): Int = data.size override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -25,6 +26,12 @@ class ArtistAdapter(
holder.bind(data[position]) holder.bind(data[position])
} }
fun updateData(newData: List<Artist>) {
data = newData
notifyDataSetChanged()
}
inner class ViewHolder( inner class ViewHolder(
private val binding: ItemArtistBinding private val binding: ItemArtistBinding
) : BaseViewHolder<Artist>(binding, listener) { ) : BaseViewHolder<Artist>(binding, listener) {

View file

@ -2,18 +2,16 @@ package org.oxycblt.auxio.library.adapters
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.ListAdapter
import org.oxycblt.auxio.databinding.ItemGenreBinding import org.oxycblt.auxio.databinding.ItemGenreBinding
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.recycler.BaseViewHolder import org.oxycblt.auxio.recycler.BaseViewHolder
import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.DiffCallback
class GenreAdapter( class GenreAdapter(
private val data: List<Genre>,
private val listener: ClickListener<Genre> private val listener: ClickListener<Genre>
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() { ) : ListAdapter<Genre, GenreAdapter.ViewHolder>(DiffCallback()) {
override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder( return ViewHolder(
@ -22,7 +20,7 @@ class GenreAdapter(
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(data[position]) holder.bind(getItem(position))
} }
inner class ViewHolder( inner class ViewHolder(

View file

@ -21,7 +21,11 @@ class MusicSorter(
sortAlbumsIntoArtists() sortAlbumsIntoArtists()
sortArtistsIntoGenres() sortArtistsIntoGenres()
finalizeMusic() // Remove genre duplicates at the end, as duplicate genres can be added during
// the sorting process as well.
genres = genres.distinctBy {
it.name
}.toMutableList()
} }
private fun sortSongsIntoAlbums() { private fun sortSongsIntoAlbums() {
@ -155,25 +159,4 @@ class MusicSorter(
) )
} }
} }
// Finalize music
private fun finalizeMusic() {
// Remove genre duplicates now, as duplicate genres can be added during the sorting process.
genres = genres.distinctBy {
it.name
}.toMutableList()
// Then finally sort the music
genres.sortWith(
compareBy(String.CASE_INSENSITIVE_ORDER, { it.name })
)
artists.sortWith(
compareBy(String.CASE_INSENSITIVE_ORDER, { it.name })
)
albums.sortWith(
compareBy(String.CASE_INSENSITIVE_ORDER, { it.name })
)
}
} }

View file

@ -3,11 +3,7 @@ package org.oxycblt.auxio.recycler
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Song
// RecyclerView click listener // RecyclerView click listener
class ClickListener<T>(val onClick: (T) -> Unit) class ClickListener<T>(val onClick: (T) -> Unit)
@ -44,44 +40,3 @@ abstract class BaseViewHolder<T : BaseModel>(
abstract fun onBind(model: T) abstract fun onBind(model: T)
} }
// Sorting modes
enum class SortMode(val iconRes: Int) {
// Icons for each mode are assigned to the enums themselves
NONE(R.drawable.ic_sort_alpha_down),
ALPHA_UP(R.drawable.ic_sort_alpha_up),
ALPHA_DOWN(R.drawable.ic_sort_alpha_down),
NUMERIC_UP(R.drawable.ic_sort_numeric_up),
NUMERIC_DOWN(R.drawable.ic_sort_numeric_down);
companion object {
// Sort comparators are different for each music model, so they are static maps instead.
val songSortComparators = mapOf<SortMode, Comparator<Song>>(
NUMERIC_DOWN to compareBy { it.track },
NUMERIC_UP to compareByDescending { it.track }
)
val albumSortComparators = mapOf<SortMode, Comparator<Album>>(
NUMERIC_DOWN to compareByDescending { it.year },
NUMERIC_UP to compareBy { it.year },
// Alphabetic sorting needs to be case-insensitive
ALPHA_DOWN to compareByDescending(
String.CASE_INSENSITIVE_ORDER
) { it.name },
ALPHA_UP to compareBy(
String.CASE_INSENSITIVE_ORDER
) { it.name }
)
val artistSortComparators = mapOf<SortMode, Comparator<Artist>>(
// Alphabetic sorting needs to be case-insensitive
ALPHA_DOWN to compareBy(
String.CASE_INSENSITIVE_ORDER
) { it.name },
ALPHA_UP to compareByDescending(
String.CASE_INSENSITIVE_ORDER
) { it.name }
)
}
}

View file

@ -0,0 +1,89 @@
package org.oxycblt.auxio.recycler
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
// Sorting modes
enum class SortMode(val iconRes: Int) {
// Icons for each mode are assigned to the enums themselves
NONE(R.drawable.ic_sort_none),
ALPHA_UP(R.drawable.ic_sort_alpha_up),
ALPHA_DOWN(R.drawable.ic_sort_alpha_down),
NUMERIC_UP(R.drawable.ic_sort_numeric_up),
NUMERIC_DOWN(R.drawable.ic_sort_numeric_down);
fun getSortedGenreList(list: List<Genre>): List<Genre> {
return when (this) {
ALPHA_UP -> list.sortedWith(
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name }
)
ALPHA_DOWN -> list.sortedWith(
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
)
else -> list
}
}
fun getSortedArtistList(list: List<Artist>): List<Artist> {
return when (this) {
ALPHA_UP -> list.sortedWith(
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name }
)
ALPHA_DOWN -> list.sortedWith(
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
)
else -> list
}
}
fun getSortedAlbumList(list: List<Album>): List<Album> {
return when (this) {
ALPHA_UP -> list.sortedWith(
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name }
)
ALPHA_DOWN -> list.sortedWith(
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
)
NUMERIC_UP -> list.sortedBy { it.year }
NUMERIC_DOWN -> list.sortedByDescending { it.year }
else -> list
}
}
fun getSortedSongList(list: List<Song>): List<Song> {
return when (this) {
ALPHA_UP -> list.sortedWith(
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name }
)
ALPHA_DOWN -> list.sortedWith(
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
)
NUMERIC_UP -> list.sortedWith(compareByDescending { it.track })
NUMERIC_DOWN -> list.sortedWith(compareBy { it.track })
else -> list
}
}
fun toMenuId(): Int {
return when (this) {
NONE -> R.id.sort_none
ALPHA_UP -> R.id.sort_alpha_up
ALPHA_DOWN -> R.id.sort_alpha_down
else -> R.id.sort_none
}
}
}

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorPrimary">
<path
android:fillColor="@android:color/white"
android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
</vector>

View file

@ -7,7 +7,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:animateLayoutChanges="true"> android:animateLayoutChanges="true"
android:descendantFocusability="blocksDescendants">
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/library_toolbar" android:id="@+id/library_toolbar"

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/sort_none"
android:icon="@drawable/ic_sort_none"
android:title="@string/label_sort_none"
android:contentDescription="@string/description_sort_none"/>
<item
android:id="@+id/sort_alpha_down"
android:icon="@drawable/ic_sort_alpha_down"
android:title="@string/label_sort_alpha_down"
android:contentDescription="@string/description_sort_alpha_down"/>
<item
android:id="@+id/sort_alpha_up"
android:icon="@drawable/ic_sort_alpha_up"
android:title="@string/label_sort_alpha_up"
android:contentDescription="@string/description_sort_alpha_up"/>
</menu>

View file

@ -73,7 +73,7 @@
android:name="albumId" android:name="albumId"
app:argType="long" /> app:argType="long" />
<argument <argument
android:name="fromLibrary" android:name="enableParentNav"
app:argType="boolean" /> app:argType="boolean" />
<action <action
android:id="@+id/action_show_parent_artist" android:id="@+id/action_show_parent_artist"

View file

@ -2,35 +2,48 @@
<resources> <resources>
<string name="app_name">Auxio</string> <string name="app_name">Auxio</string>
<!-- Title Namespace | Toolbar titles -->
<string name="title_library_fragment">Library</string> <string name="title_library_fragment">Library</string>
<string name="title_all_songs">All Songs</string> <string name="title_all_songs">All Songs</string>
<!-- Error Namespace | Error Labels -->
<string name="error_no_music">No music found.</string> <string name="error_no_music">No music found.</string>
<string name="error_music_load_failed">Music loading failed.</string> <string name="error_music_load_failed">Music loading failed.</string>
<string name="error_no_perms">Permissions to read storage are needed.</string> <string name="error_no_perms">Permissions to read storage are needed.</string>
<!-- Label Namespace | Static Labels -->
<string name="label_retry">Retry</string> <string name="label_retry">Retry</string>
<string name="label_grant">Grant</string> <string name="label_grant">Grant</string>
<string name="label_artists">Artists</string> <string name="label_artists">Artists</string>
<string name="label_albums">Albums</string> <string name="label_albums">Albums</string>
<string name="label_songs">Songs</string> <string name="label_songs">Songs</string>
<string name="label_sort_none">Default</string>
<string name="label_sort_alpha_down">A-Z</string>
<string name="label_sort_alpha_up">Z-A</string>
<!-- Description Namespace | Accessibility Strings -->
<string name="description_album_cover">Album Cover for %s</string> <string name="description_album_cover">Album Cover for %s</string>
<string name="description_artist_image">Artist Image for %s</string> <string name="description_artist_image">Artist Image for %s</string>
<string name="description_genre_image">Genre Image for %s</string> <string name="description_genre_image">Genre Image for %s</string>
<string name="description_track_number">Track %s</string> <string name="description_track_number">Track %s</string>
<string name="description_error">Error</string> <string name="description_error">Error</string>
<string name="description_sort_button">Change Sorting Mode</string> <string name="description_sort_button">Change Sorting Mode</string>
<string name="description_sort_none">Default Sort Order</string>
<string name="description_sort_alpha_down">Sort from A to Z</string>
<string name="description_sort_alpha_up">Sort from Z to A</string>
<!-- Placeholder Namespace | Placeholder values -->
<string name="placeholder_genre">Unknown Genre</string> <string name="placeholder_genre">Unknown Genre</string>
<string name="placeholder_artist">Unknown Artist</string> <string name="placeholder_artist">Unknown Artist</string>
<string name="placeholder_album">Unknown Album</string> <string name="placeholder_album">Unknown Album</string>
<string name="placeholder_no_date">No Date</string> <string name="placeholder_no_date">No Date</string>
<!-- Format Namespace | Value formatting -->
<string name="format_info">%1$s / %2$s</string> <string name="format_info">%1$s / %2$s</string>
<string name="format_double_info">%1$s / %2$s / %3$s</string> <string name="format_double_info">%1$s / %2$s / %3$s</string>
<string name="format_double_counts">%1$s, %2$s</string> <string name="format_double_counts">%1$s, %2$s</string>
<!-- Format Namespace | Value formatting with plurals -->
<plurals name="format_song_count"> <plurals name="format_song_count">
<item quantity="one">%s Song</item> <item quantity="one">%s Song</item>
<item quantity="other">%s Songs</item> <item quantity="other">%s Songs</item>