Files
ReelShort/lib/core/widgets/remote_image.dart
T

79 lines
2.2 KiB
Dart

// Author: fruit.com.cn
import 'package:flutter/material.dart';
import '../config/app_config.dart';
import '../theme/app_colors.dart';
/// 封面图统一入口:后端给的是相对路径,这里补服务地址并处理加载失败。
class RemoteImage extends StatelessWidget {
const RemoteImage(
this.path, {
super.key,
this.width,
this.height,
this.fit = BoxFit.cover,
this.showFallbackIcon = false,
this.fallbackIconKey,
this.fallbackAspectRatio,
this.fallbackColor = AppColors.raised,
});
final String path;
final double? width;
final double? height;
final BoxFit fit;
final bool showFallbackIcon;
final Key? fallbackIconKey;
final double? fallbackAspectRatio;
final Color fallbackColor;
@override
Widget build(BuildContext context) {
final url = AppConfig.mediaUrl(path);
if (url.isEmpty) return _fallback(brand: showFallbackIcon);
return Image.network(
url,
width: width,
height: height,
fit: fit,
gaplessPlayback: true,
errorBuilder: (_, _, _) => _fallback(brand: showFallbackIcon),
frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
if (wasSynchronouslyLoaded || frame != null) return child;
return _fallback(brand: showFallbackIcon);
},
);
}
Widget _fallback({required bool brand}) {
final mark = brand
? LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth.isFinite
? constraints.maxWidth
: 120.0;
return Center(
child: Image.asset(
'assets/icon/splash_logo.png',
key: fallbackIconKey,
width: width * 0.72,
fit: BoxFit.contain,
),
);
},
)
: null;
final fallback = Container(
width: width,
height: height,
color: brand ? AppColors.mediaBlack : fallbackColor,
alignment: Alignment.center,
child: mark,
);
final ratio = fallbackAspectRatio;
if (ratio == null) return fallback;
return AspectRatio(aspectRatio: ratio, child: fallback);
}
}