mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
fix #107
This commit is contained in:
@@ -13,7 +13,7 @@ class _Appdata {
|
||||
|
||||
bool _isSavingData = false;
|
||||
|
||||
Future<void> saveData() async {
|
||||
Future<void> saveData([bool sync = true]) async {
|
||||
if (_isSavingData) {
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(milliseconds: 20));
|
||||
@@ -25,7 +25,9 @@ class _Appdata {
|
||||
var file = File(FilePath.join(App.dataPath, 'appdata.json'));
|
||||
await file.writeAsString(data);
|
||||
_isSavingData = false;
|
||||
DataSync().uploadData();
|
||||
if (sync) {
|
||||
DataSync().uploadData();
|
||||
}
|
||||
}
|
||||
|
||||
void addSearchHistory(String keyword) {
|
||||
@@ -78,6 +80,25 @@ class _Appdata {
|
||||
};
|
||||
}
|
||||
|
||||
/// Following fields are related to device-specific data and should not be synced.
|
||||
static const _disableSync = [
|
||||
"proxy",
|
||||
"authorizationRequired",
|
||||
"customImageProcessing",
|
||||
];
|
||||
|
||||
/// Sync data from another device
|
||||
void syncData(Map<String, dynamic> data) {
|
||||
for (var key in data.keys) {
|
||||
if (_disableSync.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
settings[key] = data[key];
|
||||
}
|
||||
searchHistory = List.from(data['searchHistory']);
|
||||
saveData();
|
||||
}
|
||||
|
||||
var implicitData = <String, dynamic>{};
|
||||
|
||||
void writeImplicitData() {
|
||||
@@ -126,6 +147,8 @@ class _Settings with ChangeNotifier {
|
||||
'onClickFavorite': 'viewDetail', // viewDetail, read
|
||||
'enableDnsOverrides': false,
|
||||
'dnsOverrides': {},
|
||||
'enableCustomImageProcessing': false,
|
||||
'customImageProcessing': _defaultCustomImageProcessing,
|
||||
};
|
||||
|
||||
operator [](String key) {
|
||||
@@ -142,3 +165,16 @@ class _Settings with ChangeNotifier {
|
||||
return _data.toString();
|
||||
}
|
||||
}
|
||||
|
||||
const _defaultCustomImageProcessing = '''
|
||||
/**
|
||||
* Process an image
|
||||
* @param image {ArayBuffer} - The image to process
|
||||
* @param cid {string} - The comic ID
|
||||
* @param eid {string} - The episode ID
|
||||
* @returns {Promise<ArrayBuffer>} - The processed image
|
||||
*/
|
||||
async function processImage(image, cid, eid) {
|
||||
return image;
|
||||
}
|
||||
''';
|
@@ -1,10 +1,13 @@
|
||||
import 'dart:async' show Future, StreamController;
|
||||
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> {
|
||||
@@ -21,25 +24,50 @@ class ReaderImageProvider
|
||||
|
||||
@override
|
||||
Future<Uint8List> load(StreamController<ImageChunkEvent> chunkEvents) async {
|
||||
Uint8List? imageBytes;
|
||||
if (imageKey.startsWith('file://')) {
|
||||
var file = File(imageKey);
|
||||
if (await file.exists()) {
|
||||
return file.readAsBytes();
|
||||
imageBytes = await file.readAsBytes();
|
||||
} else {
|
||||
throw "Error: File not found.";
|
||||
}
|
||||
throw "Error: File not found.";
|
||||
}
|
||||
|
||||
await for (var event
|
||||
} else {
|
||||
await for (var event
|
||||
in ImageDownloader.loadComicImage(imageKey, sourceKey, cid, eid)) {
|
||||
chunkEvents.add(ImageChunkEvent(
|
||||
cumulativeBytesLoaded: event.currentBytes,
|
||||
expectedTotalBytes: event.totalBytes,
|
||||
));
|
||||
if (event.imageBytes != null) {
|
||||
return event.imageBytes!;
|
||||
chunkEvents.add(ImageChunkEvent(
|
||||
cumulativeBytesLoaded: event.currentBytes,
|
||||
expectedTotalBytes: event.totalBytes,
|
||||
));
|
||||
if (event.imageBytes != null) {
|
||||
imageBytes = event.imageBytes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw "Error: Empty response body.";
|
||||
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 = await func.invoke([imageBytes, cid, eid]);
|
||||
func.free();
|
||||
if (result is Uint8List) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return imageBytes;
|
||||
}
|
||||
|
||||
@override
|
||||
|
Reference in New Issue
Block a user