Glimpse: Use SharedFlow in ViewModels
Since we collect data using the Lifecycle State as a trigger using a SharedFlow is (one of) the optimal way to emit updates. Change-Id: Ib69b6790e52fa5e05181ebce078c72a5a7314598
This commit is contained in:
parent
065618e18b
commit
3addfcb9a2
|
@ -44,7 +44,9 @@ import org.lineageos.glimpse.viewmodels.MediaViewModel
|
|||
*/
|
||||
class AlbumFragment : Fragment(R.layout.fragment_album) {
|
||||
// View models
|
||||
private val mediaViewModel: MediaViewModel by viewModels { MediaViewModel.Factory }
|
||||
private val mediaViewModel: MediaViewModel by viewModels {
|
||||
MediaViewModel.factory(lifecycleScope, album.id)
|
||||
}
|
||||
|
||||
// Views
|
||||
private val albumRecyclerView by getViewProperty<RecyclerView>(R.id.albumRecyclerView)
|
||||
|
@ -54,10 +56,9 @@ class AlbumFragment : Fragment(R.layout.fragment_album) {
|
|||
// Permissions
|
||||
private val permissionsGatedCallback = PermissionsGatedCallback(this) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mediaViewModel.setBucketId(album.id)
|
||||
mediaViewModel.mediaForAlbum.collectLatest { data ->
|
||||
thumbnailAdapter.data = data.toTypedArray()
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
mediaViewModel.media.collectLatest {
|
||||
thumbnailAdapter.data = it.toTypedArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,9 @@ import org.lineageos.glimpse.viewmodels.AlbumsViewModel
|
|||
*/
|
||||
class AlbumsFragment : Fragment() {
|
||||
// View models
|
||||
private val albumsViewModel: AlbumsViewModel by viewModels { AlbumsViewModel.Factory }
|
||||
private val albumsViewModel: AlbumsViewModel by viewModels {
|
||||
AlbumsViewModel.factory(lifecycleScope)
|
||||
}
|
||||
|
||||
// Views
|
||||
private val albumsRecyclerView by getViewProperty<RecyclerView>(R.id.albumsRecyclerView)
|
||||
|
@ -54,7 +56,7 @@ class AlbumsFragment : Fragment() {
|
|||
// Permissions
|
||||
private val permissionsGatedCallback = PermissionsGatedCallback(this) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
albumsViewModel.albums.collectLatest {
|
||||
albumThumbnailAdapter.data = it.toTypedArray()
|
||||
}
|
||||
|
|
|
@ -56,7 +56,11 @@ import java.text.SimpleDateFormat
|
|||
*/
|
||||
class MediaViewerFragment : Fragment(R.layout.fragment_media_viewer) {
|
||||
// View models
|
||||
private val mediaViewModel: MediaViewerViewModel by viewModels { MediaViewerViewModel.Factory }
|
||||
private val mediaViewModel: MediaViewerViewModel by viewModels {
|
||||
albumId?.let {
|
||||
MediaViewerViewModel.factory(lifecycleScope, it)
|
||||
} ?: MediaViewerViewModel.factory(lifecycleScope)
|
||||
}
|
||||
|
||||
// Views
|
||||
private val adjustButton by getViewProperty<ImageButton>(R.id.adjustButton)
|
||||
|
@ -85,9 +89,8 @@ class MediaViewerFragment : Fragment(R.layout.fragment_media_viewer) {
|
|||
|
||||
initData(medias.toSet().sortedByDescending { it.dateAdded })
|
||||
} ?: albumId?.also {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mediaViewModel.setBucketId(it)
|
||||
mediaViewModel.mediaForAlbum.collectLatest(::initData)
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
mediaViewModel.media.collectLatest(::initData)
|
||||
}
|
||||
} ?: media?.also {
|
||||
initData(listOf(it))
|
||||
|
|
|
@ -40,7 +40,9 @@ import org.lineageos.glimpse.viewmodels.MediaViewModel
|
|||
*/
|
||||
class ReelsFragment : Fragment(R.layout.fragment_reels) {
|
||||
// View models
|
||||
private val mediaViewModel: MediaViewModel by viewModels { MediaViewModel.Factory }
|
||||
private val mediaViewModel: MediaViewModel by viewModels {
|
||||
MediaViewModel.factory(lifecycleScope)
|
||||
}
|
||||
|
||||
// Views
|
||||
private val appBarLayout by getViewProperty<AppBarLayout>(R.id.appBarLayout)
|
||||
|
@ -55,9 +57,9 @@ class ReelsFragment : Fragment(R.layout.fragment_reels) {
|
|||
private val permissionsUtils by lazy { PermissionsUtils(requireContext()) }
|
||||
private val permissionsGatedCallback = PermissionsGatedCallback(this) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
mediaViewModel.media.collectLatest { data ->
|
||||
thumbnailAdapter.data = data.toTypedArray()
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
mediaViewModel.media.collectLatest {
|
||||
thumbnailAdapter.data = it.toTypedArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,23 +6,31 @@
|
|||
package org.lineageos.glimpse.viewmodels
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import org.lineageos.glimpse.GlimpseApplication
|
||||
import org.lineageos.glimpse.repository.MediaRepository
|
||||
|
||||
open class AlbumsViewModel(
|
||||
private val mediaRepository: MediaRepository
|
||||
private val mediaRepository: MediaRepository,
|
||||
private val externalScope: CoroutineScope,
|
||||
) : ViewModel() {
|
||||
val albums = mediaRepository.albums()
|
||||
val albums = mediaRepository.albums().shareIn(
|
||||
externalScope,
|
||||
replay = 1,
|
||||
started = SharingStarted.WhileSubscribed()
|
||||
)
|
||||
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
fun factory(externalScope: CoroutineScope) = viewModelFactory {
|
||||
initializer {
|
||||
AlbumsViewModel(
|
||||
mediaRepository = (this[APPLICATION_KEY] as GlimpseApplication).mediaRepository,
|
||||
externalScope = externalScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,37 +6,40 @@
|
|||
package org.lineageos.glimpse.viewmodels
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import org.lineageos.glimpse.GlimpseApplication
|
||||
import org.lineageos.glimpse.repository.MediaRepository
|
||||
import org.lineageos.glimpse.utils.MediaStoreBuckets
|
||||
|
||||
open class MediaViewModel(
|
||||
private val mediaRepository: MediaRepository
|
||||
private val mediaRepository: MediaRepository,
|
||||
private val externalScope: CoroutineScope,
|
||||
private val bucketId: Int
|
||||
) : ViewModel() {
|
||||
val media = mediaRepository.media(MediaStoreBuckets.MEDIA_STORE_BUCKET_REELS.id)
|
||||
|
||||
private val bucketId = MutableStateFlow(MediaStoreBuckets.MEDIA_STORE_BUCKET_REELS.id)
|
||||
fun setBucketId(bucketId: Int) {
|
||||
this.bucketId.value = bucketId
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val mediaForAlbum = bucketId.flatMapLatest { mediaRepository.media(it) }
|
||||
val media = mediaRepository.media(bucketId).shareIn(
|
||||
externalScope,
|
||||
replay = 1,
|
||||
started = SharingStarted.WhileSubscribed()
|
||||
)
|
||||
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
MediaViewModel(
|
||||
mediaRepository = (this[APPLICATION_KEY] as GlimpseApplication).mediaRepository,
|
||||
)
|
||||
fun factory(
|
||||
externalScope: CoroutineScope,
|
||||
bucketId: Int = MediaStoreBuckets.MEDIA_STORE_BUCKET_REELS.id
|
||||
) =
|
||||
viewModelFactory {
|
||||
initializer {
|
||||
MediaViewModel(
|
||||
mediaRepository = (this[APPLICATION_KEY] as GlimpseApplication).mediaRepository,
|
||||
externalScope = externalScope,
|
||||
bucketId = bucketId,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,18 +8,21 @@ package org.lineageos.glimpse.viewmodels
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
|
||||
import androidx.lifecycle.createSavedStateHandle
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.lineageos.glimpse.GlimpseApplication
|
||||
import org.lineageos.glimpse.repository.MediaRepository
|
||||
import org.lineageos.glimpse.utils.MediaStoreBuckets
|
||||
|
||||
class MediaViewerViewModel(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
mediaRepository: MediaRepository,
|
||||
) : MediaViewModel(mediaRepository) {
|
||||
externalScope: CoroutineScope,
|
||||
bucketId: Int,
|
||||
) : MediaViewModel(mediaRepository, externalScope, bucketId) {
|
||||
private val mediaPositionInternal = savedStateHandle.getLiveData<Int>(MEDIA_POSITION_KEY)
|
||||
val mediaPositionLiveData: LiveData<Int> = mediaPositionInternal
|
||||
var mediaPosition: Int
|
||||
|
@ -51,13 +54,19 @@ class MediaViewerViewModel(
|
|||
companion object {
|
||||
private const val MEDIA_POSITION_KEY = "position"
|
||||
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
MediaViewerViewModel(
|
||||
savedStateHandle = createSavedStateHandle(),
|
||||
mediaRepository = (this[APPLICATION_KEY] as GlimpseApplication).mediaRepository,
|
||||
)
|
||||
fun factory(
|
||||
externalScope: CoroutineScope,
|
||||
bucketId: Int = MediaStoreBuckets.MEDIA_STORE_BUCKET_REELS.id
|
||||
) =
|
||||
viewModelFactory {
|
||||
initializer {
|
||||
MediaViewerViewModel(
|
||||
savedStateHandle = createSavedStateHandle(),
|
||||
mediaRepository = (this[APPLICATION_KEY] as GlimpseApplication).mediaRepository,
|
||||
externalScope = externalScope,
|
||||
bucketId = bucketId,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue