mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
refactor: Do not use JellyfinApiClient in viewModels. Use MediaRepository for consistency
This commit is contained in:
@@ -3,30 +3,23 @@ package hu.bbara.purefin.app.content.movie
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import hu.bbara.purefin.client.JellyfinApiClient
|
||||
import hu.bbara.purefin.data.MediaRepository
|
||||
import hu.bbara.purefin.data.model.Movie
|
||||
import hu.bbara.purefin.download.DownloadState
|
||||
import hu.bbara.purefin.download.MediaDownloadManager
|
||||
import hu.bbara.purefin.image.JellyfinImageHelper
|
||||
import hu.bbara.purefin.navigation.NavigationManager
|
||||
import hu.bbara.purefin.navigation.Route
|
||||
import hu.bbara.purefin.session.UserSessionRepository
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.UUID
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import org.jellyfin.sdk.model.api.BaseItemPerson
|
||||
import org.jellyfin.sdk.model.api.ImageType
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class MovieScreenViewModel @Inject constructor(
|
||||
private val jellyfinApiClient: JellyfinApiClient,
|
||||
private val mediaRepository: MediaRepository,
|
||||
private val navigationManager: NavigationManager,
|
||||
private val userSessionRepository: UserSessionRepository,
|
||||
private val mediaDownloadManager: MediaDownloadManager
|
||||
): ViewModel() {
|
||||
|
||||
@@ -47,15 +40,12 @@ class MovieScreenViewModel @Inject constructor(
|
||||
|
||||
fun selectMovie(movieId: UUID) {
|
||||
viewModelScope.launch {
|
||||
val movieInfo = jellyfinApiClient.getItemInfo(movieId)
|
||||
if (movieInfo == null) {
|
||||
val movieData = mediaRepository.movies.value[movieId]
|
||||
if (movieData == null) {
|
||||
_movie.value = null
|
||||
return@launch
|
||||
}
|
||||
val serverUrl = userSessionRepository.serverUrl.first().trim().ifBlank {
|
||||
"https://jellyfin.bbara.hu"
|
||||
}
|
||||
_movie.value = movieInfo.toUiModel(serverUrl)
|
||||
_movie.value = movieData.toUiModel()
|
||||
|
||||
launch {
|
||||
mediaDownloadManager.observeDownloadState(movieId.toString()).collect {
|
||||
@@ -82,54 +72,20 @@ class MovieScreenViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun BaseItemDto.toUiModel(serverUrl: String): MovieUiModel {
|
||||
val year = productionYear?.toString() ?: premiereDate?.year?.toString().orEmpty()
|
||||
val rating = officialRating ?: "NR"
|
||||
val runtime = formatRuntime(runTimeTicks)
|
||||
val format = container?.uppercase() ?: "VIDEO"
|
||||
val synopsis = overview ?: "No synopsis available."
|
||||
val heroImageUrl = id?.let { itemId ->
|
||||
JellyfinImageHelper.toImageUrl(
|
||||
url = serverUrl,
|
||||
itemId = itemId,
|
||||
type = ImageType.BACKDROP
|
||||
)
|
||||
} ?: ""
|
||||
val cast = people.orEmpty().map { it.toCastMember() }
|
||||
private fun Movie.toUiModel(): MovieUiModel {
|
||||
return MovieUiModel(
|
||||
id = id,
|
||||
|
||||
title = name ?: "Unknown title",
|
||||
title = title,
|
||||
year = year,
|
||||
rating = rating,
|
||||
runtime = runtime,
|
||||
format = format,
|
||||
synopsis = synopsis,
|
||||
heroImageUrl = heroImageUrl,
|
||||
audioTrack = "Default",
|
||||
subtitles = "Unknown",
|
||||
cast = cast
|
||||
audioTrack = audioTrack,
|
||||
subtitles = subtitles,
|
||||
cast = cast.map { CastMember(name = it.name, role = it.role, imageUrl = it.imageUrl) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun BaseItemPerson.toCastMember(): CastMember {
|
||||
return CastMember(
|
||||
name = name ?: "Unknown",
|
||||
role = role ?: "",
|
||||
imageUrl = null
|
||||
)
|
||||
}
|
||||
|
||||
private fun formatRuntime(ticks: Long?): String {
|
||||
if (ticks == null || ticks <= 0) return "—"
|
||||
val totalSeconds = ticks / 10_000_000
|
||||
val hours = TimeUnit.SECONDS.toHours(totalSeconds)
|
||||
val minutes = TimeUnit.SECONDS.toMinutes(totalSeconds) % 60
|
||||
return if (hours > 0) {
|
||||
"${hours}h ${minutes}m"
|
||||
} else {
|
||||
"${minutes}m"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import hu.bbara.purefin.app.home.ui.HomeNavItem
|
||||
import hu.bbara.purefin.app.home.ui.LibraryItem
|
||||
import hu.bbara.purefin.app.home.ui.NextUpItem
|
||||
import hu.bbara.purefin.app.home.ui.PosterItem
|
||||
import hu.bbara.purefin.client.JellyfinApiClient
|
||||
import hu.bbara.purefin.data.MediaRepository
|
||||
import hu.bbara.purefin.data.model.Media
|
||||
import hu.bbara.purefin.domain.usecase.RefreshHomeDataUseCase
|
||||
@@ -20,15 +19,14 @@ import hu.bbara.purefin.navigation.NavigationManager
|
||||
import hu.bbara.purefin.navigation.Route
|
||||
import hu.bbara.purefin.navigation.SeriesDto
|
||||
import hu.bbara.purefin.session.UserSessionRepository
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.UUID
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.CollectionType
|
||||
import org.jellyfin.sdk.model.api.ImageType
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -37,7 +35,6 @@ class HomePageViewModel @Inject constructor(
|
||||
private val mediaRepository: MediaRepository,
|
||||
private val userSessionRepository: UserSessionRepository,
|
||||
private val navigationManager: NavigationManager,
|
||||
private val jellyfinApiClient: JellyfinApiClient,
|
||||
private val refreshHomeDataUseCase: RefreshHomeDataUseCase
|
||||
) : ViewModel() {
|
||||
|
||||
@@ -47,8 +44,20 @@ class HomePageViewModel @Inject constructor(
|
||||
initialValue = ""
|
||||
)
|
||||
|
||||
private val _libraries = MutableStateFlow<List<LibraryItem>>(emptyList())
|
||||
val libraries = _libraries.asStateFlow()
|
||||
val libraries = mediaRepository.libraries.map { libraries ->
|
||||
libraries.map {
|
||||
LibraryItem(
|
||||
id = it.id,
|
||||
name = it.name,
|
||||
type = it.type,
|
||||
isEmpty = when(it.type) {
|
||||
CollectionType.MOVIES -> mediaRepository.movies.value.isEmpty()
|
||||
CollectionType.TVSHOWS -> mediaRepository.series.value.isEmpty()
|
||||
else -> true
|
||||
}
|
||||
)
|
||||
}
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
|
||||
|
||||
val isOfflineMode = userSessionRepository.isOfflineMode.stateIn(
|
||||
scope = viewModelScope,
|
||||
@@ -56,12 +65,6 @@ class HomePageViewModel @Inject constructor(
|
||||
initialValue = false
|
||||
)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
loadLibraries()
|
||||
}
|
||||
}
|
||||
|
||||
val continueWatching = combine(
|
||||
mediaRepository.continueWatching,
|
||||
mediaRepository.movies,
|
||||
@@ -182,19 +185,6 @@ class HomePageViewModel @Inject constructor(
|
||||
navigationManager.replaceAll(Route.Home)
|
||||
}
|
||||
|
||||
private suspend fun loadLibraries() {
|
||||
val libraries: List<BaseItemDto> = jellyfinApiClient.getLibraries()
|
||||
val mappedLibraries = libraries.map {
|
||||
LibraryItem(
|
||||
name = it.name!!,
|
||||
id = it.id,
|
||||
isEmpty = it.childCount!! == 0,
|
||||
type = it.collectionType!!
|
||||
)
|
||||
}
|
||||
_libraries.value = mappedLibraries
|
||||
}
|
||||
|
||||
fun getImageUrl(itemId: UUID, type: ImageType): String {
|
||||
return JellyfinImageHelper.toImageUrl(
|
||||
url = _url.value,
|
||||
|
||||
@@ -4,28 +4,21 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import hu.bbara.purefin.app.home.ui.PosterItem
|
||||
import hu.bbara.purefin.client.JellyfinApiClient
|
||||
import hu.bbara.purefin.data.MediaRepository
|
||||
import hu.bbara.purefin.data.model.Media
|
||||
import hu.bbara.purefin.image.JellyfinImageHelper
|
||||
import hu.bbara.purefin.navigation.MovieDto
|
||||
import hu.bbara.purefin.navigation.NavigationManager
|
||||
import hu.bbara.purefin.navigation.Route
|
||||
import hu.bbara.purefin.navigation.SeriesDto
|
||||
import hu.bbara.purefin.session.UserSessionRepository
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.UUID
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.CollectionType
|
||||
import org.jellyfin.sdk.model.api.ImageType
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.emptyList
|
||||
|
||||
@HiltViewModel
|
||||
class LibraryViewModel @Inject constructor(
|
||||
|
||||
Reference in New Issue
Block a user