diff --git a/CHANGELOG.md b/CHANGELOG.md index d9ba4c489..074f01388 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/app/build.gradle b/app/build.gradle index 09e3c64dc..28ae802c2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,6 @@ plugins { id "kotlin-android" id "androidx.navigation.safeargs.kotlin" id "com.diffplug.spotless" - id "kotlin-kapt" id "kotlin-parcelize" } diff --git a/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt b/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt index 1b75b2f1b..8879c4558 100644 --- a/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt +++ b/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt @@ -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 } diff --git a/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt b/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt new file mode 100644 index 000000000..f8ffc0cf1 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt @@ -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 . + */ + +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 + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/BaseFetcher.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/BaseFetcher.kt index 921b11820..6a69ac978 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/extractor/BaseFetcher.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/BaseFetcher.kt @@ -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") diff --git a/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt index 91f0c7c37..2201eb9d1 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt @@ -56,7 +56,7 @@ class MusicKeyer : Keyer { 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) } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/ActionMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/ActionMode.kt index 6c9f2eb92..6bceaacb1 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/ActionMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/ActionMode.kt @@ -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 } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt index 650bf9ab3..a5371f8fb 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt @@ -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() } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt index b546d37cc..9ec104e64 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt @@ -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" } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/prefs/SettingsListFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt similarity index 97% rename from app/src/main/java/org/oxycblt/auxio/settings/prefs/SettingsListFragment.kt rename to app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt index af4181792..06ab07128 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/prefs/SettingsListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt @@ -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() diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt index 730ddb8c1..1a3e74481 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt @@ -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() diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 6c4ad78a1..7ce79e13d 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -26,7 +26,7 @@ auxio_accent2 auxio_lib_tabs - KEY_SHOW_COVERS - KEY_QUALITY_COVERS + auxio_cover_mode auxio_round_covers auxio_bar_action auxio_notif_action @@ -63,6 +62,18 @@ @integer/theme_dark + + @string/set_cover_mode_off + @string/set_cover_mode_media_store + @string/set_cover_mode_quality + + + + @integer/cover_mode_off + @integer/cover_mode_media_store + @integer/cover_mode_quality + + @string/set_bar_action_next @string/set_bar_action_repeat @@ -127,10 +138,6 @@ 1 2 - 0xA119 - 0xA11A - 0xA11B - -2147483648 0xA109 0xA10A @@ -139,4 +146,12 @@ 0xA111 0xA112 0xA113 + + 0xA119 + 0xA11A + 0xA11B + + 0xA11C + 0xA11D + 0xA11E \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3cc5d0bf8..fe5fa8360 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -170,10 +170,10 @@ Display Library tabs Change visibility and order of library tabs - Show album covers - Turn off to save memory usage - Ignore MediaStore covers - Increases album cover quality, but results in longer loading times and higher memory usage + Album covers + Off + Fast + High quality Round mode Enable rounded corners on additional UI elements (Requires album covers to be rounded) Custom playback bar action diff --git a/app/src/main/res/xml/prefs_main.xml b/app/src/main/res/xml/prefs_main.xml index 858569d0a..aff0caadc 100644 --- a/app/src/main/res/xml/prefs_main.xml +++ b/app/src/main/res/xml/prefs_main.xml @@ -31,18 +31,12 @@ app:summary="@string/set_lib_tabs_desc" app:title="@string/set_lib_tabs" /> - - - +