mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-17 15:32:01 +00:00
Merge 55a16954db into 70d3eee9d2
This commit is contained in:
commit
cd61c7659b
14 changed files with 87 additions and 30 deletions
|
|
@ -757,8 +757,8 @@
|
|||
<string name="theme_emerald">Esmeralda</string>
|
||||
<string name="theme_ocean">Océano</string>
|
||||
<string name="theme_rose">Rosa</string>
|
||||
<string name="theme_violet">Violeta</string>
|
||||
<string name="theme_white">Blanco</string>
|
||||
<string name="theme_violet">Amatista</string>
|
||||
<string name="theme_white">Glaciar</string>
|
||||
<string name="player_next_episode">Siguiente episodio</string>
|
||||
<string name="player_next_episode_finding_source">Buscando fuente…</string>
|
||||
<string name="player_next_episode_playing_via_countdown">Reproduciendo vía %1$s en %2$d…</string>
|
||||
|
|
|
|||
|
|
@ -790,8 +790,8 @@
|
|||
<string name="theme_emerald">Émeraude</string>
|
||||
<string name="theme_ocean">Océan</string>
|
||||
<string name="theme_rose">Rose</string>
|
||||
<string name="theme_violet">Violet</string>
|
||||
<string name="theme_white">Blanc</string>
|
||||
<string name="theme_violet">Améthyste</string>
|
||||
<string name="theme_white">Glacier</string>
|
||||
<string name="player_next_episode">Épisode suivant</string>
|
||||
<string name="player_next_episode_finding_source">Recherche de la source…</string>
|
||||
<string name="player_next_episode_playing_via_countdown">Lecture via %1$s dans %2$d…</string>
|
||||
|
|
|
|||
|
|
@ -905,8 +905,8 @@
|
|||
<string name="theme_emerald">Emerald</string>
|
||||
<string name="theme_ocean">Ocean</string>
|
||||
<string name="theme_rose">Rose</string>
|
||||
<string name="theme_violet">Violet</string>
|
||||
<string name="theme_white">White</string>
|
||||
<string name="theme_violet">Amethyst</string>
|
||||
<string name="theme_white">Glacier</string>
|
||||
<string name="player_next_episode">Next Episode</string>
|
||||
<string name="player_next_episode_finding_source">Finding source…</string>
|
||||
<string name="player_next_episode_playing_via_countdown">Playing via %1$s in %2$d…</string>
|
||||
|
|
|
|||
|
|
@ -13,20 +13,20 @@ import org.jetbrains.compose.resources.StringResource
|
|||
enum class AppTheme {
|
||||
CRIMSON,
|
||||
OCEAN,
|
||||
VIOLET,
|
||||
AMETHYST,
|
||||
EMERALD,
|
||||
AMBER,
|
||||
ROSE,
|
||||
WHITE,
|
||||
GLACIER,
|
||||
}
|
||||
|
||||
val AppTheme.labelRes: StringResource
|
||||
get() = when (this) {
|
||||
AppTheme.CRIMSON -> Res.string.theme_crimson
|
||||
AppTheme.OCEAN -> Res.string.theme_ocean
|
||||
AppTheme.VIOLET -> Res.string.theme_violet
|
||||
AppTheme.AMETHYST -> Res.string.theme_violet
|
||||
AppTheme.EMERALD -> Res.string.theme_emerald
|
||||
AppTheme.AMBER -> Res.string.theme_amber
|
||||
AppTheme.ROSE -> Res.string.theme_rose
|
||||
AppTheme.WHITE -> Res.string.theme_white
|
||||
AppTheme.GLACIER -> Res.string.theme_white
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import nuvio.composeapp.generated.resources.jetbrains_sans_regular
|
|||
import nuvio.composeapp.generated.resources.jetbrains_sans_semibold
|
||||
import org.jetbrains.compose.resources.Font
|
||||
|
||||
val LocalAppTheme = staticCompositionLocalOf { AppTheme.WHITE }
|
||||
val LocalAppTheme = staticCompositionLocalOf { AppTheme.GLACIER }
|
||||
|
||||
val MaterialTheme.appTheme: AppTheme
|
||||
@Composable
|
||||
|
|
@ -207,7 +207,7 @@ private val NuvioRippleConfiguration = RippleConfiguration(
|
|||
@Composable
|
||||
fun NuvioTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
appTheme: AppTheme = AppTheme.WHITE,
|
||||
appTheme: AppTheme = AppTheme.GLACIER,
|
||||
amoled: Boolean = false,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ object ThemeColors {
|
|||
backgroundCard = Color(0xFF1A1F24),
|
||||
)
|
||||
|
||||
val Violet = ThemeColorPalette(
|
||||
val Amethyst = ThemeColorPalette(
|
||||
secondary = Color(0xFF8E24AA),
|
||||
secondaryVariant = Color(0xFF6A1B9A),
|
||||
focusRing = Color(0xFFAB47BC),
|
||||
|
|
@ -76,7 +76,7 @@ object ThemeColors {
|
|||
backgroundCard = Color(0xFF241A1F),
|
||||
)
|
||||
|
||||
val White = ThemeColorPalette(
|
||||
val Glacier = ThemeColorPalette(
|
||||
secondary = Color(0xFFF5F5F5),
|
||||
secondaryVariant = Color(0xFFE0E0E0),
|
||||
onSecondary = Color(0xFF111111),
|
||||
|
|
@ -91,10 +91,10 @@ object ThemeColors {
|
|||
fun getColorPalette(theme: AppTheme): ThemeColorPalette = when (theme) {
|
||||
AppTheme.CRIMSON -> Crimson
|
||||
AppTheme.OCEAN -> Ocean
|
||||
AppTheme.VIOLET -> Violet
|
||||
AppTheme.AMETHYST -> Amethyst
|
||||
AppTheme.EMERALD -> Emerald
|
||||
AppTheme.AMBER -> Amber
|
||||
AppTheme.ROSE -> Rose
|
||||
AppTheme.WHITE -> White
|
||||
AppTheme.GLACIER -> Glacier
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,17 @@ data class MetaDetails(
|
|||
val videos: List<MetaVideo> = emptyList(),
|
||||
)
|
||||
|
||||
fun MetaDetails.toMetaPreview(): MetaPreview = MetaPreview(
|
||||
id = id,
|
||||
type = type,
|
||||
name = name,
|
||||
poster = poster,
|
||||
banner = background,
|
||||
logo = logo,
|
||||
description = description,
|
||||
releaseInfo = releaseInfo,
|
||||
)
|
||||
|
||||
data class MetaExternalRating(
|
||||
val source: String,
|
||||
val value: Double,
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ import com.nuvio.app.features.trailer.TrailerPlaybackSource
|
|||
import com.nuvio.app.features.watched.WatchedRepository
|
||||
import com.nuvio.app.features.watched.previousReleasedEpisodesBefore
|
||||
import com.nuvio.app.features.watched.releasedEpisodesForSeason
|
||||
import com.nuvio.app.features.watched.watchedItemKey
|
||||
import com.nuvio.app.features.watchprogress.CurrentDateProvider
|
||||
import com.nuvio.app.features.watchprogress.WatchProgressEntry
|
||||
import com.nuvio.app.features.watchprogress.WatchProgressRepository
|
||||
|
|
@ -662,10 +663,12 @@ fun MetaDetailsScreen(
|
|||
isTablet = isTablet,
|
||||
playButtonLabel = playButtonLabel,
|
||||
isSaved = isSaved,
|
||||
isWatched = WatchingState.isPosterWatched(watchedUiState.watchedKeys, meta.type, meta.id),
|
||||
onPrimaryPlayClick = onPrimaryPlayClick,
|
||||
onPrimaryPlayLongClick = onPrimaryPlayLongClick,
|
||||
onSaveClick = toggleSaved,
|
||||
onSaveLongClick = openLibraryListPicker,
|
||||
onWatchedClick = { WatchingActions.toggleMetaWatched(meta) },
|
||||
showManualPlayOption = showManualPlayOption,
|
||||
preferredEpisodeSeasonNumber = seriesAction?.seasonNumber,
|
||||
preferredEpisodeNumber = seriesAction?.episodeNumber,
|
||||
|
|
@ -996,10 +999,12 @@ private fun ConfiguredMetaSections(
|
|||
isTablet: Boolean,
|
||||
playButtonLabel: String,
|
||||
isSaved: Boolean,
|
||||
isWatched: Boolean,
|
||||
onPrimaryPlayClick: () -> Unit,
|
||||
onPrimaryPlayLongClick: (() -> Unit)?,
|
||||
onSaveClick: () -> Unit,
|
||||
onSaveLongClick: (() -> Unit)?,
|
||||
onWatchedClick: () -> Unit,
|
||||
showManualPlayOption: Boolean,
|
||||
preferredEpisodeSeasonNumber: Int?,
|
||||
preferredEpisodeNumber: Int?,
|
||||
|
|
@ -1062,11 +1067,13 @@ private fun ConfiguredMetaSections(
|
|||
stringResource(Res.string.action_save)
|
||||
},
|
||||
isSaved = isSaved,
|
||||
isWatched = isWatched,
|
||||
isTablet = isTablet,
|
||||
onPlayClick = onPrimaryPlayClick,
|
||||
onPlayLongClick = if (showManualPlayOption) onPrimaryPlayLongClick else null,
|
||||
onSaveClick = onSaveClick,
|
||||
onSaveLongClick = onSaveLongClick,
|
||||
onWatchedClick = onWatchedClick,
|
||||
)
|
||||
}
|
||||
MetaScreenSectionKey.OVERVIEW -> {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import androidx.compose.foundation.layout.width
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.Visibility
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
|
|
@ -37,11 +39,13 @@ fun DetailActionButtons(
|
|||
playLabel: String = stringResource(Res.string.action_play),
|
||||
saveLabel: String = stringResource(Res.string.action_save),
|
||||
isSaved: Boolean = false,
|
||||
isWatched: Boolean = false,
|
||||
isTablet: Boolean = false,
|
||||
onPlayClick: () -> Unit = {},
|
||||
onPlayLongClick: (() -> Unit)? = null,
|
||||
onSaveClick: () -> Unit = {},
|
||||
onSaveLongClick: (() -> Unit)? = null,
|
||||
onWatchedClick: () -> Unit = {},
|
||||
) {
|
||||
val playPainter = appIconPainter(AppIconResource.PlayerPlay)
|
||||
val libraryAddPainter = appIconPainter(AppIconResource.LibraryAddPlus)
|
||||
|
|
@ -138,5 +142,21 @@ fun DetailActionButtons(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.size(50.dp),
|
||||
shape = RoundedCornerShape(40.dp),
|
||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outline),
|
||||
color = if (isWatched) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface.copy(alpha = 0f),
|
||||
contentColor = if (isWatched) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconButton(onClick = onWatchedClick) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Visibility,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(20.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,21 +40,23 @@ import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
|||
private fun rememberHomeSkeletonBrush(): Brush {
|
||||
val shimmerColors = listOf(
|
||||
MaterialTheme.colorScheme.surface,
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = 0.5f),
|
||||
MaterialTheme.colorScheme.surface,
|
||||
MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f),
|
||||
MaterialTheme.colorScheme.surface,
|
||||
MaterialTheme.colorScheme.surface,
|
||||
)
|
||||
val transition = rememberInfiniteTransition()
|
||||
val translateAnim by transition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 1000f,
|
||||
targetValue = 1300f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(durationMillis = 1200, easing = LinearEasing),
|
||||
animation = tween(durationMillis = 1500, easing = LinearEasing),
|
||||
repeatMode = RepeatMode.Restart,
|
||||
),
|
||||
)
|
||||
val brush = Brush.linearGradient(
|
||||
colors = shimmerColors,
|
||||
start = Offset(translateAnim - 200f, 0f),
|
||||
start = Offset(translateAnim - 600f, 0f),
|
||||
end = Offset(translateAnim, 0f),
|
||||
)
|
||||
return brush
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ internal fun LazyListScope.appearanceSettingsContent(
|
|||
isTablet = isTablet,
|
||||
) {
|
||||
SettingsGroup(isTablet = isTablet) {
|
||||
val themes = listOf(AppTheme.WHITE) + AppTheme.entries.filterNot { it == AppTheme.WHITE }
|
||||
val themes = listOf(AppTheme.GLACIER) + AppTheme.entries.filterNot { it == AppTheme.GLACIER }
|
||||
FlowRow(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
object ThemeSettingsRepository {
|
||||
private val _selectedTheme = MutableStateFlow(AppTheme.WHITE)
|
||||
private val _selectedTheme = MutableStateFlow(AppTheme.GLACIER)
|
||||
val selectedTheme: StateFlow<AppTheme> = _selectedTheme.asStateFlow()
|
||||
|
||||
private val _amoledEnabled = MutableStateFlow(false)
|
||||
|
|
@ -32,10 +32,10 @@ object ThemeSettingsRepository {
|
|||
|
||||
fun clearLocalState() {
|
||||
hasLoaded = false
|
||||
_selectedTheme.value = AppTheme.WHITE
|
||||
_selectedTheme.value = AppTheme.GLACIER
|
||||
_amoledEnabled.value = false
|
||||
_liquidGlassNativeTabBarEnabled.value = false
|
||||
NativeTabBridge.publishAccentColor(AppTheme.WHITE.nativeTabAccentHex())
|
||||
NativeTabBridge.publishAccentColor(AppTheme.GLACIER.nativeTabAccentHex())
|
||||
NativeTabBridge.publishLiquidGlassEnabled(false)
|
||||
_selectedAppLanguage.value = AppLanguage.ENGLISH
|
||||
}
|
||||
|
|
@ -45,12 +45,16 @@ object ThemeSettingsRepository {
|
|||
val stored = ThemeSettingsStorage.loadSelectedTheme()
|
||||
val theme = if (stored != null) {
|
||||
try {
|
||||
AppTheme.valueOf(stored)
|
||||
when (stored) {
|
||||
"VIOLET" -> AppTheme.AMETHYST
|
||||
"WHITE" -> AppTheme.GLACIER
|
||||
else -> AppTheme.valueOf(stored)
|
||||
}
|
||||
} catch (_: IllegalArgumentException) {
|
||||
AppTheme.WHITE
|
||||
AppTheme.GLACIER
|
||||
}
|
||||
} else {
|
||||
AppTheme.WHITE
|
||||
AppTheme.GLACIER
|
||||
}
|
||||
_selectedTheme.value = theme
|
||||
NativeTabBridge.publishAccentColor(theme.nativeTabAccentHex())
|
||||
|
|
@ -98,9 +102,9 @@ object ThemeSettingsRepository {
|
|||
private fun AppTheme.nativeTabAccentHex(): String = when (this) {
|
||||
AppTheme.CRIMSON -> "#E53935"
|
||||
AppTheme.OCEAN -> "#1E88E5"
|
||||
AppTheme.VIOLET -> "#8E24AA"
|
||||
AppTheme.AMETHYST -> "#8E24AA"
|
||||
AppTheme.EMERALD -> "#43A047"
|
||||
AppTheme.AMBER -> "#FB8C00"
|
||||
AppTheme.ROSE -> "#D81B60"
|
||||
AppTheme.WHITE -> "#F5F5F5"
|
||||
AppTheme.GLACIER -> "#F5F5F5"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.nuvio.app.features.watching.application
|
|||
import com.nuvio.app.features.details.MetaDetails
|
||||
import com.nuvio.app.features.details.MetaDetailsRepository
|
||||
import com.nuvio.app.features.details.MetaVideo
|
||||
import com.nuvio.app.features.details.toMetaPreview
|
||||
import com.nuvio.app.features.home.MetaPreview
|
||||
import com.nuvio.app.features.watched.WatchedItem
|
||||
import com.nuvio.app.features.watched.WatchedRepository
|
||||
|
|
@ -22,6 +23,12 @@ import kotlinx.coroutines.launch
|
|||
object WatchingActions {
|
||||
private val actionScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||
|
||||
fun toggleMetaWatched(meta: MetaDetails) {
|
||||
actionScope.launch {
|
||||
togglePosterWatched(meta.toMetaPreview())
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun togglePosterWatched(preview: MetaPreview) {
|
||||
if (preview.type != "series") {
|
||||
WatchedRepository.toggleWatched(preview.toWatchedItem(markedAtEpochMs = 0L))
|
||||
|
|
|
|||
|
|
@ -18,7 +18,13 @@ object WatchingState {
|
|||
fun isPosterWatched(
|
||||
watchedKeys: Set<String>,
|
||||
item: MetaPreview,
|
||||
): Boolean = watchedKeys.contains(watchedItemKey(item.type, item.id))
|
||||
): Boolean = isPosterWatched(watchedKeys, item.type, item.id)
|
||||
|
||||
fun isPosterWatched(
|
||||
watchedKeys: Set<String>,
|
||||
type: String,
|
||||
id: String,
|
||||
): Boolean = watchedKeys.contains(watchedItemKey(type, id))
|
||||
|
||||
fun isEpisodeWatched(
|
||||
watchedKeys: Set<String>,
|
||||
|
|
|
|||
Loading…
Reference in a new issue