import React from 'react'; import { useTranslation } from 'react-i18next'; import { AudioLines, ChevronRight, Play, Square, X } from 'lucide-react'; import type { ColDef } from '../../utils/useTracklistColumns'; import type { SubsonicSong } from '../../api/subsonicTypes'; import { codecLabel } from '../../utils/componentHelpers/playlistDetailHelpers'; import { formatLastSeen } from '../../utils/componentHelpers/userMgmtHelpers'; import i18n from '../../i18n'; import { formatTrackTime } from '../../utils/format/formatDuration'; import StarRating from '../StarRating'; import { OpenArtistRefInline } from '../OpenArtistRefInline'; import { resolveTrackArtistRefs } from '../../utils/playback/trackArtistRefs'; export interface FavoriteSongRowCallbacks { activate: (song: SubsonicSong, index: number, e: React.MouseEvent) => void; dblOrbit: (songId: string, e: React.MouseEvent) => void; context: (song: SubsonicSong, e: React.MouseEvent) => void; mouseDownRow: (song: SubsonicSong, e: React.MouseEvent) => void; toggleSelect: (songId: string, index: number, shift: boolean) => void; play: (index: number) => void; startPreview: (song: SubsonicSong) => void; rate: (songId: string, rating: number) => void; remove: (songId: string) => void; navArtist: (artistId: string, serverId?: string) => void; navAlbum: (albumId: string, serverId?: string) => void; } interface Props { song: SubsonicSong; index: number; visibleCols: ColDef[]; gridStyle: React.CSSProperties; showBitrate: boolean; isActive: boolean; showEq: boolean; isSelected: boolean; inSelectMode: boolean; ratingValue: number; isPreviewing: boolean; previewStarted: boolean; orbitActive: boolean; cb: FavoriteSongRowCallbacks; } function FavoriteSongRow({ song, index: i, visibleCols, gridStyle, showBitrate, isActive, showEq, isSelected, inSelectMode, ratingValue, isPreviewing, previewStarted, orbitActive, cb, }: Props) { const { t } = useTranslation(); return (
cb.activate(song, i, e)} onDoubleClick={orbitActive ? e => cb.dblOrbit(song.id, e) : undefined} onContextMenu={e => cb.context(song, e)} onMouseDown={e => cb.mouseDownRow(song, e)} > {visibleCols.map(colDef => { switch (colDef.key) { case 'num': return (
{ e.stopPropagation(); cb.toggleSelect(song.id, i, e.shiftKey); }} /> {showEq ? ( ) : ( {i + 1} )}
); case 'title': return (
{song.title}
); case 'artist': return (
cb.navArtist(id, song.serverId)} as="none" linkTag="span" linkClassName="track-artist track-artist-link" separatorClassName="track-artist-sep" />
); case 'album': return (
{ if (song.albumId) { e.stopPropagation(); cb.navAlbum(song.albumId, song.serverId); } }}>{song.album}
); case 'genre': return (
{song.genre ?? '—'}
); case 'format': return (
{(song.suffix || (showBitrate && song.bitRate)) && {codecLabel(song, showBitrate)}}
); case 'rating': return cb.rate(song.id, r)} />; case 'duration': return
{formatTrackTime(song.duration)}
; case 'playCount': return (
{song.playCount ?? '—'}
); case 'lastPlayed': return (
{song.played ? formatLastSeen(song.played, i18n.language, '—') : '—'}
); case 'bpm': return (
{song.bpm && song.bpm > 0 ? song.bpm : '—'}
); case 'remove': return (
); default: return null; } })}
); } export default React.memo(FavoriteSongRow);