mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
130 lines
3.8 KiB
Dart
130 lines
3.8 KiB
Dart
import 'dart:async' show Future;
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_qjs/flutter_qjs.dart';
|
|
import 'package:venera/foundation/js_engine.dart';
|
|
import 'package:venera/network/images.dart';
|
|
import 'package:venera/utils/io.dart';
|
|
import 'base_image_provider.dart';
|
|
import 'reader_image.dart' as image_provider;
|
|
import 'package:venera/foundation/appdata.dart';
|
|
|
|
class ReaderImageProvider
|
|
extends BaseImageProvider<image_provider.ReaderImageProvider> {
|
|
/// Image provider for normal image.
|
|
const ReaderImageProvider(this.imageKey, this.sourceKey, this.cid, this.eid, this.page);
|
|
|
|
final String imageKey;
|
|
|
|
final String? sourceKey;
|
|
|
|
final String cid;
|
|
|
|
final String eid;
|
|
|
|
final int page;
|
|
|
|
@override
|
|
Future<Uint8List> load(chunkEvents, checkStop) async {
|
|
Uint8List? imageBytes;
|
|
if (imageKey.startsWith('file://')) {
|
|
var file = File(imageKey);
|
|
if (await file.exists()) {
|
|
imageBytes = await file.readAsBytes();
|
|
} else {
|
|
throw "Error: File not found.";
|
|
}
|
|
} else {
|
|
await for (var event
|
|
in ImageDownloader.loadComicImage(imageKey, sourceKey, cid, eid)) {
|
|
checkStop();
|
|
chunkEvents.add(ImageChunkEvent(
|
|
cumulativeBytesLoaded: event.currentBytes,
|
|
expectedTotalBytes: event.totalBytes,
|
|
));
|
|
if (event.imageBytes != null) {
|
|
imageBytes = event.imageBytes;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (imageBytes == null) {
|
|
throw "Error: Empty response body.";
|
|
}
|
|
if (appdata.settings['enableCustomImageProcessing']) {
|
|
var script = appdata.settings['customImageProcessing'].toString();
|
|
if (!script.contains('async function processImage')) {
|
|
return imageBytes;
|
|
}
|
|
var func = JsEngine().runCode('''
|
|
(() => {
|
|
$script
|
|
return processImage;
|
|
})()
|
|
''');
|
|
if (func is JSInvokable) {
|
|
var result = func.invoke([imageBytes, cid, eid, page, sourceKey]);
|
|
if (result is Uint8List) {
|
|
imageBytes = result;
|
|
} else if (result is Future) {
|
|
var futureResult = await result;
|
|
if (futureResult is Uint8List) {
|
|
imageBytes = futureResult;
|
|
}
|
|
} else if (result is Map) {
|
|
var image = result['image'];
|
|
if (image is Uint8List) {
|
|
imageBytes = image;
|
|
} else if (image is Future) {
|
|
JSInvokable? onCancel;
|
|
if (result['onCancel'] is JSInvokable) {
|
|
onCancel = result['onCancel'];
|
|
}
|
|
if (onCancel == null) {
|
|
var futureImage = await image;
|
|
if (futureImage is Uint8List) {
|
|
imageBytes = futureImage;
|
|
}
|
|
} else {
|
|
dynamic futureImage;
|
|
image.then((value) {
|
|
futureImage = value;
|
|
futureImage ??= Uint8List(0);
|
|
});
|
|
while (futureImage == null) {
|
|
try {
|
|
checkStop();
|
|
}
|
|
catch(e) {
|
|
onCancel.invoke([]);
|
|
onCancel.free();
|
|
func.free();
|
|
rethrow;
|
|
}
|
|
await Future.delayed(Duration(milliseconds: 50));
|
|
}
|
|
if (futureImage is Uint8List) {
|
|
imageBytes = futureImage;
|
|
}
|
|
}
|
|
onCancel?.free();
|
|
}
|
|
}
|
|
func.free();
|
|
}
|
|
}
|
|
return imageBytes!;
|
|
}
|
|
|
|
@override
|
|
Future<ReaderImageProvider> obtainKey(ImageConfiguration configuration) {
|
|
return SynchronousFuture(this);
|
|
}
|
|
|
|
@override
|
|
String get key => "$imageKey@$sourceKey@$cid@$eid";
|
|
|
|
@override
|
|
bool get enableResize => true;
|
|
}
|