feat(android): TrackActions button on Playlist / Library tabs / Search
Spreads TrackActionsButton across the second wave of surfaces. PlaylistDetail track rows, LikedTab tracks, HistoryTab rows, and Search results now expose the full 7-item menu. Each screen-level Scaffold gains a SnackbarHost that collects TrackActionsViewModel transient messages. Search tracks section upgraded from text-only TextRow to TrackRow with cover thumb + secondary line (artist or album) + kebab. MiniPlayer + NowPlaying kebabs follow in a separate commit so the shell-level snackbar plumbing can land independently. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,7 @@ import com.fabledsword.minstrel.models.TrackRef
|
||||
import com.fabledsword.minstrel.player.PlayerController
|
||||
import com.fabledsword.minstrel.shared.widgets.EmptyState
|
||||
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -95,7 +96,11 @@ class HistoryTabViewModel @Inject constructor(
|
||||
// ─── Composable ──────────────────────────────────────────────────────
|
||||
|
||||
@Composable
|
||||
fun HistoryTab(viewModel: HistoryTabViewModel = hiltViewModel()) {
|
||||
fun HistoryTab(
|
||||
onNavigateToAlbum: (String) -> Unit = {},
|
||||
onNavigateToArtist: (String) -> Unit = {},
|
||||
viewModel: HistoryTabViewModel = hiltViewModel(),
|
||||
) {
|
||||
val state by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
when (val s = state) {
|
||||
@@ -111,23 +116,40 @@ fun HistoryTab(viewModel: HistoryTabViewModel = hiltViewModel()) {
|
||||
is HistoryUiState.Success -> HistoryList(
|
||||
entries = s.entries,
|
||||
onPlay = viewModel::playTrack,
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HistoryList(entries: List<HistoryEntry>, onPlay: (TrackRef) -> Unit) {
|
||||
private fun HistoryList(
|
||||
entries: List<HistoryEntry>,
|
||||
onPlay: (TrackRef) -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||
items(items = entries, key = { it.id }) { entry ->
|
||||
HistoryRow(entry = entry, onClick = { onPlay(entry.track) })
|
||||
HistoryRow(
|
||||
entry = entry,
|
||||
onClick = { onPlay(entry.track) },
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HistoryRow(entry: HistoryEntry, onClick: () -> Unit) {
|
||||
private fun HistoryRow(
|
||||
entry: HistoryEntry,
|
||||
onClick: () -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -158,6 +180,11 @@ private fun HistoryRow(entry: HistoryEntry, onClick: () -> Unit) {
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
TrackActionsButton(
|
||||
track = entry.track,
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,13 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.PrimaryScrollableTabRow
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -41,6 +44,7 @@ import com.fabledsword.minstrel.nav.Library
|
||||
import com.fabledsword.minstrel.shared.widgets.EmptyState
|
||||
import com.fabledsword.minstrel.shared.widgets.ErrorRetry
|
||||
import com.fabledsword.minstrel.shared.widgets.MainAppBarActions
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsViewModel
|
||||
|
||||
/**
|
||||
* Library tab. Five-tab TabBar (Artists / Albums / History / Liked /
|
||||
@@ -60,9 +64,16 @@ import com.fabledsword.minstrel.shared.widgets.MainAppBarActions
|
||||
fun LibraryScreen(
|
||||
navController: NavHostController,
|
||||
viewModel: LibraryViewModel = hiltViewModel(),
|
||||
trackActionsViewModel: TrackActionsViewModel = hiltViewModel(),
|
||||
) {
|
||||
var selectedTab by remember { mutableIntStateOf(0) }
|
||||
val tabs = LIBRARY_TABS
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
LaunchedEffect(Unit) {
|
||||
trackActionsViewModel.transientMessages.collect { msg ->
|
||||
snackbarHostState.showSnackbar(msg)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@@ -91,12 +102,16 @@ fun LibraryScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
) { inner ->
|
||||
Box(modifier = Modifier.fillMaxSize().padding(inner)) {
|
||||
when (selectedTab) {
|
||||
TAB_ARTISTS -> ArtistsTab(viewModel = viewModel, navController = navController)
|
||||
TAB_ALBUMS -> AlbumsTab(viewModel = viewModel, navController = navController)
|
||||
TAB_HISTORY -> HistoryTab()
|
||||
TAB_HISTORY -> HistoryTab(
|
||||
onNavigateToAlbum = { id -> navController.navigate(AlbumDetail(id)) },
|
||||
onNavigateToArtist = { id -> navController.navigate(ArtistDetail(id)) },
|
||||
)
|
||||
TAB_LIKED -> LikedTab(navController = navController)
|
||||
TAB_HIDDEN -> HiddenTab()
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ 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
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -140,6 +141,8 @@ fun LikedTab(
|
||||
onTrackClick = { index ->
|
||||
viewModel.playTracks(s.sections.tracks, index)
|
||||
},
|
||||
onNavigateToAlbum = { id -> navController.navigate(AlbumDetail(id)) },
|
||||
onNavigateToArtist = { id -> navController.navigate(ArtistDetail(id)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -151,6 +154,8 @@ private fun LikedContent(
|
||||
onArtistClick: (String) -> Unit,
|
||||
onAlbumClick: (String) -> Unit,
|
||||
onTrackClick: (Int) -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@@ -185,7 +190,12 @@ private fun LikedContent(
|
||||
SectionHeader("Tracks", sections.tracks.size)
|
||||
}
|
||||
itemsIndexed(items = sections.tracks, key = { _, t -> "trk-${t.id}" }) { index, track ->
|
||||
LikedTrackRow(track = track, onClick = { onTrackClick(index) })
|
||||
LikedTrackRow(
|
||||
track = track,
|
||||
onClick = { onTrackClick(index) },
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
@@ -216,7 +226,12 @@ private fun SectionHeader(label: String, count: Int) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LikedTrackRow(track: TrackRef, onClick: () -> Unit) {
|
||||
private fun LikedTrackRow(
|
||||
track: TrackRef,
|
||||
onClick: () -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -242,6 +257,11 @@ private fun LikedTrackRow(track: TrackRef, onClick: () -> Unit) {
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
TrackActionsButton(
|
||||
track = track,
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
@@ -27,9 +27,12 @@ import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -55,6 +58,8 @@ import com.composables.icons.lucide.Shuffle
|
||||
import com.fabledsword.minstrel.models.PlaylistRef
|
||||
import com.fabledsword.minstrel.models.PlaylistTrackRef
|
||||
import com.fabledsword.minstrel.models.TrackRef
|
||||
import com.fabledsword.minstrel.nav.AlbumDetail
|
||||
import com.fabledsword.minstrel.nav.ArtistDetail
|
||||
import com.fabledsword.minstrel.nav.PlaylistDetail
|
||||
import com.fabledsword.minstrel.player.PlayerController
|
||||
import com.fabledsword.minstrel.likes.data.LikesRepository
|
||||
@@ -62,6 +67,8 @@ import com.fabledsword.minstrel.playlists.data.PlaylistDetailRef
|
||||
import com.fabledsword.minstrel.playlists.data.PlaylistsRepository
|
||||
import com.fabledsword.minstrel.shared.widgets.LikeButton
|
||||
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsViewModel
|
||||
import com.fabledsword.minstrel.theme.FabledSwordFlatTokens
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -152,8 +159,15 @@ class PlaylistDetailViewModel @Inject constructor(
|
||||
fun PlaylistDetailScreen(
|
||||
navController: NavHostController,
|
||||
viewModel: PlaylistDetailViewModel = hiltViewModel(),
|
||||
trackActionsViewModel: TrackActionsViewModel = hiltViewModel(),
|
||||
) {
|
||||
val state by viewModel.uiState.collectAsState()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
LaunchedEffect(Unit) {
|
||||
trackActionsViewModel.transientMessages.collect { msg ->
|
||||
snackbarHostState.showSnackbar(msg)
|
||||
}
|
||||
}
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
topBar = {
|
||||
@@ -166,6 +180,7 @@ fun PlaylistDetailScreen(
|
||||
},
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
) { inner ->
|
||||
Box(modifier = Modifier.fillMaxSize().padding(inner)) {
|
||||
when (val s = state) {
|
||||
@@ -184,6 +199,8 @@ fun PlaylistDetailScreen(
|
||||
viewModel.play(s.detail.tracks, startTrackId = id)
|
||||
},
|
||||
onToggleTrackLike = viewModel::toggleLikeTrack,
|
||||
onNavigateToAlbum = { id -> navController.navigate(AlbumDetail(id)) },
|
||||
onNavigateToArtist = { id -> navController.navigate(ArtistDetail(id)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -206,6 +223,8 @@ private fun PlaylistDetailBody(
|
||||
onShuffleAll: () -> Unit,
|
||||
onTrackClick: (String) -> Unit,
|
||||
onToggleTrackLike: (String) -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@@ -219,6 +238,8 @@ private fun PlaylistDetailBody(
|
||||
liked = row.trackId != null && row.trackId in likedTrackIds,
|
||||
onClick = { row.trackId?.let(onTrackClick) },
|
||||
onToggleLike = { row.trackId?.let(onToggleTrackLike) },
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
HorizontalDivider()
|
||||
}
|
||||
@@ -327,6 +348,8 @@ private fun TrackRow(
|
||||
liked: Boolean,
|
||||
onClick: () -> Unit,
|
||||
onToggleLike: () -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
val enabled = row.isAvailable
|
||||
val rowAlpha = if (enabled) 1f else UNAVAILABLE_ALPHA
|
||||
@@ -366,6 +389,11 @@ private fun TrackRow(
|
||||
)
|
||||
if (enabled) {
|
||||
LikeButton(liked = liked, onToggle = onToggleLike)
|
||||
TrackActionsButton(
|
||||
track = row.toTrackRef(),
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
@@ -48,16 +50,26 @@ import com.fabledsword.minstrel.models.SearchResponseRef
|
||||
import com.fabledsword.minstrel.models.TrackRef
|
||||
import com.fabledsword.minstrel.nav.AlbumDetail
|
||||
import com.fabledsword.minstrel.nav.ArtistDetail
|
||||
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsButton
|
||||
import com.fabledsword.minstrel.shared.widgets.track_actions.TrackActionsViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SearchScreen(
|
||||
navController: NavHostController,
|
||||
viewModel: SearchViewModel = hiltViewModel(),
|
||||
trackActionsViewModel: TrackActionsViewModel = hiltViewModel(),
|
||||
) {
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
LaunchedEffect(Unit) { focusRequester.requestFocus() }
|
||||
LaunchedEffect(Unit) {
|
||||
trackActionsViewModel.transientMessages.collect { msg ->
|
||||
snackbarHostState.showSnackbar(msg)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@@ -84,6 +96,7 @@ fun SearchScreen(
|
||||
},
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
) { inner ->
|
||||
Box(modifier = Modifier.fillMaxSize().padding(inner)) {
|
||||
ResultsPane(
|
||||
@@ -91,6 +104,8 @@ fun SearchScreen(
|
||||
onArtistClick = { id -> navController.navigate(ArtistDetail(id)) },
|
||||
onAlbumClick = { id -> navController.navigate(AlbumDetail(id)) },
|
||||
onTrackPlay = viewModel::playTrack,
|
||||
onNavigateToAlbum = { id -> navController.navigate(AlbumDetail(id)) },
|
||||
onNavigateToArtist = { id -> navController.navigate(ArtistDetail(id)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -126,6 +141,8 @@ private fun ResultsPane(
|
||||
onArtistClick: (String) -> Unit,
|
||||
onAlbumClick: (String) -> Unit,
|
||||
onTrackPlay: (TrackRef) -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
when (state) {
|
||||
SearchResultsState.Idle -> CenteredHint("Type to search your library.")
|
||||
@@ -135,7 +152,14 @@ private fun ResultsPane(
|
||||
if (state.response.isEmpty) {
|
||||
CenteredHint("No matches for that query.")
|
||||
} else {
|
||||
ResultsList(state.response, onArtistClick, onAlbumClick, onTrackPlay)
|
||||
ResultsList(
|
||||
response = state.response,
|
||||
onArtistClick = onArtistClick,
|
||||
onAlbumClick = onAlbumClick,
|
||||
onTrackPlay = onTrackPlay,
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +171,8 @@ private fun ResultsList(
|
||||
onArtistClick: (String) -> Unit,
|
||||
onAlbumClick: (String) -> Unit,
|
||||
onTrackPlay: (TrackRef) -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
@@ -154,7 +180,7 @@ private fun ResultsList(
|
||||
) {
|
||||
artistsSection(response.artists, onArtistClick)
|
||||
albumsSection(response.albums, onAlbumClick)
|
||||
tracksSection(response.tracks, onTrackPlay)
|
||||
tracksSection(response.tracks, onTrackPlay, onNavigateToAlbum, onNavigateToArtist)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,20 +219,66 @@ private fun LazyListScope.albumsSection(
|
||||
private fun LazyListScope.tracksSection(
|
||||
tracks: List<TrackRef>,
|
||||
onTrackPlay: (TrackRef) -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
if (tracks.isEmpty()) return
|
||||
item { SectionHeader("Tracks") }
|
||||
items(items = tracks, key = { "trk-${it.id}" }) { track ->
|
||||
TextRow(
|
||||
primary = track.title,
|
||||
secondary = track.artistName.takeIf { it.isNotEmpty() }
|
||||
?: track.albumTitle.takeIf { it.isNotEmpty() },
|
||||
TrackResultRow(
|
||||
track = track,
|
||||
onClick = { onTrackPlay(track) },
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TrackResultRow(
|
||||
track: TrackRef,
|
||||
onClick: () -> Unit,
|
||||
onNavigateToAlbum: (String) -> Unit,
|
||||
onNavigateToArtist: (String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(enabled = track.streamUrl.isNotEmpty(), onClick = onClick)
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
TrackCoverThumb(coverUrl = track.coverUrl, contentDescription = track.title)
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = track.title,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
val secondary = track.artistName.takeIf { it.isNotEmpty() }
|
||||
?: track.albumTitle.takeIf { it.isNotEmpty() }
|
||||
if (secondary != null) {
|
||||
Text(
|
||||
text = secondary,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
TrackActionsButton(
|
||||
track = track,
|
||||
onNavigateToAlbum = onNavigateToAlbum,
|
||||
onNavigateToArtist = onNavigateToArtist,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SectionHeader(text: String) {
|
||||
Text(
|
||||
|
||||
Reference in New Issue
Block a user