fix(android): LikedTab tracks tap to play
Track rows in the Liked tab had .clickable(enabled = false) with a "Phase 9" deferral comment, silently breaking the most common interaction on the list. Mirror the HistoryTab pattern: inject PlayerController, expose playTracks(list, index), and route taps through to PlayerController.setQueue with source = "liked". Row clickability is gated on streamUrl so rows that can't be played stay inert. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -36,6 +37,7 @@ import com.fabledsword.minstrel.models.ArtistRef
|
||||
import com.fabledsword.minstrel.models.TrackRef
|
||||
import com.fabledsword.minstrel.nav.AlbumDetail
|
||||
import com.fabledsword.minstrel.nav.ArtistDetail
|
||||
import com.fabledsword.minstrel.player.PlayerController
|
||||
import com.fabledsword.minstrel.shared.widgets.EmptyState
|
||||
import com.fabledsword.minstrel.shared.widgets.HorizontalScrollRow
|
||||
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
|
||||
@@ -73,6 +75,7 @@ sealed interface LikedTabUiState {
|
||||
@HiltViewModel
|
||||
class LikedTabViewModel @Inject constructor(
|
||||
private val repository: LikesRepository,
|
||||
private val player: PlayerController,
|
||||
) : ViewModel() {
|
||||
|
||||
init {
|
||||
@@ -95,6 +98,19 @@ class LikedTabViewModel @Inject constructor(
|
||||
started = SharingStarted.WhileSubscribed(SHARE_STOP_TIMEOUT_MS),
|
||||
initialValue = LikedTabUiState.Loading,
|
||||
)
|
||||
|
||||
/**
|
||||
* Build a queue from the currently-displayed liked tracks and start
|
||||
* playback at [initialIndex]. Mirrors Flutter's tap-on-liked-track
|
||||
* behavior: the visible track list becomes the play queue. Tracks
|
||||
* with empty streamUrl are ignored as queue entries (the row that
|
||||
* routes here is itself click-gated on streamUrl).
|
||||
*/
|
||||
fun playTracks(tracks: List<TrackRef>, initialIndex: Int) {
|
||||
if (tracks.isEmpty() || initialIndex !in tracks.indices) return
|
||||
if (tracks[initialIndex].streamUrl.isEmpty()) return
|
||||
player.setQueue(tracks, initialIndex = initialIndex, source = "liked")
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Composable ──────────────────────────────────────────────────────
|
||||
@@ -121,6 +137,9 @@ fun LikedTab(
|
||||
sections = s.sections,
|
||||
onArtistClick = { id -> navController.navigate(ArtistDetail(id)) },
|
||||
onAlbumClick = { id -> navController.navigate(AlbumDetail(id)) },
|
||||
onTrackClick = { index ->
|
||||
viewModel.playTracks(s.sections.tracks, index)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -131,6 +150,7 @@ private fun LikedContent(
|
||||
sections: LikedSections,
|
||||
onArtistClick: (String) -> Unit,
|
||||
onAlbumClick: (String) -> Unit,
|
||||
onTrackClick: (Int) -> Unit,
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@@ -164,8 +184,8 @@ private fun LikedContent(
|
||||
item {
|
||||
SectionHeader("Tracks", sections.tracks.size)
|
||||
}
|
||||
items(items = sections.tracks, key = { "trk-${it.id}" }) { track ->
|
||||
LikedTrackRow(track = track)
|
||||
itemsIndexed(items = sections.tracks, key = { _, t -> "trk-${t.id}" }) { index, track ->
|
||||
LikedTrackRow(track = track, onClick = { onTrackClick(index) })
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
@@ -196,15 +216,11 @@ private fun SectionHeader(label: String, count: Int) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LikedTrackRow(track: TrackRef) {
|
||||
private fun LikedTrackRow(track: TrackRef, onClick: () -> Unit) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
// Track-row taps will route to the player queue once Phase 9
|
||||
// wires history + recently-played tap-to-play; for now the
|
||||
// row is informational so swiping the tab still feels
|
||||
// responsive without an unfinished playback affordance.
|
||||
.clickable(enabled = false, onClick = {})
|
||||
.clickable(enabled = track.streamUrl.isNotEmpty(), onClick = onClick)
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
|
||||
Reference in New Issue
Block a user