🎤 Feature B: Artist-Browse UI (Phase 2, Part 3/3)
- Toggle-Buttons in Navidrome-Tab: "📀 Alben" ↔ "🎤 Künstler" - Artist-Liste zeigt Namen pro Künstler, Tap lädt alle Songs des Künstlers - _playArtist() Methode lädt Künstler-Songs via getArtistSongs() API - Albums/Artists sind Lazy-Loaded (nur beim Toggle laden) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XJzQjUtnvYUtHdnTs3iCru
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
2548e38af9
commit
3068bbdabb
@@ -253,7 +253,9 @@ class _NavidromeTab extends StatefulWidget {
|
||||
class _NavidromeTabState extends State<_NavidromeTab> {
|
||||
late final NavidromeService _nav = NavidromeService();
|
||||
List<SubsonicAlbum> _albums = [];
|
||||
List<SubsonicArtist> _artists = [];
|
||||
bool _loading = false;
|
||||
bool _showArtists = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -286,6 +288,23 @@ class _NavidromeTabState extends State<_NavidromeTab> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _loadArtists() async {
|
||||
if (!_nav.istVerbunden) return;
|
||||
setState(() => _loading = true);
|
||||
try {
|
||||
final artists = await _nav.getArtists();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_artists = artists;
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) setState(() => _loading = false);
|
||||
debugPrint('Fehler beim Laden der Künstler: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!_nav.istVerbunden) {
|
||||
@@ -331,8 +350,59 @@ class _NavidromeTabState extends State<_NavidromeTab> {
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: FilledButton(
|
||||
onPressed: () => setState(() {
|
||||
_showArtists = false;
|
||||
if (_albums.isEmpty) _loadAlbums();
|
||||
}),
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: !_showArtists ? Colors.redAccent : Colors.grey.shade700,
|
||||
),
|
||||
child: const Text('📀 Alben'),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: FilledButton(
|
||||
onPressed: () => setState(() {
|
||||
_showArtists = true;
|
||||
if (_artists.isEmpty) _loadArtists();
|
||||
}),
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: _showArtists ? Colors.redAccent : Colors.grey.shade700,
|
||||
),
|
||||
child: const Text('🎤 Künstler'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _showArtists
|
||||
? ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
itemCount: _artists.length,
|
||||
itemBuilder: (context, i) {
|
||||
final artist = _artists[i];
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
child: ListTile(
|
||||
leading: const Icon(Icons.person, size: 48),
|
||||
title: Text(artist.name),
|
||||
onTap: () => _playArtist(artist),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
itemCount: _albums.length,
|
||||
itemBuilder: (context, i) {
|
||||
final album = _albums[i];
|
||||
@@ -350,6 +420,9 @@ class _NavidromeTabState extends State<_NavidromeTab> {
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -387,4 +460,33 @@ class _NavidromeTabState extends State<_NavidromeTab> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _playArtist(SubsonicArtist artist) async {
|
||||
final handler = context.read<MeloAudioHandler>();
|
||||
try {
|
||||
final songs = await _nav.getArtistSongs(artist.id);
|
||||
if (songs.isEmpty) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Künstler hat keine Songs')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
final items = songs
|
||||
.map((s) => MediaItem(
|
||||
id: _nav.streamUrl(s.id).toString(),
|
||||
title: s.titel,
|
||||
artist: s.kuenstler,
|
||||
album: s.album,
|
||||
duration: Duration(seconds: s.dauerSekunden),
|
||||
))
|
||||
.toList();
|
||||
await handler.loadPlaylist(items);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Fehler: $e')),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user