diff --git a/android/app/src/main/java/com/fabledsword/minstrel/shared/widgets/TrackRow.kt b/android/app/src/main/java/com/fabledsword/minstrel/shared/widgets/TrackRow.kt new file mode 100644 index 00000000..e4e88cbc --- /dev/null +++ b/android/app/src/main/java/com/fabledsword/minstrel/shared/widgets/TrackRow.kt @@ -0,0 +1,80 @@ +package com.fabledsword.minstrel.shared.widgets + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp + +/** + * Shared track-list row. Replaces the 5 per-screen `TrackRow`s — every + * track list shares the same row skeleton (clickable Row, title + artist + * column, CachedDot, nowPlaying highlight); only the leading element + * (track number vs cover thumb) and the trailing controls (duration, + * relative time, LikeButton, TrackActionsButton) vary. Callers fill + * those via the [leading] and [trailing] slots so each screen's row is + * a thin wrapper that no longer re-implements the Row layout. + * + * [enabled] gates the click (use for unavailable rows). [contentAlpha] + * dims the title + artist text colors — pass <1f for the + * playlist-track-unavailable case. The trailing slot is responsible + * for applying its own alpha if it should match (the row doesn't + * cascade because the trailing slot's content is the caller's, not + * ours). + */ +@Composable +fun TrackRow( + title: String, + artist: String, + trackId: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + nowPlaying: Boolean = false, + enabled: Boolean = true, + contentAlpha: Float = 1f, + leading: @Composable () -> Unit = {}, + trailing: @Composable RowScope.() -> Unit = {}, +) { + val titleColor = if (nowPlaying) { + MaterialTheme.colorScheme.primary + } else { + MaterialTheme.colorScheme.onSurface + } + Row( + modifier = modifier + .fillMaxWidth() + .clickable(enabled = enabled, onClick = onClick) + .padding(horizontal = 16.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + leading() + Column(modifier = Modifier.weight(1f)) { + Text( + text = title, + style = MaterialTheme.typography.bodyLarge, + color = titleColor.copy(alpha = contentAlpha), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + if (artist.isNotEmpty()) { + Text( + text = artist, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = contentAlpha), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } + CachedDot(trackId) + trailing() + } +}