feat(playlists): show playlist cover in the "add to playlist" picker (web + Android)
The picker listed playlists with a generic list icon; now each row shows the playlist's cover art (falling back to the icon when there's none), so you can tell them apart at a glance when adding a song. - web (modals.js): 34px cover thumbnail per row. - android (PlaylistPickerSheet): 40dp AsyncImage cover, coverUrl passed from AppNavigation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
1775ec5b9b
commit
17a28b3011
3 files changed
+28
-3
No files matched your search
@@ -464,6 +464,7 @@ fun AppNavigation() {
|
|||||||
PlaylistPickerSheet(
|
PlaylistPickerSheet(
|
||||||
song = song,
|
song = song,
|
||||||
loadPlaylists = { repo.getPlaylists() },
|
loadPlaylists = { repo.getPlaylists() },
|
||||||
|
coverUrl = { id -> coverUrl(id) },
|
||||||
onAdd = { pl ->
|
onAdd = { pl ->
|
||||||
playlistPickerSong = null
|
playlistPickerSong = null
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.novasonic.app.ui.component
|
package com.novasonic.app.ui.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.QueueMusic
|
import androidx.compose.material.icons.automirrored.filled.QueueMusic
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
@@ -11,9 +13,12 @@ import androidx.compose.material3.*
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import coil.compose.AsyncImage
|
||||||
import com.novasonic.app.api.model.Playlist
|
import com.novasonic.app.api.model.Playlist
|
||||||
import com.novasonic.app.api.model.Song
|
import com.novasonic.app.api.model.Song
|
||||||
import com.novasonic.app.ui.theme.*
|
import com.novasonic.app.ui.theme.*
|
||||||
@@ -23,6 +28,7 @@ import com.novasonic.app.ui.theme.*
|
|||||||
fun PlaylistPickerSheet(
|
fun PlaylistPickerSheet(
|
||||||
song: Song,
|
song: Song,
|
||||||
loadPlaylists: suspend () -> List<Playlist>,
|
loadPlaylists: suspend () -> List<Playlist>,
|
||||||
|
coverUrl: (String?) -> String?,
|
||||||
onAdd: (Playlist) -> Unit,
|
onAdd: (Playlist) -> Unit,
|
||||||
onCreate: (String) -> Unit,
|
onCreate: (String) -> Unit,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
@@ -117,8 +123,22 @@ fun PlaylistPickerSheet(
|
|||||||
.padding(horizontal = 20.dp, vertical = 14.dp),
|
.padding(horizontal = 20.dp, vertical = 14.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Icon(Icons.AutoMirrored.Filled.QueueMusic, null,
|
val cv = coverUrl(pl.coverArt)
|
||||||
tint = NsOnSurface2, modifier = Modifier.size(20.dp))
|
Box(
|
||||||
|
Modifier.size(40.dp).clip(RoundedCornerShape(6.dp)).background(NsSurface2),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
if (cv != null) {
|
||||||
|
AsyncImage(
|
||||||
|
model = cv, contentDescription = null,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Icon(Icons.AutoMirrored.Filled.QueueMusic, null,
|
||||||
|
tint = NsOnSurface2, modifier = Modifier.size(20.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
Spacer(Modifier.width(14.dp))
|
Spacer(Modifier.width(14.dp))
|
||||||
Text(
|
Text(
|
||||||
pl.name,
|
pl.name,
|
||||||
|
|||||||
+5
-1
@@ -87,7 +87,11 @@ export async function openPlModal(songs) {
|
|||||||
}
|
}
|
||||||
S.cachedPlaylists.forEach(pl => {
|
S.cachedPlaylists.forEach(pl => {
|
||||||
const row = document.createElement('div'); row.className = 'pl-row';
|
const row = document.createElement('div'); row.className = 'pl-row';
|
||||||
row.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/></svg>
|
const cv = pl.coverArt ? coverUrl(pl.coverArt, 96) : null;
|
||||||
|
const inner = cv
|
||||||
|
? `<img src="${cv}" alt="" style="width:100%;height:100%;object-fit:cover" onerror="this.remove()">`
|
||||||
|
: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/></svg>';
|
||||||
|
row.innerHTML = `<span style="width:34px;height:34px;border-radius:6px;flex-shrink:0;background:var(--surface2);display:flex;align-items:center;justify-content:center;overflow:hidden;color:var(--text3)">${inner}</span>
|
||||||
<span>${esc(pl.name)}</span><span style="margin-left:auto;font-size:11px;color:var(--text3)">${pl.songCount} Titel</span>`;
|
<span>${esc(pl.name)}</span><span style="margin-left:auto;font-size:11px;color:var(--text3)">${pl.songCount} Titel</span>`;
|
||||||
row.onclick = () => addSongsToPlaylist(pl.id, pl.name);
|
row.onclick = () => addSongsToPlaylist(pl.id, pl.name);
|
||||||
list.appendChild(row);
|
list.appendChild(row);
|
||||||
|
|||||||
Reference in new issue
Block a user