// lib/widgets/song_artwork.dart import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/material.dart'; /// 歌曲封面:优先进内存字节,其次本地封面文件,最后回退图标。 /// /// 列表页一次会构建几十行,这里用 `existsSync` 判断一次即可, /// 图片本身由 Flutter 按需解码。 class SongArtwork extends StatelessWidget { final Uint8List? bytes; final String? filePath; final double size; final IconData fallbackIcon; final Color? fallbackColor; const SongArtwork({ super.key, this.bytes, this.filePath, this.size = 44, this.fallbackIcon = Icons.music_note, this.fallbackColor, }); @override Widget build(BuildContext context) { Widget child; if (bytes != null && bytes!.isNotEmpty) { child = Image.memory( bytes!, width: size, height: size, fit: BoxFit.cover, gaplessPlayback: true, errorBuilder: (_, __, ___) => _fallback(), ); } else if (filePath != null && filePath!.isNotEmpty && File(filePath!).existsSync()) { child = Image.file( File(filePath!), width: size, height: size, fit: BoxFit.cover, gaplessPlayback: true, errorBuilder: (_, __, ___) => _fallback(), ); } else { child = _fallback(); } return ClipRRect( borderRadius: BorderRadius.circular(6), child: SizedBox(width: size, height: size, child: child), ); } Widget _fallback() { return Container( width: size, height: size, color: const Color(0xFF232928), child: Icon( fallbackIcon, size: size * 0.55, color: fallbackColor ?? const Color(0xFFB8D4D0), ), ); } }