summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/main/java/org/terst/listen/ui/SubscriptionRow.kt87
1 files changed, 45 insertions, 42 deletions
diff --git a/app/src/main/java/org/terst/listen/ui/SubscriptionRow.kt b/app/src/main/java/org/terst/listen/ui/SubscriptionRow.kt
index 1ffa4a9..49ea000 100644
--- a/app/src/main/java/org/terst/listen/ui/SubscriptionRow.kt
+++ b/app/src/main/java/org/terst/listen/ui/SubscriptionRow.kt
@@ -2,14 +2,13 @@ package org.terst.listen.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.PlaylistAdd
@@ -18,9 +17,11 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
+import coil3.compose.AsyncImage
import org.terst.listen.data.EpisodeEntity
import org.terst.listen.data.SubscriptionEntity
import org.terst.listen.data.SubscriptionListing
@@ -52,48 +53,52 @@ internal fun SubscriptionRow(
val subscription = listing.subscription
val alpha = if (listing.hasWaiting) 1f else CAUGHT_UP_ALPHA
- Column(Modifier.fillMaxWidth().clickable(onClick = onClick).padding(start = 16.dp, end = 4.dp)) {
- ShowHeadline(listing, alpha)
- if (latest != null && actions != null) LatestEpisodeLine(latest, actions)
+ Row(
+ Modifier.fillMaxWidth().clickable(onClick = onClick).padding(start = 16.dp, end = 4.dp),
+ verticalAlignment = Alignment.Top,
+ ) {
+ AsyncImage(
+ model = subscription.imageUrl,
+ contentDescription = null,
+ modifier = Modifier
+ .padding(top = 12.dp)
+ .size(SHOW_ICON)
+ .clip(RoundedCornerShape(8.dp))
+ .background(MaterialTheme.colorScheme.surfaceVariant)
+ .alpha(alpha),
+ )
+ Column(Modifier.weight(1f).padding(start = 12.dp)) {
+ ShowHeadline(listing, alpha)
+ if (latest != null && actions != null) LatestEpisodeLine(latest, actions)
- // A feed that has quietly stopped working is otherwise indistinguishable from one with
- // nothing new, which is the whole reason the error is stored rather than logged.
- subscription.lastError?.let {
- Text(
- "Last refresh failed: $it",
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.error,
- maxLines = 2,
- overflow = TextOverflow.Ellipsis,
- modifier = Modifier.padding(start = WAITING_DOT + 12.dp, bottom = 4.dp),
- )
+ // A feed that has quietly stopped working is otherwise indistinguishable from one
+ // with nothing new, which is the whole reason the error is stored rather than logged.
+ subscription.lastError?.let {
+ Text(
+ "Last refresh failed: $it",
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.error,
+ maxLines = 2,
+ overflow = TextOverflow.Ellipsis,
+ modifier = Modifier.padding(bottom = 4.dp),
+ )
+ }
+ Spacer(Modifier.size(6.dp))
}
- Spacer(Modifier.size(6.dp))
}
}
-/** The show's own line: a dot for whether anything is waiting, its name, and how much. */
+/** The show's own line: its name, and how much is waiting on it. */
@Composable
private fun ShowHeadline(listing: SubscriptionListing, alpha: Float) {
Row(Modifier.fillMaxWidth().padding(top = 10.dp), verticalAlignment = Alignment.CenterVertically) {
- // A dot rather than artwork. Forty-three shows is a list to scan, not a shelf to
- // browse, and the one thing worth seeing per row is whether there is anything in it.
- Box(
- Modifier
- .size(WAITING_DOT)
- .clip(CircleShape)
- .background(
- if (listing.hasWaiting) MaterialTheme.colorScheme.primary
- else MaterialTheme.colorScheme.surfaceVariant
- )
- )
Text(
listing.subscription.title,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = alpha),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
- modifier = Modifier.weight(1f).padding(start = 12.dp),
+ modifier = Modifier.weight(1f),
)
Text(
if (listing.hasWaiting) listing.waiting.toString() else "\u2014",
@@ -104,18 +109,10 @@ private fun ShowHeadline(listing: SubscriptionListing, alpha: Float) {
}
}
-/**
- * The newest waiting episode, indented under the show's name and offered directly.
- *
- * Indented to the show title's text, not the dot: the dot belongs to the show, and lining the
- * episode up with it would read as a second show rather than as this one's contents.
- */
+/** The newest waiting episode, under the show's name and offered directly. */
@Composable
private fun LatestEpisodeLine(latest: EpisodeEntity, actions: EpisodeActions) {
- Row(
- Modifier.fillMaxWidth().padding(start = WAITING_DOT + 12.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
+ Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(
latest.title,
style = MaterialTheme.typography.bodySmall,
@@ -130,8 +127,14 @@ private fun LatestEpisodeLine(latest: EpisodeEntity, actions: EpisodeActions) {
}
}
-/** How big the "something waiting" dot is. Small enough to read as punctuation, not a control. */
-private val WAITING_DOT = 8.dp
+/**
+ * How big the show's artwork is.
+ *
+ * Tall enough to carry both lines of the row, which is what makes the artwork read as belonging
+ * to the show rather than to the episode named under it. It replaced a dot that said only
+ * whether anything was waiting -- the count beside the title says that, and says how much.
+ */
+private val SHOW_ICON = 44.dp
/**
* The controls the library row offers on a show's newest waiting episode.