pikapika/lib/screens/components/Images.dart

366 lines
9.2 KiB
Dart
Raw Normal View History

2021-11-06 11:25:44 +00:00
import 'dart:typed_data';
2021-09-29 23:57:09 +00:00
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
2021-11-12 05:41:26 +00:00
import 'package:pikapika/basic/Common.dart';
import 'package:pikapika/basic/Cross.dart';
2021-11-11 03:00:38 +00:00
import 'package:pikapika/basic/Method.dart';
2021-09-29 23:57:09 +00:00
import 'package:flutter_svg/svg.dart';
2021-11-11 03:00:38 +00:00
import 'package:pikapika/basic/config/ConvertToPNG.dart';
2021-11-30 11:34:26 +00:00
import 'package:pikapika/basic/config/ImageAddress.dart';
2021-09-29 23:57:09 +00:00
import 'dart:io';
import 'dart:ui' as ui show Codec;
2021-11-12 05:41:26 +00:00
import '../FilePhotoViewScreen.dart';
2021-11-06 11:25:44 +00:00
Future<Uint8List> _loadImageFile(String path) {
if (convertToPNG()) {
return method.convertToPNG(path);
}
return File(path).readAsBytes();
}
2021-09-29 23:57:09 +00:00
// 从本地加载图片
2021-11-06 11:25:44 +00:00
class ResourceFileImageProvider
extends ImageProvider<ResourceFileImageProvider> {
2021-09-29 23:57:09 +00:00
final String path;
final double scale;
2021-11-06 07:01:25 +00:00
ResourceFileImageProvider(this.path, {this.scale = 1.0});
2021-09-29 23:57:09 +00:00
@override
2021-11-06 11:25:44 +00:00
ImageStreamCompleter load(
ResourceFileImageProvider key, DecoderCallback decode) {
2021-09-29 23:57:09 +00:00
return MultiFrameImageStreamCompleter(
codec: _loadAsync(key),
scale: key.scale,
);
}
@override
2021-11-06 11:25:44 +00:00
Future<ResourceFileImageProvider> obtainKey(
ImageConfiguration configuration) {
2021-11-06 07:01:25 +00:00
return SynchronousFuture<ResourceFileImageProvider>(this);
2021-09-29 23:57:09 +00:00
}
2021-11-06 07:01:25 +00:00
Future<ui.Codec> _loadAsync(ResourceFileImageProvider key) async {
2021-09-29 23:57:09 +00:00
assert(key == this);
return PaintingBinding.instance!
2021-11-06 11:25:44 +00:00
.instantiateImageCodec(await _loadImageFile(path));
2021-09-29 23:57:09 +00:00
}
@override
bool operator ==(dynamic other) {
if (other.runtimeType != runtimeType) return false;
2021-11-06 07:01:25 +00:00
final ResourceFileImageProvider typedOther = other;
2021-09-29 23:57:09 +00:00
return path == typedOther.path && scale == typedOther.scale;
}
@override
int get hashCode => hashValues(path, scale);
@override
String toString() => '$runtimeType('
'path: ${describeIdentity(path)},'
' scale: $scale'
')';
}
// 从本地加载图片
2021-11-06 07:01:25 +00:00
class ResourceDownloadFileImageProvider
extends ImageProvider<ResourceDownloadFileImageProvider> {
2021-09-29 23:57:09 +00:00
final String path;
final double scale;
2021-11-06 07:01:25 +00:00
ResourceDownloadFileImageProvider(this.path, {this.scale = 1.0});
2021-09-29 23:57:09 +00:00
@override
ImageStreamCompleter load(
2021-11-06 07:01:25 +00:00
ResourceDownloadFileImageProvider key, DecoderCallback decode) {
2021-09-29 23:57:09 +00:00
return MultiFrameImageStreamCompleter(
codec: _loadAsync(key),
scale: key.scale,
);
}
@override
2021-11-06 07:01:25 +00:00
Future<ResourceDownloadFileImageProvider> obtainKey(
2021-09-29 23:57:09 +00:00
ImageConfiguration configuration) {
2021-11-06 07:01:25 +00:00
return SynchronousFuture<ResourceDownloadFileImageProvider>(this);
2021-09-29 23:57:09 +00:00
}
2021-11-06 07:01:25 +00:00
Future<ui.Codec> _loadAsync(ResourceDownloadFileImageProvider key) async {
2021-09-29 23:57:09 +00:00
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;
2021-11-06 07:01:25 +00:00
final ResourceDownloadFileImageProvider typedOther = other;
2021-09-29 23:57:09 +00:00
return path == typedOther.path && scale == typedOther.scale;
}
@override
int get hashCode => hashValues(path, scale);
@override
String toString() => '$runtimeType('
'path: ${describeIdentity(path)},'
' scale: $scale'
')';
}
2021-12-05 13:13:24 +00:00
// 从远端加载图片
2021-11-06 11:25:44 +00:00
class ResourceRemoteImageProvider
extends ImageProvider<ResourceRemoteImageProvider> {
2021-09-29 23:57:09 +00:00
final String fileServer;
final String path;
final double scale;
2021-11-06 07:01:25 +00:00
ResourceRemoteImageProvider(this.fileServer, this.path, {this.scale = 1.0});
2021-09-29 23:57:09 +00:00
@override
ImageStreamCompleter load(
2021-11-06 07:01:25 +00:00
ResourceRemoteImageProvider key, DecoderCallback decode) {
2021-09-29 23:57:09 +00:00
return MultiFrameImageStreamCompleter(
codec: _loadAsync(key),
scale: key.scale,
);
}
@override
2021-11-06 11:25:44 +00:00
Future<ResourceRemoteImageProvider> obtainKey(
ImageConfiguration configuration) {
2021-11-06 07:01:25 +00:00
return SynchronousFuture<ResourceRemoteImageProvider>(this);
2021-09-29 23:57:09 +00:00
}
2021-11-06 07:01:25 +00:00
Future<ui.Codec> _loadAsync(ResourceRemoteImageProvider key) async {
2021-09-29 23:57:09 +00:00
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;
2021-11-06 07:01:25 +00:00
final ResourceRemoteImageProvider typedOther = other;
2021-09-29 23:57:09 +00:00
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<StatefulWidget> createState() => _DownloadImageState();
}
class _DownloadImageState extends State<DownloadImage> {
2022-03-17 03:31:25 +00:00
late final Future<String> _future = method.downloadImagePath(widget.path);
2021-09-29 23:57:09 +00:00
@override
Widget build(BuildContext context) {
2021-11-12 05:41:26 +00:00
return pathFutureImage(
_future,
widget.width,
widget.height,
context: context,
);
2021-09-29 23:57:09 +00:00
}
}
// 远端图片
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<StatefulWidget> createState() => _RemoteImageState();
}
class _RemoteImageState extends State<RemoteImage> {
late bool _mock;
late Future<String> _future;
@override
void initState() {
2021-11-30 11:34:26 +00:00
_mock = widget.fileServer == "" ||
(widget.fileServer.contains(".xyz/") && currentImageAddress() < 0);
2021-09-29 23:57:09 +00:00
if (!_mock) {
_future = method
.remoteImageData(widget.fileServer, widget.path)
.then((value) => value.finalPath);
}
super.initState();
}
@override
Widget build(BuildContext context) {
if (_mock) {
return buildMock(widget.width, widget.height);
}
2021-11-12 05:41:26 +00:00
return pathFutureImage(
_future,
widget.width,
widget.height,
fit: widget.fit,
context: context,
);
2021-09-29 23:57:09 +00:00
}
}
2021-11-12 05:41:26 +00:00
Widget pathFutureImage(Future<String> future, double? width, double? height,
{BoxFit fit = BoxFit.cover, BuildContext? context}) {
return FutureBuilder(
future: future,
builder: (BuildContext context, AsyncSnapshot<String> 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,
);
});
}
2021-09-29 23:57:09 +00:00
// 通用方法
Widget buildSvg(String source, double? width, double? height,
{Color? color, double? margin}) {
2021-11-12 05:41:26 +00:00
var widget = Container(
2021-09-29 23:57:09 +00:00
width: width,
height: height,
2022-03-17 03:31:25 +00:00
padding: margin != null ? const EdgeInsets.all(10) : null,
2021-09-29 23:57:09 +00:00
child: Center(
child: SvgPicture.asset(
source,
width: width,
height: height,
color: color,
),
),
);
2021-11-12 05:41:26 +00:00
return GestureDetector(onLongPress: () {}, child: widget);
2021-09-29 23:57:09 +00:00
}
Widget buildMock(double? width, double? height) {
2021-11-12 05:41:26 +00:00
var widget = Container(
2021-09-29 23:57:09 +00:00
width: width,
height: height,
2022-03-19 04:12:27 +00:00
padding: const EdgeInsets.all(10),
2021-09-29 23:57:09 +00:00
child: Center(
child: SvgPicture.asset(
'lib/assets/unknown.svg',
width: width,
height: height,
color: Colors.grey.shade600,
),
),
);
2021-11-12 05:41:26 +00:00
return GestureDetector(onLongPress: () {}, child: widget);
2021-09-29 23:57:09 +00:00
}
Widget buildError(double? width, double? height) {
return Image(
image: AssetImage('lib/assets/error.png'),
width: width,
height: height,
);
}
Widget buildLoading(double? width, double? height) {
2021-10-13 13:57:35 +00:00
double? size;
if (width != null && height != null) {
size = width < height ? width : height;
}
2022-03-17 03:31:25 +00:00
return SizedBox(
2021-09-29 23:57:09 +00:00
width: width,
height: height,
child: Center(
child: Icon(
Icons.downloading,
2021-10-13 13:57:35 +00:00
size: size,
2021-09-29 23:57:09 +00:00
color: Colors.black12,
),
),
);
}
Widget buildFile(String file, double? width, double? height,
2021-11-12 05:41:26 +00:00
{BoxFit fit = BoxFit.cover, BuildContext? context}) {
var image = Image(
2021-11-06 07:01:25 +00:00
image: ResourceFileImageProvider(file),
2021-09-29 23:57:09 +00:00
width: width,
height: height,
errorBuilder: (a, b, c) {
print("$b");
print("$c");
return buildError(width, height);
},
fit: fit,
);
2021-11-12 05:41:26 +00:00
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 '保存图片':
saveImage(file, context);
break;
}
},
child: image,
);
2021-09-29 23:57:09 +00:00
}