Update music loading init process

Change the loading process so that LoadingViewModel no longer requires an application instance to start. Also move the main music loading code to an internal function.
This commit is contained in:
OxygenCobalt 2021-03-05 13:45:43 -07:00
parent 2c93e3f362
commit 466629e43d
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
7 changed files with 43 additions and 54 deletions

View file

@ -20,9 +20,7 @@ import org.oxycblt.auxio.music.MusicStore
* @author OxygenCobalt * @author OxygenCobalt
*/ */
class LoadingFragment : Fragment() { class LoadingFragment : Fragment() {
private val loadingModel: LoadingViewModel by viewModels { private val loadingModel: LoadingViewModel by viewModels()
LoadingViewModel.Factory(requireActivity().application)
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -71,7 +69,7 @@ class LoadingFragment : Fragment() {
} }
if (loadingModel.response.value == null) { if (loadingModel.response.value == null) {
loadingModel.load() loadingModel.load(requireContext())
} }
return binding.root return binding.root
@ -110,7 +108,7 @@ class LoadingFragment : Fragment() {
if (granted) { if (granted) {
// If granted, its now safe to load, which will clear the NO_PERMS response // If granted, its now safe to load, which will clear the NO_PERMS response
// we applied earlier. // we applied earlier.
loadingModel.load() loadingModel.load(requireContext())
} }
} }

View file

@ -1,10 +1,9 @@
package org.oxycblt.auxio.loading package org.oxycblt.auxio.loading
import android.app.Application import android.content.Context
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.MusicStore
@ -13,7 +12,7 @@ import org.oxycblt.auxio.music.MusicStore
* ViewModel responsible for the loading UI and beginning the loading process overall. * ViewModel responsible for the loading UI and beginning the loading process overall.
* @author OxygenCobalt * @author OxygenCobalt
*/ */
class LoadingViewModel(private val app: Application) : ViewModel() { class LoadingViewModel : ViewModel() {
private val mResponse = MutableLiveData<MusicStore.Response?>(null) private val mResponse = MutableLiveData<MusicStore.Response?>(null)
private val mDoGrant = MutableLiveData(false) private val mDoGrant = MutableLiveData(false)
@ -27,9 +26,9 @@ class LoadingViewModel(private val app: Application) : ViewModel() {
private val musicStore = MusicStore.getInstance() private val musicStore = MusicStore.getInstance()
/** /**
* Begin the music loading process. The response is pushed to [response] * Begin the music loading process. The response from MusicStore is pushed to [response]
*/ */
fun load() { fun load(context: Context) {
// Dont start a new load if the last one hasnt finished // Dont start a new load if the last one hasnt finished
if (isBusy) return if (isBusy) return
@ -37,7 +36,7 @@ class LoadingViewModel(private val app: Application) : ViewModel() {
mResponse.value = null mResponse.value = null
viewModelScope.launch { viewModelScope.launch {
mResponse.value = musicStore.load(app) mResponse.value = musicStore.load(context)
isBusy = false isBusy = false
} }
} }
@ -62,15 +61,4 @@ class LoadingViewModel(private val app: Application) : ViewModel() {
fun notifyNoPermissions() { fun notifyNoPermissions() {
mResponse.value = MusicStore.Response.NO_PERMS mResponse.value = MusicStore.Response.NO_PERMS
} }
@Suppress("UNCHECKED_CAST")
class Factory(private val application: Application) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(LoadingViewModel::class.java)) {
return LoadingViewModel(application) as T
}
throw IllegalArgumentException("Unknown ViewModel class.")
}
}
} }

View file

@ -1,7 +1,7 @@
package org.oxycblt.auxio.music package org.oxycblt.auxio.music
import android.app.Application
import android.content.ContentResolver import android.content.ContentResolver
import android.content.Context
import android.net.Uri import android.net.Uri
import android.provider.OpenableColumns import android.provider.OpenableColumns
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -42,21 +42,27 @@ class MusicStore private constructor() {
/** /**
* Load/Sort the entire music library. Should always be ran on a coroutine. * Load/Sort the entire music library. Should always be ran on a coroutine.
* @param app [Application] required to load the music.
*/ */
suspend fun load(app: Application): Response { suspend fun load(context: Context): Response {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
// TODO: Move this to an internal function loadMusicInternal(context)
this@MusicStore.logD("Starting initial music load...") }
}
val start = System.currentTimeMillis() /**
* Do the internal music loading process.
*/
private fun loadMusicInternal(context: Context): Response {
logD("Starting initial music load...")
try { try {
val loader = MusicLoader(app) val start = System.currentTimeMillis()
val loader = MusicLoader(context)
loader.load() loader.load()
if (loader.songs.isEmpty()) { if (loader.songs.isEmpty()) {
return@withContext Response.NO_MUSIC return Response.NO_MUSIC
} }
mSongs = loader.songs mSongs = loader.songs
@ -64,20 +70,17 @@ class MusicStore private constructor() {
mArtists = loader.artists mArtists = loader.artists
mGenres = loader.genres mGenres = loader.genres
this@MusicStore.logD( logD("Music load completed successfully in ${System.currentTimeMillis() - start}ms.")
"Music load completed successfully in ${System.currentTimeMillis() - start}ms."
)
} catch (e: Exception) { } catch (e: Exception) {
logE("Something went horribly wrong.") logE("Something went horribly wrong.")
logE(e.stackTraceToString()) logE(e.stackTraceToString())
return@withContext Response.FAILED return Response.FAILED
} }
loaded = true loaded = true
return@withContext Response.SUCCESS return Response.SUCCESS
}
} }
/** /**

View file

@ -12,8 +12,8 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.ui.getPlural import org.oxycblt.auxio.ui.getPlural
/** /**
* List of ID3 genres + Winamp extensions, each index corresponds to their int value. * A complete array of all the hardcoded genre values for ID3 <v3, contains standard genres and
* There are a lot more int-genre extensions as far as Im aware, but this works for most cases. * winamp extensions.
*/ */
private val ID3_GENRES = arrayOf( private val ID3_GENRES = arrayOf(
// ID3 Standard // ID3 Standard

View file

@ -172,6 +172,8 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
if (playbackManager.isRestored && musicStore.loaded) { if (playbackManager.isRestored && musicStore.loaded) {
playWithUriInternal(uri, context) playWithUriInternal(uri, context)
} else { } else {
logD("Cant play this URI right now, waiting...")
mIntentUri = uri mIntentUri = uri
} }
} }

View file

@ -247,8 +247,6 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
notification.setPlaying(this, isPlaying) notification.setPlaying(this, isPlaying)
startForegroundOrNotify() startForegroundOrNotify()
logD("Playing Status: $isPlaying")
} }
override fun onLoopUpdate(loopMode: LoopMode) { override fun onLoopUpdate(loopMode: LoopMode) {

View file

@ -53,7 +53,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/inter_semibold" android:fontFamily="@font/inter_semibold"
android:onClick="@{() -> loadingModel.load()}" android:onClick="@{() -> loadingModel.load(context)}"
android:text="@string/label_retry" android:text="@string/label_retry"
android:textColor="?attr/colorPrimary" android:textColor="?attr/colorPrimary"
android:visibility="gone" android:visibility="gone"