mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 08:01:20 +02:00
Fix only loading 100 episode in a season (#187)
Fixes #184 Data was being fetched, but the UI wasn't being properly notified to display the data. This PR also adjusts so that "focused episode header" still takes up the space even if the focused episode hasn't fully loaded yet. This prevents the UI from jumping up and down. Also #42 is _not_ fixed by this PR because it is a different issue.
This commit is contained in:
parent
5720603447
commit
0fb1a69556
4 changed files with 47 additions and 28 deletions
|
|
@ -24,18 +24,18 @@ import org.jellyfin.sdk.model.extensions.ticks
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FocusedEpisodeHeader(
|
fun FocusedEpisodeHeader(
|
||||||
ep: BaseItem,
|
ep: BaseItem?,
|
||||||
overviewOnClick: () -> Unit,
|
overviewOnClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val dto = ep.data
|
val dto = ep?.data
|
||||||
Column(
|
Column(
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = dto.episodeTitle ?: dto.name ?: "",
|
text = dto?.episodeTitle ?: dto?.name ?: "",
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
|
@ -46,17 +46,17 @@ fun FocusedEpisodeHeader(
|
||||||
) {
|
) {
|
||||||
val details =
|
val details =
|
||||||
buildList {
|
buildList {
|
||||||
dto.seasonEpisode?.let(::add)
|
dto?.seasonEpisode?.let(::add)
|
||||||
dto.premiereDate?.let { add(formatDateTime(it)) }
|
dto?.premiereDate?.let { add(formatDateTime(it)) }
|
||||||
val duration = dto.runTimeTicks?.ticks
|
val duration = dto?.runTimeTicks?.ticks
|
||||||
duration
|
duration
|
||||||
?.roundMinutes
|
?.roundMinutes
|
||||||
?.toString()
|
?.toString()
|
||||||
?.let {
|
?.let {
|
||||||
add(it)
|
add(it)
|
||||||
}
|
}
|
||||||
dto.officialRating?.let(::add)
|
dto?.officialRating?.let(::add)
|
||||||
dto.timeRemaining?.roundMinutes?.let { add("$it left") }
|
dto?.timeRemaining?.roundMinutes?.let { add("$it left") }
|
||||||
}
|
}
|
||||||
DotSeparatedRow(
|
DotSeparatedRow(
|
||||||
texts = details,
|
texts = details,
|
||||||
|
|
@ -68,12 +68,12 @@ fun FocusedEpisodeHeader(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
SimpleStarRating(
|
SimpleStarRating(
|
||||||
dto.communityRating,
|
dto?.communityRating,
|
||||||
Modifier.height(20.dp),
|
Modifier.height(20.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
OverviewText(
|
OverviewText(
|
||||||
overview = dto.overview ?: "",
|
overview = dto?.overview ?: "",
|
||||||
maxLines = 3,
|
maxLines = 3,
|
||||||
onClick = overviewOnClick,
|
onClick = overviewOnClick,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -162,14 +162,12 @@ fun SeriesOverviewContent(
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
// Episode header
|
// Episode header
|
||||||
focusedEpisode?.let { ep ->
|
|
||||||
FocusedEpisodeHeader(
|
FocusedEpisodeHeader(
|
||||||
ep = ep,
|
ep = focusedEpisode,
|
||||||
overviewOnClick = overviewOnClick,
|
overviewOnClick = overviewOnClick,
|
||||||
modifier = Modifier.fillMaxWidth(.66f),
|
modifier = Modifier.fillMaxWidth(.66f),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
item {
|
item {
|
||||||
key(position.seasonTabIndex) {
|
key(position.seasonTabIndex) {
|
||||||
when (val eps = episodes) {
|
when (val eps = episodes) {
|
||||||
|
|
|
||||||
|
|
@ -293,17 +293,11 @@ class SeriesViewModel
|
||||||
itemId: UUID,
|
itemId: UUID,
|
||||||
listIndex: Int,
|
listIndex: Int,
|
||||||
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
|
) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
|
||||||
val base = api.userLibraryApi.getItem(itemId).content
|
|
||||||
val item = BaseItem.Companion.from(base, api)
|
|
||||||
val eps = episodes.value
|
val eps = episodes.value
|
||||||
if (eps is EpisodeList.Success) {
|
if (eps is EpisodeList.Success) {
|
||||||
val newItems =
|
eps.episodes.refreshItem(listIndex, itemId)
|
||||||
eps.episodes.toMutableList().apply {
|
|
||||||
this[listIndex] = item
|
|
||||||
}
|
|
||||||
val newValue = eps.copy(episodes = newItems)
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
episodes.value = newValue
|
episodes.value = eps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -409,7 +403,7 @@ sealed interface EpisodeList {
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Success(
|
data class Success(
|
||||||
val episodes: List<BaseItem?>,
|
val episodes: ApiRequestPager<GetEpisodesRequest>,
|
||||||
val initialIndex: Int,
|
val initialIndex: Int,
|
||||||
) : EpisodeList
|
) : EpisodeList
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import org.jellyfin.sdk.api.client.extensions.liveTvApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.playlistsApi
|
import org.jellyfin.sdk.api.client.extensions.playlistsApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.suggestionsApi
|
import org.jellyfin.sdk.api.client.extensions.suggestionsApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.tvShowsApi
|
import org.jellyfin.sdk.api.client.extensions.tvShowsApi
|
||||||
|
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDtoQueryResult
|
import org.jellyfin.sdk.model.api.BaseItemDtoQueryResult
|
||||||
import org.jellyfin.sdk.model.api.GetProgramsDto
|
import org.jellyfin.sdk.model.api.GetProgramsDto
|
||||||
import org.jellyfin.sdk.model.api.request.GetEpisodesRequest
|
import org.jellyfin.sdk.model.api.request.GetEpisodesRequest
|
||||||
|
|
@ -31,6 +32,7 @@ import org.jellyfin.sdk.model.api.request.GetPlaylistItemsRequest
|
||||||
import org.jellyfin.sdk.model.api.request.GetResumeItemsRequest
|
import org.jellyfin.sdk.model.api.request.GetResumeItemsRequest
|
||||||
import org.jellyfin.sdk.model.api.request.GetSuggestionsRequest
|
import org.jellyfin.sdk.model.api.request.GetSuggestionsRequest
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.UUID
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -58,7 +60,7 @@ class ApiRequestPager<T>(
|
||||||
CacheBuilder
|
CacheBuilder
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.maximumSize(cacheSize)
|
.maximumSize(cacheSize)
|
||||||
.build<Int, List<BaseItem>>()
|
.build<Int, MutableList<BaseItem>>()
|
||||||
|
|
||||||
suspend fun init(): ApiRequestPager<T> {
|
suspend fun init(): ApiRequestPager<T> {
|
||||||
if (totalCount < 0) {
|
if (totalCount < 0) {
|
||||||
|
|
@ -122,13 +124,38 @@ class ApiRequestPager<T>(
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
val result = requestHandler.execute(api, newRequest).content
|
val result = requestHandler.execute(api, newRequest).content
|
||||||
val data = result.items.map { BaseItem.from(it, api, useSeriesForPrimary) }
|
val data = mutableListOf<BaseItem>()
|
||||||
|
result.items.forEach { data.add(BaseItem.from(it, api, useSeriesForPrimary)) }
|
||||||
cachedPages.put(pageNumber, data)
|
cachedPages.put(pageNumber, data)
|
||||||
items = ItemList(totalCount, pageSize, cachedPages.asMap())
|
items = ItemList(totalCount, pageSize, cachedPages.asMap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun refreshItem(
|
||||||
|
position: Int,
|
||||||
|
itemId: UUID,
|
||||||
|
) {
|
||||||
|
val item =
|
||||||
|
api.userLibraryApi.getItem(itemId).content.let {
|
||||||
|
BaseItem.from(
|
||||||
|
it,
|
||||||
|
api,
|
||||||
|
useSeriesForPrimary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val pageNumber = position / pageSize
|
||||||
|
val index = position - pageNumber * pageSize
|
||||||
|
mutex.withLock {
|
||||||
|
val page = cachedPages.getIfPresent(pageNumber)
|
||||||
|
if (page != null && index in page.indices) {
|
||||||
|
page[index] = item
|
||||||
|
cachedPages.put(pageNumber, page)
|
||||||
|
items = ItemList(totalCount, pageSize, cachedPages.asMap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val DEBUG = false
|
private const val DEBUG = false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue