Thorium-android-app/app/src/main/java/net/schueller/peertube/feature_video/presentation/video/VideoPlayViewModel.kt

271 lines
10 KiB
Kotlin

package net.schueller.peertube.feature_video.presentation.video
import android.util.Log
import android.widget.Toast
import androidx.compose.runtime.*
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.cachedIn
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import net.schueller.peertube.common.Constants
import net.schueller.peertube.common.Resource
import net.schueller.peertube.feature_video.data.remote.auth.Session
import net.schueller.peertube.feature_video.domain.model.Description
import net.schueller.peertube.feature_video.domain.model.Video
import net.schueller.peertube.feature_video.domain.repository.VideoRepository
import net.schueller.peertube.feature_video.domain.source.VideoPagingSource
import net.schueller.peertube.feature_video.domain.use_case.*
import net.schueller.peertube.feature_video.presentation.video.events.VideoPlayEvent
import net.schueller.peertube.feature_video.presentation.video.states.VideoDescriptionState
import net.schueller.peertube.feature_video.presentation.video.states.VideoPlayState
import net.schueller.peertube.feature_video.presentation.video.states.VideoRatingState
import javax.inject.Inject
@HiltViewModel
class VideoPlayViewModel @Inject constructor(
private val videoPlayUseCases: VideoPlayUseCases,
private val session: Session,
private val repository: VideoRepository,
savedStateHandle: SavedStateHandle
) : ViewModel() {
private val _state = mutableStateOf(VideoPlayState())
val state: State<VideoPlayState> = _state
private val _stateVideoDescription = mutableStateOf(VideoDescriptionState())
val stateVideoDescription: State<VideoDescriptionState> = _stateVideoDescription
private val _stateVideoRating = mutableStateOf(VideoRatingState())
val stateVideoRating: State<VideoRatingState> = _stateVideoRating
var playerVisible = mutableStateOf(false)
private val _eventFlow = MutableSharedFlow<UiEvent>()
val eventFlow = _eventFlow.asSharedFlow()
// init {
// savedStateHandle.get<String>(Constants.PARAM_VIDEO_UUID)?.let { uuid ->
// getVideo(uuid)
// getDescription(uuid)
// }
// }
var relatedVideos: Flow<PagingData<Video>> = Pager(
PagingConfig(
pageSize = Constants.VIDEOS_API_PAGE_SIZE,
maxSize = 100
)
) {
// if (session.isLoggedIn()) {
// PlaylistVideoPagingSource(repository, "-publishedAt", video)
// } else {
VideoPagingSource(repository, "-publishedAt", null, null ,null)
// }
}.flow.cachedIn(viewModelScope)
private fun getVideo(uuid: String) {
videoPlayUseCases.getVideoUseCase(uuid).onEach { result ->
when (result) {
is Resource.Success -> {
_state.value = VideoPlayState(video = result.data)
// Add short description
_stateVideoDescription.value = VideoDescriptionState(description = Description(description = result.data?.description ?: "") )
if (result.data != null) {
getRating(result.data.id)
}
getDescription(uuid)
}
is Resource.Error -> {
_state.value = VideoPlayState(
error = result.message ?: "An unexpected error occurred"
)
}
is Resource.Loading -> {
_state.value = VideoPlayState(isLoading = true)
}
}
}.launchIn(viewModelScope)
}
private fun getDescription(uuid: String) {
// get description data
videoPlayUseCases.getVideoDescriptionUseCase(uuid).onEach { result ->
when (result) {
is Resource.Success -> {
_stateVideoDescription.value = VideoDescriptionState(description = result.data)
}
is Resource.Error -> {
_stateVideoDescription.value = VideoDescriptionState(
error = result.message ?: "An unexpected error occurred"
)
}
is Resource.Loading -> {
_stateVideoDescription.value = VideoDescriptionState(isLoading = true)
}
}
}.launchIn(viewModelScope)
}
fun onEvent(event: VideoPlayEvent) {
when (event) {
is VideoPlayEvent.UpVoteVideo -> {
if (session.isLoggedIn()) {
videoPlayUseCases.upVoteVideoUseCase(event.video).onEach { result ->
when (result) {
is Resource.Success -> {
// Update rating
if (result.data != null) {
getRating(result.data.id)
}
}
is Resource.Error -> {
_eventFlow.emit(
UiEvent.ShowToast(
"Up vote Failed: " + result.message,
Toast.LENGTH_SHORT
)
)
}
is Resource.Loading -> {
// Upvote Pending
}
}
}.launchIn(viewModelScope)
} else {
viewModelScope.launch {
_eventFlow.emit(
UiEvent.ShowToast(
"You must be logged in",
Toast.LENGTH_SHORT
)
)
}
}
}
is VideoPlayEvent.DownVoteVideo -> {
if (session.isLoggedIn()) {
videoPlayUseCases.downVoteVideoUseCase(event.video).onEach { result ->
when (result) {
is Resource.Success -> {
// Update rating
if (result.data != null) {
getRating(result.data.id)
}
}
is Resource.Error -> {
_eventFlow.emit(
UiEvent.ShowToast(
"Down vote Failed: " + result.message,
Toast.LENGTH_SHORT
)
)
}
is Resource.Loading -> {
// Down vote Pending
}
}
}.launchIn(viewModelScope)
} else {
viewModelScope.launch {
_eventFlow.emit(
UiEvent.ShowToast(
"You must be logged in",
Toast.LENGTH_SHORT
)
)
}
}
}
is VideoPlayEvent.ShareVideo -> {
videoPlayUseCases.shareVideoUseCase(event.video)
}
is VideoPlayEvent.AddVideoToPlaylist -> {
videoPlayUseCases.addVideoToPlaylistUseCase(event.video)
}
is VideoPlayEvent.BlockVideo -> {
videoPlayUseCases.blockVideoUseCase(event.video)
}
is VideoPlayEvent.FlagVideo -> {
videoPlayUseCases.flagVideoUseCase(event.video)
}
is VideoPlayEvent.DownloadVideo -> {
// TODO: permissions
videoPlayUseCases.downloadVideoUseCase(event.video)
}
is VideoPlayEvent.OpenDescription -> {
// Show description before we have the data
viewModelScope.launch {
_eventFlow.emit(UiEvent.ShowDescription)
}
}
is VideoPlayEvent.CloseDescription -> {
viewModelScope.launch {
_eventFlow.emit(UiEvent.HideDescription)
}
}
is VideoPlayEvent.MoreButton -> {
// TODO: implement video options menu
Log.v("VPVM", "Video More Pressed")
viewModelScope.launch {
_eventFlow.emit(UiEvent.ShowMore)
}
}
is VideoPlayEvent.MiniPlayerButton -> {
Log.v("VPVM", "Video Miniplayer Pressed")
viewModelScope.launch {
_eventFlow.emit(UiEvent.ShowMiniPlayer)
}
}
is VideoPlayEvent.PlayVideo -> {
// Load new video
getVideo(event.video.uuid)
// show video
playerVisible.value = true
}
is VideoPlayEvent.CloseVideo -> {
playerVisible.value = false
}
}
}
private fun getRating(id: Int) {
Log.v("VPVM", "Get Rating: " + id)
videoPlayUseCases.getVideoRatingUseCase(id).onEach { res ->
when (res) {
is Resource.Success -> {
Log.v("VPVM", "Update Rating: " + res.data)
_stateVideoRating.value = VideoRatingState(rating = res.data)
}
is Resource.Error -> {
Log.v("VPVM", "Error getting rating")
}
is Resource.Loading -> {
// updating rating
Log.v("VPVM", "updating rating")
}
}
}.launchIn(viewModelScope)
}
sealed class UiEvent {
data class ShowToast(val message: String, val length: Int): UiEvent()
object ShowDescription : UiEvent()
object HideDescription : UiEvent()
object ShowMore : UiEvent()
object HideMore : UiEvent()
object ShowMiniPlayer : UiEvent()
object HideMiniPlayer : UiEvent()
}
}