package com.suno.android.ui.screens.following_clips import androidx.lifecycle.viewModelScope import arrow.core.getOrElse import com.suno.android.common_core_utils.model.UiString.Resource import com.suno.android.common_data.mappers.clips.xAsLocalClipData import com.suno.android.common_data.repos.ClipsRepository import com.suno.android.common_mvi.MviProcessorFactory import com.suno.android.common_mvi.MviViewModel import com.suno.android.common_res.R import com.suno.android.media.MediaManager import com.suno.android.ui.screens.following_clips.FollowingClipsState.ListState.Error import com.suno.android.ui.screens.following_clips.FollowingClipsState.ListState.Loaded import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class FollowingClipsVM @Inject constructor( mviProcessorFactory: MviProcessorFactory, private val clipsRepository: ClipsRepository, private val mediaManager: MediaManager, ) : MviViewModel( processorFactory = mviProcessorFactory, initialState = FollowingClipsState.Default, ) { init { sendEvent(FollowingClipsEvent.Internal.StartLoadClips) } override suspend fun reduceEvent( currentState: FollowingClipsState, event: FollowingClipsEvent, emitEffect: suspend (FollowingClipsEffect) -> Unit, ): FollowingClipsState = when (event) { FollowingClipsEvent.Internal.StartLoadClips -> { viewModelScope.launch { loadClips() } currentState.copy( listState = FollowingClipsState.ListState.Loading, ) } FollowingClipsEvent.Internal.ClipLoadError -> { currentState.copy( listState = Error(Resource(R.string.unknown_error)), ) } is FollowingClipsEvent.Internal.ClipsLoaded -> { currentState.copy( listState = when (currentState.listState) { is Loaded -> { currentState.listState.copy( clips = (currentState.listState.clips + event.clips).toImmutableList(), isLoadingMore = false, ) } is Error, FollowingClipsState.ListState.Loading, -> Loaded( clips = event.clips, ) }, ) } is FollowingClipsEvent.OnSongOverflowOpened -> { currentState.copy( songActionsSheetClip = event.song, ) } is FollowingClipsEvent.OnSongSelected -> { val listState = currentState.listState if (listState is Loaded) { mediaManager.setCurrentlyPlayingPlaylist( songList = listState.clips.map { it.xAsLocalClipData() }, chosenSong = event.song.xAsLocalClipData(), enablePlayback = true, ) } currentState } FollowingClipsEvent.OnListBottomReached -> { when (currentState.listState) { is FollowingClipsState.ListState.Loaded -> { viewModelScope.launch { loadClips(startIndex = currentState.listState.clips.size) } currentState.copy( listState = currentState.listState.copy( isLoadingMore = true, ), ) } FollowingClipsState.ListState.Loading -> { currentState } is FollowingClipsState.ListState.Error -> { viewModelScope.launch { loadClips() } currentState.copy( listState = FollowingClipsState.ListState.Loading, ) } } } } private suspend fun loadClips( startIndex: Int = 0, ) { val clips = clipsRepository.getFollowingFeed(startIndex).getOrElse { sendEvent(FollowingClipsEvent.Internal.ClipLoadError) return } sendEvent(FollowingClipsEvent.Internal.ClipsLoaded(clips)) } }