image: unify cover settings

Unify the "Show Covers" and "Ignore MediaStore Covers" settings under an
new "Album covers" setting.

This will make it easier to extend to new forms of album cover
collection.
This commit is contained in:
Alexander Capehart 2022-09-26 13:47:03 -06:00
parent fc18f9d042
commit 5e0f778daf
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
15 changed files with 136 additions and 64 deletions

View file

@ -30,7 +30,9 @@ audio focus was lost
#### What's Changed
- Ignore MediaStore tags is now on by default
- Removed the "Play from genre" option in the library/detail playback mode settings
- Removed the "Play from genre" option in the library/detail playback mode settings+
- "Use alternate notification action" is now "Custom notification action"
- "Show covers" and "Ignore MediaStore covers" have been unified into "Album covers"
#### Dev/Meta
- Completed migration to reactive playback system

View file

@ -3,7 +3,6 @@ plugins {
id "kotlin-android"
id "androidx.navigation.safeargs.kotlin"
id "com.diffplug.spotless"
id "kotlin-kapt"
id "kotlin-parcelize"
}

View file

@ -144,11 +144,20 @@ object IntegerTable {
const val REPLAY_GAIN_MODE_DYNAMIC = 0xA113
/** ActionMode.Next */
const val BAR_ACTION_NEXT = 0xA119
const val ACTION_MODE_NEXT = 0xA119
/** ActionMode.Repeat */
const val BAR_ACTION_REPEAT = 0xA11A
const val ACTION_MODE_REPEAT = 0xA11A
/** ActionMode.Shuffle */
const val BAR_ACTION_SHUFFLE = 0xA11B
const val ACTION_MODE_SHUFFLE = 0xA11B
/** CoverMode.Off */
const val COVER_MODE_OFF = 0xA11C
/** CoverMode.MediaStore */
const val COVER_MODE_MEDIA_STORE = 0xA11D
/** CoverMode.Quality */
const val COVER_MODE_QUALITY = 0xA11E
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022 Auxio Project
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.image
import org.oxycblt.auxio.IntegerTable
/**
* Represents the options available for album cover loading.
* @author OxygenCobalt
*/
enum class CoverMode {
OFF,
MEDIA_STORE,
QUALITY;
val intCode: Int get() = when (this) {
OFF -> IntegerTable.COVER_MODE_OFF
MEDIA_STORE -> IntegerTable.COVER_MODE_MEDIA_STORE
QUALITY -> IntegerTable.COVER_MODE_QUALITY
}
companion object {
fun fromIntCode(intCode: Int) = when (intCode) {
IntegerTable.COVER_MODE_OFF -> OFF
IntegerTable.COVER_MODE_MEDIA_STORE -> MEDIA_STORE
IntegerTable.COVER_MODE_QUALITY -> QUALITY
else -> null
}
}
}

View file

@ -41,6 +41,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okio.buffer
import okio.source
import org.oxycblt.auxio.image.CoverMode
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.settings.Settings
import org.oxycblt.auxio.util.logD
@ -57,21 +58,17 @@ import android.util.Size as AndroidSize
*/
abstract class BaseFetcher : Fetcher {
/**
* Fetch the artwork of an [album]. This call respects user configuration and has proper
* Fetch the [album] cover. This call respects user configuration and has proper
* redundancy in the case that metadata fails to load.
*/
protected suspend fun fetchArt(context: Context, album: Album): InputStream? {
protected suspend fun fetchCover(context: Context, album: Album): InputStream? {
val settings = Settings(context)
if (!settings.showCovers) {
return null
}
return try {
if (settings.useQualityCovers) {
fetchQualityCovers(context, album)
} else {
fetchMediaStoreCovers(context, album)
when (settings.coverMode) {
CoverMode.OFF -> null
CoverMode.MEDIA_STORE -> fetchMediaStoreCovers(context, album)
CoverMode.QUALITY -> fetchQualityCovers(context, album)
}
} catch (e: Exception) {
logW("Unable to extract album cover due to an error: $e")

View file

@ -56,7 +56,7 @@ class MusicKeyer : Keyer<Music> {
class AlbumCoverFetcher
private constructor(private val context: Context, private val album: Album) : BaseFetcher() {
override suspend fun fetch(): FetchResult? =
fetchArt(context, album)?.let { stream ->
fetchCover(context, album)?.let { stream ->
SourceResult(
source = ImageSource(stream.source().buffer(), context),
mimeType = null,
@ -87,7 +87,7 @@ private constructor(
) : BaseFetcher() {
override suspend fun fetch(): FetchResult? {
val albums = Sort(Sort.Mode.ByName, true).albums(artist.albums)
val results = albums.mapAtMost(4) { album -> fetchArt(context, album) }
val results = albums.mapAtMost(4) { album -> fetchCover(context, album) }
return createMosaic(context, results, size)
}
@ -108,7 +108,7 @@ private constructor(
private val genre: Genre
) : BaseFetcher() {
override suspend fun fetch(): FetchResult? {
val results = genre.albums.mapAtMost(4) { fetchArt(context, it) }
val results = genre.albums.mapAtMost(4) { fetchCover(context, it) }
return createMosaic(context, results, size)
}

View file

@ -19,7 +19,7 @@ package org.oxycblt.auxio.playback
import org.oxycblt.auxio.IntegerTable
/** Represents the action that should be shown on the playback bar. */
/** Represents custom actions available in certain areas of the playback UI. */
enum class ActionMode {
NEXT,
REPEAT,
@ -27,18 +27,18 @@ enum class ActionMode {
val intCode: Int
get() = when (this) {
NEXT -> IntegerTable.BAR_ACTION_NEXT
REPEAT -> IntegerTable.BAR_ACTION_REPEAT
SHUFFLE -> IntegerTable.BAR_ACTION_SHUFFLE
NEXT -> IntegerTable.ACTION_MODE_NEXT
REPEAT -> IntegerTable.ACTION_MODE_REPEAT
SHUFFLE -> IntegerTable.ACTION_MODE_SHUFFLE
}
companion object {
/** Convert an int [code] into an instance, or null if it isn't valid. */
fun fromIntCode(code: Int) =
when (code) {
IntegerTable.BAR_ACTION_NEXT -> NEXT
IntegerTable.BAR_ACTION_REPEAT -> REPEAT
IntegerTable.BAR_ACTION_SHUFFLE -> SHUFFLE
IntegerTable.ACTION_MODE_NEXT -> NEXT
IntegerTable.ACTION_MODE_REPEAT -> REPEAT
IntegerTable.ACTION_MODE_SHUFFLE -> SHUFFLE
else -> null
}
}

View file

@ -252,8 +252,7 @@ class MediaSessionComponent(private val context: Context, private val callback:
override fun onSettingChanged(key: String) {
when (key) {
context.getString(R.string.set_key_show_covers),
context.getString(R.string.set_key_quality_covers) ->
context.getString(R.string.set_key_cover_mode) ->
updateMediaMetadata(playbackManager.song, playbackManager.parent)
context.getString(R.string.set_key_notif_action) -> invalidateSecondaryAction()
}

View file

@ -27,6 +27,7 @@ import androidx.preference.PreferenceManager
import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.image.CoverMode
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.Sort
import org.oxycblt.auxio.music.storage.Directory
@ -80,6 +81,22 @@ class Settings(private val context: Context, private val callback: Callback? = n
}
}
if (inner.contains(OldKeys.KEY_SHOW_COVERS) || inner.contains(OldKeys.KEY_QUALITY_COVERS)) {
logD("Migrating cover settings")
val mode = when {
!inner.getBoolean(OldKeys.KEY_SHOW_COVERS, true) -> CoverMode.OFF
!inner.getBoolean(OldKeys.KEY_QUALITY_COVERS, true) -> CoverMode.MEDIA_STORE
else -> CoverMode.QUALITY
}
inner.edit {
putInt(context.getString(R.string.set_key_cover_mode), mode.intCode)
remove(OldKeys.KEY_SHOW_COVERS)
remove(OldKeys.KEY_QUALITY_COVERS)
}
}
if (inner.contains(OldKeys.KEY_ALT_NOTIF_ACTION)) {
logD("Migrating ${OldKeys.KEY_ALT_NOTIF_ACTION}")
@ -187,13 +204,9 @@ class Settings(private val context: Context, private val callback: Callback? = n
}
}
/** Whether to load embedded covers */
val showCovers: Boolean
get() = inner.getBoolean(context.getString(R.string.set_key_show_covers), true)
/** Whether to ignore MediaStore covers */
val useQualityCovers: Boolean
get() = inner.getBoolean(context.getString(R.string.set_key_quality_covers), false)
/** The strategy used when loading images. */
val coverMode: CoverMode
get() = CoverMode.fromIntCode(inner.getInt(context.getString(R.string.set_key_cover_mode), Int.MIN_VALUE)) ?: CoverMode.MEDIA_STORE
/** Whether to round additional UI elements (including album covers) */
val roundMode: Boolean
@ -208,8 +221,7 @@ class Settings(private val context: Context, private val callback: Callback? = n
?: ActionMode.NEXT
/**
* Whether to display the RepeatMode or the shuffle status on the notification. False if repeat,
* true if shuffle.
* The custom action to display in the notification.
*/
val notifAction: ActionMode
get() = ActionMode.fromIntCode(inner.getInt(context.getString(R.string.set_key_notif_action), Int.MIN_VALUE)) ?: ActionMode.REPEAT
@ -458,6 +470,8 @@ class Settings(private val context: Context, private val callback: Callback? = n
private object OldKeys {
const val KEY_ACCENT3 = "auxio_accent"
const val KEY_ALT_NOTIF_ACTION = "KEY_ALT_NOTIF_ACTION"
const val KEY_SHOW_COVERS = "KEY_SHOW_COVERS"
const val KEY_QUALITY_COVERS = "KEY_QUALITY_COVERS"
const val KEY_LIB_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE2"
const val KEY_DETAIL_PLAYBACK_MODE = "auxio_detail_song_play_mode"
}

View file

@ -47,7 +47,7 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat
* @author OxygenCobalt
*/
@Suppress("UNUSED")
class SettingsListFragment : PreferenceFragmentCompat() {
class PreferenceFragment : PreferenceFragmentCompat() {
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val musicModel: MusicViewModel by activityViewModels()
private val navModel: NavigationViewModel by activityViewModels()
@ -171,8 +171,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
true
}
}
context.getString(R.string.set_key_show_covers),
context.getString(R.string.set_key_quality_covers) -> {
context.getString(R.string.set_key_cover_mode) -> {
preference.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _, _ ->
Coil.imageLoader(context).memoryCache?.clear()

View file

@ -146,8 +146,7 @@ class WidgetComponent(private val context: Context) :
override fun onShuffledChanged(isShuffled: Boolean) = update()
override fun onRepeatChanged(repeatMode: RepeatMode) = update()
override fun onSettingChanged(key: String) {
if (key == context.getString(R.string.set_key_show_covers) ||
key == context.getString(R.string.set_key_quality_covers) ||
if (key == context.getString(R.string.set_key_cover_mode) ||
key == context.getString(R.string.set_key_round_mode)
) {
update()

View file

@ -26,7 +26,7 @@
<androidx.fragment.app.FragmentContainerView
android:id="@+id/settings_list_fragment"
android:name="org.oxycblt.auxio.settings.prefs.SettingsListFragment"
android:name="org.oxycblt.auxio.settings.prefs.PreferenceFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"

View file

@ -6,8 +6,7 @@
<string name="set_key_accent" translatable="false">auxio_accent2</string>
<string name="set_key_lib_tabs" translatable="false">auxio_lib_tabs</string>
<string name="set_key_show_covers" translatable="false">KEY_SHOW_COVERS</string>
<string name="set_key_quality_covers" translatable="false">KEY_QUALITY_COVERS</string>
<string name="set_key_cover_mode" translatable="false">auxio_cover_mode</string>
<string name="set_key_round_mode" translatable="false">auxio_round_covers</string>
<string name="set_key_bar_action" translatable="false">auxio_bar_action</string>
<string name="set_key_notif_action" translatable="false">auxio_notif_action</string>
@ -63,6 +62,18 @@
<item>@integer/theme_dark</item>
</integer-array>
<string-array name="entries_cover_mode">
<item>@string/set_cover_mode_off</item>
<item>@string/set_cover_mode_media_store</item>
<item>@string/set_cover_mode_quality</item>
</string-array>
<integer-array name="values_cover_mode">
<item>@integer/cover_mode_off</item>
<item>@integer/cover_mode_media_store</item>
<item>@integer/cover_mode_quality</item>
</integer-array>
<string-array name="entries_bar_action">
<item>@string/set_bar_action_next</item>
<item>@string/set_bar_action_repeat</item>
@ -127,10 +138,6 @@
<integer name="theme_light">1</integer>
<integer name="theme_dark">2</integer>
<integer name="action_mode_next">0xA119</integer>
<integer name="action_mode_repeat">0xA11A</integer>
<integer name="action_mode_shuffle">0xA11B</integer>
<integer name="music_mode_none">-2147483648</integer>
<integer name="music_mode_artist">0xA109</integer>
<integer name="music_mode_album">0xA10A</integer>
@ -139,4 +146,12 @@
<integer name="replay_gain_track">0xA111</integer>
<integer name="replay_gain_album">0xA112</integer>
<integer name="replay_gain_dynamic">0xA113</integer>
<integer name="action_mode_next">0xA119</integer>
<integer name="action_mode_repeat">0xA11A</integer>
<integer name="action_mode_shuffle">0xA11B</integer>
<integer name="cover_mode_off">0xA11C</integer>
<integer name="cover_mode_media_store">0xA11D</integer>
<integer name="cover_mode_quality">0xA11E</integer>
</resources>

View file

@ -170,10 +170,10 @@
<string name="set_display">Display</string>
<string name="set_lib_tabs">Library tabs</string>
<string name="set_lib_tabs_desc">Change visibility and order of library tabs</string>
<string name="set_show_covers">Show album covers</string>
<string name="set_show_covers_desc">Turn off to save memory usage</string>
<string name="set_quality_covers">Ignore MediaStore covers</string>
<string name="set_quality_covers_desc">Increases album cover quality, but results in longer loading times and higher memory usage</string>
<string name="set_cover_mode">Album covers</string>
<string name="set_cover_mode_off">Off</string>
<string name="set_cover_mode_media_store">Fast</string>
<string name="set_cover_mode_quality">High quality</string>
<string name="set_round_mode">Round mode</string>
<string name="set_round_mode_desc">Enable rounded corners on additional UI elements (Requires album covers to be rounded)</string>
<string name="set_bar_action">Custom playback bar action</string>

View file

@ -31,18 +31,12 @@
app:summary="@string/set_lib_tabs_desc"
app:title="@string/set_lib_tabs" />
<SwitchPreferenceCompat
app:defaultValue="true"
app:key="@string/set_key_show_covers"
app:summary="@string/set_show_covers_desc"
app:title="@string/set_show_covers" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:dependency="@string/set_key_show_covers"
app:key="@string/set_key_quality_covers"
app:summary="@string/set_quality_covers_desc"
app:title="@string/set_quality_covers" />
<org.oxycblt.auxio.settings.prefs.IntListPreference
app:defaultValue="@integer/cover_mode_media_store"
app:entries="@array/entries_cover_mode"
app:entryValues="@array/values_cover_mode"
app:key="@string/set_key_cover_mode"
app:title="@string/set_cover_mode" />
<SwitchPreferenceCompat
app:defaultValue="false"