Twelve: VM housekeeping

* Reorder code
* Add missing flowOn and stateIn
* Make sure all flows that uses RequestStatus use non-null values

Change-Id: If3693ff54386d4d2d7872573f7762f64fffdfe8c
diff --git a/app/src/main/java/org/lineageos/twelve/ext/LinearProgressIndicator.kt b/app/src/main/java/org/lineageos/twelve/ext/LinearProgressIndicator.kt
index 6e6a78e..c533b1c 100644
--- a/app/src/main/java/org/lineageos/twelve/ext/LinearProgressIndicator.kt
+++ b/app/src/main/java/org/lineageos/twelve/ext/LinearProgressIndicator.kt
@@ -12,18 +12,9 @@
  * @see LinearProgressIndicator.setProgressCompat
  */
 fun <T : Any> LinearProgressIndicator.setProgressCompat(
-    status: RequestStatus<T>?, animated: Boolean
+    status: RequestStatus<T>, animated: Boolean
 ) {
     when (status) {
-        null -> {
-            if (!isIndeterminate) {
-                hide()
-                isIndeterminate = true
-            }
-
-            show()
-        }
-
         is RequestStatus.Loading -> {
             status.progress?.also {
                 setProgressCompat(it, animated)
diff --git a/app/src/main/java/org/lineageos/twelve/fragments/AlbumFragment.kt b/app/src/main/java/org/lineageos/twelve/fragments/AlbumFragment.kt
index c7a2183..b804736 100644
--- a/app/src/main/java/org/lineageos/twelve/fragments/AlbumFragment.kt
+++ b/app/src/main/java/org/lineageos/twelve/fragments/AlbumFragment.kt
@@ -139,13 +139,6 @@
             linearProgressIndicator.setProgressCompat(it, true)
 
             when (it) {
-                null -> {
-                    adapter.submitList(listOf())
-
-                    recyclerView.isVisible = false
-                    noElementsNestedScrollView.isVisible = false
-                }
-
                 is RequestStatus.Loading -> {
                     // Do nothing
                 }
diff --git a/app/src/main/java/org/lineageos/twelve/fragments/ArtistFragment.kt b/app/src/main/java/org/lineageos/twelve/fragments/ArtistFragment.kt
index 01c5078..49ba900 100644
--- a/app/src/main/java/org/lineageos/twelve/fragments/ArtistFragment.kt
+++ b/app/src/main/java/org/lineageos/twelve/fragments/ArtistFragment.kt
@@ -150,10 +150,6 @@
             linearProgressIndicator.setProgressCompat(it, true)
 
             when (it) {
-                null -> {
-                    // Do nothing
-                }
-
                 is RequestStatus.Loading -> {
                     // Do nothing
                 }
diff --git a/app/src/main/java/org/lineageos/twelve/fragments/AudioBottomSheetDialogFragment.kt b/app/src/main/java/org/lineageos/twelve/fragments/AudioBottomSheetDialogFragment.kt
index d62924e..4d5c294 100644
--- a/app/src/main/java/org/lineageos/twelve/fragments/AudioBottomSheetDialogFragment.kt
+++ b/app/src/main/java/org/lineageos/twelve/fragments/AudioBottomSheetDialogFragment.kt
@@ -98,10 +98,6 @@
     private suspend fun loadData() {
         viewModel.audio.collect {
             when (it) {
-                null -> {
-                    // Do nothing
-                }
-
                 is RequestStatus.Loading -> {
                     // Do nothing
                 }
diff --git a/app/src/main/java/org/lineageos/twelve/fragments/PlaylistFragment.kt b/app/src/main/java/org/lineageos/twelve/fragments/PlaylistFragment.kt
index 981dc1c..19b7084 100644
--- a/app/src/main/java/org/lineageos/twelve/fragments/PlaylistFragment.kt
+++ b/app/src/main/java/org/lineageos/twelve/fragments/PlaylistFragment.kt
@@ -152,13 +152,6 @@
             linearProgressIndicator.setProgressCompat(it, true)
 
             when (it) {
-                null -> {
-                    adapter.submitList(listOf())
-
-                    recyclerView.isVisible = false
-                    noElementsNestedScrollView.isVisible = false
-                }
-
                 is RequestStatus.Loading -> {
                     // Do nothing
                 }
diff --git a/app/src/main/java/org/lineageos/twelve/fragments/SearchFragment.kt b/app/src/main/java/org/lineageos/twelve/fragments/SearchFragment.kt
index 8ac6481..6663985 100644
--- a/app/src/main/java/org/lineageos/twelve/fragments/SearchFragment.kt
+++ b/app/src/main/java/org/lineageos/twelve/fragments/SearchFragment.kt
@@ -171,13 +171,6 @@
             linearProgressIndicator.setProgressCompat(it, true)
 
             when (it) {
-                null -> {
-                    adapter.submitList(listOf())
-
-                    recyclerView.isVisible = false
-                    noElementsLinearLayout.isVisible = false
-                }
-
                 is RequestStatus.Loading -> {
                     // Do nothing
                 }
diff --git a/app/src/main/java/org/lineageos/twelve/viewmodels/AddOrRemoveFromPlaylistsViewModel.kt b/app/src/main/java/org/lineageos/twelve/viewmodels/AddOrRemoveFromPlaylistsViewModel.kt
index c98df8f..bffbdd2 100644
--- a/app/src/main/java/org/lineageos/twelve/viewmodels/AddOrRemoveFromPlaylistsViewModel.kt
+++ b/app/src/main/java/org/lineageos/twelve/viewmodels/AddOrRemoveFromPlaylistsViewModel.kt
@@ -18,9 +18,11 @@
 
 class AddOrRemoveFromPlaylistsViewModel(application: Application) : AudioViewModel(application) {
     @OptIn(ExperimentalCoroutinesApi::class)
-    val playlistToHasAudio = audioUri.filterNotNull().flatMapLatest {
-        mediaRepository.audioPlaylistsStatus(it)
-    }
+    val playlistToHasAudio = audioUri
+        .filterNotNull()
+        .flatMapLatest {
+            mediaRepository.audioPlaylistsStatus(it)
+        }
         .flowOn(Dispatchers.IO)
         .stateIn(
             viewModelScope,
diff --git a/app/src/main/java/org/lineageos/twelve/viewmodels/AlbumViewModel.kt b/app/src/main/java/org/lineageos/twelve/viewmodels/AlbumViewModel.kt
index 95908be..8a99120 100644
--- a/app/src/main/java/org/lineageos/twelve/viewmodels/AlbumViewModel.kt
+++ b/app/src/main/java/org/lineageos/twelve/viewmodels/AlbumViewModel.kt
@@ -12,25 +12,26 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.stateIn
+import org.lineageos.twelve.models.RequestStatus
 
 class AlbumViewModel(application: Application) : TwelveViewModel(application) {
     private val albumUri = MutableStateFlow<Uri?>(null)
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val album = albumUri.flatMapLatest {
-        it?.let {
+    val album = albumUri
+        .filterNotNull()
+        .flatMapLatest {
             mediaRepository.album(it)
-        } ?: flowOf(null)
-    }
+        }
         .flowOn(Dispatchers.IO)
         .stateIn(
             viewModelScope,
             SharingStarted.WhileSubscribed(),
-            null
+            RequestStatus.Loading()
         )
 
     fun loadAlbum(albumUri: Uri) {
diff --git a/app/src/main/java/org/lineageos/twelve/viewmodels/ArtistViewModel.kt b/app/src/main/java/org/lineageos/twelve/viewmodels/ArtistViewModel.kt
index 934a8fb..830715e 100644
--- a/app/src/main/java/org/lineageos/twelve/viewmodels/ArtistViewModel.kt
+++ b/app/src/main/java/org/lineageos/twelve/viewmodels/ArtistViewModel.kt
@@ -12,25 +12,26 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.stateIn
+import org.lineageos.twelve.models.RequestStatus
 
 class ArtistViewModel(application: Application) : TwelveViewModel(application) {
     private val artistUri = MutableStateFlow<Uri?>(null)
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val artist = artistUri.flatMapLatest {
-        it?.let {
+    val artist = artistUri
+        .filterNotNull()
+        .flatMapLatest {
             mediaRepository.artist(it)
-        } ?: flowOf(null)
-    }
+        }
         .flowOn(Dispatchers.IO)
         .stateIn(
             viewModelScope,
             SharingStarted.WhileSubscribed(),
-            null
+            RequestStatus.Loading()
         )
 
     fun loadAlbum(artistUri: Uri) {
diff --git a/app/src/main/java/org/lineageos/twelve/viewmodels/AudioViewModel.kt b/app/src/main/java/org/lineageos/twelve/viewmodels/AudioViewModel.kt
index ae86333..75cf379 100644
--- a/app/src/main/java/org/lineageos/twelve/viewmodels/AudioViewModel.kt
+++ b/app/src/main/java/org/lineageos/twelve/viewmodels/AudioViewModel.kt
@@ -12,26 +12,27 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.launch
+import org.lineageos.twelve.models.RequestStatus
 
 open class AudioViewModel(application: Application) : TwelveViewModel(application) {
     protected val audioUri = MutableStateFlow<Uri?>(null)
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val audio = audioUri.flatMapLatest {
-        it?.let {
+    val audio = audioUri
+        .filterNotNull()
+        .flatMapLatest {
             mediaRepository.audio(it)
-        } ?: flowOf(null)
-    }
+        }
         .flowOn(Dispatchers.IO)
         .stateIn(
             viewModelScope,
             SharingStarted.WhileSubscribed(),
-            null
+            RequestStatus.Loading()
         )
 
     fun loadAudio(audioUri: Uri) {
diff --git a/app/src/main/java/org/lineageos/twelve/viewmodels/PlaylistViewModel.kt b/app/src/main/java/org/lineageos/twelve/viewmodels/PlaylistViewModel.kt
index 2246669..31e8563 100644
--- a/app/src/main/java/org/lineageos/twelve/viewmodels/PlaylistViewModel.kt
+++ b/app/src/main/java/org/lineageos/twelve/viewmodels/PlaylistViewModel.kt
@@ -12,26 +12,27 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.launch
+import org.lineageos.twelve.models.RequestStatus
 
 class PlaylistViewModel(application: Application) : TwelveViewModel(application) {
     private val playlistUri = MutableStateFlow<Uri?>(null)
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val playlist = playlistUri.flatMapLatest {
-        it?.let {
+    val playlist = playlistUri
+        .filterNotNull()
+        .flatMapLatest {
             mediaRepository.playlist(it)
-        } ?: flowOf(null)
-    }
+        }
         .flowOn(Dispatchers.IO)
         .stateIn(
             viewModelScope,
             SharingStarted.WhileSubscribed(),
-            null
+            RequestStatus.Loading()
         )
 
     fun loadPlaylist(playlistUri: Uri) {
diff --git a/app/src/main/java/org/lineageos/twelve/viewmodels/SearchViewModel.kt b/app/src/main/java/org/lineageos/twelve/viewmodels/SearchViewModel.kt
index 744f655..f3f56e2 100644
--- a/app/src/main/java/org/lineageos/twelve/viewmodels/SearchViewModel.kt
+++ b/app/src/main/java/org/lineageos/twelve/viewmodels/SearchViewModel.kt
@@ -6,15 +6,21 @@
 package org.lineageos.twelve.viewmodels
 
 import android.app.Application
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+import org.lineageos.twelve.models.RequestStatus
 
 class SearchViewModel(application: Application) : TwelveViewModel(application) {
-    private val searchQuery = MutableStateFlow<String?>(null)
+    private val searchQuery = MutableStateFlow("")
 
     @OptIn(ExperimentalCoroutinesApi::class)
     val searchResults = searchQuery
@@ -23,12 +29,18 @@
             it
         }
         .flatMapLatest { query ->
-            query?.trim()?.takeIf { it.isNotEmpty() }?.let {
+            query.trim().takeIf { it.isNotEmpty() }?.let {
                 mediaRepository.search("%${it}%")
-            } ?: flowOf(null)
+            } ?: flowOf(RequestStatus.Success(listOf()))
         }
+        .flowOn(Dispatchers.IO)
+        .stateIn(
+            viewModelScope,
+            SharingStarted.WhileSubscribed(),
+            RequestStatus.Loading()
+        )
 
-    fun setSearchQuery(query: String?) {
+    fun setSearchQuery(query: String) {
         searchQuery.value = query
     }
 }
diff --git a/app/src/main/java/org/lineageos/twelve/viewmodels/TwelveViewModel.kt b/app/src/main/java/org/lineageos/twelve/viewmodels/TwelveViewModel.kt
index 8831f7a..198d742 100644
--- a/app/src/main/java/org/lineageos/twelve/viewmodels/TwelveViewModel.kt
+++ b/app/src/main/java/org/lineageos/twelve/viewmodels/TwelveViewModel.kt
@@ -82,7 +82,8 @@
         )
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val mediaMetadata = mediaController.filterNotNull()
+    val mediaMetadata = mediaController
+        .filterNotNull()
         .flatMapLatest { it.mediaMetadataFlow() }
         .flowOn(Dispatchers.Main)
         .stateIn(
@@ -92,7 +93,8 @@
         )
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val mediaItem = mediaController.filterNotNull()
+    val mediaItem = mediaController
+        .filterNotNull()
         .flatMapLatest { it.mediaItemFlow() }
         .flowOn(Dispatchers.Main)
         .stateIn(
@@ -102,7 +104,8 @@
         )
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val isPlaying = mediaController.filterNotNull()
+    val isPlaying = mediaController
+        .filterNotNull()
         .flatMapLatest { it.isPlayingFlow() }
         .flowOn(Dispatchers.Main)
         .stateIn(
@@ -112,7 +115,8 @@
         )
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val shuffleMode = mediaController.filterNotNull()
+    val shuffleMode = mediaController
+        .filterNotNull()
         .flatMapLatest { it.shuffleModeFlow() }
         .flowOn(Dispatchers.Main)
         .stateIn(
@@ -122,7 +126,8 @@
         )
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val repeatMode = mediaController.filterNotNull()
+    val repeatMode = mediaController
+        .filterNotNull()
         .flatMapLatest { it.repeatModeFlow() }
         .flowOn(Dispatchers.Main)
         .stateIn(
@@ -132,7 +137,8 @@
         )
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val playbackParameters = mediaController.filterNotNull()
+    val playbackParameters = mediaController
+        .filterNotNull()
         .flatMapLatest { it.playbackParametersFlow() }
         .flowOn(Dispatchers.Main)
         .stateIn(
@@ -143,7 +149,8 @@
 
     @androidx.annotation.OptIn(UnstableApi::class)
     @OptIn(ExperimentalCoroutinesApi::class)
-    val currentTrackFormat = mediaController.filterNotNull()
+    val currentTrackFormat = mediaController
+        .filterNotNull()
         .flatMapLatest { it.tracksFlow() }
         .flowOn(Dispatchers.Main)
         .mapLatest { tracks ->
@@ -169,18 +176,17 @@
             initialValue = null
         )
 
-    val mimeType =
-        combine(currentTrackFormat, mediaItem) { format, mediaItem ->
-            format?.sampleMimeType
-                ?: format?.containerMimeType
-                ?: mediaItem?.localConfiguration?.mimeType
-        }
-            .flowOn(Dispatchers.IO)
-            .stateIn(
-                viewModelScope,
-                started = SharingStarted.WhileSubscribed(),
-                initialValue = null
-            )
+    val mimeType = combine(currentTrackFormat, mediaItem) { format, mediaItem ->
+        format?.sampleMimeType
+            ?: format?.containerMimeType
+            ?: mediaItem?.localConfiguration?.mimeType
+    }
+        .flowOn(Dispatchers.IO)
+        .stateIn(
+            viewModelScope,
+            started = SharingStarted.WhileSubscribed(),
+            initialValue = null
+        )
 
     @androidx.annotation.OptIn(UnstableApi::class)
     @OptIn(ExperimentalCoroutinesApi::class)
@@ -202,7 +208,8 @@
         )
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    fun availableCommands() = mediaController.filterNotNull()
+    fun availableCommands() = mediaController
+        .filterNotNull()
         .flatMapLatest { it.availableCommandsFlow() }
         .flowOn(Dispatchers.Main)
         .stateIn(
@@ -212,7 +219,8 @@
         )
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    val durationCurrentPositionMs = mediaController.filterNotNull()
+    val durationCurrentPositionMs = mediaController
+        .filterNotNull()
         .flatMapLatest { mediaController ->
             flow {
                 while (true) {