feat: enhance album page by managing starred songs and removing unnecessary User icon
This commit is contained in:
@@ -4,10 +4,9 @@ import { useParams } from 'next/navigation';
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { Album, Song } from '@/lib/navidrome';
|
import { Album, Song } from '@/lib/navidrome';
|
||||||
import { useNavidrome } from '@/app/components/NavidromeContext';
|
import { useNavidrome } from '@/app/components/NavidromeContext';
|
||||||
import { Play, Heart, User, Plus } from 'lucide-react';
|
import { Play, Heart } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { PlusIcon } from "@radix-ui/react-icons";
|
|
||||||
import { useAudioPlayer } from '@/app/components/AudioPlayerContext'
|
import { useAudioPlayer } from '@/app/components/AudioPlayerContext'
|
||||||
import Loading from "@/app/components/loading";
|
import Loading from "@/app/components/loading";
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
@@ -20,8 +19,9 @@ export default function AlbumPage() {
|
|||||||
const [tracklist, setTracklist] = useState<Song[]>([]);
|
const [tracklist, setTracklist] = useState<Song[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [isStarred, setIsStarred] = useState(false);
|
const [isStarred, setIsStarred] = useState(false);
|
||||||
|
const [starredSongs, setStarredSongs] = useState<Set<string>>(new Set());
|
||||||
const { getAlbum, starItem, unstarItem } = useNavidrome();
|
const { getAlbum, starItem, unstarItem } = useNavidrome();
|
||||||
const { playTrack, addAlbumToQueue, playAlbum, playAlbumFromTrack, addToQueue, currentTrack } = useAudioPlayer();
|
const { playTrack, addAlbumToQueue, playAlbum, playAlbumFromTrack, currentTrack } = useAudioPlayer();
|
||||||
const api = getNavidromeAPI();
|
const api = getNavidromeAPI();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -34,6 +34,13 @@ export default function AlbumPage() {
|
|||||||
setAlbum(albumData.album);
|
setAlbum(albumData.album);
|
||||||
setTracklist(albumData.songs);
|
setTracklist(albumData.songs);
|
||||||
setIsStarred(!!albumData.album.starred);
|
setIsStarred(!!albumData.album.starred);
|
||||||
|
|
||||||
|
// Initialize starred songs state
|
||||||
|
const starredSongIds = new Set(
|
||||||
|
albumData.songs.filter(song => song.starred).map(song => song.id)
|
||||||
|
);
|
||||||
|
setStarredSongs(starredSongIds);
|
||||||
|
|
||||||
console.log(`Album found: ${albumData.album.name}`);
|
console.log(`Album found: ${albumData.album.name}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch album:', error);
|
console.error('Failed to fetch album:', error);
|
||||||
@@ -63,6 +70,26 @@ export default function AlbumPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSongStar = async (song: Song) => {
|
||||||
|
try {
|
||||||
|
const isCurrentlyStarred = starredSongs.has(song.id);
|
||||||
|
|
||||||
|
if (isCurrentlyStarred) {
|
||||||
|
await unstarItem(song.id, 'song');
|
||||||
|
setStarredSongs(prev => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
newSet.delete(song.id);
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await starItem(song.id, 'song');
|
||||||
|
setStarredSongs(prev => new Set(prev).add(song.id));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to star/unstar song:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
}
|
}
|
||||||
@@ -80,26 +107,6 @@ export default function AlbumPage() {
|
|||||||
console.error('Failed to play album from track:', error);
|
console.error('Failed to play album from track:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleAddToQueue = (song: Song) => {
|
|
||||||
if (!api) {
|
|
||||||
console.error('Navidrome API not available');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const track = {
|
|
||||||
id: song.id,
|
|
||||||
name: song.title,
|
|
||||||
url: api.getStreamUrl(song.id),
|
|
||||||
artist: song.artist,
|
|
||||||
album: song.album,
|
|
||||||
duration: song.duration,
|
|
||||||
coverArt: song.coverArt ? api.getCoverArtUrl(song.coverArt, 300) : undefined,
|
|
||||||
albumId: song.albumId,
|
|
||||||
artistId: song.artistId
|
|
||||||
};
|
|
||||||
|
|
||||||
addToQueue(track);
|
|
||||||
};
|
|
||||||
|
|
||||||
const isCurrentlyPlaying = (song: Song): boolean => {
|
const isCurrentlyPlaying = (song: Song): boolean => {
|
||||||
return currentTrack?.id === song.id;
|
return currentTrack?.id === song.id;
|
||||||
@@ -182,7 +189,6 @@ export default function AlbumPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center text-sm text-muted-foreground">
|
<div className="flex items-center text-sm text-muted-foreground">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<User className="w-3 h-3" />
|
|
||||||
<span className="truncate">{song.artist}</span>
|
<span className="truncate">{song.artist}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -194,17 +200,20 @@ export default function AlbumPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Actions */}
|
{/* Actions */}
|
||||||
<div className="flex items-center space-x-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
<div className="flex items-center space-x-2 group-hover:opacity-100 transition-opacity">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handleAddToQueue(song);
|
handleSongStar(song);
|
||||||
}}
|
}}
|
||||||
className="h-8 w-8 p-0"
|
className="h-8 w-8 p-0"
|
||||||
>
|
>
|
||||||
<Plus className="w-4 h-4" />
|
<Heart
|
||||||
|
className={`w-4 h-4 ${starredSongs.has(song.id) ? 'text-primary' : 'text-gray-500'}`}
|
||||||
|
fill={starredSongs.has(song.id) ? 'var(--primary)' : 'none'}
|
||||||
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user