mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Refresh programs for series recordings
This commit is contained in:
parent
fd853acdd5
commit
0438b889b6
3 changed files with 94 additions and 87 deletions
|
|
@ -1,7 +0,0 @@
|
||||||
package com.github.damontecres.wholphin.ui.detail.livetv
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ChannelRow() {
|
|
||||||
}
|
|
||||||
|
|
@ -48,6 +48,7 @@ class LiveTvViewModel
|
||||||
|
|
||||||
val start =
|
val start =
|
||||||
LocalDateTime.now().truncatedTo(ChronoUnit.HOURS)
|
LocalDateTime.now().truncatedTo(ChronoUnit.HOURS)
|
||||||
|
private lateinit var channelsIdToIndex: Map<UUID, Int>
|
||||||
|
|
||||||
val channels = MutableLiveData<List<TvChannel>>()
|
val channels = MutableLiveData<List<TvChannel>>()
|
||||||
val programs = MutableLiveData<List<TvProgram>>()
|
val programs = MutableLiveData<List<TvProgram>>()
|
||||||
|
|
@ -75,91 +76,94 @@ class LiveTvViewModel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Timber.d("Got ${channels.size} channels")
|
Timber.d("Got ${channels.size} channels")
|
||||||
val channelsIdToIndex =
|
channelsIdToIndex =
|
||||||
channels.withIndex().associateBy({ it.value.id }, { it.index })
|
channels.withIndex().associateBy({ it.value.id }, { it.index })
|
||||||
val maxStartDate = start.plusHours(MAX_HOURS).minusMinutes(1)
|
fetchPrograms(channels)
|
||||||
val minEndDate = start.plusMinutes(1L)
|
|
||||||
val request =
|
|
||||||
GetProgramsDto(
|
|
||||||
maxStartDate = maxStartDate,
|
|
||||||
minEndDate = minEndDate,
|
|
||||||
// maxEndDate = start.plusHours(25),
|
|
||||||
channelIds = channels.map { it.id },
|
|
||||||
sortBy = listOf(ItemSortBy.START_DATE),
|
|
||||||
)
|
|
||||||
// val pager = ApiRequestPager(api, request, GetProgramsDtoHandler, viewModelScope).init()
|
|
||||||
// (0..<pager.size).forEach { pager.getBlocking(it) }
|
|
||||||
val programs =
|
|
||||||
GetProgramsDtoHandler
|
|
||||||
.execute(api, request)
|
|
||||||
.content.items
|
|
||||||
.map { dto ->
|
|
||||||
TvProgram(
|
|
||||||
id = dto.id,
|
|
||||||
channelId = dto.channelId!!,
|
|
||||||
start = dto.startDate!!,
|
|
||||||
end = dto.endDate!!,
|
|
||||||
startHours = hoursBetween(start, dto.startDate!!),
|
|
||||||
endHours = hoursBetween(start, dto.endDate!!),
|
|
||||||
duration = dto.runTimeTicks!!.ticks,
|
|
||||||
name = dto.seriesName ?: dto.name,
|
|
||||||
subtitle = dto.episodeTitle.takeIf { dto.isSeries ?: false },
|
|
||||||
seasonEpisode =
|
|
||||||
if (dto.indexNumber != null && dto.parentIndexNumber != null) {
|
|
||||||
SeasonEpisode(dto.parentIndexNumber!!, dto.indexNumber!!)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
},
|
|
||||||
isRecording = dto.timerId.isNotNullOrBlank(),
|
|
||||||
isSeriesRecording = dto.seriesTimerId.isNotNullOrBlank(),
|
|
||||||
)
|
|
||||||
}.filter { it.startHours >= 0 && it.endHours >= 0 } // TODO shouldn't need to filter client side
|
|
||||||
|
|
||||||
val programsByChannel = programs.groupBy { it.channelId }
|
|
||||||
val emptyChannels = channels.filter { programsByChannel[it.id].orEmpty().isEmpty() }
|
|
||||||
val fake = mutableListOf<TvProgram>()
|
|
||||||
val finalProgramsByChannel =
|
|
||||||
programsByChannel.toMutableMap().apply {
|
|
||||||
emptyChannels.forEach { channel ->
|
|
||||||
val fakePrograms =
|
|
||||||
(0..<MAX_HOURS).map {
|
|
||||||
TvProgram(
|
|
||||||
id = UUID.randomUUID(), // TODO
|
|
||||||
channelId = channel.id,
|
|
||||||
start = start.plusHours(it),
|
|
||||||
end = start.plusHours(it + 1),
|
|
||||||
startHours = it.toFloat(),
|
|
||||||
endHours = (it + 1).toFloat(),
|
|
||||||
duration = 60.seconds,
|
|
||||||
name = "No data",
|
|
||||||
subtitle = null,
|
|
||||||
seasonEpisode = null,
|
|
||||||
isRecording = false,
|
|
||||||
isSeriesRecording = false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
put(channel.id, fakePrograms)
|
|
||||||
fake.addAll(fakePrograms)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val finalProgramList =
|
|
||||||
(programs + fake).sortedWith(
|
|
||||||
compareBy(
|
|
||||||
{ channelsIdToIndex[it.channelId]!! },
|
|
||||||
{ it.start },
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
Timber.d("Got ${programs.size} programs & ${fake.size} fake programs")
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
this@LiveTvViewModel.channels.value = channels
|
this@LiveTvViewModel.channels.value = channels
|
||||||
this@LiveTvViewModel.programs.value = finalProgramList
|
|
||||||
this@LiveTvViewModel.programsByChannel.value = finalProgramsByChannel
|
|
||||||
loading.value = LoadingState.Success
|
loading.value = LoadingState.Success
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun fetchPrograms(channels: List<TvChannel>) {
|
||||||
|
val maxStartDate = start.plusHours(MAX_HOURS).minusMinutes(1)
|
||||||
|
val minEndDate = start.plusMinutes(1L)
|
||||||
|
val request =
|
||||||
|
GetProgramsDto(
|
||||||
|
maxStartDate = maxStartDate,
|
||||||
|
minEndDate = minEndDate,
|
||||||
|
channelIds = channels.map { it.id },
|
||||||
|
sortBy = listOf(ItemSortBy.START_DATE),
|
||||||
|
)
|
||||||
|
val programs =
|
||||||
|
GetProgramsDtoHandler
|
||||||
|
.execute(api, request)
|
||||||
|
.content.items
|
||||||
|
.map { dto ->
|
||||||
|
TvProgram(
|
||||||
|
id = dto.id,
|
||||||
|
channelId = dto.channelId!!,
|
||||||
|
start = dto.startDate!!,
|
||||||
|
end = dto.endDate!!,
|
||||||
|
startHours = hoursBetween(start, dto.startDate!!),
|
||||||
|
endHours = hoursBetween(start, dto.endDate!!),
|
||||||
|
duration = dto.runTimeTicks!!.ticks,
|
||||||
|
name = dto.seriesName ?: dto.name,
|
||||||
|
subtitle = dto.episodeTitle.takeIf { dto.isSeries ?: false },
|
||||||
|
seasonEpisode =
|
||||||
|
if (dto.indexNumber != null && dto.parentIndexNumber != null) {
|
||||||
|
SeasonEpisode(dto.parentIndexNumber!!, dto.indexNumber!!)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
isRecording = dto.timerId.isNotNullOrBlank(),
|
||||||
|
isSeriesRecording = dto.seriesTimerId.isNotNullOrBlank(),
|
||||||
|
)
|
||||||
|
}.filter { it.startHours >= 0 && it.endHours >= 0 } // TODO shouldn't need to filter client side
|
||||||
|
|
||||||
|
val programsByChannel = programs.groupBy { it.channelId }
|
||||||
|
val emptyChannels = channels.filter { programsByChannel[it.id].orEmpty().isEmpty() }
|
||||||
|
val fake = mutableListOf<TvProgram>()
|
||||||
|
val finalProgramsByChannel =
|
||||||
|
programsByChannel.toMutableMap().apply {
|
||||||
|
emptyChannels.forEach { channel ->
|
||||||
|
val fakePrograms =
|
||||||
|
(0..<MAX_HOURS).map {
|
||||||
|
TvProgram(
|
||||||
|
id = UUID.randomUUID(), // TODO
|
||||||
|
channelId = channel.id,
|
||||||
|
start = start.plusHours(it),
|
||||||
|
end = start.plusHours(it + 1),
|
||||||
|
startHours = it.toFloat(),
|
||||||
|
endHours = (it + 1).toFloat(),
|
||||||
|
duration = 60.seconds,
|
||||||
|
name = "No data",
|
||||||
|
subtitle = null,
|
||||||
|
seasonEpisode = null,
|
||||||
|
isRecording = false,
|
||||||
|
isSeriesRecording = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
put(channel.id, fakePrograms)
|
||||||
|
fake.addAll(fakePrograms)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val finalProgramList =
|
||||||
|
(programs + fake).sortedWith(
|
||||||
|
compareBy(
|
||||||
|
{ channelsIdToIndex[it.channelId]!! },
|
||||||
|
{ it.start },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
Timber.d("Got ${programs.size} programs & ${fake.size} fake programs")
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
this@LiveTvViewModel.programs.value = finalProgramList
|
||||||
|
this@LiveTvViewModel.programsByChannel.value = finalProgramsByChannel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getItem(programId: UUID) {
|
fun getItem(programId: UUID) {
|
||||||
fetchingItem.value = LoadingState.Loading
|
fetchingItem.value = LoadingState.Loading
|
||||||
viewModelScope.launchIO(LoadingExceptionHandler(fetchingItem, "Error")) {
|
viewModelScope.launchIO(LoadingExceptionHandler(fetchingItem, "Error")) {
|
||||||
|
|
@ -172,6 +176,13 @@ class LiveTvViewModel
|
||||||
fetchedItem.value = result
|
fetchedItem.value = result
|
||||||
fetchingItem.value = LoadingState.Success
|
fetchingItem.value = LoadingState.Success
|
||||||
}
|
}
|
||||||
|
if (result.data.seriesTimerId != null) {
|
||||||
|
val items =
|
||||||
|
api.liveTvApi
|
||||||
|
.getPrograms(GetProgramsDto(seriesTimerId = result.data.seriesTimerId))
|
||||||
|
.content.items
|
||||||
|
Timber.v("items=$items")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,10 +196,11 @@ class LiveTvViewModel
|
||||||
viewModelScope.launch(ExceptionHandler(autoToast = true)) {
|
viewModelScope.launch(ExceptionHandler(autoToast = true)) {
|
||||||
if (series) {
|
if (series) {
|
||||||
api.liveTvApi.cancelSeriesTimer(timerId)
|
api.liveTvApi.cancelSeriesTimer(timerId)
|
||||||
|
fetchPrograms(channels.value.orEmpty())
|
||||||
} else {
|
} else {
|
||||||
api.liveTvApi.cancelTimer(timerId)
|
api.liveTvApi.cancelTimer(timerId)
|
||||||
|
refreshProgram(programIndex, programId)
|
||||||
}
|
}
|
||||||
refreshProgram(programIndex, programId)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -202,6 +214,7 @@ class LiveTvViewModel
|
||||||
val d by api.liveTvApi.getDefaultTimer(programId.toServerString())
|
val d by api.liveTvApi.getDefaultTimer(programId.toServerString())
|
||||||
if (series) {
|
if (series) {
|
||||||
api.liveTvApi.createSeriesTimer(d)
|
api.liveTvApi.createSeriesTimer(d)
|
||||||
|
fetchPrograms(channels.value.orEmpty())
|
||||||
} else {
|
} else {
|
||||||
val payload =
|
val payload =
|
||||||
TimerInfoDto(
|
TimerInfoDto(
|
||||||
|
|
@ -227,8 +240,8 @@ class LiveTvViewModel
|
||||||
keepUntil = d.keepUntil,
|
keepUntil = d.keepUntil,
|
||||||
)
|
)
|
||||||
api.liveTvApi.createTimer(payload)
|
api.liveTvApi.createTimer(payload)
|
||||||
|
refreshProgram(programIndex, programId)
|
||||||
}
|
}
|
||||||
refreshProgram(programIndex, programId)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -559,12 +559,13 @@ fun TvGuideGrid(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (program.isSeriesRecording) {
|
if (program.isSeriesRecording) {
|
||||||
|
val color = if (program.isRecording) Color.Red else Color.Gray
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.padding(4.dp)
|
.padding(4.dp)
|
||||||
.size(16.dp)
|
.size(16.dp)
|
||||||
.background(Color.Red.copy(alpha = .5f), shape = CircleShape)
|
.background(color.copy(alpha = .5f), shape = CircleShape)
|
||||||
.align(Alignment.BottomEnd),
|
.align(Alignment.BottomEnd),
|
||||||
)
|
)
|
||||||
Box(
|
Box(
|
||||||
|
|
@ -572,7 +573,7 @@ fun TvGuideGrid(
|
||||||
Modifier
|
Modifier
|
||||||
.padding(start = 4.dp, top = 4.dp, bottom = 4.dp, end = 10.dp)
|
.padding(start = 4.dp, top = 4.dp, bottom = 4.dp, end = 10.dp)
|
||||||
.size(16.dp)
|
.size(16.dp)
|
||||||
.background(Color.Red, shape = CircleShape)
|
.background(color, shape = CircleShape)
|
||||||
.align(Alignment.BottomEnd),
|
.align(Alignment.BottomEnd),
|
||||||
)
|
)
|
||||||
} else if (program.isRecording) {
|
} else if (program.isRecording) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue