mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Customize which ratings to display (#1407)
## Description Adds a setting, Settings->Advanced->"Customize which ratings to display", which allows for toggling parental, community, or critic ratings to be displayed in the quick details. This doesn't apply to discover yet. ### Related issues Related to #1020 ### Testing Emulator ## Screenshots ### Just community rating <img width="1280" height="720" alt="ratings Large" src="https://github.com/user-attachments/assets/d6f9ad8a-6cc5-4680-9d2f-66d16a44b41e" /> ## AI or LLM usage None
This commit is contained in:
parent
45d466d76f
commit
366483599c
15 changed files with 333 additions and 206 deletions
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -36,6 +37,8 @@ import com.github.damontecres.wholphin.ui.components.AppScreensaver
|
||||||
import com.github.damontecres.wholphin.ui.nav.ApplicationContent
|
import com.github.damontecres.wholphin.ui.nav.ApplicationContent
|
||||||
import com.github.damontecres.wholphin.ui.setup.SwitchServerContent
|
import com.github.damontecres.wholphin.ui.setup.SwitchServerContent
|
||||||
import com.github.damontecres.wholphin.ui.setup.SwitchUserContent
|
import com.github.damontecres.wholphin.ui.setup.SwitchUserContent
|
||||||
|
import com.github.damontecres.wholphin.ui.util.InterfaceCustomization
|
||||||
|
import com.github.damontecres.wholphin.ui.util.LocalInterfaceCustomization
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainContent(
|
fun MainContent(
|
||||||
|
|
@ -55,64 +58,22 @@ fun MainContent(
|
||||||
) {
|
) {
|
||||||
// val backStack = rememberNavBackStack(SetupDestination.Loading)
|
// val backStack = rememberNavBackStack(SetupDestination.Loading)
|
||||||
// setupNavigationManager.backStack = backStack
|
// setupNavigationManager.backStack = backStack
|
||||||
NavDisplay(
|
val interfaceCustomization =
|
||||||
backStack = backStack,
|
remember(appPreferences) { InterfaceCustomization(appPreferences) }
|
||||||
onBack = { backStack.removeLastOrNull() },
|
CompositionLocalProvider(LocalInterfaceCustomization provides interfaceCustomization) {
|
||||||
entryDecorators =
|
NavDisplay(
|
||||||
listOf(
|
backStack = backStack,
|
||||||
rememberSaveableStateHolderNavEntryDecorator(),
|
onBack = { backStack.removeLastOrNull() },
|
||||||
rememberViewModelStoreNavEntryDecorator(),
|
entryDecorators =
|
||||||
),
|
listOf(
|
||||||
entryProvider = { key ->
|
rememberSaveableStateHolderNavEntryDecorator(),
|
||||||
key as SetupDestination
|
rememberViewModelStoreNavEntryDecorator(),
|
||||||
NavEntry(key) {
|
),
|
||||||
when (key) {
|
entryProvider = { key ->
|
||||||
SetupDestination.Loading -> {
|
key as SetupDestination
|
||||||
Box(
|
NavEntry(key) {
|
||||||
modifier = Modifier.size(200.dp),
|
when (key) {
|
||||||
contentAlignment = Alignment.Center,
|
SetupDestination.Loading -> {
|
||||||
) {
|
|
||||||
CircularProgressIndicator(
|
|
||||||
color = MaterialTheme.colorScheme.border,
|
|
||||||
modifier = Modifier.align(Alignment.Center),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SetupDestination.ServerList -> {
|
|
||||||
SwitchServerContent(Modifier.fillMaxSize())
|
|
||||||
}
|
|
||||||
|
|
||||||
is SetupDestination.UserList -> {
|
|
||||||
SwitchUserContent(
|
|
||||||
server = key.server,
|
|
||||||
Modifier.fillMaxSize(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
is SetupDestination.AppContent -> {
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
backdropService.clearBackdrop()
|
|
||||||
}
|
|
||||||
val current = key.current
|
|
||||||
var showContent by remember {
|
|
||||||
mutableStateOf(true)
|
|
||||||
}
|
|
||||||
LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
|
|
||||||
if (!appPreferences.signInAutomatically) {
|
|
||||||
showContent = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showContent) {
|
|
||||||
ApplicationContent(
|
|
||||||
user = current.user,
|
|
||||||
server = current.server,
|
|
||||||
navigationManager = navigationManager,
|
|
||||||
preferences = preferences,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.size(200.dp),
|
modifier = Modifier.size(200.dp),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
|
|
@ -123,18 +84,64 @@ fun MainContent(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetupDestination.ServerList -> {
|
||||||
|
SwitchServerContent(Modifier.fillMaxSize())
|
||||||
|
}
|
||||||
|
|
||||||
|
is SetupDestination.UserList -> {
|
||||||
|
SwitchUserContent(
|
||||||
|
server = key.server,
|
||||||
|
Modifier.fillMaxSize(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
is SetupDestination.AppContent -> {
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
backdropService.clearBackdrop()
|
||||||
|
}
|
||||||
|
val current = key.current
|
||||||
|
var showContent by remember {
|
||||||
|
mutableStateOf(true)
|
||||||
|
}
|
||||||
|
LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
|
||||||
|
if (!appPreferences.signInAutomatically) {
|
||||||
|
showContent = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showContent) {
|
||||||
|
ApplicationContent(
|
||||||
|
user = current.user,
|
||||||
|
server = current.server,
|
||||||
|
navigationManager = navigationManager,
|
||||||
|
preferences = preferences,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.size(200.dp),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
color = MaterialTheme.colorScheme.border,
|
||||||
|
modifier = Modifier.align(Alignment.Center),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
val screenSaverState by screensaverService.state.collectAsState()
|
||||||
|
if (screenSaverState.enabled || screenSaverState.enabledTemp) {
|
||||||
|
AnimatedVisibility(
|
||||||
|
screenSaverState.show,
|
||||||
|
Modifier.fillMaxSize(),
|
||||||
|
) {
|
||||||
|
AppScreensaver(appPreferences, Modifier.fillMaxSize())
|
||||||
}
|
}
|
||||||
},
|
|
||||||
)
|
|
||||||
val screenSaverState by screensaverService.state.collectAsState()
|
|
||||||
if (screenSaverState.enabled || screenSaverState.enabledTemp) {
|
|
||||||
AnimatedVisibility(
|
|
||||||
screenSaverState.show,
|
|
||||||
Modifier.fillMaxSize(),
|
|
||||||
) {
|
|
||||||
AppScreensaver(appPreferences, Modifier.fillMaxSize())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,61 +117,71 @@ data class BaseItem(
|
||||||
null
|
null
|
||||||
},
|
},
|
||||||
quickDetails =
|
quickDetails =
|
||||||
buildAnnotatedString {
|
QuickDetailsData(
|
||||||
val details =
|
basic =
|
||||||
buildList {
|
buildAnnotatedString {
|
||||||
if (type == BaseItemKind.EPISODE) {
|
val details =
|
||||||
data.seasonEpisode?.let(::add)
|
buildList {
|
||||||
data.premiereDate?.let { add(getDateFormatter().format(it)) }
|
if (type == BaseItemKind.EPISODE) {
|
||||||
} else if (type == BaseItemKind.SERIES) {
|
data.seasonEpisode?.let(::add)
|
||||||
data.seriesProductionYears?.let(::add)
|
data.premiereDate?.let { add(getDateFormatter().format(it)) }
|
||||||
} else if (type == BaseItemKind.PHOTO) {
|
} else if (type == BaseItemKind.SERIES) {
|
||||||
if (data.productionYear != null) {
|
data.seriesProductionYears?.let(::add)
|
||||||
add(data.productionYear!!.toString())
|
} else if (type == BaseItemKind.PHOTO) {
|
||||||
} else if (data.premiereDate != null) {
|
if (data.productionYear != null) {
|
||||||
add(data.premiereDate!!.toLocalDate().toString())
|
add(data.productionYear!!.toString())
|
||||||
|
} else if (data.premiereDate != null) {
|
||||||
|
add(data.premiereDate!!.toLocalDate().toString())
|
||||||
|
}
|
||||||
|
} else if (type == BaseItemKind.BOX_SET) {
|
||||||
|
data.productionYear?.let { add(it.toString()) }
|
||||||
|
data.childCount?.let { add("$it items") }
|
||||||
|
} else {
|
||||||
|
data.productionYear?.let { add(it.toString()) }
|
||||||
|
}
|
||||||
|
data.runTimeTicks
|
||||||
|
?.ticks
|
||||||
|
?.roundMinutes
|
||||||
|
?.let { add(it.toString()) }
|
||||||
|
data.timeRemaining
|
||||||
|
?.roundMinutes
|
||||||
|
?.let { add("$it left") }
|
||||||
|
}
|
||||||
|
details.forEachIndexed { index, string ->
|
||||||
|
append(string)
|
||||||
|
if (index != details.lastIndex) {
|
||||||
|
dot()
|
||||||
}
|
}
|
||||||
} else if (type == BaseItemKind.BOX_SET) {
|
|
||||||
data.productionYear?.let { add(it.toString()) }
|
|
||||||
data.childCount?.let { add("$it items") }
|
|
||||||
} else {
|
|
||||||
data.productionYear?.let { add(it.toString()) }
|
|
||||||
}
|
}
|
||||||
data.runTimeTicks
|
},
|
||||||
?.ticks
|
officialRating =
|
||||||
?.roundMinutes
|
data.officialRating?.let {
|
||||||
?.let { add(it.toString()) }
|
buildAnnotatedString {
|
||||||
data.timeRemaining
|
dot()
|
||||||
?.roundMinutes
|
append(it)
|
||||||
?.let { add("$it left") }
|
}
|
||||||
}
|
},
|
||||||
details.forEachIndexed { index, string ->
|
communityRating =
|
||||||
append(string)
|
data.communityRating?.let {
|
||||||
if (index != details.lastIndex) {
|
buildAnnotatedString {
|
||||||
dot()
|
dot()
|
||||||
}
|
append(String.format(Locale.getDefault(), "%.1f", it))
|
||||||
}
|
appendInlineContent(id = "star")
|
||||||
// TODO time remaining
|
}
|
||||||
|
},
|
||||||
data.officialRating?.let {
|
criticRating =
|
||||||
dot()
|
data.criticRating?.let {
|
||||||
append(it)
|
buildAnnotatedString {
|
||||||
}
|
dot()
|
||||||
data.communityRating?.let {
|
append("${it.toInt()}%")
|
||||||
dot()
|
if (it >= 60f) {
|
||||||
append(String.format(Locale.getDefault(), "%.1f", it))
|
appendInlineContent(id = "fresh")
|
||||||
appendInlineContent(id = "star")
|
} else {
|
||||||
}
|
appendInlineContent(id = "rotten")
|
||||||
data.criticRating?.let {
|
}
|
||||||
dot()
|
}
|
||||||
append("${it.toInt()}%")
|
},
|
||||||
if (it >= 60f) {
|
),
|
||||||
appendInlineContent(id = "fresh")
|
|
||||||
} else {
|
|
||||||
appendInlineContent(id = "rotten")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun dateAsIndex(): Int? =
|
private fun dateAsIndex(): Int? =
|
||||||
|
|
@ -254,7 +264,14 @@ val BaseItemDto.aspectRatioFloat: Float? get() = width?.let { w -> height?.let {
|
||||||
data class BaseItemUi(
|
data class BaseItemUi(
|
||||||
val episodeCornerText: String?,
|
val episodeCornerText: String?,
|
||||||
val episodeUnplayedCornerText: String?,
|
val episodeUnplayedCornerText: String?,
|
||||||
val quickDetails: AnnotatedString,
|
val quickDetails: QuickDetailsData,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class QuickDetailsData(
|
||||||
|
val basic: AnnotatedString,
|
||||||
|
val officialRating: AnnotatedString? = null,
|
||||||
|
val criticRating: AnnotatedString? = null,
|
||||||
|
val communityRating: AnnotatedString? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -516,6 +516,25 @@ sealed interface AppPreference<Pref, T> {
|
||||||
summaryOff = R.string.disabled,
|
summaryOff = R.string.disabled,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val DisplayTogglesPref =
|
||||||
|
AppMultiChoicePreference<AppPreferences, DisplayToggle>(
|
||||||
|
title = R.string.display_toggles_title,
|
||||||
|
summary = R.string.display_toggles_summary,
|
||||||
|
defaultValue = DisplayToggle.entries.filterNot { it == DisplayToggle.UNRECOGNIZED },
|
||||||
|
allValues = DisplayToggle.entries.filterNot { it == DisplayToggle.UNRECOGNIZED },
|
||||||
|
displayValues = R.array.display_toggle_types,
|
||||||
|
displayValuesSubtitles = R.array.display_toggle_types_subtitles,
|
||||||
|
getter = {
|
||||||
|
it.interfacePreferences.displayTogglesList
|
||||||
|
},
|
||||||
|
setter = { prefs, value ->
|
||||||
|
prefs.updateInterfacePreferences {
|
||||||
|
clearDisplayToggles()
|
||||||
|
addAllDisplayToggles(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
val InstalledVersion =
|
val InstalledVersion =
|
||||||
AppClickablePreference<AppPreferences>(
|
AppClickablePreference<AppPreferences>(
|
||||||
title = R.string.installed_version,
|
title = R.string.installed_version,
|
||||||
|
|
@ -1058,8 +1077,8 @@ val basicPreferences =
|
||||||
preferences =
|
preferences =
|
||||||
listOf(
|
listOf(
|
||||||
AppPreference.SignInAuto,
|
AppPreference.SignInAuto,
|
||||||
AppPreference.PlayThemeMusic,
|
|
||||||
AppPreference.RememberSelectedTab,
|
AppPreference.RememberSelectedTab,
|
||||||
|
AppPreference.PlayThemeMusic,
|
||||||
AppPreference.SubtitleStyle,
|
AppPreference.SubtitleStyle,
|
||||||
AppPreference.ThemeColors,
|
AppPreference.ThemeColors,
|
||||||
AppPreference.ScreensaverSettings,
|
AppPreference.ScreensaverSettings,
|
||||||
|
|
@ -1172,13 +1191,13 @@ val advancedPreferences =
|
||||||
preferences =
|
preferences =
|
||||||
listOf(
|
listOf(
|
||||||
AppPreference.ShowClock,
|
AppPreference.ShowClock,
|
||||||
|
AppPreference.BackdropStylePref,
|
||||||
AppPreference.ShowLogos,
|
AppPreference.ShowLogos,
|
||||||
AppPreference.ManageMedia,
|
AppPreference.ManageMedia,
|
||||||
AppPreference.CombineContinueNext,
|
AppPreference.CombineContinueNext,
|
||||||
|
AppPreference.DisplayTogglesPref,
|
||||||
// Temporarily disabled, see https://github.com/damontecres/Wholphin/pull/127#issuecomment-3478058418
|
// Temporarily disabled, see https://github.com/damontecres/Wholphin/pull/127#issuecomment-3478058418
|
||||||
// AppPreference.NavDrawerSwitchOnFocus,
|
// AppPreference.NavDrawerSwitchOnFocus,
|
||||||
AppPreference.ControllerTimeout,
|
|
||||||
AppPreference.BackdropStylePref,
|
|
||||||
AppPreference.SlideshowDuration,
|
AppPreference.SlideshowDuration,
|
||||||
AppPreference.SlideshowPlayVideos,
|
AppPreference.SlideshowPlayVideos,
|
||||||
),
|
),
|
||||||
|
|
@ -1190,6 +1209,7 @@ val advancedPreferences =
|
||||||
preferences =
|
preferences =
|
||||||
listOf(
|
listOf(
|
||||||
AppPreference.OneClickPause,
|
AppPreference.OneClickPause,
|
||||||
|
AppPreference.ControllerTimeout,
|
||||||
AppPreference.CinemaMode,
|
AppPreference.CinemaMode,
|
||||||
AppPreference.GlobalContentScale,
|
AppPreference.GlobalContentScale,
|
||||||
AppPreference.SkipSegments,
|
AppPreference.SkipSegments,
|
||||||
|
|
@ -1337,6 +1357,7 @@ data class AppMultiChoicePreference<Pref, T>(
|
||||||
override val getter: (prefs: Pref) -> List<T>,
|
override val getter: (prefs: Pref) -> List<T>,
|
||||||
override val setter: (prefs: Pref, value: List<T>) -> Pref,
|
override val setter: (prefs: Pref, value: List<T>) -> Pref,
|
||||||
@param:StringRes val summary: Int? = null,
|
@param:StringRes val summary: Int? = null,
|
||||||
|
@param:ArrayRes val displayValuesSubtitles: Int? = null,
|
||||||
) : AppPreference<Pref, List<T>>
|
) : AppPreference<Pref, List<T>>
|
||||||
|
|
||||||
data class AppClickablePreference<Pref>(
|
data class AppClickablePreference<Pref>(
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.text.InlineTextContent
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Star
|
import androidx.compose.material.icons.filled.Star
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.NonRestartableComposable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -21,82 +22,110 @@ import androidx.tv.material3.Icon
|
||||||
import androidx.tv.material3.MaterialTheme
|
import androidx.tv.material3.MaterialTheme
|
||||||
import androidx.tv.material3.Text
|
import androidx.tv.material3.Text
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
|
import com.github.damontecres.wholphin.data.model.QuickDetailsData
|
||||||
|
import com.github.damontecres.wholphin.preferences.DisplayToggle
|
||||||
import com.github.damontecres.wholphin.ui.dot
|
import com.github.damontecres.wholphin.ui.dot
|
||||||
import com.github.damontecres.wholphin.ui.getTimeFormatter
|
import com.github.damontecres.wholphin.ui.getTimeFormatter
|
||||||
import com.github.damontecres.wholphin.ui.util.LocalClock
|
import com.github.damontecres.wholphin.ui.util.LocalClock
|
||||||
|
import com.github.damontecres.wholphin.ui.util.LocalInterfaceCustomization
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun QuickDetails(
|
fun QuickDetails(
|
||||||
details: AnnotatedString,
|
details: QuickDetailsData?,
|
||||||
timeRemaining: Duration?,
|
timeRemaining: Duration?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
textStyle: TextStyle = MaterialTheme.typography.titleSmall,
|
textStyle: TextStyle = MaterialTheme.typography.titleSmall,
|
||||||
) {
|
) {
|
||||||
val inlineContentMap =
|
val enabled = LocalInterfaceCustomization.current.enabledDisplayToggles
|
||||||
remember(textStyle) {
|
val inlineContentMap = rememberQuickDetailsContentMap(textStyle)
|
||||||
mapOf(
|
|
||||||
"star" to
|
|
||||||
InlineTextContent(
|
|
||||||
Placeholder(
|
|
||||||
textStyle.fontSize,
|
|
||||||
textStyle.fontSize,
|
|
||||||
PlaceholderVerticalAlign.TextCenter,
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Star,
|
|
||||||
tint = FilledStarColor,
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
"rotten" to
|
|
||||||
InlineTextContent(
|
|
||||||
Placeholder(
|
|
||||||
textStyle.fontSize,
|
|
||||||
textStyle.fontSize,
|
|
||||||
PlaceholderVerticalAlign.TextCenter,
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(R.drawable.ic_rotten_tomatoes_rotten),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
tint = Color.Unspecified,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
"fresh" to
|
|
||||||
InlineTextContent(
|
|
||||||
Placeholder(
|
|
||||||
textStyle.fontSize,
|
|
||||||
textStyle.fontSize,
|
|
||||||
PlaceholderVerticalAlign.TextCenter,
|
|
||||||
),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(R.drawable.ic_rotten_tomatoes_fresh),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
tint = Color.Unspecified,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Row(modifier = modifier) {
|
Row(modifier = modifier) {
|
||||||
Text(
|
if (details != null) {
|
||||||
text = details,
|
QuickDetailsText(details.basic, Modifier, textStyle, inlineContentMap)
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
if (DisplayToggle.OFFICIAL_RATING in enabled) {
|
||||||
style = textStyle,
|
QuickDetailsText(details.officialRating, Modifier, textStyle, inlineContentMap)
|
||||||
inlineContent = inlineContentMap,
|
}
|
||||||
maxLines = 1,
|
if (DisplayToggle.COMMUNITY_RATING in enabled) {
|
||||||
modifier = Modifier,
|
QuickDetailsText(details.communityRating, Modifier, textStyle, inlineContentMap)
|
||||||
)
|
}
|
||||||
|
if (DisplayToggle.CRITIC_RATING in enabled) {
|
||||||
|
QuickDetailsText(details.criticRating, Modifier, textStyle, inlineContentMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
timeRemaining?.let { TimeRemaining(it, textStyle = textStyle) }
|
timeRemaining?.let { TimeRemaining(it, textStyle = textStyle) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonRestartableComposable
|
||||||
|
@Composable
|
||||||
|
fun QuickDetailsText(
|
||||||
|
str: AnnotatedString?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
textStyle: TextStyle = MaterialTheme.typography.titleSmall,
|
||||||
|
inlineContentMap: Map<String, InlineTextContent> = rememberQuickDetailsContentMap(textStyle),
|
||||||
|
) = str?.let {
|
||||||
|
Text(
|
||||||
|
text = str,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
style = textStyle,
|
||||||
|
inlineContent = inlineContentMap,
|
||||||
|
maxLines = 1,
|
||||||
|
modifier = modifier,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberQuickDetailsContentMap(textStyle: TextStyle = MaterialTheme.typography.titleSmall) =
|
||||||
|
remember(textStyle) {
|
||||||
|
mapOf(
|
||||||
|
"star" to
|
||||||
|
InlineTextContent(
|
||||||
|
Placeholder(
|
||||||
|
textStyle.fontSize,
|
||||||
|
textStyle.fontSize,
|
||||||
|
PlaceholderVerticalAlign.TextCenter,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Star,
|
||||||
|
tint = FilledStarColor,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
"rotten" to
|
||||||
|
InlineTextContent(
|
||||||
|
Placeholder(
|
||||||
|
textStyle.fontSize,
|
||||||
|
textStyle.fontSize,
|
||||||
|
PlaceholderVerticalAlign.TextCenter,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_rotten_tomatoes_rotten),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
tint = Color.Unspecified,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
"fresh" to
|
||||||
|
InlineTextContent(
|
||||||
|
Placeholder(
|
||||||
|
textStyle.fontSize,
|
||||||
|
textStyle.fontSize,
|
||||||
|
PlaceholderVerticalAlign.TextCenter,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_rotten_tomatoes_fresh),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
tint = Color.Unspecified,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimeRemaining(
|
fun TimeRemaining(
|
||||||
remaining: Duration,
|
remaining: Duration,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import com.github.damontecres.wholphin.data.model.DiscoverRating
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||||
import com.github.damontecres.wholphin.ui.components.GenreText
|
import com.github.damontecres.wholphin.ui.components.GenreText
|
||||||
import com.github.damontecres.wholphin.ui.components.OverviewText
|
import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||||
import com.github.damontecres.wholphin.ui.components.QuickDetails
|
import com.github.damontecres.wholphin.ui.components.QuickDetailsText
|
||||||
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
||||||
import com.github.damontecres.wholphin.ui.letNotEmpty
|
import com.github.damontecres.wholphin.ui.letNotEmpty
|
||||||
import com.github.damontecres.wholphin.ui.listToDotString
|
import com.github.damontecres.wholphin.ui.listToDotString
|
||||||
|
|
@ -100,7 +100,7 @@ fun DiscoverMovieDetailsHeader(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickDetails(details, null)
|
QuickDetailsText(details)
|
||||||
movie.genres?.mapNotNull { it.name }?.letNotEmpty {
|
movie.genres?.mapNotNull { it.name }?.letNotEmpty {
|
||||||
GenreText(it, Modifier.padding(bottom = padding))
|
GenreText(it, Modifier.padding(bottom = padding))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
||||||
import com.github.damontecres.wholphin.ui.components.GenreText
|
import com.github.damontecres.wholphin.ui.components.GenreText
|
||||||
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
||||||
import com.github.damontecres.wholphin.ui.components.OverviewText
|
import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||||
import com.github.damontecres.wholphin.ui.components.QuickDetails
|
import com.github.damontecres.wholphin.ui.components.QuickDetailsText
|
||||||
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialog
|
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialog
|
||||||
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialogInfo
|
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialogInfo
|
||||||
import com.github.damontecres.wholphin.ui.letNotEmpty
|
import com.github.damontecres.wholphin.ui.letNotEmpty
|
||||||
|
|
@ -477,7 +477,7 @@ fun DiscoverSeriesDetailsHeader(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickDetails(details, null)
|
QuickDetailsText(details)
|
||||||
series.genres?.mapNotNull { it.name }?.letNotEmpty {
|
series.genres?.mapNotNull { it.name }?.letNotEmpty {
|
||||||
GenreText(it, Modifier.padding(bottom = padding))
|
GenreText(it, Modifier.padding(bottom = padding))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import com.github.damontecres.wholphin.ui.CrossFadeFactory
|
||||||
import com.github.damontecres.wholphin.ui.components.EpisodeName
|
import com.github.damontecres.wholphin.ui.components.EpisodeName
|
||||||
import com.github.damontecres.wholphin.ui.components.HeaderUtils
|
import com.github.damontecres.wholphin.ui.components.HeaderUtils
|
||||||
import com.github.damontecres.wholphin.ui.components.OverviewText
|
import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||||
import com.github.damontecres.wholphin.ui.components.QuickDetails
|
import com.github.damontecres.wholphin.ui.components.QuickDetailsText
|
||||||
import com.github.damontecres.wholphin.ui.components.StreamLabel
|
import com.github.damontecres.wholphin.ui.components.StreamLabel
|
||||||
import com.github.damontecres.wholphin.ui.components.TitleOrLogo
|
import com.github.damontecres.wholphin.ui.components.TitleOrLogo
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
@ -65,9 +65,8 @@ fun TvGuideHeader(
|
||||||
modifier = Modifier.padding(start = HeaderUtils.startPadding),
|
modifier = Modifier.padding(start = HeaderUtils.startPadding),
|
||||||
) {
|
) {
|
||||||
program?.quickDetails?.let {
|
program?.quickDetails?.let {
|
||||||
QuickDetails(
|
QuickDetailsText(
|
||||||
it,
|
it,
|
||||||
null,
|
|
||||||
modifier = Modifier.padding(vertical = 4.dp),
|
modifier = Modifier.padding(vertical = 4.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.api.seerr.infrastructure.ClientException
|
import com.github.damontecres.wholphin.api.seerr.infrastructure.ClientException
|
||||||
import com.github.damontecres.wholphin.data.model.DiscoverItem
|
import com.github.damontecres.wholphin.data.model.DiscoverItem
|
||||||
import com.github.damontecres.wholphin.data.model.DiscoverRating
|
import com.github.damontecres.wholphin.data.model.DiscoverRating
|
||||||
|
import com.github.damontecres.wholphin.data.model.QuickDetailsData
|
||||||
import com.github.damontecres.wholphin.data.model.SeerrItemType
|
import com.github.damontecres.wholphin.data.model.SeerrItemType
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||||
import com.github.damontecres.wholphin.services.BackdropService
|
import com.github.damontecres.wholphin.services.BackdropService
|
||||||
|
|
@ -275,11 +276,13 @@ fun SeerrDiscoverPage(
|
||||||
?.let(::add)
|
?.let(::add)
|
||||||
}.let {
|
}.let {
|
||||||
val rating = focusedItem?.id?.let { ratingMap[it] }
|
val rating = focusedItem?.id?.let { ratingMap[it] }
|
||||||
listToDotString(
|
val str =
|
||||||
it,
|
listToDotString(
|
||||||
rating?.audienceRating,
|
it,
|
||||||
rating?.criticRating?.toFloat(),
|
rating?.audienceRating,
|
||||||
)
|
rating?.criticRating?.toFloat(),
|
||||||
|
)
|
||||||
|
QuickDetailsData(str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HomePageHeader(
|
HomePageHeader(
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ import androidx.compose.ui.input.key.onKeyEvent
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.DpSize
|
import androidx.compose.ui.unit.DpSize
|
||||||
|
|
@ -52,6 +51,7 @@ import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||||
import com.github.damontecres.wholphin.data.model.HomeRowConfig
|
import com.github.damontecres.wholphin.data.model.HomeRowConfig
|
||||||
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
||||||
|
import com.github.damontecres.wholphin.data.model.QuickDetailsData
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||||
import com.github.damontecres.wholphin.ui.Cards
|
import com.github.damontecres.wholphin.ui.Cards
|
||||||
import com.github.damontecres.wholphin.ui.cards.BannerCard
|
import com.github.damontecres.wholphin.ui.cards.BannerCard
|
||||||
|
|
@ -546,7 +546,7 @@ fun HomePageHeader(
|
||||||
subtitle = if (isEpisode) dto?.name else null,
|
subtitle = if (isEpisode) dto?.name else null,
|
||||||
overview = dto?.overview,
|
overview = dto?.overview,
|
||||||
overviewTwoLines = isEpisode,
|
overviewTwoLines = isEpisode,
|
||||||
quickDetails = item?.ui?.quickDetails ?: AnnotatedString(""),
|
quickDetails = item?.ui?.quickDetails,
|
||||||
timeRemaining = item?.timeRemainingOrRuntime,
|
timeRemaining = item?.timeRemainingOrRuntime,
|
||||||
showLogo = showLogo,
|
showLogo = showLogo,
|
||||||
logoImageUrl = rememberLogoUrl(item),
|
logoImageUrl = rememberLogoUrl(item),
|
||||||
|
|
@ -560,7 +560,7 @@ fun HomePageHeader(
|
||||||
subtitle: String?,
|
subtitle: String?,
|
||||||
overview: String?,
|
overview: String?,
|
||||||
overviewTwoLines: Boolean,
|
overviewTwoLines: Boolean,
|
||||||
quickDetails: AnnotatedString?,
|
quickDetails: QuickDetailsData?,
|
||||||
timeRemaining: Duration?,
|
timeRemaining: Duration?,
|
||||||
showLogo: Boolean,
|
showLogo: Boolean,
|
||||||
logoImageUrl: String?,
|
logoImageUrl: String?,
|
||||||
|
|
@ -585,7 +585,7 @@ fun HomePageHeader(
|
||||||
if (subtitle != null) {
|
if (subtitle != null) {
|
||||||
EpisodeName(subtitle)
|
EpisodeName(subtitle)
|
||||||
}
|
}
|
||||||
QuickDetails(quickDetails ?: AnnotatedString(""), timeRemaining)
|
QuickDetails(quickDetails, timeRemaining)
|
||||||
val overviewModifier =
|
val overviewModifier =
|
||||||
Modifier
|
Modifier
|
||||||
.padding(0.dp)
|
.padding(0.dp)
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,7 @@ fun <T> ComposablePreference(
|
||||||
|
|
||||||
is AppMultiChoicePreference<*, *> -> {
|
is AppMultiChoicePreference<*, *> -> {
|
||||||
val values = stringArrayResource(preference.displayValues)
|
val values = stringArrayResource(preference.displayValues)
|
||||||
|
val subtitles = preference.displayValuesSubtitles?.let { stringArrayResource(it) }
|
||||||
val summary =
|
val summary =
|
||||||
preference.summary?.let { stringResource(it) }
|
preference.summary?.let { stringResource(it) }
|
||||||
?: preference.summary(context, value)
|
?: preference.summary(context, value)
|
||||||
|
|
@ -219,6 +220,9 @@ fun <T> ComposablePreference(
|
||||||
valueDisplay = { index, _ ->
|
valueDisplay = { index, _ ->
|
||||||
Text(values[index])
|
Text(values[index])
|
||||||
},
|
},
|
||||||
|
subtitleDisplay = { index, _ ->
|
||||||
|
subtitles?.getOrNull(index)?.let { Text(it) }
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ fun <T> MultiChoicePreference(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
valueDisplay: @Composable (index: Int, item: T) -> Unit = { _, item -> Text(item.toString()) },
|
valueDisplay: @Composable (index: Int, item: T) -> Unit = { _, item -> Text(item.toString()) },
|
||||||
|
subtitleDisplay: @Composable (index: Int, item: T) -> Unit = { _, item -> },
|
||||||
) {
|
) {
|
||||||
// val values = stringArrayResource(preference.displayValues).toList()
|
// val values = stringArrayResource(preference.displayValues).toList()
|
||||||
// val summary =
|
// val summary =
|
||||||
|
|
@ -60,6 +61,7 @@ fun <T> MultiChoicePreference(
|
||||||
possibleValues.mapIndexed { index, item ->
|
possibleValues.mapIndexed { index, item ->
|
||||||
DialogItem(
|
DialogItem(
|
||||||
headlineContent = { valueDisplay.invoke(index, item) },
|
headlineContent = { valueDisplay.invoke(index, item) },
|
||||||
|
supportingContent = { subtitleDisplay.invoke(index, item) },
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
Switch(
|
Switch(
|
||||||
checked = selectedValues.contains(item),
|
checked = selectedValues.contains(item),
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||||
import com.github.damontecres.wholphin.ui.components.QuickDetails
|
import com.github.damontecres.wholphin.ui.components.QuickDetails
|
||||||
import com.github.damontecres.wholphin.ui.components.StreamLabel
|
import com.github.damontecres.wholphin.ui.components.StreamLabel
|
||||||
import com.github.damontecres.wholphin.ui.components.VideoStreamDetails
|
import com.github.damontecres.wholphin.ui.components.VideoStreamDetails
|
||||||
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
|
||||||
import org.jellyfin.sdk.model.api.MediaType
|
import org.jellyfin.sdk.model.api.MediaType
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
|
|
@ -64,11 +63,7 @@ fun ImageDetailsHeader(
|
||||||
modifier = Modifier.fillMaxWidth(.75f),
|
modifier = Modifier.fillMaxWidth(.75f),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (image.image.ui.quickDetails
|
QuickDetails(image.image.ui.quickDetails, null)
|
||||||
.isNotNullOrBlank()
|
|
||||||
) {
|
|
||||||
QuickDetails(image.image.ui.quickDetails, null)
|
|
||||||
}
|
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.github.damontecres.wholphin.ui.util
|
||||||
|
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||||
|
import com.github.damontecres.wholphin.preferences.DisplayToggle
|
||||||
|
import java.util.EnumSet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents various UI preferences made available via [LocalInterfaceCustomization]
|
||||||
|
*/
|
||||||
|
data class InterfaceCustomization(
|
||||||
|
val enabledDisplayToggles: EnumSet<DisplayToggle>,
|
||||||
|
) {
|
||||||
|
constructor(prefs: AppPreferences) : this(
|
||||||
|
prefs.interfacePreferences.displayTogglesList.let {
|
||||||
|
if (it.isEmpty()) {
|
||||||
|
EnumSet.noneOf(DisplayToggle::class.java)
|
||||||
|
} else {
|
||||||
|
EnumSet.copyOf(it)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val LocalInterfaceCustomization =
|
||||||
|
staticCompositionLocalOf<InterfaceCustomization> {
|
||||||
|
InterfaceCustomization(EnumSet.allOf(DisplayToggle::class.java))
|
||||||
|
}
|
||||||
|
|
@ -170,6 +170,12 @@ message SearchPreferences {
|
||||||
bool combined_search_results = 1;
|
bool combined_search_results = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DisplayToggle{
|
||||||
|
OFFICIAL_RATING = 0;
|
||||||
|
CRITIC_RATING = 1;
|
||||||
|
COMMUNITY_RATING = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message InterfacePreferences {
|
message InterfacePreferences {
|
||||||
ThemeSongVolume play_theme_songs = 1;
|
ThemeSongVolume play_theme_songs = 1;
|
||||||
bool remember_selected_tab = 2;
|
bool remember_selected_tab = 2;
|
||||||
|
|
@ -185,6 +191,7 @@ message InterfacePreferences {
|
||||||
bool enable_media_management = 12;
|
bool enable_media_management = 12;
|
||||||
bool show_logos = 13;
|
bool show_logos = 13;
|
||||||
SearchPreferences search_preferences = 14;
|
SearchPreferences search_preferences = 14;
|
||||||
|
repeated DisplayToggle display_toggles = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AdvancedPreferences {
|
message AdvancedPreferences {
|
||||||
|
|
|
||||||
|
|
@ -726,6 +726,17 @@
|
||||||
<item>@string/photos</item>
|
<item>@string/photos</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="display_toggle_types">
|
||||||
|
<item>@string/official_rating</item>
|
||||||
|
<item>@string/critic_rating</item>
|
||||||
|
<item>@string/community_rating</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="display_toggle_types_subtitles">
|
||||||
|
<item></item><!-- Intentionally blank -->
|
||||||
|
<item>@string/tomatoes</item>
|
||||||
|
<item>@string/stars</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string name="search_for">Search %s</string>
|
<string name="search_for">Search %s</string>
|
||||||
|
|
||||||
<string name="actor">Actor</string>
|
<string name="actor">Actor</string>
|
||||||
|
|
@ -779,6 +790,8 @@
|
||||||
<string name="skip_behavior_summary">For intros, credits, etc</string>
|
<string name="skip_behavior_summary">For intros, credits, etc</string>
|
||||||
<string name="play_with">Play with</string>
|
<string name="play_with">Play with</string>
|
||||||
<string name="transcoding">Transcoding</string>
|
<string name="transcoding">Transcoding</string>
|
||||||
|
<string name="display_toggles_title">Ratings display</string>
|
||||||
|
<string name="display_toggles_summary">Customize which to display</string>
|
||||||
<string name="profile_protection">Profile protection</string>
|
<string name="profile_protection">Profile protection</string>
|
||||||
<string name="continue_watching_click_behavior">Continue watching/Next up click behavior</string>
|
<string name="continue_watching_click_behavior">Continue watching/Next up click behavior</string>
|
||||||
<string name="continue_watching_click_summary_on">Play on click</string>
|
<string name="continue_watching_click_summary_on">Play on click</string>
|
||||||
|
|
@ -793,4 +806,6 @@
|
||||||
<item></item><!-- Intentionally blank -->
|
<item></item><!-- Intentionally blank -->
|
||||||
<item></item><!-- Intentionally blank -->
|
<item></item><!-- Intentionally blank -->
|
||||||
</array>
|
</array>
|
||||||
|
<string name="stars">Stars</string>
|
||||||
|
<string name="tomatoes">Tomatoes</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue