Skip to content

Commit

Permalink
fix(episode): watch status
Browse files Browse the repository at this point in the history
toggle watch status on episode by double clicking and indicate the next episode or season

fixes #68
  • Loading branch information
DatL4g committed Dec 29, 2023
1 parent 2b1944f commit ca21d1a
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ interface SeriesComponent : Component {
val dbEpisodes: StateFlow<List<Episode>>
val nextEpisodeToWatch: Flow<Series.Episode?>

val nextSeasonToWatch: Flow<Series.Season?>

fun retryLoadingSeries(): Any?

fun goBack()
Expand All @@ -37,4 +39,6 @@ interface SeriesComponent : Component {
fun toggleFavorite(): Any?
fun itemClicked(episode: Series.Episode): Any?
fun itemLongClicked(episode: Series.Episode)
fun watchToggle(series: Series, episode: Series.Episode, watched: Boolean): Any?
fun switchToSeason(season: Series.Season): Any?
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.FavoriteBorder
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
Expand Down Expand Up @@ -53,6 +50,7 @@ fun SeriesScreen(component: SeriesComponent) {
val dialogState by component.dialog.subscribeAsState()
val childState by component.child.subscribeAsState()
val nextEpisode by component.nextEpisodeToWatch.collectAsStateWithLifecycle(initialValue = null)
val nextSeason by component.nextSeasonToWatch.collectAsStateWithLifecycle(initialValue = null)

LaunchedEffect(href) {
SchemeTheme.setCommon(href)
Expand All @@ -79,11 +77,35 @@ fun SeriesScreen(component: SeriesComponent) {
) {
Icon(
imageVector = Icons.Default.PlayArrow,
contentDescription = next.episodeTitle
contentDescription = next.episodeTitle,
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
Text(text = next.episodeTitle)
}
}
nextSeason?.let { next ->
ExtendedFloatingActionButton(
onClick = {
component.switchToSeason(next)
},
modifier = Modifier.align(Alignment.BottomEnd).padding(16.dp)
) {
val seasonText = if (next.title.toIntOrNull() != null) {
stringResource(SharedRes.strings.season_placeholder, next.title)
} else {
next.title
}

Icon(
imageVector = Icons.Default.Redo,
contentDescription = next.title,
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
Text(text = seasonText)
}
}
}

DisposableEffect(Unit) {
Expand Down Expand Up @@ -284,6 +306,9 @@ private fun CompactScreen(component: SeriesComponent) {
},
onEpisodeLongClick = {
component.itemLongClicked(it)
},
onWatchToggle = { episode, watched ->
component.watchToggle(current.series, episode, watched)
}
)
}
Expand Down Expand Up @@ -423,6 +448,9 @@ private fun DefaultScreen(component: SeriesComponent) {
},
onEpisodeLongClick = {
component.itemLongClicked(it)
},
onWatchToggle = { episode, watched ->
component.watchToggle(current.series, episode, watched)
}
)
}
Expand All @@ -444,7 +472,8 @@ private fun LazyListScope.SeriesContent(
dbEpisodes: List<Episode>,
loadingEpisode: String?,
onEpisodeClick: (Series.Episode) -> Unit,
onEpisodeLongClick: (Series.Episode) -> Unit
onEpisodeLongClick: (Series.Episode) -> Unit,
onWatchToggle: (episode: Series.Episode, Boolean) -> Unit
) {
items(content.episodes, key = { it.href }) { episode ->
val dbEpisode = remember(dbEpisodes, episode.href) {
Expand All @@ -460,6 +489,9 @@ private fun LazyListScope.SeriesContent(
},
onLongClick = {
onEpisodeLongClick(episode)
},
onWatchToggle = { watched ->
onWatchToggle(episode, watched)
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import dev.datlag.burningseries.model.BSUtil
import dev.datlag.burningseries.model.Series
import dev.datlag.burningseries.model.common.collectSafe
import dev.datlag.burningseries.model.common.safeCast
import dev.datlag.burningseries.model.common.suspendCatching
import dev.datlag.burningseries.model.state.EpisodeAction
import dev.datlag.burningseries.model.state.EpisodeState
import dev.datlag.burningseries.model.state.SeriesAction
Expand Down Expand Up @@ -149,7 +150,8 @@ class SeriesScreenComponent(
seriesEpisodes.firstOrNull {
it.number.equals(wantedNumber, true)
} ?: seriesEpisodes.firstOrNull {
it.number.toIntOrNull() == (wantedNumber.toIntOrNull() ?: return@firstOrNull false)
val compareNumber = wantedNumber.toIntOrNull() ?: return@firstOrNull false
it.number.toIntOrNull() == compareNumber
}
} else {
null
Expand All @@ -158,6 +160,20 @@ class SeriesScreenComponent(
}
}.flowOn(ioDispatcher())

override val nextSeasonToWatch = combine(
currentSeries.map { it?.seasons },
currentSeries.map { it?.currentSeason },
nextEpisodeToWatch
) { seasons, current, episode ->
if (episode != null) {
null
} else {
seasons?.firstOrNull {
it.value == current?.value?.plus(1)
}
}
}.flowOn(ioDispatcher())

private val navigation = SlotNavigation<SeriesConfig>()
override val child: Value<ChildSlot<*, Component>> = childSlot(
source = navigation,
Expand Down Expand Up @@ -345,6 +361,33 @@ class SeriesScreenComponent(
}
}

override fun watchToggle(series: Series, episode: Series.Episode, watched: Boolean): Any? = ioScope().launchIO {
val maxLength = suspendCatching {
database.burningSeriesQueries.selectEpisodeByHref(episode.href).executeAsOneOrNull()?.length
}.getOrNull() ?: 0L

val progress = if (watched) {
0L
} else {
if (maxLength == 0L) {
Long.MIN_VALUE
} else {
maxLength
}
}

database.burningSeriesQueries.updateEpisodeProgress(
progress = progress,
href = episode.href,
number = episode.number,
title = episode.title,
length = maxLength,
seriesHref = BSUtil.commonSeriesHref(series.href)
)
}

override fun switchToSeason(season: Series.Season): Any? = loadNewSeason(season)

private fun loadNewSeason(season: Series.Season) = ioScope().launchIO {
(currentSeries.value ?: currentSeries.firstOrNull())?.let { series ->
seriesStateMachine.dispatch(SeriesAction.Load(series.hrefBuilder(season.value)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
Expand All @@ -34,22 +37,29 @@ fun EpisodeItem(
dbEpisode: Episode?,
isLoading: Boolean,
onClick: () -> Unit,
onLongClick: () -> Unit
onLongClick: () -> Unit,
onWatchToggle: (Boolean) -> Unit
) {
val blurHash = remember(content.href) { BlurHash.random() }
val enabled = content.hosters.isNotEmpty()

val length = remember(dbEpisode) {
val length = remember(dbEpisode?.length) {
max(dbEpisode?.length ?: 0L, 0L)
}
val progress = remember(dbEpisode) {
max(dbEpisode?.progress ?: 0L, 0L)
val progress = remember(dbEpisode?.progress) {
val value = dbEpisode?.progress ?: 0L

if (value == Long.MIN_VALUE) {
Long.MIN_VALUE
} else {
max(value, 0L)
}
}
val isFinished = remember(length, progress) {
if (length > 0L && progress > 0L) {
(progress.toDouble() / length.toDouble() * 100.0).toFloat() >= 85F
} else {
false
progress == Long.MIN_VALUE
}
}

Expand All @@ -62,6 +72,9 @@ fun EpisodeItem(
.clip(MaterialTheme.shapes.medium)
.onClick(
enabled = enabled,
onDoubleClick = {
onWatchToggle(isFinished)
},
onLongClick = onLongClick,
onClick = onClick
).ifTrue(enabled) { bounceClick(0.95F) }.ifFalse(enabled) { alpha(0.5F) },
Expand Down Expand Up @@ -127,9 +140,9 @@ fun EpisodeItem(
maxLines = 3
)
}
if (length != 0L && progress != 0L) {
if (length != 0L && max(progress, 0L) != 0L) {
Text(
text = stringResource(SharedRes.strings.episode_progress, progress.toDuration(), length.toDuration()),
text = stringResource(SharedRes.strings.episode_progress, max(progress, 0L).toDuration(), length.toDuration()),
style = MaterialTheme.typography.labelSmall
)
}
Expand Down

0 comments on commit ca21d1a

Please sign in to comment.