Add filtering to library search
Add filtering to the library search bar.
This commit is contained in:
parent
406ba212f8
commit
6627de4b62
7 changed files with 195 additions and 66 deletions
|
@ -41,8 +41,7 @@ import org.oxycblt.auxio.ui.toColor
|
||||||
* search functionality.
|
* search functionality.
|
||||||
* FIXME: Heisenleak when navving from search
|
* FIXME: Heisenleak when navving from search
|
||||||
* FIXME: Heisenleak on older versions
|
* FIXME: Heisenleak on older versions
|
||||||
* TODO: Filtering & Search order upgrades
|
* TODO: Filtering
|
||||||
* TODO: Show result counts?
|
|
||||||
*/
|
*/
|
||||||
class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
|
class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
|
||||||
|
|
||||||
|
@ -61,10 +60,46 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
|
||||||
val searchAdapter = SearchAdapter(::onItemSelection, ::showActionsForItem)
|
val searchAdapter = SearchAdapter(::onItemSelection, ::showActionsForItem)
|
||||||
|
|
||||||
val sortAction = binding.libraryToolbar.menu.findItem(R.id.submenu_sorting)
|
val sortAction = binding.libraryToolbar.menu.findItem(R.id.submenu_sorting)
|
||||||
|
val filterAction = binding.libraryToolbar.menu.findItem(R.id.submenu_filtering)
|
||||||
|
val searchView: SearchView
|
||||||
|
|
||||||
// --- UI SETUP ---
|
// --- UI SETUP ---
|
||||||
|
|
||||||
binding.libraryToolbar.apply {
|
binding.libraryToolbar.apply {
|
||||||
|
menu.apply {
|
||||||
|
val searchAction = findItem(R.id.action_search)
|
||||||
|
searchView = searchAction.actionView as SearchView
|
||||||
|
|
||||||
|
searchView.queryHint = getString(R.string.hint_search_library)
|
||||||
|
searchView.maxWidth = Int.MAX_VALUE
|
||||||
|
searchView.setOnQueryTextListener(this@LibraryFragment)
|
||||||
|
|
||||||
|
searchAction.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
||||||
|
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||||
|
binding.libraryRecycler.adapter = searchAdapter
|
||||||
|
|
||||||
|
searchAction.isVisible = false
|
||||||
|
sortAction.isVisible = false
|
||||||
|
filterAction.isVisible = true
|
||||||
|
|
||||||
|
libraryModel.resetQuery()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||||
|
binding.libraryRecycler.adapter = libraryAdapter
|
||||||
|
|
||||||
|
searchAction.isVisible = true
|
||||||
|
sortAction.isVisible = true
|
||||||
|
filterAction.isVisible = false
|
||||||
|
|
||||||
|
libraryModel.resetQuery()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
setOnMenuItemClickListener {
|
setOnMenuItemClickListener {
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.action_search -> {
|
R.id.action_search -> {
|
||||||
|
@ -74,45 +109,22 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
|
||||||
it.expandActionView()
|
it.expandActionView()
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.submenu_sorting -> {
|
R.id.submenu_sorting -> {}
|
||||||
}
|
|
||||||
|
|
||||||
else -> libraryModel.updateSortMode(it.itemId)
|
R.id.submenu_filtering -> {}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
if (sortAction.isVisible) {
|
||||||
|
libraryModel.updateSortMode(it.itemId)
|
||||||
|
} else if (filterAction.isVisible) {
|
||||||
|
libraryModel.updateFilterMode(it.itemId)
|
||||||
|
libraryModel.doSearch(searchView.query.toString(), requireContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.apply {
|
|
||||||
val searchAction = findItem(R.id.action_search)
|
|
||||||
val searchView = searchAction.actionView as SearchView
|
|
||||||
|
|
||||||
searchView.queryHint = getString(R.string.hint_search_library)
|
|
||||||
searchView.maxWidth = Int.MAX_VALUE
|
|
||||||
searchView.setOnQueryTextListener(this@LibraryFragment)
|
|
||||||
|
|
||||||
searchAction.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
|
||||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
|
||||||
binding.libraryRecycler.adapter = searchAdapter
|
|
||||||
item.isVisible = false
|
|
||||||
sortAction.isVisible = false
|
|
||||||
|
|
||||||
libraryModel.resetQuery()
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
|
||||||
binding.libraryRecycler.adapter = libraryAdapter
|
|
||||||
item.isVisible = true
|
|
||||||
sortAction.isVisible = true
|
|
||||||
|
|
||||||
libraryModel.resetQuery()
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.libraryRecycler.apply {
|
binding.libraryRecycler.apply {
|
||||||
|
@ -164,6 +176,20 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
libraryModel.filterMode.observe(viewLifecycleOwner) { mode ->
|
||||||
|
logD("Updating filter mode to $mode")
|
||||||
|
|
||||||
|
val modeId = mode.toMenuId()
|
||||||
|
|
||||||
|
filterAction.subMenu.forEach {
|
||||||
|
if (it.itemId == modeId) {
|
||||||
|
it.applyColor(accent.first.toColor(requireContext()))
|
||||||
|
} else {
|
||||||
|
it.applyColor(resolveAttr(requireContext(), android.R.attr.textColorPrimary))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
detailModel.navToItem.observe(viewLifecycleOwner) {
|
detailModel.navToItem.observe(viewLifecycleOwner) {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
libraryModel.updateNavigationStatus(false)
|
libraryModel.updateNavigationStatus(false)
|
||||||
|
|
|
@ -22,16 +22,22 @@ import org.oxycblt.auxio.settings.SettingsManager
|
||||||
*/
|
*/
|
||||||
class LibraryViewModel : ViewModel(), SettingsManager.Callback {
|
class LibraryViewModel : ViewModel(), SettingsManager.Callback {
|
||||||
private val mSortMode = MutableLiveData(SortMode.ALPHA_DOWN)
|
private val mSortMode = MutableLiveData(SortMode.ALPHA_DOWN)
|
||||||
private val mLibraryData = MutableLiveData(listOf<BaseModel>())
|
|
||||||
private val mSearchResults = MutableLiveData(listOf<BaseModel>())
|
|
||||||
private var mDisplayMode = DisplayMode.SHOW_ARTISTS
|
|
||||||
private var mIsNavigating = false
|
|
||||||
|
|
||||||
val sortMode: LiveData<SortMode> get() = mSortMode
|
val sortMode: LiveData<SortMode> get() = mSortMode
|
||||||
|
|
||||||
|
private val mLibraryData = MutableLiveData(listOf<BaseModel>())
|
||||||
val libraryData: LiveData<List<BaseModel>> get() = mLibraryData
|
val libraryData: LiveData<List<BaseModel>> get() = mLibraryData
|
||||||
|
|
||||||
|
private val mFilterMode = MutableLiveData(DisplayMode.SHOW_ALL)
|
||||||
|
val filterMode: LiveData<DisplayMode> get() = mFilterMode
|
||||||
|
|
||||||
|
private val mSearchResults = MutableLiveData(listOf<BaseModel>())
|
||||||
val searchResults: LiveData<List<BaseModel>> get() = mSearchResults
|
val searchResults: LiveData<List<BaseModel>> get() = mSearchResults
|
||||||
|
|
||||||
|
private var mIsNavigating = false
|
||||||
val isNavigating: Boolean get() = mIsNavigating
|
val isNavigating: Boolean get() = mIsNavigating
|
||||||
|
|
||||||
|
private var mDisplayMode = DisplayMode.SHOW_ARTISTS
|
||||||
|
|
||||||
private val settingsManager = SettingsManager.getInstance()
|
private val settingsManager = SettingsManager.getInstance()
|
||||||
private val musicStore = MusicStore.getInstance()
|
private val musicStore = MusicStore.getInstance()
|
||||||
|
|
||||||
|
@ -41,6 +47,7 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback {
|
||||||
// Set up the display/sort modes
|
// Set up the display/sort modes
|
||||||
mDisplayMode = settingsManager.libraryDisplayMode
|
mDisplayMode = settingsManager.libraryDisplayMode
|
||||||
mSortMode.value = settingsManager.librarySortMode
|
mSortMode.value = settingsManager.librarySortMode
|
||||||
|
mFilterMode.value = settingsManager.libraryFilterMode
|
||||||
|
|
||||||
updateLibraryData()
|
updateLibraryData()
|
||||||
}
|
}
|
||||||
|
@ -74,8 +81,8 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplayMode.SHOW_ARTISTS -> {
|
DisplayMode.SHOW_ARTISTS -> {
|
||||||
searchForArtists(combined, query, context) -
|
searchForArtists(combined, query, context)
|
||||||
searchForAlbums(combined, query, context)
|
searchForAlbums(combined, query, context)
|
||||||
searchForGenres(combined, query, context)
|
searchForGenres(combined, query, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +91,8 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback {
|
||||||
searchForArtists(combined, query, context)
|
searchForArtists(combined, query, context)
|
||||||
searchForGenres(combined, query, context)
|
searchForGenres(combined, query, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
mSearchResults.value = combined
|
mSearchResults.value = combined
|
||||||
|
@ -95,11 +104,15 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback {
|
||||||
query: String,
|
query: String,
|
||||||
context: Context
|
context: Context
|
||||||
): MutableList<BaseModel> {
|
): MutableList<BaseModel> {
|
||||||
val genres = musicStore.genres.filter { it.name.contains(query, true) }
|
if (mFilterMode.value == DisplayMode.SHOW_ALL ||
|
||||||
|
mFilterMode.value == DisplayMode.SHOW_GENRES
|
||||||
|
) {
|
||||||
|
val genres = musicStore.genres.filter { it.name.contains(query, true) }
|
||||||
|
|
||||||
if (genres.isNotEmpty()) {
|
if (genres.isNotEmpty()) {
|
||||||
data.add(Header(id = 0, name = context.getString(R.string.label_genres)))
|
data.add(Header(id = 0, name = context.getString(R.string.label_genres)))
|
||||||
data.addAll(genres)
|
data.addAll(genres)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
@ -110,11 +123,15 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback {
|
||||||
query: String,
|
query: String,
|
||||||
context: Context
|
context: Context
|
||||||
): MutableList<BaseModel> {
|
): MutableList<BaseModel> {
|
||||||
val artists = musicStore.artists.filter { it.name.contains(query, true) }
|
if (mFilterMode.value == DisplayMode.SHOW_ALL ||
|
||||||
|
mFilterMode.value == DisplayMode.SHOW_ARTISTS
|
||||||
|
) {
|
||||||
|
val artists = musicStore.artists.filter { it.name.contains(query, true) }
|
||||||
|
|
||||||
if (artists.isNotEmpty()) {
|
if (artists.isNotEmpty()) {
|
||||||
data.add(Header(id = 1, name = context.getString(R.string.label_artists)))
|
data.add(Header(id = 1, name = context.getString(R.string.label_artists)))
|
||||||
data.addAll(artists)
|
data.addAll(artists)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
@ -125,16 +142,36 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback {
|
||||||
query: String,
|
query: String,
|
||||||
context: Context
|
context: Context
|
||||||
): MutableList<BaseModel> {
|
): MutableList<BaseModel> {
|
||||||
val albums = musicStore.albums.filter { it.name.contains(query, true) }
|
if (mFilterMode.value == DisplayMode.SHOW_ALL ||
|
||||||
|
mFilterMode.value == DisplayMode.SHOW_ALBUMS
|
||||||
|
) {
|
||||||
|
val albums = musicStore.albums.filter { it.name.contains(query, true) }
|
||||||
|
|
||||||
if (albums.isNotEmpty()) {
|
if (albums.isNotEmpty()) {
|
||||||
data.add(Header(id = 2, name = context.getString(R.string.label_albums)))
|
data.add(Header(id = 2, name = context.getString(R.string.label_albums)))
|
||||||
data.addAll(albums)
|
data.addAll(albums)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateFilterMode(@IdRes itemId: Int) {
|
||||||
|
val mode = when (itemId) {
|
||||||
|
R.id.option_filter_all -> DisplayMode.SHOW_ALL
|
||||||
|
R.id.option_filter_albums -> DisplayMode.SHOW_ALBUMS
|
||||||
|
R.id.option_filter_artists -> DisplayMode.SHOW_ARTISTS
|
||||||
|
R.id.option_filter_genres -> DisplayMode.SHOW_GENRES
|
||||||
|
|
||||||
|
else -> DisplayMode.SHOW_ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFilterMode.value != mode) {
|
||||||
|
mFilterMode.value = mode
|
||||||
|
settingsManager.libraryFilterMode = mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun resetQuery() {
|
fun resetQuery() {
|
||||||
mSearchResults.value = listOf()
|
mSearchResults.value = listOf()
|
||||||
}
|
}
|
||||||
|
@ -203,6 +240,8 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback {
|
||||||
DisplayMode.SHOW_ALBUMS -> {
|
DisplayMode.SHOW_ALBUMS -> {
|
||||||
mSortMode.value!!.getSortedAlbumList(musicStore.albums)
|
mSortMode.value!!.getSortedAlbumList(musicStore.albums)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else -> error("DisplayMode $mDisplayMode is unsupported.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.oxycblt.auxio.recycler
|
package org.oxycblt.auxio.recycler
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.IdRes
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,20 +9,22 @@ import org.oxycblt.auxio.R
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*/
|
*/
|
||||||
enum class DisplayMode(@DrawableRes val iconRes: Int) {
|
enum class DisplayMode(@DrawableRes val iconRes: Int) {
|
||||||
|
SHOW_ALL(R.drawable.ic_sort_none),
|
||||||
SHOW_GENRES(R.drawable.ic_genre),
|
SHOW_GENRES(R.drawable.ic_genre),
|
||||||
SHOW_ARTISTS(R.drawable.ic_artist),
|
SHOW_ARTISTS(R.drawable.ic_artist),
|
||||||
SHOW_ALBUMS(R.drawable.ic_album);
|
SHOW_ALBUMS(R.drawable.ic_album);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a slice of all the values that this DisplayMode covers.
|
* Get a menu action for this show mode. Corresponds to filter actions.
|
||||||
*
|
|
||||||
* ex. SHOW_ARTISTS would return SHOW_ARTISTS, SHOW_ALBUMS, and SHOW_SONGS
|
|
||||||
* @return The values that this DisplayMode covers.
|
|
||||||
*/
|
*/
|
||||||
fun getChildren(): List<DisplayMode> {
|
@IdRes
|
||||||
val vals = values()
|
fun toMenuId(): Int {
|
||||||
|
return when (this) {
|
||||||
return vals.slice(vals.indexOf(this) until vals.size)
|
SHOW_ALL -> (R.id.option_filter_all)
|
||||||
|
SHOW_ALBUMS -> (R.id.option_filter_albums)
|
||||||
|
SHOW_ARTISTS -> (R.id.option_filter_artists)
|
||||||
|
SHOW_GENRES -> (R.id.option_filter_genres)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -144,6 +144,22 @@ class SettingsManager private constructor(context: Context) :
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current [DisplayMode] of the library search filtering
|
||||||
|
*/
|
||||||
|
var libraryFilterMode: DisplayMode
|
||||||
|
get() = DisplayMode.valueOfOrFallback(
|
||||||
|
sharedPrefs.getString(
|
||||||
|
Keys.KEY_LIBRARY_FILTER_MODE,
|
||||||
|
DisplayMode.SHOW_ARTISTS.toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
set(value) {
|
||||||
|
sharedPrefs.edit()
|
||||||
|
.putString(Keys.KEY_LIBRARY_FILTER_MODE, value.toString())
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
|
||||||
// --- CALLBACKS ---
|
// --- CALLBACKS ---
|
||||||
|
|
||||||
private val callbacks = mutableListOf<Callback>()
|
private val callbacks = mutableListOf<Callback>()
|
||||||
|
@ -231,6 +247,7 @@ class SettingsManager private constructor(context: Context) :
|
||||||
const val KEY_PREV_REWIND = "KEY_PREV_REWIND"
|
const val KEY_PREV_REWIND = "KEY_PREV_REWIND"
|
||||||
|
|
||||||
const val KEY_LIBRARY_SORT_MODE = "KEY_LIBRARY_SORT_MODE"
|
const val KEY_LIBRARY_SORT_MODE = "KEY_LIBRARY_SORT_MODE"
|
||||||
|
const val KEY_LIBRARY_FILTER_MODE = "KEY_LIBRARY_FILTER_MODE"
|
||||||
const val KEY_DEBUG_SAVE = "KEY_SAVE_STATE"
|
const val KEY_DEBUG_SAVE = "KEY_SAVE_STATE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
app/src/main/res/drawable/ic_filter.xml
Normal file
11
app/src/main/res/drawable/ic_filter.xml
Normal 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/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/>
|
||||||
|
</vector>
|
|
@ -12,8 +12,8 @@
|
||||||
tools:ignore="AlwaysShowAction" />
|
tools:ignore="AlwaysShowAction" />
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
This action has to be always shown since android mangles this action when I make it invisible
|
This action has to be always shown since otherwise android mangles this action when I make '
|
||||||
and then visible again.
|
it invisible and then visible again.
|
||||||
I hate this platform so much.
|
I hate this platform so much.
|
||||||
-->
|
-->
|
||||||
<item
|
<item
|
||||||
|
@ -38,4 +38,32 @@
|
||||||
</group>
|
</group>
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/submenu_filtering"
|
||||||
|
android:title="@string/label_filter"
|
||||||
|
android:icon="@drawable/ic_filter"
|
||||||
|
android:visible="false"
|
||||||
|
app:showAsAction="always">
|
||||||
|
<menu>
|
||||||
|
<group android:id="@+id/group_filtering">
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_filter_all"
|
||||||
|
android:title="@string/label_filter_all"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_filter_albums"
|
||||||
|
android:title="@string/label_albums"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_filter_artists"
|
||||||
|
android:title="@string/label_artists"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_filter_genres"
|
||||||
|
android:title="@string/label_genres"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
</menu>
|
</menu>
|
|
@ -11,7 +11,10 @@
|
||||||
<string name="label_genres">Genres</string>
|
<string name="label_genres">Genres</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_search">Search</string>
|
<string name="label_search">Search</string>
|
||||||
|
<string name="label_filter">Filter</string>
|
||||||
|
<string name="label_filter_all">All</string>
|
||||||
|
|
||||||
<string name="label_sort">Sort</string>
|
<string name="label_sort">Sort</string>
|
||||||
<string name="label_sort_none">Default</string>
|
<string name="label_sort_none">Default</string>
|
||||||
|
@ -69,7 +72,9 @@
|
||||||
<string name="setting_show_covers_desc">Turn off to save memory usage</string>
|
<string name="setting_show_covers_desc">Turn off to save memory usage</string>
|
||||||
|
|
||||||
<string name="setting_quality_covers">Ignore MediaStore covers</string>
|
<string name="setting_quality_covers">Ignore MediaStore covers</string>
|
||||||
<string name="setting_quality_covers_desc">Results in higher quality album covers, but causes slower loading and higher memory usage</string>
|
<string name="setting_quality_covers_desc">
|
||||||
|
Results in higher quality album covers, but causes slower loading and higher memory usage
|
||||||
|
</string>
|
||||||
|
|
||||||
<string name="setting_use_alt_action">Use alternate notification action</string>
|
<string name="setting_use_alt_action">Use alternate notification action</string>
|
||||||
<string name="setting_use_alt_loop">Prefer repeat mode action</string>
|
<string name="setting_use_alt_loop">Prefer repeat mode action</string>
|
||||||
|
|
Loading…
Reference in a new issue