Better indicators

This commit is contained in:
Damontecres 2026-01-06 15:28:15 -05:00
parent ee640f82db
commit f89eec622a
No known key found for this signature in database
4 changed files with 170 additions and 48 deletions

View file

@ -21,8 +21,7 @@ val LocalImageUrlService =
/** /**
* Colors not associated with the theme * Colors not associated with the theme
*/ */
sealed class AppColors private constructor() { object AppColors {
companion object {
val TransparentBlack25 = Color(0x40000000) val TransparentBlack25 = Color(0x40000000)
val TransparentBlack50 = Color(0x80000000) val TransparentBlack50 = Color(0x80000000)
val TransparentBlack75 = Color(0xBF000000) val TransparentBlack75 = Color(0xBF000000)
@ -33,6 +32,12 @@ sealed class AppColors private constructor() {
val DarkPurple = Color(0xFF261370) val DarkPurple = Color(0xFF261370)
val GoldenYellow = Color(0xFFDAB440) val GoldenYellow = Color(0xFFDAB440)
object Discover {
val Blue = Color(37, 99, 235)
val Purple = Color(147, 51, 234)
val Green = Color(74, 222, 128)
val Yellow = Color(234, 179, 8)
} }
} }

View file

@ -2,6 +2,7 @@ package com.github.damontecres.wholphin.ui.cards
import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -24,20 +25,27 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.tv.material3.Card import androidx.tv.material3.Card
import androidx.tv.material3.CardDefaults import androidx.tv.material3.CardDefaults
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.DiscoverItem import com.github.damontecres.wholphin.data.model.DiscoverItem
import com.github.damontecres.wholphin.data.model.SeerrAvailability import com.github.damontecres.wholphin.data.model.SeerrAvailability
import com.github.damontecres.wholphin.data.model.SeerrItemType import com.github.damontecres.wholphin.data.model.SeerrItemType
import com.github.damontecres.wholphin.ui.AppColors
import com.github.damontecres.wholphin.ui.AspectRatios import com.github.damontecres.wholphin.ui.AspectRatios
import com.github.damontecres.wholphin.ui.Cards import com.github.damontecres.wholphin.ui.Cards
import com.github.damontecres.wholphin.ui.FontAwesome
import com.github.damontecres.wholphin.ui.PreviewTvSpec
import com.github.damontecres.wholphin.ui.enableMarquee import com.github.damontecres.wholphin.ui.enableMarquee
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@Composable @Composable
@ -106,49 +114,50 @@ fun DiscoverItemCard(
Modifier Modifier
.fillMaxSize(), .fillMaxSize(),
) )
val availabilityColor =
when (item?.availability) { when (item?.availability) {
SeerrAvailability.PENDING, SeerrAvailability.PENDING,
SeerrAvailability.PROCESSING, SeerrAvailability.PROCESSING,
-> Color.Yellow -> {
PendingIndicator(Modifier.align(Alignment.TopEnd))
SeerrAvailability.PARTIALLY_AVAILABLE,
SeerrAvailability.AVAILABLE,
-> Color.Green
else -> null
} }
availabilityColor?.let {
Box( SeerrAvailability.PARTIALLY_AVAILABLE -> {
modifier = PartiallyAvailableIndicator(Modifier.align(Alignment.TopEnd))
Modifier }
.padding(4.dp)
.background( SeerrAvailability.AVAILABLE,
color = it, -> {
shape = CircleShape, AvailableIndicator(Modifier.align(Alignment.TopEnd))
).size(12.dp) }
.align(Alignment.TopEnd),
) else -> {}
} }
if (showOverlay) { if (showOverlay) {
// TODO better colors
val color = val color =
remember(item?.type) {
when (item?.type) { when (item?.type) {
SeerrItemType.MOVIE -> Color.Blue SeerrItemType.MOVIE -> AppColors.Discover.Blue
SeerrItemType.TV -> Color.Red SeerrItemType.TV -> AppColors.Discover.Purple
SeerrItemType.PERSON -> Color.Green SeerrItemType.PERSON -> AppColors.Discover.Green
SeerrItemType.UNKNOWN -> Color.Black SeerrItemType.UNKNOWN -> Color.Black
null -> Color.Black null -> Color.Black
}.copy(alpha = .5f) }.copy(alpha = .8f)
}
val text =
remember(item?.type) {
when (item?.type) { when (item?.type) {
SeerrItemType.MOVIE -> R.string.movies SeerrItemType.MOVIE -> R.plurals.movies
SeerrItemType.TV -> R.string.tv_shows SeerrItemType.TV -> R.plurals.tv_shows
SeerrItemType.PERSON -> R.string.people SeerrItemType.PERSON -> R.plurals.people
SeerrItemType.UNKNOWN -> null SeerrItemType.UNKNOWN -> null
null -> null null -> null
}?.let { }
}
text?.let {
Text( Text(
text = stringResource(it), text = pluralStringResource(it, 1),
style = MaterialTheme.typography.bodySmall,
fontSize = 10.sp,
modifier = modifier =
Modifier Modifier
.align(Alignment.TopStart) .align(Alignment.TopStart)
@ -192,3 +201,93 @@ fun DiscoverItemCard(
} }
} }
} }
@Composable
fun PendingIndicator(modifier: Modifier = Modifier) {
Box(
modifier =
modifier
.padding(4.dp)
.border(
width = .5.dp,
color = AppColors.Discover.Yellow,
shape = CircleShape,
).background(
color = Color.White.copy(alpha = .85f),
shape = CircleShape,
).size(16.dp),
) {
Text(
text = stringResource(R.string.fa_bell),
fontFamily = FontAwesome,
fontSize = 10.sp,
color = AppColors.Discover.Yellow,
modifier = Modifier.align(Alignment.Center),
)
}
}
@Composable
fun AvailableIndicator(modifier: Modifier = Modifier) {
Box(
modifier =
modifier
.padding(4.dp)
.border(
width = .5.dp,
color = Color.White,
shape = CircleShape,
).background(
color = AppColors.Discover.Green.copy(alpha = .85f),
shape = CircleShape,
).size(16.dp),
) {
Text(
text = stringResource(R.string.fa_check),
fontFamily = FontAwesome,
fontSize = 10.sp,
color = Color.White,
modifier = Modifier.align(Alignment.Center),
)
}
}
@Composable
fun PartiallyAvailableIndicator(modifier: Modifier = Modifier) {
Box(
modifier =
modifier
.padding(4.dp)
.border(
width = .5.dp,
color = Color.White,
shape = CircleShape,
).background(
color = AppColors.Discover.Green.copy(alpha = .85f),
shape = CircleShape,
).size(16.dp),
) {
Box(
modifier =
Modifier
.align(Alignment.Center)
.size(width = 10.dp, height = 2.dp)
.background(
color = Color.White,
shape = CircleShape,
),
)
}
}
@PreviewTvSpec
@Composable
private fun Preview() {
WholphinTheme {
Column {
PendingIndicator()
AvailableIndicator()
PartiallyAvailableIndicator()
}
}
}

View file

@ -47,4 +47,6 @@
<string name="fa_sliders" translatable="false">&#xf1de;</string> <string name="fa_sliders" translatable="false">&#xf1de;</string>
<string name="fa_download" translatable="false">&#xf019;</string> <string name="fa_download" translatable="false">&#xf019;</string>
<string name="fa_clock" translatable="false">&#xf017;</string> <string name="fa_clock" translatable="false">&#xf017;</string>
<string name="fa_bell" translatable="false">&#xf0f3;</string>
<string name="fa_check" translatable="false">&#xf00c;</string>
</resources> </resources>

View file

@ -252,6 +252,22 @@
<item quantity="other">%d seconds</item> <item quantity="other">%d seconds</item>
</plurals> </plurals>
<plurals name="movies">
<item quantity="zero">Movies</item>
<item quantity="one">Movie</item>
<item quantity="other">Movies</item>
</plurals>
<plurals name="tv_shows">
<item quantity="zero">TV Shows</item>
<item quantity="one">TV Show</item>
<item quantity="other">TV Shows</item>
</plurals>
<plurals name="people">
<item quantity="zero">People</item>
<item quantity="one">Person</item>
<item quantity="other">People</item>
</plurals>
<!-- Preferences/Setting specific strings --> <!-- Preferences/Setting specific strings -->
<string name="pref_key_update_last_check_threshold" translatable="false">preference.update.threshold</string> <string name="pref_key_update_last_check_threshold" translatable="false">preference.update.threshold</string>
<string name="pref_key_update_last_check" translatable="false">preference.update.lastTimestamp</string> <string name="pref_key_update_last_check" translatable="false">preference.update.lastTimestamp</string>