Added Features: - Created NowPlayingScreen for proper remote playback control - Shows album artwork, track info, player controls - Volume control, shuffle/repeat toggles - Player status display - Queue navigation button Fixed Loading Issues: - Convert AlbumRow to StatefulWidget to prevent infinite reloading - Future now created once in initState(), not on every rebuild - Fixes "loading forever" issue caused by provider polling triggering rebuilds - Convert LibraryStats to StatefulWidget with same fix - Remove animated loading bar from mini player - Replaced with simple status indicator bar Fixed Player Selection: - Player selection now STICKY - won't auto-switch to other players - Once a player is selected, it stays selected - Only auto-selects when NO player is currently selected - Fixes issue where app showed wrong track info (Beatles on all speakers) - Mini player now navigates to NowPlayingScreen instead of QueueScreen Player State Polling: - Continues to poll every 2 seconds for current track updates - Properly updates selected player state - Auto-advance should now work as Music Assistant handles it server-side This should resolve: 1. ✅ Now playing bar opens proper player screen 2. ✅ Home page no longer loading forever 3. ✅ Wrong player/track info fixed (sticky selection) 4. ✅ Loading bar no longer "always thinking" 5. ✅ Auto-advance (Music Assistant handles this, app just polls for updates)
117 lines
2.8 KiB
Dart
117 lines
2.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
class LibraryStats extends StatefulWidget {
|
|
final Future<Map<String, int>> Function() loadStats;
|
|
|
|
const LibraryStats({
|
|
super.key,
|
|
required this.loadStats,
|
|
});
|
|
|
|
@override
|
|
State<LibraryStats> createState() => _LibraryStatsState();
|
|
}
|
|
|
|
class _LibraryStatsState extends State<LibraryStats> {
|
|
late Future<Map<String, int>> _statsFuture;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_statsFuture = widget.loadStats();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FutureBuilder<Map<String, int>>(
|
|
future: _statsFuture,
|
|
builder: (context, snapshot) {
|
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
return const Center(
|
|
child: Padding(
|
|
padding: EdgeInsets.all(16.0),
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
);
|
|
}
|
|
|
|
final stats = snapshot.data ?? {'artists': 0, 'albums': 0, 'tracks': 0};
|
|
|
|
return Container(
|
|
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
|
padding: const EdgeInsets.all(16.0),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[900],
|
|
borderRadius: BorderRadius.circular(12.0),
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: [
|
|
_StatItem(
|
|
icon: Icons.person,
|
|
label: 'Artists',
|
|
count: stats['artists'] ?? 0,
|
|
),
|
|
_StatItem(
|
|
icon: Icons.album,
|
|
label: 'Albums',
|
|
count: stats['albums'] ?? 0,
|
|
),
|
|
_StatItem(
|
|
icon: Icons.music_note,
|
|
label: 'Tracks',
|
|
count: stats['tracks'] ?? 0,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class _StatItem extends StatelessWidget {
|
|
final IconData icon;
|
|
final String label;
|
|
final int count;
|
|
|
|
const _StatItem({
|
|
required this.icon,
|
|
required this.label,
|
|
required this.count,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(icon, size: 32, color: Colors.blue[400]),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
_formatCount(count),
|
|
style: const TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
label,
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: Colors.grey[400],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
String _formatCount(int count) {
|
|
if (count >= 1000) {
|
|
return '${(count / 1000).toStringAsFixed(1)}k';
|
|
}
|
|
return count.toString();
|
|
}
|
|
}
|