diff --git a/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt b/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt
index e33205029..1da5824b9 100644
--- a/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt
+++ b/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt
@@ -123,10 +123,10 @@ object IntegerTable {
const val ACTION_MODE_SHUFFLE = 0xA11B
/** CoverMode.Off */
const val COVER_MODE_OFF = 0xA11C
- /** CoverMode.MediaStore */
- const val COVER_MODE_FAST = 0xA11D
+ /** CoverMode.Balanced */
+ const val COVER_MODE_BALANCED = 0xA11D
/** CoverMode.Quality */
- const val COVER_MODE_QUALITY = 0xA11E
+ const val COVER_MODE_HIGH_QUALITY = 0xA11E
/** PlaySong.FromAll */
const val PLAY_SONG_FROM_ALL = 0xA11F
/** PlaySong.FromAlbum */
@@ -139,4 +139,6 @@ object IntegerTable {
const val PLAY_SONG_FROM_PLAYLIST = 0xA123
/** PlaySong.ByItself */
const val PLAY_SONG_BY_ITSELF = 0xA124
+ /** CoverMode.SaveSpace */
+ const val COVER_MODE_SAVE_SPACE = 0xA125
}
diff --git a/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt b/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt
index e28ddf55b..cad4a2ab2 100644
--- a/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt
+++ b/app/src/main/java/org/oxycblt/auxio/image/CoverMode.kt
@@ -26,12 +26,10 @@ import org.oxycblt.auxio.IntegerTable
* @author Alexander Capehart (OxygenCobalt)
*/
enum class CoverMode {
- /** Do not load album covers ("Off"). */
OFF,
- /** Load covers from the fast, but lower-quality media store database ("Fast"). */
- FAST,
- /** Load high-quality covers directly from music files ("Quality"). */
- QUALITY;
+ SAVE_SPACE,
+ BALANCED,
+ HIGH_QUALITY;
/**
* The integer representation of this instance.
@@ -42,8 +40,9 @@ enum class CoverMode {
get() =
when (this) {
OFF -> IntegerTable.COVER_MODE_OFF
- FAST -> IntegerTable.COVER_MODE_FAST
- QUALITY -> IntegerTable.COVER_MODE_QUALITY
+ SAVE_SPACE -> IntegerTable.COVER_MODE_SAVE_SPACE
+ BALANCED -> IntegerTable.COVER_MODE_BALANCED
+ HIGH_QUALITY -> IntegerTable.COVER_MODE_HIGH_QUALITY
}
companion object {
@@ -57,8 +56,9 @@ enum class CoverMode {
fun fromIntCode(intCode: Int) =
when (intCode) {
IntegerTable.COVER_MODE_OFF -> OFF
- IntegerTable.COVER_MODE_FAST -> FAST
- IntegerTable.COVER_MODE_QUALITY -> QUALITY
+ IntegerTable.COVER_MODE_SAVE_SPACE -> SAVE_SPACE
+ IntegerTable.COVER_MODE_BALANCED -> BALANCED
+ IntegerTable.COVER_MODE_HIGH_QUALITY -> HIGH_QUALITY
else -> null
}
}
diff --git a/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt b/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt
index 1ebbcf7b5..12671f822 100644
--- a/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt
+++ b/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt
@@ -49,7 +49,7 @@ class ImageSettingsImpl @Inject constructor(@ApplicationContext context: Context
get() =
CoverMode.fromIntCode(
sharedPreferences.getInt(getString(R.string.set_key_cover_mode), Int.MIN_VALUE))
- ?: CoverMode.FAST
+ ?: CoverMode.BALANCED
override val forceSquareCovers: Boolean
get() = sharedPreferences.getBoolean(getString(R.string.set_key_square_covers), false)
@@ -64,8 +64,8 @@ class ImageSettingsImpl @Inject constructor(@ApplicationContext context: Context
when {
!sharedPreferences.getBoolean(OLD_KEY_SHOW_COVERS, true) -> CoverMode.OFF
!sharedPreferences.getBoolean(OLD_KEY_QUALITY_COVERS, true) ->
- CoverMode.FAST
- else -> CoverMode.QUALITY
+ CoverMode.BALANCED
+ else -> CoverMode.BALANCED
}
sharedPreferences.edit {
@@ -74,6 +74,24 @@ class ImageSettingsImpl @Inject constructor(@ApplicationContext context: Context
remove(OLD_KEY_QUALITY_COVERS)
}
}
+
+ if (sharedPreferences.contains(OLD_KEY_COVER_MODE)) {
+ L.d("Migrating cover mode setting")
+
+ var mode =
+ CoverMode.fromIntCode(sharedPreferences.getInt(OLD_KEY_COVER_MODE, Int.MIN_VALUE))
+ ?: CoverMode.BALANCED
+ if (mode == CoverMode.HIGH_QUALITY) {
+ // High quality now has space characteristics that could be
+ // undesirable, clamp to balanced.
+ mode = CoverMode.BALANCED
+ }
+
+ sharedPreferences.edit {
+ putInt(getString(R.string.set_key_cover_mode), mode.intCode)
+ remove(OLD_KEY_COVER_MODE)
+ }
+ }
}
override fun onSettingChanged(key: String, listener: ImageSettings.Listener) {
@@ -87,5 +105,6 @@ class ImageSettingsImpl @Inject constructor(@ApplicationContext context: Context
private companion object {
const val OLD_KEY_SHOW_COVERS = "KEY_SHOW_COVERS"
const val OLD_KEY_QUALITY_COVERS = "KEY_QUALITY_COVERS"
+ const val OLD_KEY_COVER_MODE = "auxio_cover_mode"
}
}
diff --git a/app/src/main/java/org/oxycblt/auxio/image/covers/CoverModule.kt b/app/src/main/java/org/oxycblt/auxio/image/covers/CoverModule.kt
new file mode 100644
index 000000000..860ca10c5
--- /dev/null
+++ b/app/src/main/java/org/oxycblt/auxio/image/covers/CoverModule.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2024 Auxio Project
+ * CoverModule.kt is part of Auxio.
+ *
+ * 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.covers
+
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import org.oxycblt.musikr.cover.CoverIdentifier
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class CoverModule {
+ @Binds abstract fun configCovers(impl: SettingCoversImpl): SettingCovers
+}
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class CoverProvidesModule {
+ @Provides fun identifier(): CoverIdentifier = CoverIdentifier.md5()
+}
diff --git a/app/src/main/java/org/oxycblt/auxio/image/covers/CoverUtil.kt b/app/src/main/java/org/oxycblt/auxio/image/covers/CoverUtil.kt
index e556124dc..67058e8b6 100644
--- a/app/src/main/java/org/oxycblt/auxio/image/covers/CoverUtil.kt
+++ b/app/src/main/java/org/oxycblt/auxio/image/covers/CoverUtil.kt
@@ -1,9 +1,26 @@
+/*
+ * Copyright (c) 2024 Auxio Project
+ * CoverUtil.kt is part of Auxio.
+ *
+ * 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.covers
import android.content.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
-suspend fun Context.coversDir() = withContext(Dispatchers.IO) {
- filesDir.resolve("covers").apply { mkdirs() }
-}
\ No newline at end of file
+suspend fun Context.coversDir() =
+ withContext(Dispatchers.IO) { filesDir.resolve("covers").apply { mkdirs() } }
diff --git a/app/src/main/java/org/oxycblt/auxio/image/covers/NullCovers.kt b/app/src/main/java/org/oxycblt/auxio/image/covers/NullCovers.kt
index b97d274f2..d88bbd4ac 100644
--- a/app/src/main/java/org/oxycblt/auxio/image/covers/NullCovers.kt
+++ b/app/src/main/java/org/oxycblt/auxio/image/covers/NullCovers.kt
@@ -1,18 +1,34 @@
+/*
+ * Copyright (c) 2024 Auxio Project
+ * NullCovers.kt is part of Auxio.
+ *
+ * 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.covers
import android.content.Context
import org.oxycblt.musikr.cover.Cover
import org.oxycblt.musikr.cover.CoverIdentifier
-import org.oxycblt.musikr.cover.Covers
import org.oxycblt.musikr.cover.MutableCovers
import org.oxycblt.musikr.cover.ObtainResult
-import java.io.InputStream
-class NullCovers(private val context: Context, private val identifier: CoverIdentifier) : MutableCovers {
+class NullCovers(private val context: Context, private val identifier: CoverIdentifier) :
+ MutableCovers {
override suspend fun obtain(id: String) = ObtainResult.Hit(NullCover(id))
- override suspend fun write(data: ByteArray): Cover =
- NullCover(identifier.identify(data))
+ override suspend fun write(data: ByteArray): Cover = NullCover(identifier.identify(data))
override suspend fun cleanup(excluding: Collection) {
context.coversDir().listFiles()?.forEach { it.deleteRecursively() }
@@ -21,4 +37,4 @@ class NullCovers(private val context: Context, private val identifier: CoverIden
private class NullCover(override val id: String) : Cover {
override suspend fun open() = null
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/org/oxycblt/auxio/image/covers/SettingCovers.kt b/app/src/main/java/org/oxycblt/auxio/image/covers/SettingCovers.kt
new file mode 100644
index 000000000..eb3603175
--- /dev/null
+++ b/app/src/main/java/org/oxycblt/auxio/image/covers/SettingCovers.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2024 Auxio Project
+ * SettingCovers.kt is part of Auxio.
+ *
+ * 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.covers
+
+import android.content.Context
+import java.util.UUID
+import javax.inject.Inject
+import org.oxycblt.auxio.image.CoverMode
+import org.oxycblt.auxio.image.ImageSettings
+import org.oxycblt.musikr.cover.CoverIdentifier
+import org.oxycblt.musikr.cover.CoverParams
+import org.oxycblt.musikr.cover.MutableCovers
+
+interface SettingCovers {
+ suspend fun create(context: Context, revision: UUID): MutableCovers
+}
+
+class SettingCoversImpl
+@Inject
+constructor(private val imageSettings: ImageSettings, private val identifier: CoverIdentifier) :
+ SettingCovers {
+ override suspend fun create(context: Context, revision: UUID): MutableCovers =
+ when (imageSettings.coverMode) {
+ CoverMode.OFF -> NullCovers(context, identifier)
+ CoverMode.SAVE_SPACE -> siloedCovers(context, revision, CoverParams.of(750, 70))
+ CoverMode.BALANCED -> siloedCovers(context, revision, CoverParams.of(750, 85))
+ CoverMode.HIGH_QUALITY -> siloedCovers(context, revision, CoverParams.of(1000, 100))
+ }
+
+ private suspend fun siloedCovers(context: Context, revision: UUID, with: CoverParams) =
+ SiloedCovers.from(context, CoverSilo(revision, with), identifier)
+}
diff --git a/app/src/main/java/org/oxycblt/auxio/image/covers/SiloedCovers.kt b/app/src/main/java/org/oxycblt/auxio/image/covers/SiloedCovers.kt
index 2448845ed..8a9949835 100644
--- a/app/src/main/java/org/oxycblt/auxio/image/covers/SiloedCovers.kt
+++ b/app/src/main/java/org/oxycblt/auxio/image/covers/SiloedCovers.kt
@@ -57,7 +57,11 @@ class SiloedCovers(
}
companion object {
- suspend fun from(context: Context, silo: CoverSilo, identifier: CoverIdentifier): SiloedCovers {
+ suspend fun from(
+ context: Context,
+ silo: CoverSilo,
+ identifier: CoverIdentifier
+ ): SiloedCovers {
val rootDir: File
val revisionDir: File
withContext(Dispatchers.IO) {
diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt
index 8fc2c9839..86cbf834e 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
package org.oxycblt.auxio.music
import android.content.Context
@@ -27,9 +27,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
+import org.oxycblt.auxio.image.covers.SettingCovers
import org.oxycblt.auxio.music.MusicRepository.IndexingWorker
-import org.oxycblt.auxio.image.covers.CoverSilo
-import org.oxycblt.auxio.image.covers.SiloedCovers
import org.oxycblt.musikr.IndexingProgress
import org.oxycblt.musikr.Interpretation
import org.oxycblt.musikr.Library
@@ -40,8 +39,6 @@ import org.oxycblt.musikr.Playlist
import org.oxycblt.musikr.Song
import org.oxycblt.musikr.Storage
import org.oxycblt.musikr.cache.StoredCache
-import org.oxycblt.musikr.cover.CoverIdentifier
-import org.oxycblt.musikr.cover.CoverParams
import org.oxycblt.musikr.playlist.db.StoredPlaylists
import org.oxycblt.musikr.tag.interpret.Naming
import org.oxycblt.musikr.tag.interpret.Separators
@@ -241,19 +238,16 @@ constructor(
@ApplicationContext private val context: Context,
private val storedCache: StoredCache,
private val storedPlaylists: StoredPlaylists,
+ private val settingCovers: SettingCovers,
private val musicSettings: MusicSettings
) : MusicRepository {
private val updateListeners = mutableListOf()
private val indexingListeners = mutableListOf()
- @Volatile
- private var indexingWorker: MusicRepository.IndexingWorker? = null
+ @Volatile private var indexingWorker: MusicRepository.IndexingWorker? = null
- @Volatile
- override var library: MutableLibrary? = null
- @Volatile
- private var previousCompletedState: IndexingState.Completed? = null
- @Volatile
- private var currentIndexingState: IndexingState? = null
+ @Volatile override var library: MutableLibrary? = null
+ @Volatile private var previousCompletedState: IndexingState.Completed? = null
+ @Volatile private var currentIndexingState: IndexingState? = null
override val indexingState: IndexingState?
get() = currentIndexingState ?: previousCompletedState
@@ -393,11 +387,7 @@ constructor(
val currentRevision = musicSettings.revision
val newRevision = currentRevision?.takeIf { withCache } ?: UUID.randomUUID()
val cache = if (withCache) storedCache.visible() else storedCache.invisible()
- val covers = SiloedCovers.from(
- context,
- CoverSilo(newRevision, CoverParams.of(750, 80)),
- CoverIdentifier.md5()
- )
+ val covers = settingCovers.create(context, newRevision)
val storage = Storage(cache, covers, storedPlaylists)
val interpretation = Interpretation(nameFactory, separators)
@@ -423,9 +413,9 @@ constructor(
// TODO: Remove this once you start work on kindred.
deviceLibraryChanged =
this.library?.songs != newLibrary.songs ||
- this.library?.albums != newLibrary.albums ||
- this.library?.artists != newLibrary.artists ||
- this.library?.genres != newLibrary.genres
+ this.library?.albums != newLibrary.albums ||
+ this.library?.artists != newLibrary.artists ||
+ this.library?.genres != newLibrary.genres
userLibraryChanged = this.library?.playlists != newLibrary.playlists
if (!deviceLibraryChanged && !userLibraryChanged) {
L.d("Library has not changed, skipping update")
diff --git a/app/src/main/java/org/oxycblt/auxio/settings/categories/MusicPreferenceFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/categories/MusicPreferenceFragment.kt
index c98d3b55c..8727aba3d 100644
--- a/app/src/main/java/org/oxycblt/auxio/settings/categories/MusicPreferenceFragment.kt
+++ b/app/src/main/java/org/oxycblt/auxio/settings/categories/MusicPreferenceFragment.kt
@@ -18,12 +18,14 @@
package org.oxycblt.auxio.settings.categories
+import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.preference.Preference
import coil3.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import org.oxycblt.auxio.R
+import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.settings.BasePreferenceFragment
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
import org.oxycblt.auxio.util.navigateSafe
@@ -36,6 +38,7 @@ import timber.log.Timber as L
*/
@AndroidEntryPoint
class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music) {
+ private val musicModel: MusicViewModel by viewModels()
@Inject lateinit var imageLoader: ImageLoader
override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
@@ -46,9 +49,17 @@ class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music)
}
override fun onSetupPreference(preference: Preference) {
- if (preference.key == getString(R.string.set_key_cover_mode) ||
- preference.key == getString(R.string.set_key_square_covers)) {
+ if (preference.key == getString(R.string.set_key_cover_mode)) {
L.d("Configuring cover mode setting")
+ preference.onPreferenceChangeListener =
+ Preference.OnPreferenceChangeListener { _, _ ->
+ L.d("Cover mode changed, reloading music")
+ musicModel.refresh()
+ true
+ }
+ }
+ if (preference.key == getString(R.string.set_key_square_covers)) {
+ L.d("Configuring square cover setting")
preference.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _, _ ->
L.d("Cover mode changed, resetting image memory cache")
diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml
index a3502babb..cf397237a 100644
--- a/app/src/main/res/values/settings.xml
+++ b/app/src/main/res/values/settings.xml
@@ -14,7 +14,7 @@
auxio_rescan
auxio_observing
auxio_music_dirs
- auxio_cover_mode
+ auxio_cover_mode2
auxio_square_covers
auxio_include_dirs
auxio_exclude_non_music