import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/svg.dart'; import 'dart:io'; import 'dart:ui' as ui show Codec; import '../../basic/Common.dart'; import '../../basic/Method.dart'; import '../FilePhotoViewScreen.dart'; // 从本地加载图片 class ResourceFileImageProvider extends ImageProvider { final String path; final double scale; ResourceFileImageProvider(this.path, {this.scale = 1.0}); @override ImageStreamCompleter loadBuffer( ResourceFileImageProvider key, DecoderBufferCallback decode) { return MultiFrameImageStreamCompleter( codec: _loadAsync(key), scale: key.scale, ); } @override Future obtainKey( ImageConfiguration configuration) { return SynchronousFuture(this); } Future _loadAsync(ResourceFileImageProvider key) async { assert(key == this); return PaintingBinding.instance .instantiateImageCodecFromBuffer(await ImmutableBuffer.fromUint8List(await File(path).readAsBytes())); } @override bool operator ==(dynamic other) { if (other.runtimeType != runtimeType) return false; final ResourceFileImageProvider typedOther = other; return path == typedOther.path && scale == typedOther.scale; } @override int get hashCode => Object.hash(path, scale); @override String toString() => '$runtimeType(' 'path: ${describeIdentity(path)},' ' scale: $scale' ')'; } // 从本地加载图片 // class ResourceDownloadFileImageProvider // extends ImageProvider { // final String path; // final double scale; // // ResourceDownloadFileImageProvider(this.path, {this.scale = 1.0}); // // @override // ImageStreamCompleter load( // ResourceDownloadFileImageProvider key, DecoderCallback decode) { // return MultiFrameImageStreamCompleter( // codec: _loadAsync(key), // scale: key.scale, // ); // } // // @override // Future obtainKey( // ImageConfiguration configuration) { // return SynchronousFuture(this); // } // // Future _loadAsync(ResourceDownloadFileImageProvider key) async { // assert(key == this); // return PaintingBinding.instance!.instantiateImageCodec( // await File(await method.downloadImagePath(path)).readAsBytes()); // } // // @override // bool operator ==(dynamic other) { // if (other.runtimeType != runtimeType) return false; // final ResourceDownloadFileImageProvider typedOther = other; // return path == typedOther.path && scale == typedOther.scale; // } // // @override // int get hashCode => hashValues(path, scale); // // @override // String toString() => '$runtimeType(' // 'path: ${describeIdentity(path)},' // ' scale: $scale' // ')'; // } // 从远端加载图片 // class ResourceRemoteImageProvider // extends ImageProvider { // final String fileServer; // final String path; // final double scale; // // ResourceRemoteImageProvider(this.fileServer, this.path, {this.scale = 1.0}); // // @override // ImageStreamCompleter load( // ResourceRemoteImageProvider key, DecoderCallback decode) { // return MultiFrameImageStreamCompleter( // codec: _loadAsync(key), // scale: key.scale, // ); // } // // @override // Future obtainKey( // ImageConfiguration configuration) { // return SynchronousFuture(this); // } // // Future _loadAsync(ResourceRemoteImageProvider key) async { // assert(key == this); // var downloadTo = await method.remoteImageData(fileServer, path); // return PaintingBinding.instance! // .instantiateImageCodec(await File(downloadTo.finalPath).readAsBytes()); // } // // @override // bool operator ==(dynamic other) { // if (other.runtimeType != runtimeType) return false; // final ResourceRemoteImageProvider typedOther = other; // return fileServer == typedOther.fileServer && // path == typedOther.path && // scale == typedOther.scale; // } // // @override // int get hashCode => hashValues(fileServer, path, scale); // // @override // String toString() => '$runtimeType(' // 'fileServer: ${describeIdentity(fileServer)},' // ' path: ${describeIdentity(path)},' // ' scale: $scale' // ')'; // } // 下载的图片 // class DownloadImage extends StatefulWidget { // final String path; // final double? width; // final double? height; // // const DownloadImage({ // Key? key, // required this.path, // this.width, // this.height, // }) : super(key: key); // // @override // State createState() => _DownloadImageState(); // } // // class _DownloadImageState extends State { // late final Future _future = method.downloadImagePath(widget.path); // // @override // Widget build(BuildContext context) { // return pathFutureImage( // _future, // widget.width, // widget.height, // context: context, // ); // } // } // 远端图片 class RemoteImage extends StatefulWidget { final String fileServer; final String path; final double? width; final double? height; final BoxFit fit; const RemoteImage({ Key? key, required this.fileServer, required this.path, this.width, this.height, this.fit = BoxFit.cover, }) : super(key: key); @override State createState() => _RemoteImageState(); } class _RemoteImageState extends State { late bool _mock; late Future _future; @override void initState() { debugPrint("path=${widget.path}"); _mock = widget.fileServer == "" || widget.path == ""; if (!_mock) { _future = method.downloadImage(widget.path, widget.fileServer).then((value) => value!); } super.initState(); } @override Widget build(BuildContext context) { // return buildMock(widget.width, widget.height); if (_mock) { return buildMock(widget.width, widget.height); } return pathFutureImage( _future, widget.width, widget.height, fit: widget.fit, context: context, ); } } Widget pathFutureImage(Future future, double? width, double? height, {BoxFit fit = BoxFit.cover, BuildContext? context}) { return FutureBuilder( future: future, builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasError) { print("${snapshot.error}"); print("${snapshot.stackTrace}"); return buildError(width, height); } if (snapshot.connectionState != ConnectionState.done) { return buildLoading(width, height); } return buildFile( snapshot.data!, width, height, fit: fit, context: context, ); }); } // 通用方法 Widget buildSvg(String source, double? width, double? height, {Color? color, double? margin}) { var widget = Container( width: width, height: height, padding: margin != null ? const EdgeInsets.all(10) : null, child: Center( child: SvgPicture.asset( source, width: width, height: height, color: color, ), ), ); return GestureDetector(onLongPress: () {}, child: widget); } Widget buildMock(double? width, double? height) { var widget = Container( width: width, height: height, padding: const EdgeInsets.all(10), child: Center( child: SvgPicture.asset( 'lib/assets/unknown.svg', width: width, height: height, color: Colors.grey.shade600, ), ), ); return GestureDetector(onLongPress: () {}, child: widget); } Widget buildError(double? width, double? height) { return Image( image: const AssetImage('lib/assets/error.png'), width: width, height: height, ); } Widget buildLoading(double? width, double? height) { double? size; if (width != null && height != null) { size = width < height ? width : height; } return SizedBox( width: width, height: height, child: Center( child: Icon( Icons.downloading, size: size, color: Colors.black12, ), ), ); } Widget buildFile(String file, double? width, double? height, {BoxFit fit = BoxFit.cover, BuildContext? context}) { var image = Image( image: ResourceFileImageProvider(file), width: width, height: height, errorBuilder: (a, b, c) { print("$b"); print("$c"); return buildError(width, height); }, fit: fit, ); if (context == null) return image; return GestureDetector( onLongPress: () async { String? choose = await chooseListDialog(context, '请选择', ['预览图片', '保存图片']); switch (choose) { case '预览图片': Navigator.of(context).push(MaterialPageRoute( builder: (context) => FilePhotoViewScreen(file), )); break; case '保存图片': //TODO: SAVE image // saveImage(file, context); break; } }, child: image, ); }