wonders/lib/ui/common/controls/app_image.dart

100 lines
3.0 KiB
Dart
Raw Normal View History

2023-09-05 17:48:20 -06:00
import 'package:flutter/foundation.dart';
2022-08-29 20:38:28 -06:00
import 'package:image_fade/image_fade.dart';
import 'package:wonders/common_libs.dart';
import 'package:wonders/logic/common/retry_image.dart';
import 'package:wonders/ui/common/controls/app_loading_indicator.dart';
class AppImage extends StatefulWidget {
const AppImage({
super.key,
2022-08-29 20:38:28 -06:00
required this.image,
this.fit = BoxFit.scaleDown,
this.alignment = Alignment.center,
this.duration,
this.syncDuration,
this.distractor = false,
this.progress = false,
this.color,
this.scale,
});
2022-08-29 20:38:28 -06:00
final ImageProvider? image;
final BoxFit fit;
final Alignment alignment;
final Duration? duration;
final Duration? syncDuration;
final bool distractor;
final bool progress;
final Color? color;
final double? scale;
@override
State<AppImage> createState() => _AppImageState();
}
class _AppImageState extends State<AppImage> {
ImageProvider? _displayImage;
ImageProvider? _sourceImage;
@override
void didChangeDependencies() {
_updateImage();
super.didChangeDependencies();
}
@override
void didUpdateWidget(AppImage oldWidget) {
_updateImage();
super.didUpdateWidget(oldWidget);
}
void _updateImage() {
if (widget.image == _sourceImage) return;
_sourceImage = widget.image;
_displayImage = _capImageSize(_addRetry(_sourceImage));
}
@override
Widget build(BuildContext context) {
return ImageFade(
image: _displayImage,
fit: widget.fit,
alignment: widget.alignment,
duration: widget.duration ?? $styles.times.fast,
syncDuration: widget.syncDuration ?? 0.ms,
loadingBuilder: (_, value, ___) {
if (!widget.distractor && !widget.progress) return SizedBox();
return Center(child: AppLoadingIndicator(value: widget.progress ? value : null, color: widget.color));
},
errorBuilder: (_, __) => Container(
padding: EdgeInsets.all($styles.insets.xs),
alignment: Alignment.center,
child: LayoutBuilder(builder: (_, constraints) {
double size = min(constraints.biggest.width, constraints.biggest.height);
if (size < 16) return SizedBox();
return Icon(
Icons.image_not_supported_outlined,
color: $styles.colors.white.withOpacity(0.1),
size: min(size, $styles.insets.lg),
);
}),
),
);
}
ImageProvider? _addRetry(ImageProvider? image) {
return image == null ? image : RetryImage(image);
}
ImageProvider? _capImageSize(ImageProvider? image) {
// Disable resizing for web as it is currently single-threaded and causes the UI to lock up when resizing large images
if (kIsWeb) {
return image; // TODO: Remove this when the web engine is updated to support non-blocking image resizing
}
2022-08-29 20:38:28 -06:00
if (image == null || widget.scale == null) return image;
final MediaQueryData mq = MediaQuery.of(context);
final Size screenSize = mq.size * mq.devicePixelRatio * widget.scale!;
return ResizeImage(image, width: screenSize.width.round());
}
}