Fix: Review-Findings korrigiert (Tag-Leiste, Profil, Singleton u.a.)

CRIT:
- Tag-Leiste: Toggle-Kopf 'Tags & Filter' eingebaut (war unerreichbar) + TagStats
- Profil: Cloud-Count vor Dialog aufloesen (kein 'Instance of Future' mehr)
HIGH:
- CloudEinstellungen: toten Sync-Timer entfernt (echter Timer im ViewModel)
- StatistikCard + RecentWidget jetzt eingebaut (gesamtMB/gesamtMin endlich genutzt)
- CloudService als Singleton (konsistenter Token-Zustand in allen Services)
MED/LOW:
- Playlist-Erkennung nur noch via list= Parameter
- Player: fehlende Quelle wird geloggt statt still
- song_tile: null-ID-Guard vor Tag-Dialog
- Scanner-Log mit Exception-Objekt
- FavoritenService: anzahlFavoriten() fuer StatistikCard
This commit is contained in:
Hermes (Server)
2026-07-31 15:42:54 +02:00
parent b3aedc53f9
commit 8b6a04ead8
18 changed files with 767 additions and 503 deletions
+50 -5
View File
@@ -8,9 +8,12 @@ import '../models/playlist.dart';
import '../utils/farb_theme.dart';
import '../utils/user_effekte.dart';
import '../services/cloud_service.dart';
import '../services/favoriten_service.dart';
import '../widgets/mini_player.dart';
import '../widgets/melo_header.dart';
import '../widgets/statistik_card.dart';
import '../widgets/recent_widget.dart';
import '../widgets/tag_stats_widget.dart';
import '../widgets/tag_leiste.dart';
import '../widgets/song_tile.dart';
import '../widgets/navidrome_browser.dart';
@@ -35,6 +38,7 @@ class _MeloHomeState extends State<MeloHome> {
int _aktiverTab = 0;
String _nutzer = 'Baka'; // Aktueller Nutzer
final Future<int> _favoritenZahl = FavoritenService().anzahlFavoriten();
@override
void initState() {
@@ -106,6 +110,8 @@ class _MeloHomeState extends State<MeloHome> {
Future<void> _zeigeProfil() async {
final p = await SharedPreferences.getInstance();
final modus = p.getString('melo_modus') ?? 'cloud';
// Cloud-Count VOR dem Dialog auflösen (sonst stünde "Instance of Future" da)
final cloudCount = await _cloud.status();
if (!mounted) return;
showDialog(
context: context,
@@ -120,7 +126,7 @@ class _MeloHomeState extends State<MeloHome> {
mainAxisSize: MainAxisSize.min,
children: [
_profilZeile(Icons.music_note, 'Lieder auf Gerät', '${_vm.songs.length}'),
_profilZeile(Icons.cloud, 'Cloud-Server', '${_cloud.status().then((s) => s?['total'] ?? 0)}'),
_profilZeile(Icons.cloud, 'Cloud-Server', '${cloudCount?['total'] ?? 0}'),
const Divider(color: MeloTheme.dunkel2),
// Später von "nur lokal" auf Cloud wechseln jederzeit möglich
if (modus == 'lokal') ...[
@@ -543,6 +549,16 @@ class _MeloHomeState extends State<MeloHome> {
MeloHeader(onDownload: _zeigeDownloadDialog, onSearch: _zeigeSuche, onServer: _zeigeProfil, onSettings: _zeigeEinstellungen),
if (_vm.zeigeBotschaft) _botschaftBanner(),
_tagBereich(),
FutureBuilder<int>(
future: _favoritenZahl,
builder: (context, snap) => StatistikCard(
anzahlSongs: _vm.songs.length,
gesamtMB: gesamtMB,
gesamtMin: gesamtMin,
anzahlFavoriten: snap.data ?? 0,
),
),
RecentWidget(songs: _vm.letzteSongs, onPlay: _vm.spieleSong),
Expanded(child: _songListe()),
const MiniPlayer(),
const SizedBox(height: 8),
@@ -803,13 +819,42 @@ class _MeloHomeState extends State<MeloHome> {
Widget _tagBereich() {
return AnimatedSize(
duration: const Duration(milliseconds: 200),
child: _tagsOffen
? TagLeiste(
child: Column(
children: [
// Toggle-Kopf: Tag-Leiste ein-/ausklappen (war vorher unerreichbar!)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
Icon(Icons.label_outline,
size: 14, color: MeloTheme.textSekundaer),
const SizedBox(width: 6),
Text('Tags & Filter',
style: const TextStyle(
color: MeloTheme.textSekundaer, fontSize: 12)),
const Spacer(),
IconButton(
visualDensity: VisualDensity.compact,
icon: Icon(
_tagsOffen ? Icons.expand_less : Icons.expand_more,
size: 18,
color: MeloTheme.textSekundaer),
onPressed: () => setState(() => _tagsOffen = !_tagsOffen),
),
],
),
),
if (_tagsOffen) ...[
TagLeiste(
tags: _vm.tags,
aktiveTags: _vm.aktiveTags,
onTagToggled: _vm.toggleTag,
)
: const SizedBox.shrink(),
),
const SizedBox(height: 8),
TagStatsWidget(tagCounts: _vm.tagCounts),
],
],
),
);
}