music: add option to disable article sort names
Add a setting to remove hard-coded sort names based on articles. This feature is nice, but does not work with some non-english music. Those individuals should have the ability to disable it. The implementation honestly is not the greatest, primarily because it does a 100% reload when it could just regenerate the library. Auxio's current music model isn't really designed for that, so it will do this until a need to that kind of "soft reload" really arises. Resolves #359.
This commit is contained in:
parent
2d9a5ad5cd
commit
45fe36bd09
7 changed files with 75 additions and 29 deletions
|
@ -6,6 +6,7 @@
|
||||||
- Added support for disc subtitles
|
- Added support for disc subtitles
|
||||||
- Added support for ALAC files
|
- Added support for ALAC files
|
||||||
- Song properties view now shows tags
|
- Song properties view now shows tags
|
||||||
|
- Added option to control whether articles like "the" are ignored when sorting
|
||||||
|
|
||||||
#### What's Improved
|
#### What's Improved
|
||||||
- Will now accept zeroed track/disc numbers in the presence of non-zero total
|
- Will now accept zeroed track/disc numbers in the presence of non-zero total
|
||||||
|
|
|
@ -42,6 +42,8 @@ interface MusicSettings : Settings<MusicSettings.Listener> {
|
||||||
val shouldBeObserving: Boolean
|
val shouldBeObserving: Boolean
|
||||||
/** A [String] of characters representing the desired characters to denote multi-value tags. */
|
/** A [String] of characters representing the desired characters to denote multi-value tags. */
|
||||||
var multiValueSeparators: String
|
var multiValueSeparators: String
|
||||||
|
/** Whether to trim english articles with song sort names. */
|
||||||
|
val automaticSortNames: Boolean
|
||||||
/** The [Sort] mode used in [Song] lists. */
|
/** The [Sort] mode used in [Song] lists. */
|
||||||
var songSort: Sort
|
var songSort: Sort
|
||||||
/** The [Sort] mode used in [Album] lists. */
|
/** The [Sort] mode used in [Album] lists. */
|
||||||
|
@ -106,6 +108,9 @@ class MusicSettingsImpl @Inject constructor(@ApplicationContext context: Context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val automaticSortNames: Boolean
|
||||||
|
get() = sharedPreferences.getBoolean(getString(R.string.set_key_auto_sort_names), true)
|
||||||
|
|
||||||
override var songSort: Sort
|
override var songSort: Sort
|
||||||
get() =
|
get() =
|
||||||
Sort.fromIntCode(
|
Sort.fromIntCode(
|
||||||
|
@ -203,11 +208,14 @@ class MusicSettingsImpl @Inject constructor(@ApplicationContext context: Context
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSettingChanged(key: String, listener: MusicSettings.Listener) {
|
override fun onSettingChanged(key: String, listener: MusicSettings.Listener) {
|
||||||
|
// TODO: Differentiate "hard reloads" (Need the cache) and "Soft reloads"
|
||||||
|
// (just need to manipulate data)
|
||||||
when (key) {
|
when (key) {
|
||||||
getString(R.string.set_key_exclude_non_music),
|
getString(R.string.set_key_exclude_non_music),
|
||||||
getString(R.string.set_key_music_dirs),
|
getString(R.string.set_key_music_dirs),
|
||||||
getString(R.string.set_key_music_dirs_include),
|
getString(R.string.set_key_music_dirs_include),
|
||||||
getString(R.string.set_key_separators) -> listener.onIndexingSettingChanged()
|
getString(R.string.set_key_separators),
|
||||||
|
getString(R.string.set_key_auto_sort_names) -> listener.onIndexingSettingChanged()
|
||||||
getString(R.string.set_key_observing) -> listener.onObservingChanged()
|
getString(R.string.set_key_observing) -> listener.onObservingChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,9 +88,9 @@ interface Library {
|
||||||
|
|
||||||
private class LibraryImpl(rawSongs: List<RawSong>, settings: MusicSettings) : Library {
|
private class LibraryImpl(rawSongs: List<RawSong>, settings: MusicSettings) : Library {
|
||||||
override val songs = buildSongs(rawSongs, settings)
|
override val songs = buildSongs(rawSongs, settings)
|
||||||
override val albums = buildAlbums(songs)
|
override val albums = buildAlbums(songs, settings)
|
||||||
override val artists = buildArtists(songs, albums)
|
override val artists = buildArtists(songs, albums, settings)
|
||||||
override val genres = buildGenres(songs)
|
override val genres = buildGenres(songs, settings)
|
||||||
|
|
||||||
// Use a mapping to make finding information based on it's UID much faster.
|
// Use a mapping to make finding information based on it's UID much faster.
|
||||||
private val uidMap = buildMap {
|
private val uidMap = buildMap {
|
||||||
|
@ -127,7 +127,7 @@ private class LibraryImpl(rawSongs: List<RawSong>, settings: MusicSettings) : Li
|
||||||
/**
|
/**
|
||||||
* Build a list [SongImpl]s from the given [RawSong].
|
* Build a list [SongImpl]s from the given [RawSong].
|
||||||
* @param rawSongs The [RawSong]s to build the [SongImpl]s from.
|
* @param rawSongs The [RawSong]s to build the [SongImpl]s from.
|
||||||
* @param settings [MusicSettings] required to build [SongImpl]s.
|
* @param settings [MusicSettings] to obtain user parsing configuration.
|
||||||
* @return A sorted list of [SongImpl]s derived from the [RawSong] that should be suitable for
|
* @return A sorted list of [SongImpl]s derived from the [RawSong] that should be suitable for
|
||||||
* grouping.
|
* grouping.
|
||||||
*/
|
*/
|
||||||
|
@ -139,14 +139,15 @@ private class LibraryImpl(rawSongs: List<RawSong>, settings: MusicSettings) : Li
|
||||||
* Build a list of [Album]s from the given [Song]s.
|
* Build a list of [Album]s from the given [Song]s.
|
||||||
* @param songs The [Song]s to build [Album]s from. These will be linked with their respective
|
* @param songs The [Song]s to build [Album]s from. These will be linked with their respective
|
||||||
* [Album]s when created.
|
* [Album]s when created.
|
||||||
|
* @param settings [MusicSettings] to obtain user parsing configuration.
|
||||||
* @return A non-empty list of [Album]s. These [Album]s will be incomplete and must be linked
|
* @return A non-empty list of [Album]s. These [Album]s will be incomplete and must be linked
|
||||||
* with parent [Artist] instances in order to be usable.
|
* with parent [Artist] instances in order to be usable.
|
||||||
*/
|
*/
|
||||||
private fun buildAlbums(songs: List<SongImpl>): List<AlbumImpl> {
|
private fun buildAlbums(songs: List<SongImpl>, settings: MusicSettings): List<AlbumImpl> {
|
||||||
// Group songs by their singular raw album, then map the raw instances and their
|
// Group songs by their singular raw album, then map the raw instances and their
|
||||||
// grouped songs to Album values. Album.Raw will handle the actual grouping rules.
|
// grouped songs to Album values. Album.Raw will handle the actual grouping rules.
|
||||||
val songsByAlbum = songs.groupBy { it.rawAlbum }
|
val songsByAlbum = songs.groupBy { it.rawAlbum }
|
||||||
val albums = songsByAlbum.map { AlbumImpl(it.key, it.value) }
|
val albums = songsByAlbum.map { AlbumImpl(it.key, settings, it.value) }
|
||||||
logD("Successfully built ${albums.size} albums")
|
logD("Successfully built ${albums.size} albums")
|
||||||
return albums
|
return albums
|
||||||
}
|
}
|
||||||
|
@ -161,10 +162,15 @@ private class LibraryImpl(rawSongs: List<RawSong>, settings: MusicSettings) : Li
|
||||||
* @param albums The [Album]s to build [Artist]s from. One [Album] can result in the creation of
|
* @param albums The [Album]s to build [Artist]s from. One [Album] can result in the creation of
|
||||||
* one or more [Artist] instances. These will be linked with their respective [Artist]s when
|
* one or more [Artist] instances. These will be linked with their respective [Artist]s when
|
||||||
* created.
|
* created.
|
||||||
|
* @param settings [MusicSettings] to obtain user parsing configuration.
|
||||||
* @return A non-empty list of [Artist]s. These [Artist]s will consist of the combined groupings
|
* @return A non-empty list of [Artist]s. These [Artist]s will consist of the combined groupings
|
||||||
* of [Song]s and [Album]s.
|
* of [Song]s and [Album]s.
|
||||||
*/
|
*/
|
||||||
private fun buildArtists(songs: List<SongImpl>, albums: List<AlbumImpl>): List<ArtistImpl> {
|
private fun buildArtists(
|
||||||
|
songs: List<SongImpl>,
|
||||||
|
albums: List<AlbumImpl>,
|
||||||
|
settings: MusicSettings
|
||||||
|
): List<ArtistImpl> {
|
||||||
// Add every raw artist credited to each Song/Album to the grouping. This way,
|
// Add every raw artist credited to each Song/Album to the grouping. This way,
|
||||||
// different multi-artist combinations are not treated as different artists.
|
// different multi-artist combinations are not treated as different artists.
|
||||||
val musicByArtist = mutableMapOf<RawArtist, MutableList<Music>>()
|
val musicByArtist = mutableMapOf<RawArtist, MutableList<Music>>()
|
||||||
|
@ -182,7 +188,7 @@ private class LibraryImpl(rawSongs: List<RawSong>, settings: MusicSettings) : Li
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the combined mapping into artist instances.
|
// Convert the combined mapping into artist instances.
|
||||||
val artists = musicByArtist.map { ArtistImpl(it.key, it.value) }
|
val artists = musicByArtist.map { ArtistImpl(it.key, settings, it.value) }
|
||||||
logD("Successfully built ${artists.size} artists")
|
logD("Successfully built ${artists.size} artists")
|
||||||
return artists
|
return artists
|
||||||
}
|
}
|
||||||
|
@ -192,9 +198,10 @@ private class LibraryImpl(rawSongs: List<RawSong>, settings: MusicSettings) : Li
|
||||||
* @param [songs] The [Song]s to build [Genre]s from. One [Song] can result in the creation of
|
* @param [songs] The [Song]s to build [Genre]s from. One [Song] can result in the creation of
|
||||||
* one or more [Genre] instances. These will be linked with their respective [Genre]s when
|
* one or more [Genre] instances. These will be linked with their respective [Genre]s when
|
||||||
* created.
|
* created.
|
||||||
|
* @param settings [MusicSettings] to obtain user parsing configuration.
|
||||||
* @return A non-empty list of [Genre]s.
|
* @return A non-empty list of [Genre]s.
|
||||||
*/
|
*/
|
||||||
private fun buildGenres(songs: List<SongImpl>): List<GenreImpl> {
|
private fun buildGenres(songs: List<SongImpl>, settings: MusicSettings): List<GenreImpl> {
|
||||||
// Add every raw genre credited to each Song to the grouping. This way,
|
// Add every raw genre credited to each Song to the grouping. This way,
|
||||||
// different multi-genre combinations are not treated as different genres.
|
// different multi-genre combinations are not treated as different genres.
|
||||||
val songsByGenre = mutableMapOf<RawGenre, MutableList<SongImpl>>()
|
val songsByGenre = mutableMapOf<RawGenre, MutableList<SongImpl>>()
|
||||||
|
@ -205,7 +212,7 @@ private class LibraryImpl(rawSongs: List<RawSong>, settings: MusicSettings) : Li
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the mapping into genre instances.
|
// Convert the mapping into genre instances.
|
||||||
val genres = songsByGenre.map { GenreImpl(it.key, it.value) }
|
val genres = songsByGenre.map { GenreImpl(it.key, settings, it.value) }
|
||||||
logD("Successfully built ${genres.size} genres")
|
logD("Successfully built ${genres.size} genres")
|
||||||
return genres
|
return genres
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
/**
|
/**
|
||||||
* Library-backed implementation of [Song].
|
* Library-backed implementation of [Song].
|
||||||
* @param rawSong The [RawSong] to derive the member data from.
|
* @param rawSong The [RawSong] to derive the member data from.
|
||||||
* @param musicSettings [MusicSettings] to perform further user-configured parsing.
|
* @param musicSettings [MusicSettings] to for user parsing configuration.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song {
|
class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song {
|
||||||
|
@ -70,7 +70,7 @@ class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song {
|
||||||
}
|
}
|
||||||
override val rawName = requireNotNull(rawSong.name) { "Invalid raw: No title" }
|
override val rawName = requireNotNull(rawSong.name) { "Invalid raw: No title" }
|
||||||
override val rawSortName = rawSong.sortName
|
override val rawSortName = rawSong.sortName
|
||||||
override val collationKey = makeCollationKey(this)
|
override val collationKey = makeCollationKey(musicSettings)
|
||||||
override fun resolveName(context: Context) = rawName
|
override fun resolveName(context: Context) = rawName
|
||||||
|
|
||||||
override val track = rawSong.track
|
override val track = rawSong.track
|
||||||
|
@ -219,11 +219,16 @@ class SongImpl(rawSong: RawSong, musicSettings: MusicSettings) : Song {
|
||||||
/**
|
/**
|
||||||
* Library-backed implementation of [Album].
|
* Library-backed implementation of [Album].
|
||||||
* @param rawAlbum The [RawAlbum] to derive the member data from.
|
* @param rawAlbum The [RawAlbum] to derive the member data from.
|
||||||
|
* @param musicSettings [MusicSettings] to for user parsing configuration.
|
||||||
* @param songs The [Song]s that are a part of this [Album]. These items will be linked to this
|
* @param songs The [Song]s that are a part of this [Album]. These items will be linked to this
|
||||||
* [Album].
|
* [Album].
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class AlbumImpl(val rawAlbum: RawAlbum, override val songs: List<SongImpl>) : Album {
|
class AlbumImpl(
|
||||||
|
private val rawAlbum: RawAlbum,
|
||||||
|
musicSettings: MusicSettings,
|
||||||
|
override val songs: List<SongImpl>
|
||||||
|
) : Album {
|
||||||
override val uid =
|
override val uid =
|
||||||
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
||||||
rawAlbum.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ALBUMS, it) }
|
rawAlbum.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ALBUMS, it) }
|
||||||
|
@ -236,7 +241,7 @@ class AlbumImpl(val rawAlbum: RawAlbum, override val songs: List<SongImpl>) : Al
|
||||||
}
|
}
|
||||||
override val rawName = rawAlbum.name
|
override val rawName = rawAlbum.name
|
||||||
override val rawSortName = rawAlbum.sortName
|
override val rawSortName = rawAlbum.sortName
|
||||||
override val collationKey = makeCollationKey(this)
|
override val collationKey = makeCollationKey(musicSettings)
|
||||||
override fun resolveName(context: Context) = rawName
|
override fun resolveName(context: Context) = rawName
|
||||||
|
|
||||||
override val dates = Date.Range.from(songs.mapNotNull { it.date })
|
override val dates = Date.Range.from(songs.mapNotNull { it.date })
|
||||||
|
@ -309,19 +314,24 @@ class AlbumImpl(val rawAlbum: RawAlbum, override val songs: List<SongImpl>) : Al
|
||||||
/**
|
/**
|
||||||
* Library-backed implementation of [Artist].
|
* Library-backed implementation of [Artist].
|
||||||
* @param rawArtist The [RawArtist] to derive the member data from.
|
* @param rawArtist The [RawArtist] to derive the member data from.
|
||||||
|
* @param musicSettings [MusicSettings] to for user parsing configuration.
|
||||||
* @param songAlbums A list of the [Song]s and [Album]s that are a part of this [Artist] , either
|
* @param songAlbums A list of the [Song]s and [Album]s that are a part of this [Artist] , either
|
||||||
* through artist or album artist tags. Providing [Song]s to the artist is optional. These instances
|
* through artist or album artist tags. Providing [Song]s to the artist is optional. These instances
|
||||||
* will be linked to this [Artist].
|
* will be linked to this [Artist].
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class ArtistImpl(private val rawArtist: RawArtist, songAlbums: List<Music>) : Artist {
|
class ArtistImpl(
|
||||||
|
private val rawArtist: RawArtist,
|
||||||
|
musicSettings: MusicSettings,
|
||||||
|
songAlbums: List<Music>
|
||||||
|
) : Artist {
|
||||||
override val uid =
|
override val uid =
|
||||||
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
||||||
rawArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ARTISTS, it) }
|
rawArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ARTISTS, it) }
|
||||||
?: Music.UID.auxio(MusicMode.ARTISTS) { update(rawArtist.name) }
|
?: Music.UID.auxio(MusicMode.ARTISTS) { update(rawArtist.name) }
|
||||||
override val rawName = rawArtist.name
|
override val rawName = rawArtist.name
|
||||||
override val rawSortName = rawArtist.sortName
|
override val rawSortName = rawArtist.sortName
|
||||||
override val collationKey = makeCollationKey(this)
|
override val collationKey = makeCollationKey(musicSettings)
|
||||||
override fun resolveName(context: Context) = rawName ?: context.getString(R.string.def_artist)
|
override fun resolveName(context: Context) = rawName ?: context.getString(R.string.def_artist)
|
||||||
override val songs: List<Song>
|
override val songs: List<Song>
|
||||||
|
|
||||||
|
@ -390,13 +400,20 @@ class ArtistImpl(private val rawArtist: RawArtist, songAlbums: List<Music>) : Ar
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Library-backed implementation of [Genre].
|
* Library-backed implementation of [Genre].
|
||||||
|
* @param rawGenre [RawGenre] to derive the member data from.
|
||||||
|
* @param musicSettings [MusicSettings] to for user parsing configuration.
|
||||||
|
* @param songs Child [SongImpl]s of this instance.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class GenreImpl(private val rawGenre: RawGenre, override val songs: List<SongImpl>) : Genre {
|
class GenreImpl(
|
||||||
|
private val rawGenre: RawGenre,
|
||||||
|
musicSettings: MusicSettings,
|
||||||
|
override val songs: List<SongImpl>
|
||||||
|
) : Genre {
|
||||||
override val uid = Music.UID.auxio(MusicMode.GENRES) { update(rawGenre.name) }
|
override val uid = Music.UID.auxio(MusicMode.GENRES) { update(rawGenre.name) }
|
||||||
override val rawName = rawGenre.name
|
override val rawName = rawGenre.name
|
||||||
override val rawSortName = rawName
|
override val rawSortName = rawName
|
||||||
override val collationKey = makeCollationKey(this)
|
override val collationKey = makeCollationKey(musicSettings)
|
||||||
override fun resolveName(context: Context) = rawName ?: context.getString(R.string.def_genre)
|
override fun resolveName(context: Context) = rawName ?: context.getString(R.string.def_genre)
|
||||||
|
|
||||||
override val albums: List<Album>
|
override val albums: List<Album>
|
||||||
|
@ -503,12 +520,15 @@ private val COLLATOR: Collator = Collator.getInstance().apply { strength = Colla
|
||||||
/**
|
/**
|
||||||
* Provided implementation to create a [CollationKey] in the way described by [Music.collationKey].
|
* Provided implementation to create a [CollationKey] in the way described by [Music.collationKey].
|
||||||
* This should be used in all overrides of all [CollationKey].
|
* This should be used in all overrides of all [CollationKey].
|
||||||
* @param music The [Music] to create the [CollationKey] for.
|
* @param musicSettings [MusicSettings] required for user parsing configuration.
|
||||||
* @return A [CollationKey] that follows the specification described by [Music.collationKey].
|
* @return A [CollationKey] that follows the specification described by [Music.collationKey].
|
||||||
*/
|
*/
|
||||||
private fun makeCollationKey(music: Music): CollationKey? {
|
private fun Music.makeCollationKey(musicSettings: MusicSettings): CollationKey? {
|
||||||
val sortName =
|
var sortName = (rawSortName ?: rawName) ?: return null
|
||||||
(music.rawSortName ?: music.rawName)?.run {
|
|
||||||
|
if (musicSettings.automaticSortNames) {
|
||||||
|
sortName =
|
||||||
|
sortName.run {
|
||||||
when {
|
when {
|
||||||
length > 5 && startsWith("the ", ignoreCase = true) -> substring(4)
|
length > 5 && startsWith("the ", ignoreCase = true) -> substring(4)
|
||||||
length > 4 && startsWith("an ", ignoreCase = true) -> substring(3)
|
length > 4 && startsWith("an ", ignoreCase = true) -> substring(3)
|
||||||
|
@ -516,6 +536,7 @@ private fun makeCollationKey(music: Music): CollationKey? {
|
||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return COLLATOR.getCollationKey(sortName)
|
return COLLATOR.getCollationKey(sortName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
<string name="set_key_music_dirs_include" translatable="false">auxio_include_dirs</string>
|
<string name="set_key_music_dirs_include" translatable="false">auxio_include_dirs</string>
|
||||||
<string name="set_key_exclude_non_music" translatable="false">auxio_exclude_non_music</string>
|
<string name="set_key_exclude_non_music" translatable="false">auxio_exclude_non_music</string>
|
||||||
<string name="set_key_separators" translatable="false">auxio_separators</string>
|
<string name="set_key_separators" translatable="false">auxio_separators</string>
|
||||||
|
<string name="set_key_auto_sort_names" translatable="false">auxio_auto_sort_names</string>
|
||||||
|
|
||||||
<string name="set_key_headset_autoplay" translatable="false">auxio_headset_autoplay</string>
|
<string name="set_key_headset_autoplay" translatable="false">auxio_headset_autoplay</string>
|
||||||
<string name="set_key_replay_gain" translatable="false">auxio_replay_gain</string>
|
<string name="set_key_replay_gain" translatable="false">auxio_replay_gain</string>
|
||||||
|
|
|
@ -212,6 +212,8 @@
|
||||||
<string name="set_separators_plus">Plus (+)</string>
|
<string name="set_separators_plus">Plus (+)</string>
|
||||||
<string name="set_separators_and">Ampersand (&)</string>
|
<string name="set_separators_and">Ampersand (&)</string>
|
||||||
<string name="set_separators_warning">Warning: Using this setting may result in some tags being incorrectly interpreted as having multiple values. You can resolve this by prefixing unwanted separator characters with a backslash (\\).</string>
|
<string name="set_separators_warning">Warning: Using this setting may result in some tags being incorrectly interpreted as having multiple values. You can resolve this by prefixing unwanted separator characters with a backslash (\\).</string>
|
||||||
|
<string name="set_auto_sort_names">Ignore articles when sorting</string>
|
||||||
|
<string name="set_auto_sort_names_desc">Ignore words like \"the\" when sorting by name (works best with english-language music)</string>
|
||||||
<string name="set_hide_collaborators">Hide collaborators</string>
|
<string name="set_hide_collaborators">Hide collaborators</string>
|
||||||
<string name="set_hide_collaborators_desc">Only show artists that are directly credited on an album (works best on well-tagged libraries)</string>
|
<string name="set_hide_collaborators_desc">Only show artists that are directly credited on an album (works best on well-tagged libraries)</string>
|
||||||
<string name="set_images">Images</string>
|
<string name="set_images">Images</string>
|
||||||
|
|
|
@ -20,6 +20,12 @@
|
||||||
app:summary="@string/set_separators_desc"
|
app:summary="@string/set_separators_desc"
|
||||||
app:title="@string/set_separators" />
|
app:title="@string/set_separators" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:defaultValue="true"
|
||||||
|
app:key="@string/set_key_auto_sort_names"
|
||||||
|
app:summary="@string/set_auto_sort_names_desc"
|
||||||
|
app:title="@string/set_auto_sort_names" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
app:defaultValue="false"
|
app:defaultValue="false"
|
||||||
app:key="@string/set_key_hide_collaborators"
|
app:key="@string/set_key_hide_collaborators"
|
||||||
|
|
Loading…
Reference in a new issue