Show loading indicator when refreshing guide data

This commit is contained in:
Damontecres 2025-10-22 12:32:31 -04:00
parent be7bb65a7e
commit 36287be5d4
No known key found for this signature in database
3 changed files with 411 additions and 371 deletions

View file

@ -90,6 +90,12 @@ class LiveTvViewModel
}
}
private suspend fun fetchProgramsWithLoading(channels: List<TvChannel>) {
loading.setValueOnMain(LoadingState.Loading)
fetchPrograms(channels)
loading.setValueOnMain(LoadingState.Success)
}
private suspend fun fetchPrograms(channels: List<TvChannel>) =
mutex.withLock {
val maxStartDate = start.plusHours(MAX_HOURS).minusMinutes(1)
@ -203,7 +209,7 @@ class LiveTvViewModel
viewModelScope.launchIO(ExceptionHandler(autoToast = true)) {
if (series) {
api.liveTvApi.cancelSeriesTimer(timerId)
fetchPrograms(channels.value.orEmpty())
fetchProgramsWithLoading(channels.value.orEmpty())
} else {
api.liveTvApi.cancelTimer(timerId)
refreshProgram(programIndex, programId)
@ -221,7 +227,7 @@ class LiveTvViewModel
val d by api.liveTvApi.getDefaultTimer(programId.toServerString())
if (series) {
api.liveTvApi.createSeriesTimer(d)
fetchPrograms(channels.value.orEmpty())
fetchProgramsWithLoading(channels.value.orEmpty())
} else {
val payload =
TimerInfoDto(
@ -256,6 +262,7 @@ class LiveTvViewModel
programIndex: Int,
programId: UUID,
) = mutex.withLock {
loading.setValueOnMain(LoadingState.Loading)
val program by api.liveTvApi.getProgram(programId.toServerString())
val newProgram =
programs.value?.getOrNull(programIndex)?.copy(
@ -272,6 +279,7 @@ class LiveTvViewModel
this@LiveTvViewModel.programs.setValueOnMain(it)
}
}
loading.setValueOnMain(LoadingState.Success)
}
}

View file

@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
@ -129,6 +130,17 @@ fun ProgramDialog(
maxLines = 3,
)
}
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier =
Modifier
.padding(top = 8.dp)
.fillMaxWidth(),
) {
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
) {
if (dto.isSeries ?: false) {
Button(
onClick = {
@ -181,6 +193,7 @@ fun ProgramDialog(
)
}
}
}
if (now.isAfter(dto.startDate!!) && now.isBefore(dto.endDate!!)) {
Button(
onClick = onWatch,
@ -206,3 +219,4 @@ fun ProgramDialog(
}
}
}
}

View file

@ -11,6 +11,8 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -43,6 +45,7 @@ import androidx.tv.material3.Text
import androidx.tv.material3.contentColorFor
import androidx.tv.material3.surfaceColorAtElevation
import coil3.compose.AsyncImage
import com.github.damontecres.wholphin.ui.components.CircularProgress
import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.enableMarquee
@ -78,12 +81,12 @@ fun TvGuideGrid(
val programsByChannel by viewModel.programsByChannel.observeAsState(mapOf())
when (val state = loading) {
is LoadingState.Error -> ErrorMessage(state, modifier)
LoadingState.Loading,
LoadingState.Pending,
-> LoadingPage(modifier)
LoadingState.Success -> {
LoadingState.Loading,
LoadingState.Success,
-> {
val context = LocalContext.current
val fetchedItem by viewModel.fetchedItem.observeAsState(null)
val loadingItem by viewModel.fetchingItem.observeAsState(LoadingState.Pending)
@ -96,6 +99,7 @@ fun TvGuideGrid(
}
Column(modifier = modifier) {
TvGuideGrid(
loading = state is LoadingState.Loading,
channels = channels,
programList = programs,
programs = programsByChannel,
@ -183,6 +187,7 @@ const val CHANNEL_COLUMN = -1
@Composable
fun TvGuideGrid(
loading: Boolean,
channels: List<TvChannel>,
programList: List<TvProgram>,
programs: Map<UUID, List<TvProgram>>,
@ -225,12 +230,13 @@ fun TvGuideGrid(
var gridHasFocus by rememberSaveable { mutableStateOf(false) }
var channelColumnFocused by rememberSaveable { mutableStateOf(false) }
Box(modifier = modifier) {
ProgramGuide(
state = state,
dimensions = dimensions,
modifier =
modifier
Modifier
.fillMaxSize()
.onFocusChanged {
gridHasFocus = it.hasFocus
}.focusable()
@ -574,4 +580,16 @@ fun TvGuideGrid(
)
}
}
if (loading) {
CircularProgress(
Modifier
.background(
MaterialTheme.colorScheme.background.copy(alpha = .5f),
shape = CircleShape,
).size(64.dp)
.padding(16.dp)
.align(Alignment.BottomEnd),
)
}
}
}