Files
Ensemble/lib/widgets/provider_icon.dart
ChrisandClaude Opus 4.5 ff34479169 feat: Provider icons and library performance optimizations
Provider Icons:
- Add provider icon overlays to series detail screen (grid/list)
- Add provider icon overlays to library playlists (grid/list)
- Add ProviderIconOverlay widget and provider manifest model

Performance Optimizations:
- Fix empty setState in SyncService listener - only rebuild on sync complete
- Add cached sorting for albums, artists, authors (avoid O(n log n) per rebuild)
- Add cached track sort keys for LetterScrollbar
- Fix image cache size mismatches (author 128px, audiobook list 128px, series 150px)
- Simplify provider toggle setState to avoid double rebuild
- Remove redundant text Hero animations from card widgets
- Defer color extraction from card tap to detail screen initState
- Increase fallback image debounce from 200ms to 400ms

Other Changes:
- Update screenshots
- Add new localizations
- Various detail screen improvements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 19:24:37 +00:00

86 lines
2.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import '../providers/music_assistant_provider.dart';
import '../services/settings_service.dart';
/// Displays a provider icon (SVG) from Music Assistant.
///
/// Shows a small icon in a rounded container, typically used as an overlay
/// on album art to indicate which provider the item comes from.
class ProviderIcon extends StatelessWidget {
/// The provider domain (e.g., "spotify", "tidal", "qobuz")
final String domain;
/// Size of the icon container
final double size;
/// Whether to use dark mode icon variant
final bool? isDark;
const ProviderIcon({
super.key,
required this.domain,
this.size = 20,
this.isDark,
});
@override
Widget build(BuildContext context) {
final maProvider = context.read<MusicAssistantProvider>();
final brightness = Theme.of(context).brightness;
final useDark = isDark ?? brightness == Brightness.dark;
final svgString = maProvider.getProviderIconSvg(domain, isDark: useDark);
if (svgString == null || svgString.isEmpty) {
return const SizedBox.shrink();
}
return SvgPicture.string(
svgString,
width: size,
height: size,
fit: BoxFit.contain,
);
}
}
/// A positioned provider icon overlay for use in Stack widgets.
///
/// Typically positioned in a corner of album art.
class ProviderIconOverlay extends StatelessWidget {
/// The provider domain (e.g., "spotify", "tidal", "qobuz")
final String domain;
/// Size of the icon container
final double size;
/// Position from the edges
final double margin;
const ProviderIconOverlay({
super.key,
required this.domain,
this.size = 20,
this.margin = 4,
});
@override
Widget build(BuildContext context) {
// Check if provider icons are enabled in settings
if (!SettingsService.getShowProviderIconsSync()) {
return const SizedBox.shrink();
}
return Positioned(
right: margin,
bottom: margin,
child: ProviderIcon(
domain: domain,
size: size,
),
);
}
}