music: introduce library revisions
Will be used to maintain image loading consistency even during loads.
This commit is contained in:
parent
7df5c5973e
commit
a1188b8d4b
4 changed files with 69 additions and 9 deletions
|
@ -43,6 +43,7 @@ import org.oxycblt.musikr.playlist.db.PlaylistDatabase
|
||||||
import org.oxycblt.musikr.playlist.db.StoredPlaylists
|
import org.oxycblt.musikr.playlist.db.StoredPlaylists
|
||||||
import org.oxycblt.musikr.tag.interpret.Naming
|
import org.oxycblt.musikr.tag.interpret.Naming
|
||||||
import org.oxycblt.musikr.tag.interpret.Separators
|
import org.oxycblt.musikr.tag.interpret.Separators
|
||||||
|
import java.util.UUID
|
||||||
import timber.log.Timber as L
|
import timber.log.Timber as L
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +58,8 @@ import timber.log.Timber as L
|
||||||
* configurations
|
* configurations
|
||||||
*/
|
*/
|
||||||
interface MusicRepository {
|
interface MusicRepository {
|
||||||
val library: Library?
|
/** The current library */
|
||||||
|
val library: RevisionedLibrary?
|
||||||
|
|
||||||
/** The current state of music loading. Null if no load has occurred yet. */
|
/** The current state of music loading. Null if no load has occurred yet. */
|
||||||
val indexingState: IndexingState?
|
val indexingState: IndexingState?
|
||||||
|
@ -222,7 +224,7 @@ constructor(
|
||||||
private val indexingListeners = mutableListOf<MusicRepository.IndexingListener>()
|
private val indexingListeners = mutableListOf<MusicRepository.IndexingListener>()
|
||||||
@Volatile private var indexingWorker: MusicRepository.IndexingWorker? = null
|
@Volatile private var indexingWorker: MusicRepository.IndexingWorker? = null
|
||||||
|
|
||||||
@Volatile override var library: MutableLibrary? = null
|
@Volatile override var library: MutableRevisionedLibrary? = null
|
||||||
@Volatile private var previousCompletedState: IndexingState.Completed? = null
|
@Volatile private var previousCompletedState: IndexingState.Completed? = null
|
||||||
@Volatile private var currentIndexingState: IndexingState? = null
|
@Volatile private var currentIndexingState: IndexingState? = null
|
||||||
override val indexingState: IndexingState?
|
override val indexingState: IndexingState?
|
||||||
|
@ -362,17 +364,19 @@ constructor(
|
||||||
}
|
}
|
||||||
val locations = musicSettings.musicLocations
|
val locations = musicSettings.musicLocations
|
||||||
|
|
||||||
val storage =
|
val revision: UUID
|
||||||
|
val storage: Storage
|
||||||
if (withCache) {
|
if (withCache) {
|
||||||
Storage(
|
revision = this.library?.revision ?: musicSettings.revision
|
||||||
|
storage = Storage(
|
||||||
Cache.full(cacheDatabase),
|
Cache.full(cacheDatabase),
|
||||||
StoredCovers.from(context, "covers"),
|
StoredCovers.from(context, "covers_$revision"),
|
||||||
StoredPlaylists.from(playlistDatabase))
|
StoredPlaylists.from(playlistDatabase))
|
||||||
} else {
|
} else {
|
||||||
// TODO: Revisioned cache (as a stateful extension of musikr)
|
revision = UUID.randomUUID()
|
||||||
Storage(
|
storage = Storage(
|
||||||
Cache.writeOnly(cacheDatabase),
|
Cache.writeOnly(cacheDatabase),
|
||||||
StoredCovers.from(context, "covers"),
|
StoredCovers.from(context, "covers_$revision"),
|
||||||
StoredPlaylists.from(playlistDatabase))
|
StoredPlaylists.from(playlistDatabase))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,6 +385,9 @@ constructor(
|
||||||
val newLibrary =
|
val newLibrary =
|
||||||
Musikr.new(context, storage, interpretation).run(locations, ::emitIndexingProgress)
|
Musikr.new(context, storage, interpretation).run(locations, ::emitIndexingProgress)
|
||||||
|
|
||||||
|
val revisionedLibrary =
|
||||||
|
MutableRevisionedLibrary(revision, newLibrary)
|
||||||
|
|
||||||
emitIndexingCompletion(null)
|
emitIndexingCompletion(null)
|
||||||
|
|
||||||
// We want to make sure that all reads and writes are synchronized due to the sheer
|
// We want to make sure that all reads and writes are synchronized due to the sheer
|
||||||
|
@ -402,7 +409,7 @@ constructor(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.library = newLibrary
|
this.library = revisionedLibrary
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consumers expect their updates to be on the main thread (notably PlaybackService),
|
// Consumers expect their updates to be on the main thread (notably PlaybackService),
|
||||||
|
@ -410,6 +417,11 @@ constructor(
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
dispatchLibraryChange(deviceLibraryChanged, userLibraryChanged)
|
dispatchLibraryChange(deviceLibraryChanged, userLibraryChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quietly update the revision if needed (this way we don't disrupt any new loads)
|
||||||
|
if (!withCache) {
|
||||||
|
musicSettings.revision = revisionedLibrary.revision
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun emitIndexingProgress(progress: IndexingProgress) {
|
private suspend fun emitIndexingProgress(progress: IndexingProgress) {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import javax.inject.Inject
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.settings.Settings
|
import org.oxycblt.auxio.settings.Settings
|
||||||
import org.oxycblt.musikr.fs.MusicLocation
|
import org.oxycblt.musikr.fs.MusicLocation
|
||||||
|
import java.util.UUID
|
||||||
import timber.log.Timber as L
|
import timber.log.Timber as L
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,6 +34,8 @@ import timber.log.Timber as L
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
interface MusicSettings : Settings<MusicSettings.Listener> {
|
interface MusicSettings : Settings<MusicSettings.Listener> {
|
||||||
|
/** The current library revision. */
|
||||||
|
var revision: UUID
|
||||||
/** The locations of music to load. */
|
/** The locations of music to load. */
|
||||||
var musicLocations: List<MusicLocation>
|
var musicLocations: List<MusicLocation>
|
||||||
/** Whether to exclude non-music audio files from the music library. */
|
/** Whether to exclude non-music audio files from the music library. */
|
||||||
|
@ -55,6 +58,17 @@ interface MusicSettings : Settings<MusicSettings.Listener> {
|
||||||
class MusicSettingsImpl @Inject constructor(@ApplicationContext private val context: Context) :
|
class MusicSettingsImpl @Inject constructor(@ApplicationContext private val context: Context) :
|
||||||
Settings.Impl<MusicSettings.Listener>(context), MusicSettings {
|
Settings.Impl<MusicSettings.Listener>(context), MusicSettings {
|
||||||
|
|
||||||
|
override var revision: UUID
|
||||||
|
get() = UUID.fromString(
|
||||||
|
sharedPreferences.getString(getString(R.string.set_key_library_revision), null)
|
||||||
|
?: UUID.randomUUID().toString())
|
||||||
|
set(value) {
|
||||||
|
sharedPreferences.edit {
|
||||||
|
putString(getString(R.string.set_key_library_revision), value.toString())
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override var musicLocations: List<MusicLocation>
|
override var musicLocations: List<MusicLocation>
|
||||||
get() {
|
get() {
|
||||||
val locations =
|
val locations =
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package org.oxycblt.auxio.music
|
||||||
|
|
||||||
|
import org.oxycblt.musikr.Library
|
||||||
|
import org.oxycblt.musikr.MutableLibrary
|
||||||
|
import org.oxycblt.musikr.Playlist
|
||||||
|
import org.oxycblt.musikr.Song
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
interface RevisionedLibrary : Library {
|
||||||
|
val revision: UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
class MutableRevisionedLibrary(
|
||||||
|
override val revision: UUID,
|
||||||
|
private val inner: MutableLibrary
|
||||||
|
) : RevisionedLibrary, Library by inner, MutableLibrary {
|
||||||
|
override suspend fun createPlaylist(name: String, songs: List<Song>) =
|
||||||
|
MutableRevisionedLibrary(revision, inner.createPlaylist(name, songs))
|
||||||
|
|
||||||
|
override suspend fun renamePlaylist(playlist: Playlist, name: String) =
|
||||||
|
MutableRevisionedLibrary(revision, inner.renamePlaylist(playlist, name))
|
||||||
|
|
||||||
|
override suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>) =
|
||||||
|
MutableRevisionedLibrary(revision, inner.addToPlaylist(playlist, songs))
|
||||||
|
|
||||||
|
override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>) =
|
||||||
|
MutableRevisionedLibrary(revision, inner.rewritePlaylist(playlist, songs))
|
||||||
|
|
||||||
|
override suspend fun deletePlaylist(playlist: Playlist) =
|
||||||
|
MutableRevisionedLibrary(revision, inner.deletePlaylist(playlist))
|
||||||
|
|
||||||
|
}
|
|
@ -53,6 +53,8 @@
|
||||||
<string name="set_key_artist_songs_sort" translatable="false">auxio_artist_sort</string>
|
<string name="set_key_artist_songs_sort" translatable="false">auxio_artist_sort</string>
|
||||||
<string name="set_key_genre_songs_sort" translatable="false">auxio_genre_sort</string>
|
<string name="set_key_genre_songs_sort" translatable="false">auxio_genre_sort</string>
|
||||||
|
|
||||||
|
<string name="set_key_library_revision" translatable="false">auxio_library_revision</string>
|
||||||
|
|
||||||
<string-array name="entries_theme">
|
<string-array name="entries_theme">
|
||||||
<item>@string/set_theme_auto</item>
|
<item>@string/set_theme_auto</item>
|
||||||
<item>@string/set_theme_day</item>
|
<item>@string/set_theme_day</item>
|
||||||
|
|
Loading…
Reference in a new issue