mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-24 03:36:51 +00:00
Compare commits
5 Commits
c2cc4e9e65
...
8d194f2baf
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d194f2baf | |||
| c836c809fc | |||
| b6fc10df57 | |||
| 18e68c6051 | |||
| e8224849cc |
@@ -73,12 +73,12 @@ import hu.bbara.purefin.ui.screen.player.components.TvPlayerLoadingErrorEndCard
|
||||
import hu.bbara.purefin.ui.screen.player.components.TvPlayerTimeRow
|
||||
import hu.bbara.purefin.ui.screen.player.components.TvTrackPanelType
|
||||
import hu.bbara.purefin.ui.screen.player.components.TvTrackSelectionPanel
|
||||
import java.time.LocalTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Locale
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.LocalTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Locale
|
||||
|
||||
private const val TV_CONTROLS_AUTO_HIDE_MS = 5_000L
|
||||
private const val CONTROLS_VISIBLE_SUBTITLE_BOTTOM_PADDING_FRACTION = 0.22f
|
||||
@@ -379,7 +379,7 @@ fun TvPlayerScreen(
|
||||
}
|
||||
}
|
||||
|
||||
if (!showSkipIntroButton) {
|
||||
if (!showSkipIntroButton && !controlsVisible) {
|
||||
ValueChangeTimedVisibility(
|
||||
value = hiddenSeekCounter,
|
||||
hideAfterMillis = 2500L,
|
||||
|
||||
@@ -3,9 +3,11 @@ package hu.bbara.purefin.ui.screen.series
|
||||
import android.content.Intent
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Download
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -144,6 +146,7 @@ private fun SeriesScreenInternal(
|
||||
val context = LocalContext.current
|
||||
val navigationManager = LocalNavigationManager.current
|
||||
var showDownloadDialog by remember { mutableStateOf(false) }
|
||||
var showMarkAsWatchedDialog by remember { mutableStateOf(false) }
|
||||
|
||||
fun getDefaultSeason(): Season? {
|
||||
return series.seasons.firstOrNull { it.unwatchedEpisodeCount > 0 } ?: series.seasons.firstOrNull()
|
||||
@@ -188,7 +191,13 @@ private fun SeriesScreenInternal(
|
||||
nextUpEpisode = nextUpEpisode,
|
||||
onPlayClick = playAction ?: {},
|
||||
onDownloadClick = { showDownloadDialog = true },
|
||||
onMarkAsWatched = onMarkAsWatched,
|
||||
onMarkAsWatched = { watched ->
|
||||
if (watched) {
|
||||
showMarkAsWatchedDialog = true
|
||||
} else {
|
||||
onMarkAsWatched(false)
|
||||
}
|
||||
},
|
||||
bodyColor = scheme.onSurface
|
||||
),
|
||||
modifier = modifier,
|
||||
@@ -233,6 +242,16 @@ private fun SeriesScreenInternal(
|
||||
onDismiss = { showDownloadDialog = false }
|
||||
)
|
||||
}
|
||||
|
||||
if (showMarkAsWatchedDialog) {
|
||||
MarkSeriesAsWatchedConfirmationDialog(
|
||||
onConfirm = {
|
||||
showMarkAsWatchedDialog = false
|
||||
onMarkAsWatched(true)
|
||||
},
|
||||
onDismiss = { showMarkAsWatchedDialog = false }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Series.toMediaDetailScaffoldUiModel(
|
||||
@@ -312,3 +331,25 @@ private fun SeriesDownloadOption.requiresNotificationPermission(): Boolean = whe
|
||||
SeriesDownloadOption.SMART -> true
|
||||
SeriesDownloadOption.DELETE_SMART -> false
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MarkSeriesAsWatchedConfirmationDialog(
|
||||
onConfirm: () -> Unit,
|
||||
onDismiss: () -> Unit
|
||||
) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text("Mark series as watched?") },
|
||||
text = { Text("This will mark every episode of this series as watched.") },
|
||||
confirmButton = {
|
||||
TextButton(onClick = onConfirm) {
|
||||
Text("Mark as watched")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text("Cancel")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package hu.bbara.purefin.ui.screen.series.components
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -60,6 +62,7 @@ import hu.bbara.purefin.ui.common.badge.WatchStateBadge
|
||||
import hu.bbara.purefin.ui.common.bar.MediaProgressBar
|
||||
import hu.bbara.purefin.ui.common.button.GhostIconButton
|
||||
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
|
||||
import hu.bbara.purefin.ui.model.MediaAction
|
||||
import hu.bbara.purefin.ui.screen.home.components.DefaultTopBar
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -315,6 +318,7 @@ internal fun EpisodeCarousel(episodes: List<Episode>, modifier: Modifier = Modif
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun EpisodeCard(
|
||||
viewModel: SeriesViewModel = hiltViewModel(),
|
||||
@@ -322,15 +326,31 @@ private fun EpisodeCard(
|
||||
) {
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
val mutedStrong = scheme.onSurfaceVariant.copy(alpha = 0.7f)
|
||||
var showBottomSheet by remember { mutableStateOf(false) }
|
||||
val popupActions = remember(episode.id) {
|
||||
listOf(
|
||||
MediaAction(name = "Mark as watched") {
|
||||
viewModel.markEpisodeAsWatched(episode.id, true)
|
||||
},
|
||||
MediaAction(name = "Mark as unwatched") {
|
||||
viewModel.markEpisodeAsWatched(episode.id, false)
|
||||
}
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag("$SeriesEpisodeCardTagPrefix${episode.id}")
|
||||
.clickable { viewModel.onSelectEpisode(
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
viewModel.onSelectEpisode(
|
||||
seriesId = episode.seriesId,
|
||||
seasonId = episode.seasonId,
|
||||
episodeId = episode.id
|
||||
) },
|
||||
)
|
||||
},
|
||||
onLongClick = { showBottomSheet = true }
|
||||
),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
@@ -389,6 +409,30 @@ private fun EpisodeCard(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (showBottomSheet) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { showBottomSheet = false },
|
||||
modifier = Modifier.testTag(SeriesEpisodeActionsDialogTag),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 24.dp)
|
||||
) {
|
||||
popupActions.forEach { action ->
|
||||
ListItem(
|
||||
headlineContent = { Text(text = action.name) },
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
modifier = Modifier.clickable {
|
||||
action.onClick()
|
||||
showBottomSheet = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal const val SeriesPlayButtonTag = "series-play-button"
|
||||
@@ -402,6 +446,7 @@ internal const val SeriesSmartDownloadButtonTag = "series-smart-download-button"
|
||||
internal const val SeriesSeasonSelectorTag = "series-season-selector"
|
||||
internal const val SeriesEpisodeCarouselTag = "series-episode-carousel"
|
||||
internal const val SeriesEpisodeCardTagPrefix = "series-episode-card-"
|
||||
internal const val SeriesEpisodeActionsDialogTag = "series-episode-actions-dialog"
|
||||
|
||||
@Composable
|
||||
internal fun CastRow(cast: List<CastMember>, modifier: Modifier = Modifier) {
|
||||
|
||||
@@ -186,6 +186,12 @@ class SeriesViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun markEpisodeAsWatched(episodeId: UUID, watched: Boolean) {
|
||||
viewModelScope.launch {
|
||||
mediaMetadataUpdater.markAsWatched(episodeId, watched)
|
||||
}
|
||||
}
|
||||
|
||||
fun selectSeries(series: SeriesDto) {
|
||||
_series.value = series
|
||||
viewModelScope.launch {
|
||||
|
||||
@@ -28,6 +28,6 @@ android.dependency.useConstraints=true
|
||||
android.r8.strictFullModeForKeepRules=false
|
||||
android.builtInKotlin=false
|
||||
android.newDsl=false
|
||||
purefinReleaseVersionCode=1000032
|
||||
purefinReleaseVersionCode=1000033
|
||||
purefinDebugVersionCode=1000003
|
||||
purefinTvVersionCode=2000016
|
||||
purefinTvVersionCode=2000017
|
||||
|
||||
Reference in New Issue
Block a user