diff --git a/android/app/build.gradle b/android/app/build.gradle
index 28493874..6d79d781 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -30,7 +30,7 @@ if (flutterVersionName == null) {
android {
namespace "com.kodjodevf.mangayomi"
- compileSdkVersion 35
+ compileSdkVersion 36
ndkVersion flutter.ndkVersion
compileOptions {
diff --git a/android/build.gradle b/android/build.gradle
index 695f504f..11b3c526 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -12,7 +12,7 @@ subprojects {
if (project.plugins.hasPlugin("com.android.application") ||
project.plugins.hasPlugin("com.android.library")) {
project.android {
- compileSdkVersion 35
+ compileSdkVersion 36
buildToolsVersion "34.0.0"
}
}
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index ac3b4792..02767eb1 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
index 892dd28e..8ae709e9 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -19,8 +19,8 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
- id "com.android.application" version "8.7.3" apply false
- id "org.jetbrains.kotlin.android" version "1.9.0" apply false
+ id "com.android.application" version "8.12.1" apply false
+ id "org.jetbrains.kotlin.android" version "2.2.0" apply false
}
include ":app"
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 7c569640..1dc6cf76 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 12.0
+ 13.0
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 4f90b1fb..005fd8b1 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -1,5 +1,5 @@
PODS:
- - app_links (0.0.2):
+ - app_links (6.4.1):
- Flutter
- audio_session (0.0.1):
- Flutter
@@ -42,6 +42,8 @@ PODS:
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
+ - flutter_discord_rpc_fork (0.0.1):
+ - Flutter
- flutter_inappwebview_ios (0.0.1):
- Flutter
- flutter_inappwebview_ios/Core (= 0.0.1)
@@ -53,7 +55,7 @@ PODS:
- Flutter
- flutter_web_auth_2 (3.0.0):
- Flutter
- - isar_flutter_libs (1.0.0):
+ - isar_community_flutter_libs (1.0.0):
- Flutter
- just_audio (0.0.1):
- Flutter
@@ -103,10 +105,11 @@ DEPENDENCIES:
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
+ - flutter_discord_rpc_fork (from `.symlinks/plugins/flutter_discord_rpc_fork/ios`)
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
- flutter_qjs (from `.symlinks/plugins/flutter_qjs/ios`)
- flutter_web_auth_2 (from `.symlinks/plugins/flutter_web_auth_2/ios`)
- - isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`)
+ - isar_community_flutter_libs (from `.symlinks/plugins/isar_community_flutter_libs/ios`)
- just_audio (from `.symlinks/plugins/just_audio/darwin`)
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
@@ -144,14 +147,16 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
+ flutter_discord_rpc_fork:
+ :path: ".symlinks/plugins/flutter_discord_rpc_fork/ios"
flutter_inappwebview_ios:
:path: ".symlinks/plugins/flutter_inappwebview_ios/ios"
flutter_qjs:
:path: ".symlinks/plugins/flutter_qjs/ios"
flutter_web_auth_2:
:path: ".symlinks/plugins/flutter_web_auth_2/ios"
- isar_flutter_libs:
- :path: ".symlinks/plugins/isar_flutter_libs/ios"
+ isar_community_flutter_libs:
+ :path: ".symlinks/plugins/isar_community_flutter_libs/ios"
just_audio:
:path: ".symlinks/plugins/just_audio/darwin"
media_kit_libs_ios_video:
@@ -184,18 +189,19 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
SPEC CHECKSUMS:
- app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7
+ app_links: 3dbc685f76b1693c66a6d9dd1e9ab6f73d97dc0a
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
- Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
+ Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
+ flutter_discord_rpc_fork: 970cf2beca17870caf8645556de01ae2b8587bb6
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_qjs: 1d5918f42171154e88dd545dd45f126c0291976f
flutter_web_auth_2: 3464a7c16dc6480b6194fc89913bae6e82f28405
- isar_flutter_libs: 9fc2cfb928c539e1b76c481ba5d143d556d94920
+ isar_community_flutter_libs: bede843185a61a05ff364a05c9b23209523f7e0d
just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
@@ -204,7 +210,7 @@ SPEC CHECKSUMS:
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
rust_lib_mangayomi: 360a904274b47351a0f7c26d3ce5aa6392bb8db3
- screen_brightness_ios: 28c5fbdb40634de44f86025d84470158ad4df48c
+ screen_brightness_ios: 9953fd7da5bd480f1a93990daeec2eb42d4f3b52
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
@@ -213,7 +219,7 @@ SPEC CHECKSUMS:
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
- webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2
+ webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d
PODFILE CHECKSUM: a57f30d18f102dd3ce366b1d62a55ecbef2158e5
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 1f1174c2..43594146 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -483,7 +483,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -610,7 +610,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -659,7 +659,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
diff --git a/lib/eval/javascript/service.dart b/lib/eval/javascript/service.dart
index a4f17727..2b11bf7f 100644
--- a/lib/eval/javascript/service.dart
+++ b/lib/eval/javascript/service.dart
@@ -19,10 +19,12 @@ class JsExtensionService implements ExtensionService {
late JavascriptRuntime runtime;
@override
late Source source;
+ bool _isInitialized = false;
JsExtensionService(this.source);
void _init() {
+ if (_isInitialized) return;
runtime = getJavascriptRuntime();
JsHttpClient(runtime).init();
JsDomSelector(runtime).init();
@@ -79,6 +81,7 @@ async function jsonStringify(fn) {
runtime.evaluate('''${source.sourceCode}
var extention = new DefaultExtension();
''');
+ _isInitialized = true;
}
@override
diff --git a/lib/eval/lib.dart b/lib/eval/lib.dart
index e5842e93..3f1999aa 100644
--- a/lib/eval/lib.dart
+++ b/lib/eval/lib.dart
@@ -4,11 +4,13 @@ import 'package:mangayomi/models/source.dart';
import 'dart/service.dart';
import 'javascript/service.dart';
import 'mihon/service.dart';
+import 'lnreader/service.dart';
ExtensionService getExtensionService(Source source, String androidProxyServer) {
return switch (source.sourceCodeLanguage) {
SourceCodeLanguage.dart => DartExtensionService(source),
SourceCodeLanguage.javascript => JsExtensionService(source),
SourceCodeLanguage.mihon => MihonExtensionService(source, androidProxyServer),
+ SourceCodeLanguage.lnreader => LNReaderExtensionService(source),
};
}
diff --git a/lib/eval/lnreader/http.dart b/lib/eval/lnreader/http.dart
new file mode 100644
index 00000000..fb8e895f
--- /dev/null
+++ b/lib/eval/lnreader/http.dart
@@ -0,0 +1,184 @@
+import 'dart:convert';
+import 'dart:io';
+import 'package:d4rt/d4rt.dart';
+import 'package:flutter_qjs/flutter_qjs.dart';
+import 'package:http_interceptor/http_interceptor.dart';
+import 'package:mangayomi/services/http/m_client.dart';
+import 'package:http/http.dart' as http;
+
+class JsHttpClient {
+ late JavascriptRuntime runtime;
+ JsHttpClient(this.runtime);
+
+ void init() {
+ InterceptedClient client() {
+ return MClient.init();
+ }
+
+ runtime.onMessage('http_head', (dynamic args) async {
+ return await _toHttpResponse(client(), "HEAD", args);
+ });
+ runtime.onMessage('http_get', (dynamic args) async {
+ return await _toHttpResponse(client(), "GET", args);
+ });
+ runtime.onMessage('http_post', (dynamic args) async {
+ return await _toHttpResponse(client(), "POST", args);
+ });
+ runtime.onMessage('http_put', (dynamic args) async {
+ return await _toHttpResponse(client(), "PUT", args);
+ });
+ runtime.onMessage('http_delete', (dynamic args) async {
+ return await _toHttpResponse(client(), "DELETE", args);
+ });
+ runtime.onMessage('http_patch', (dynamic args) async {
+ return await _toHttpResponse(client(), "PATCH", args);
+ });
+ runtime.evaluate('''
+class Response {
+ constructor(url, result) {
+ this.url = url;
+ this.response = JSON.parse(result);
+ }
+ get status() {
+ return this.response.statusCode;
+ }
+ get statusText() {
+ return this.response.reasonPhrase;
+ }
+ get ok() {
+ return this.status >= 200 && this.status <= 299;
+ }
+ get redirected() {
+ return this.response.isRedirect;
+ }
+ get headers() {
+ return this.response.headers;
+ }
+ get body() {
+ return this.response.body;
+ }
+ json() {
+ const val = JSON.parse(this.body);
+ return new Promise(function(resolve, reject) {
+ resolve(val);
+ });
+ }
+ text() {
+ const val = this.body;
+ return new Promise(function(resolve, reject) {
+ resolve(val);
+ });
+ }
+}
+
+async function fetchApi(url, init) {
+ const method = init?.method ? init.method.toLowerCase() : "get";
+ const result = await sendMessage(
+ "http_" + method,
+ JSON.stringify([url, init?.headers, init?.body])
+ );
+ return new Response(url, result);
+}
+''');
+ }
+}
+
+Future _toHttpResponse(Client client, String method, List args) async {
+ final url = args[0] as String;
+ final headers = (args[1] as Map?)?.toMapStringString ?? {};
+ final body = args.length >= 3
+ ? args[2] is List
+ ? args[2] as List
+ : args[2] is String
+ ? args[2] as String
+ : (args[2] as Map?)?.toMapStringDynamic
+ : null;
+ var request = http.Request(method, Uri.parse(url));
+ request.headers.addAll(headers);
+ if ((request.headers[HttpHeaders.contentTypeHeader]?.contains(
+ "application/json",
+ )) ??
+ false) {
+ request.body = json.encode(body);
+ request.headers.addAll(headers);
+ http.StreamedResponse response = await client.send(request);
+ final res = Response(
+ "",
+ response.statusCode,
+ request: response.request,
+ headers: response.headers,
+ isRedirect: response.isRedirect,
+ persistentConnection: response.persistentConnection,
+ reasonPhrase: response.reasonPhrase,
+ );
+ Map resMap = res.toJson();
+ resMap["body"] = await response.stream.bytesToString();
+ return jsonEncode(resMap);
+ }
+ String? formData;
+ if (body is Map && body.containsKey("_data")) {
+ formData = (body.get("_data") as List)
+ .map(
+ (e) =>
+ "${Uri.encodeQueryComponent(e[0])}"
+ "=${Uri.encodeQueryComponent(e[1])}",
+ )
+ .join("&");
+ headers["content-type"] =
+ "application/x-www-form-urlencoded; charset=UTF-8";
+ }
+ final future = switch (method) {
+ "HEAD" => client.head(Uri.parse(url), headers: headers),
+ "GET" => client.get(Uri.parse(url), headers: headers),
+ "POST" => client.post(
+ Uri.parse(url),
+ headers: headers,
+ body: formData ?? body,
+ ),
+ "PUT" => client.put(
+ Uri.parse(url),
+ headers: headers,
+ body: formData ?? body,
+ ),
+ "DELETE" => client.delete(
+ Uri.parse(url),
+ headers: headers,
+ body: formData ?? body,
+ ),
+ _ => client.patch(Uri.parse(url), headers: headers, body: formData ?? body),
+ };
+ return jsonEncode((await future).toJson());
+}
+
+extension ResponseExtexsion on Response {
+ Map toJson() => {
+ 'body': body,
+ 'headers': headers,
+ 'isRedirect': isRedirect,
+ 'persistentConnection': persistentConnection,
+ 'reasonPhrase': reasonPhrase,
+ 'statusCode': statusCode,
+ 'request': {
+ 'contentLength': request?.contentLength,
+ 'finalized': request?.finalized,
+ 'followRedirects': request?.followRedirects,
+ 'headers': request?.headers,
+ 'maxRedirects': request?.maxRedirects,
+ 'method': request?.method,
+ 'persistentConnection': request?.persistentConnection,
+ 'url': request?.url.toString(),
+ },
+ };
+}
+
+extension ToMapExtension on Map? {
+ Map? get toMapStringDynamic {
+ return this?.map((key, value) => MapEntry(key.toString(), value));
+ }
+
+ Map? get toMapStringString {
+ return this?.map(
+ (key, value) => MapEntry(key.toString(), value.toString()),
+ );
+ }
+}
diff --git a/lib/eval/lnreader/js_cheerio.dart b/lib/eval/lnreader/js_cheerio.dart
new file mode 100644
index 00000000..ff5e0729
--- /dev/null
+++ b/lib/eval/lnreader/js_cheerio.dart
@@ -0,0 +1,414 @@
+import 'dart:convert';
+
+import 'package:flutter_qjs/flutter_qjs.dart';
+import 'package:html/dom.dart';
+import 'package:html/parser.dart';
+import 'package:mangayomi/utils/extensions/dom_extensions.dart';
+
+class JsCheerio {
+ late JavascriptRuntime runtime;
+ final Map _elements = {};
+ int _elementKey = 0;
+
+ JsCheerio(this.runtime);
+
+ void init() {
+ runtime.onMessage('load', (dynamic args) {
+ final html = args[0];
+ final doc = parse(html);
+ _elementKey++;
+ _elements[_elementKey] = doc.body;
+ return _elementKey;
+ });
+
+ runtime.onMessage('element_call', (dynamic args) {
+ final method = args[0] as String;
+ final key = args[1] as int;
+ final element = _elements[key];
+
+ if (element == null) return null;
+
+ final methodArgs = args.length > 2 ? args[2] : [];
+
+ dynamic result;
+
+ switch (method) {
+ case 'text':
+ result = element.text;
+ break;
+ case 'html':
+ case 'innerHtml':
+ result = element.innerHtml;
+ break;
+ case 'outerHtml':
+ result = element.outerHtml;
+ break;
+ case 'addClass':
+ element.classes.add(methodArgs[0]);
+ break;
+ case 'removeClass':
+ element.classes.remove(methodArgs[0]);
+ break;
+ case 'hasClass':
+ result = element.classes.contains(methodArgs[0]);
+ break;
+ case 'attr':
+ result = element.attributes[methodArgs[0]] ?? '';
+ break;
+ case 'setAttr':
+ element.attributes[methodArgs[0]] = methodArgs[1];
+ break;
+ case 'removeAttr':
+ element.attributes.remove(methodArgs[0]);
+ break;
+ case 'val':
+ result = element.attributes['value'] ?? '';
+ break;
+ case 'setVal':
+ element.attributes['value'] = methodArgs[0];
+ break;
+ case 'children':
+ final children = element.children;
+ List keys = [];
+ for (var child in children) {
+ _elementKey++;
+ _elements[_elementKey] = child;
+ keys.add(_elementKey);
+ }
+ result = jsonEncode(keys);
+ break;
+ case 'parent':
+ final parent = element.parent;
+ if (parent != null) {
+ _elementKey++;
+ _elements[_elementKey] = parent;
+ result = _elementKey;
+ }
+ break;
+ case 'find':
+ final selector = methodArgs[0];
+ final elements = element.select(selector);
+ List keys = [];
+ for (var el in elements ?? []) {
+ _elementKey++;
+ _elements[_elementKey] = el;
+ keys.add(_elementKey);
+ }
+ result = jsonEncode(keys);
+ break;
+ case 'first':
+ final first = element.children.firstOrNull;
+ if (first != null) {
+ _elementKey++;
+ _elements[_elementKey] = first;
+ result = _elementKey;
+ }
+ break;
+ case 'last':
+ final last = element.children.lastOrNull;
+ if (last != null) {
+ _elementKey++;
+ _elements[_elementKey] = last;
+ result = _elementKey;
+ }
+ break;
+ case 'next':
+ final next = element.nextElementSibling;
+ if (next != null) {
+ _elementKey++;
+ _elements[_elementKey] = next;
+ result = _elementKey;
+ }
+ break;
+ case 'prev':
+ final prev = element.previousElementSibling;
+ if (prev != null) {
+ _elementKey++;
+ _elements[_elementKey] = prev;
+ result = _elementKey;
+ }
+ break;
+ case 'append':
+ final htmlToAppend = methodArgs[0];
+ final newNodes = parse(htmlToAppend).children;
+ for (var node in newNodes) {
+ element.append(node);
+ }
+ break;
+ case 'prepend':
+ final htmlToPrepend = methodArgs[0];
+ final newNodes = parse(htmlToPrepend).children;
+ for (var node in newNodes.reversed) {
+ element.insertBefore(node, element.firstChild);
+ }
+ break;
+ case 'empty':
+ element.children.clear();
+ break;
+ case 'remove':
+ element.remove();
+ break;
+ default:
+ result = 'Unsupported method: $method';
+ }
+
+ return result;
+ });
+
+ runtime.evaluate('''
+class Element {
+ constructor(key) {
+ this._key = key;
+ }
+
+ _call(method, args = []) {
+ return sendMessage("element_call", JSON.stringify([method, this._key, args]));
+ }
+
+ text() { return this._call("text"); }
+ html() { return this._call("html"); }
+ outerHtml() { return this._call("outerHtml"); }
+ val() { return this._call("val"); }
+ attr(name) { return this._call("attr", [name]); }
+ hasClass(cls) { return this._call("hasClass", [cls]); }
+
+ addClass(cls) { this._call("addClass", [cls]); return this; }
+ removeClass(cls) { this._call("removeClass", [cls]); return this; }
+ setAttr(name, value) { this._call("setAttr", [name, value]); return this; }
+ removeAttr(name) { this._call("removeAttr", [name]); return this; }
+ setVal(value) { this._call("setVal", [value]); return this; }
+
+ append(html) { this._call("append", [html]); return this; }
+ prepend(html) { this._call("prepend", [html]); return this; }
+ empty() { this._call("empty"); return this; }
+ remove() { this._call("remove"); return this; }
+
+ children() {
+ const keys = JSON.parse(this._call("children"));
+ return new ElementCollection(keys.map(k => new Element(k)));
+ }
+
+ find(selector) {
+ const keys = JSON.parse(this._call("find", [selector]));
+ return new ElementCollection(keys.map(k => new Element(k)));
+ }
+
+ parent() {
+ return new Element(this._call("parent"));
+ }
+
+ next() {
+ return new Element(this._call("next"));
+ }
+
+ prev() {
+ return new Element(this._call("prev"));
+ }
+
+ first() {
+ return new Element(this._call("first"));
+ }
+
+ last() {
+ return new Element(this._call("last"));
+ }
+}
+
+class ElementCollection {
+ constructor(elements) {
+ this.elements = elements;
+ }
+
+ text() {
+ return this.map(function(i, el) {
+ return el.text();
+ }).toArray().join("\\n") ?? "";
+ }
+
+ html() {
+ return this.first()?.html();
+ }
+
+ outerHtml() {
+ return this.first()?.outerHtml();
+ }
+
+ attr(name) {
+ return this.first()?.attr(name);
+ }
+
+ hasClass(cls) {
+ return this.first()?.hasClass(cls);
+ }
+
+ each(fn) {
+ this.elements.forEach((el, i) => fn(i, el));
+ return this;
+ }
+
+ map(fn) {
+ return new ElementCollection(this.elements.map((el, i) => fn(i, el)));
+ }
+
+ filter(fn) {
+ return new ElementCollection(this.elements.filter(function (el, i) {
+ try {
+ return fn(i, el);
+ } catch (_) {
+ return false;
+ }
+ }));
+ }
+
+ addClass(cls) {
+ this.elements.forEach(el => el.addClass(cls));
+ return this;
+ }
+
+ removeClass(cls) {
+ this.elements.forEach(el => el.removeClass(cls));
+ return this;
+ }
+
+ setAttr(name, value) {
+ this.elements.forEach(el => el.setAttr(name, value));
+ return this;
+ }
+
+ removeAttr(name) {
+ this.elements.forEach(el => el.removeAttr(name));
+ return this;
+ }
+
+ setVal(value) {
+ this.elements.forEach(el => el.setVal(value));
+ return this;
+ }
+
+ append(html) {
+ this.elements.forEach(el => el.append(html));
+ return this;
+ }
+
+ prepend(html) {
+ this.elements.forEach(el => el.prepend(html));
+ return this;
+ }
+
+ empty() {
+ this.elements.forEach(el => el.empty());
+ return this;
+ }
+
+ remove() {
+ this.elements.forEach(el => el.remove());
+ return this;
+ }
+
+ find(selector) {
+ const found = this.elements.flatMap(el => {
+ const keys = JSON.parse(el._call("find", [selector]));
+ return keys.map(k => new Element(k));
+ });
+ return new ElementCollection(found);
+ }
+
+ children() {
+ const children = this.elements.flatMap(el => {
+ const keys = JSON.parse(el._call("children"));
+ return keys.map(k => new Element(k));
+ });
+ return new ElementCollection(children);
+ }
+
+ parent() {
+ const parents = this.elements.map(el => new Element(el._call("parent")));
+ return new ElementCollection(parents);
+ }
+
+ next() {
+ const nextEls = this.elements.map(el => new Element(el._call("next")));
+ return new ElementCollection(nextEls);
+ }
+
+ prev() {
+ const prevEls = this.elements.map(el => new Element(el._call("prev")));
+ return new ElementCollection(prevEls);
+ }
+
+ first() {
+ return this.get(0);
+ }
+
+ last() {
+ return this.get(this.elements.length - 1);
+ }
+
+ get(index) {
+ return this.elements[index] || new Stub();
+ }
+
+ length() {
+ return this.elements.length;
+ }
+
+ toArray() {
+ return this.elements;
+ }
+
+ [Symbol.iterator]() {
+ return this.elements[Symbol.iterator]();
+ }
+}
+
+class Stub {
+ text() {
+ return null;
+ }
+ html() {
+ return null;
+ }
+ outerHtml() {
+ return null;
+ }
+ val() {
+ return null;
+ }
+ attr(name) {
+ return null;
+ }
+ hasClass(cls) {
+ return false;
+ }
+}
+
+function load(html) {
+ const rootKey = sendMessage("load", JSON.stringify([html]));
+ const root = new Element(rootKey);
+
+ const \$ = function(input) {
+ if (input instanceof ElementCollection) {
+ return input;
+ } else if (input instanceof Element) {
+ return input;
+ } else if (typeof input === "string") {
+ return root.find(input); // returns ElementCollection
+ } else if (input && input._key) {
+ return new ElementCollection([new Element(input._key)]);
+ } else {
+ return new ElementCollection([new Element(input)]);
+ }
+ };
+
+ \$.html = function() {
+ return root.html();
+ };
+ \$.root = root;
+ \$.Element = Element;
+ \$.Collection = ElementCollection;
+
+ return \$;
+}
+ ''');
+ }
+}
diff --git a/lib/eval/lnreader/js_htmlparser.dart b/lib/eval/lnreader/js_htmlparser.dart
new file mode 100644
index 00000000..fded1f93
--- /dev/null
+++ b/lib/eval/lnreader/js_htmlparser.dart
@@ -0,0 +1,202 @@
+import 'package:flutter_qjs/flutter_qjs.dart';
+
+class JsHtmlParser {
+ late JavascriptRuntime runtime;
+ JsHtmlParser(this.runtime);
+
+ void init() {
+ runtime.evaluate('''
+class Parser {
+ constructor(options = {}) {
+ this.options = options;
+ this.buffer = '';
+ }
+
+ isVoidElement(name) {
+ return [
+ "area",
+ "base",
+ "basefont",
+ "br",
+ "col",
+ "command",
+ "embed",
+ "frame",
+ "hr",
+ "img",
+ "input",
+ "isindex",
+ "keygen",
+ "link",
+ "meta",
+ "param",
+ "source",
+ "track",
+ "wbr",
+ ].includes(name);
+ }
+
+ write(html) {
+ this.buffer += html;
+ let i = 0;
+ let textStart = 0;
+ const len = this.buffer.length;
+ let insideQuote = null;
+
+ while (i < len) {
+ const ch = this.buffer[i];
+
+ // Track string literals
+ if ((ch === '"' || ch === "'")) {
+ if (insideQuote === ch) {
+ insideQuote = null;
+ } else if (insideQuote === null) {
+ insideQuote = ch;
+ }
+ i++;
+ continue;
+ }
+
+ if (ch === '<' && insideQuote === null) {
+ // Emit any text before the tag
+ if (i > textStart && this.options.ontext) {
+ const text = this.buffer.slice(textStart, i);
+ this.options.ontext(text);
+ }
+
+ const tagStart = i;
+ i++;
+
+ const isClosing = this.buffer[i] === '/';
+ if (isClosing) i++;
+
+ // Parse tag name
+ const nameStart = i;
+ while (i < len && /[a-zA-Z0-9:-]/.test(this.buffer[i])) i++;
+ const nameEnd = i;
+ const tagName = this.buffer.slice(nameStart, nameEnd);
+
+ if (isClosing) {
+ if (this.options.onclosetag) {
+ this.options.onclosetag(tagName);
+ }
+ } else {
+ if (this.options.onopentagname) {
+ this.options.onopentagname(tagName);
+ }
+ }
+
+ // Parse attributes
+ let attrs = {};
+ let attrName = '';
+ let attrValue = '';
+ let readingAttrName = true;
+ let inAttrQuote = null;
+
+ while (i < len && this.buffer[i] !== '>') {
+ const c = this.buffer[i];
+
+ // Skip over whitespace
+ if (/\\s/.test(c)) {
+ i++;
+ continue;
+ }
+
+ // Handle self-closing tag
+ if (c === '/' && this.buffer[i + 1] === '>') {
+ if (!isClosing && this.options.onselfclosingtag) {
+ this.options.onselfclosingtag();
+ }
+ i += 2;
+ textStart = i;
+ if (this.options.onopentag) {
+ this.options.onopentag(tagName, attrs);
+ }
+ if (this.options.onopentagend) {
+ this.options.onopentagend();
+ }
+ continue;
+ }
+
+ // Parse attribute name
+ let attrStart = i;
+ while (i < len && /[^\\s=>]/.test(this.buffer[i])) i++;
+ attrName = this.buffer.slice(attrStart, i);
+
+ // Skip whitespace after name
+ while (i < len && /\\s/.test(this.buffer[i])) i++;
+
+ // Expect '='
+ if (this.buffer[i] === '=') {
+ i++; // skip '='
+
+ // Skip whitespace after '='
+ while (i < len && /\\s/.test(this.buffer[i])) i++;
+
+ const quote = this.buffer[i];
+ if (quote === '"' || quote === "'") {
+ inAttrQuote = quote;
+ i++; // skip quote
+
+ const valStart = i;
+ while (i < len && this.buffer[i] !== inAttrQuote) i++;
+ attrValue = this.buffer.slice(valStart, i);
+ i++; // skip closing quote
+ } else {
+ // Unquoted value
+ const valStart = i;
+ while (i < len && /[^\\s>]/.test(this.buffer[i])) i++;
+ attrValue = this.buffer.slice(valStart, i);
+ }
+
+ // Emit merged attribute callback
+ if (this.options.onattribute) {
+ this.options.onattribute(attrName, attrValue);
+ }
+
+ attrs[attrName] = attrValue;
+ attrName = '';
+ attrValue = '';
+ } else {
+ // attribute without value (e.g. `disabled`)
+ if (this.options.onattribute) {
+ this.options.onattribute(attrName, null);
+ }
+ attrs[attrName] = null;
+ attrName = '';
+ }
+ }
+
+ // Closing normal tag '>'
+ i++; // skip '>'
+
+ if (!isClosing && this.options.onopentag) {
+ this.options.onopentag(tagName, attrs);
+ }
+
+ if (this.options.onopentagend) {
+ this.options.onopentagend();
+ }
+
+ textStart = i;
+ } else {
+ i++;
+ }
+ }
+
+ // Emit any remaining text
+ if (textStart < len && this.options.ontext) {
+ const text = this.buffer.slice(textStart, len);
+ this.options.ontext(text);
+ }
+ }
+
+ end() {
+ if (this.options.onend) {
+ this.options.onend();
+ }
+ }
+}
+''');
+ }
+}
diff --git a/lib/eval/lnreader/js_libs.dart b/lib/eval/lnreader/js_libs.dart
new file mode 100644
index 00000000..23d1fd65
--- /dev/null
+++ b/lib/eval/lnreader/js_libs.dart
@@ -0,0 +1,159 @@
+import 'package:flutter_qjs/flutter_qjs.dart';
+import 'package:mangayomi/utils/log/log.dart';
+
+class JsLibs {
+ late JavascriptRuntime runtime;
+ JsLibs(this.runtime);
+
+ void init() {
+ runtime.onMessage('log', (dynamic args) {
+ Logger.add(LoggerLevel.warning, "${args[0]}");
+ return null;
+ });
+ runtime.onMessage('urlencode', (dynamic args) {
+ return Uri.encodeComponent(args[0]);
+ });
+ runtime.onMessage('urldecode', (dynamic args) {
+ return Uri.decodeComponent(args[0]);
+ });
+
+ runtime.evaluate('''
+console.log = function (message) {
+ if (typeof message === "object") {
+ message = JSON.stringify(message);
+ }
+ sendMessage("log", JSON.stringify([message.toString()]));
+};
+console.warn = function (message) {
+ if (typeof message === "object") {
+ message = JSON.stringify(message);
+ }
+ sendMessage("log", JSON.stringify([message.toString()]));
+};
+console.error = function (message) {
+ if (typeof message === "object") {
+ message = JSON.stringify(message);
+ }
+ sendMessage("log", JSON.stringify([message.toString()]));
+};
+String.prototype.substringAfter = function(pattern) {
+ const startIndex = this.indexOf(pattern);
+ if (startIndex === -1) return this.substring(0);
+
+ const start = startIndex + pattern.length;
+ return this.substring(start);
+}
+
+String.prototype.substringAfterLast = function(pattern) {
+ return this.split(pattern).pop();
+}
+
+String.prototype.substringBefore = function(pattern) {
+ const endIndex = this.indexOf(pattern);
+ if (endIndex === -1) return this.substring(0);
+
+ return this.substring(0, endIndex);
+}
+
+String.prototype.substringBeforeLast = function(pattern) {
+ const endIndex = this.lastIndexOf(pattern);
+ if (endIndex === -1) return this.substring(0);
+ return this.substring(0, endIndex);
+}
+
+String.prototype.substringBetween = function(left, right) {
+ let startIndex = 0;
+ let index = this.indexOf(left, startIndex);
+ if (index === -1) return "";
+ let leftIndex = index + left.length;
+ let rightIndex = this.indexOf(right, leftIndex);
+ if (rightIndex === -1) return "";
+ startIndex = rightIndex + right.length;
+ return this.substring(leftIndex, rightIndex);
+}
+
+async function jsonStringify(fn) {
+ return JSON.stringify(await fn());
+}
+
+const isUrlAbsolute = url => {
+ if (url) {
+ if (url.indexOf("//") === 0) {
+ return true
+ } // URL is protocol-relative (= absolute)
+ if (url.indexOf("://") === -1) {
+ return false
+ } // URL has no protocol (= relative)
+ if (url.indexOf(".") === -1) {
+ return false
+ } // URL does not contain a dot, i.e. no TLD (= relative, possibly REST)
+ if (url.indexOf("/") === -1) {
+ return false
+ } // URL does not contain a single slash (= relative)
+ if (url.indexOf(":") > url.indexOf("/")) {
+ return false
+ } // The first colon comes after the first slash (= relative)
+ if (url.indexOf("://") < url.indexOf(".")) {
+ return true
+ } // Protocol is defined before first dot (= absolute)
+ }
+ return false // Anything else must be relative
+}
+
+const NovelStatus = {
+ "Unknown": "Unknown",
+ "Ongoing": "Ongoing",
+ "Completed": "Completed",
+ "Licensed": "Licensed",
+ "PublishingFinished": "Publishing Finished",
+ "Cancelled": "Cancelled",
+ "OnHiatus": "On Hiatus"
+};
+
+const FilterTypes = {
+ "TextInput": "Text",
+ "Picker": "Picker",
+ "CheckboxGroup": "Checkbox",
+ "Switch": "Switch",
+ "ExcludableCheckboxGroup": "XCheckbox"
+};
+
+const isPickerValue = q => {
+ return q.type === FilterTypes.Picker && typeof q.value === "string"
+}
+
+const isCheckboxValue = q => {
+ return q.type === FilterTypes.CheckboxGroup && Array.isArray(q.value)
+}
+
+const isSwitchValue = q => {
+ return q.type === FilterTypes.Switch && typeof q.value === "boolean"
+}
+
+const isTextValue = q => {
+ return q.type === FilterTypes.TextInput && typeof q.value === "string"
+}
+
+const isXCheckboxValue = q => {
+ return (
+ q.type === FilterTypes.ExcludableCheckboxGroup &&
+ typeof q.value === "object" &&
+ !Array.isArray(q.value)
+ )
+}
+
+function urlencode(input) {
+ return sendMessage(
+ "urlencode",
+ JSON.stringify([input])
+ );
+}
+function urldecode(input) {
+ return sendMessage(
+ "urldecode",
+ JSON.stringify([input])
+ );
+}
+''');
+ }
+}
diff --git a/lib/eval/lnreader/js_polyfills.dart b/lib/eval/lnreader/js_polyfills.dart
new file mode 100644
index 00000000..f887dc79
--- /dev/null
+++ b/lib/eval/lnreader/js_polyfills.dart
@@ -0,0 +1,39 @@
+import 'package:flutter_qjs/flutter_qjs.dart';
+
+class JsPolyfills {
+ late JavascriptRuntime runtime;
+ JsPolyfills(this.runtime);
+
+ void init() {
+ runtime.evaluate('''
+class FormData {
+ constructor() {
+ this.params = {};
+ }
+
+ append(key, value) {
+ this.params[key] = value;
+ }
+
+ toJSON() {
+ return this.params;
+ }
+}
+''');
+ runtime.evaluate('''
+/**!
+ * url-search-params-polyfill
+ *
+ * @author Jerry Bendy (https://github.com/jerrybendy)
+ * @licence MIT
+ */
+!function(t){"use strict";var n,r=function(){try{if(t.URLSearchParams&&"bar"===new t.URLSearchParams("foo=bar").get("foo"))return t.URLSearchParams}catch(t){}return null}(),e=r&&"a=1"===new r({a:1}).toString(),o=r&&"+"===new r("s=%2B").get("s"),i=r&&"size"in r.prototype,a="__URLSearchParams__",c=!r||((n=new r).append("s"," &"),"s=+%26"===n.toString()),s=p.prototype,u=!(!t.Symbol||!t.Symbol.iterator);if(!(r&&e&&o&&c&&i)){s.append=function(t,n){d(this[a],t,n)},s.delete=function(t){delete this[a][t]},s.get=function(t){var n=this[a];return this.has(t)?n[t][0]:null},s.getAll=function(t){var n=this[a];return this.has(t)?n[t].slice(0):[]},s.has=function(t){return b(this[a],t)},s.set=function(t,n){this[a][t]=[""+n]},s.toString=function(){var t,n,r,e,o=this[a],i=[];for(n in o)for(r=g(n),t=0,e=o[n];t0?"#"+t.match(/^#*(.*)/)[1]:"",t}}),Object.defineProperty(this,"host",{get:function(){return o.length>0?r+":"+o:r},set:function(t){var e=t.split(":");return this.hostname=e[0],this.port=e[1],t}}),Object.defineProperty(this,"hostname",{get:function(){return r},set:function(t){return r=t.length>0?encodeURIComponent(t):r,t}}),Object.defineProperty(this,"href",{get:function(){var t=h+"//";return(u.length>0||i.length>0)&&(u.length>0&&(t+=u),i.length>0&&(t+=":"+i),t+="@"),t+=r,o.length>0&&(t+=":"+o),t+=s+c+n},set:function(t){this.protocol=t;var e=(t=t.replace(/.*?:\\/*/,"")).match(/([^:]*).*@/);this.username=e?e[1]:"";var n=(t=t.replace(/([^:]*):?(.*@)/,a)).match(/.*(?=@)/);this.password=n?n[0]:"",t=t.replace(/.*@/,""),this.hostname=t.match(/[^:/?]*/);var r=t.match(/:(\\d+)/);this.port=r?r[1]:"";var i=t.match(/\\/([^?#]*)/);this.pathname=i?i[1]:"";var s=t.match(/\\?[^#]*/);this.search=s?s[0]:"";var o=t.match(/\\#.*/);this.hash=o?o[0]:""}}),Object.defineProperty(this,"origin",{get:function(){var t=h+"//"+r;return o.length>0&&(t+=":"+o),t},set:function(t){this.protocol=t,t=t.replace(/.*?:\\/*/,""),this.hostname=t.match(/[^:/?]*/);var e=t.match(/:(\\d+)/);this.port=e?e[1]:""}}),Object.defineProperty(this,"password",{get:function(){return i},set:function(t){return i=encodeURIComponent(t),t}}),Object.defineProperty(this,"pathname",{get:function(){return s},set:function(t){return s="/"+t.match(/\\/?(.*)/)[1],t}}),Object.defineProperty(this,"port",{get:function(){return o},set:function(t){return o=isNaN(t)||""===t?"":Math.min(65535,t).toString(),t}}),Object.defineProperty(this,"protocol",{get:function(){return h},set:function(t){return h=t.match(/[^/:]*/)[0]+":",t}}),Object.defineProperty(this,"search",{get:function(){return c},set:function(t){return c=t.length>0?"?"+t.match(/\\??(.*)/)[1]:"",t}}),Object.defineProperty(this,"username",{get:function(){return u},set:function(t){u=t}}),"string"==typeof t){var f=/^[a-zA-z]+:\\/\\/.*/.test(t),p=/^[a-zA-z]+:\\/\\/.*/.test(e);if(f)this.href=t;else{if(!p)throw new TypeError('URL string is not valid. If using a relative url, a second argument needs to be passed representing the base URL. Example: new URL("relative/path", "http://www.example.com");');this.href=e+t}}else n=t.hash,r=t.hostname,i=t.password?t.password:"",s=t.pathname,o=t.port,h=t.protocol,c=t.search,u=t.username?t.username:"";this.searchParams=function(t){var e=[],n=[];t.search.length>0&&t.search.slice(1).split("&").forEach((function(t){var r=t.split("=");e.push(r[0]),n.push(r[1])}));function r(){0===e.length?t.search="":t.search=e.map((function(t,e){return t+"="+n[e]})).join("&")}return{append:function(t,i){e.push(t),n.push(i),r()},delete:function(t){for(;e.indexOf(t)>-1;)n.splice(e.indexOf(t),1),e.splice(e.indexOf(t),1);r()},entries:function(){return e.map((function(t,e){return[t,n[e]]}))},get:function(t){return n[e.indexOf(t)]},getAll:function(t){return n.filter((function(n,r){return e[r]===t}))},has:function(t){return e.indexOf(t)>-1},keys:function(){return e},set:function(t,i){if(-1===e.indexOf(t))this.append(t,i);else{var s=!0,o=[];e=e.filter((function(e,r){return e!==t?(o.push(n[r]),!0):!!s&&(s=!1,o.push(i),!0)})),n=o,r()}},sort:function(){var t=this.entries().sort();e=[],n=[],t.forEach((function(t){e.push(t[0]),n.push(t[1])})),r()},toString:function(){return t.search.slice(1)},values:function(){return n}}}(this)}}"function"!=typeof URL?t():"searchParams"in new URL(window.location)||t()}();
+''');
+ runtime.evaluate('''
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports.dayjs=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).dayjs=e()}(this,(function(){"use strict";var t=1e3,e=6e4,n=36e5,r="millisecond",i="second",s="minute",u="hour",a="day",o="week",c="month",f="quarter",h="year",d="date",l="Invalid Date",\$=/^(\\d{4})[-/]?(\\d{1,2})?[-/]?(\\d{0,2})[Tt\\s]*(\\d{1,2})?:?(\\d{1,2})?:?(\\d{1,2})?[.:]?(\\d+)?\$/,y=/\\[([^\\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(t){var e=["th","st","nd","rd"],n=t%100;return"["+t+(e[(n-20)%10]||e[n]||e[0])+"]"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:""+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?"+":"-")+m(r,2,"0")+":"+m(i,2,"0")},m:function t(e,n){if(e.date()1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},O=function(t,e){if(S(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},b=v;b.l=w,b.i=S,b.w=function(t,e){return O(t,{locale:e.\$L,utc:e.\$u,x:e.\$x,\$offset:e.\$offset})};var _=function(){function M(t){this.\$L=w(t.locale,null,!0),this.parse(t),this.\$x=this.\$x||t.x||{},this[p]=!0}var m=M.prototype;return m.parse=function(t){this.\$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z\$/i.test(e)){var r=e.match(\$);if(r){var i=r[2]-1||0,s=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.init()},m.init=function(){var t=this.\$d;this.\$y=t.getFullYear(),this.\$M=t.getMonth(),this.\$D=t.getDate(),this.\$W=t.getDay(),this.\$H=t.getHours(),this.\$m=t.getMinutes(),this.\$s=t.getSeconds(),this.\$ms=t.getMilliseconds()},m.\$utils=function(){return b},m.isValid=function(){return!(this.\$d.toString()===l)},m.isSame=function(t,e){var n=O(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return O(t) json) {
+ return ChapterItem(
+ name: json['name'],
+ path: json['path'],
+ releaseTime: json['releaseTime'],
+ chapterNumber: json['chapterNumber'] != null
+ ? (json['chapterNumber'] as num?)?.toInt() ??
+ int.tryParse(json['chapterNumber'])
+ : null,
+ page: json['page'],
+ );
+ }
+
+ Map toJson() {
+ return {
+ 'name': name,
+ 'path': path,
+ 'releaseTime': releaseTime,
+ 'chapterNumber': chapterNumber,
+ 'page': page,
+ };
+ }
+}
+
+class NovelItem {
+ String name;
+ String path;
+ String? cover;
+
+ NovelItem({required this.name, required this.path, this.cover});
+
+ factory NovelItem.fromJson(Map json) {
+ return NovelItem(
+ name: json['name'],
+ path: json['path'],
+ cover: json['cover'],
+ );
+ }
+
+ Map toJson() {
+ return {'name': name, 'path': path, 'cover': cover};
+ }
+}
+
+class SourceNovel extends NovelItem {
+ String? genres;
+ String? summary;
+ String? author;
+ String? artist;
+ String? status;
+ double? rating;
+ List? chapters;
+
+ SourceNovel({
+ required super.name,
+ required super.path,
+ super.cover,
+ this.genres,
+ this.summary,
+ this.author,
+ this.artist,
+ this.status,
+ this.rating,
+ this.chapters,
+ });
+
+ factory SourceNovel.fromJson(Map json) {
+ if (json['path'] == null) {
+ throw 'path is null';
+ }
+ return SourceNovel(
+ name: json['name'] ?? '',
+ path: json['path'],
+ cover: json['cover'],
+ genres: json['genres'],
+ summary: json['summary'],
+ author: json['author'],
+ artist: json['artist'],
+ status: json['status'],
+ rating: json['rating'] is double
+ ? json['rating']
+ : json['rating']?.toDouble(),
+ chapters: (json['chapters'] as List?)
+ ?.map((item) => ChapterItem.fromJson(item))
+ .toList(),
+ );
+ }
+
+ @override
+ Map toJson() {
+ return {
+ 'name': name,
+ 'path': path,
+ 'cover': cover,
+ 'genres': genres,
+ 'summary': summary,
+ 'author': author,
+ 'artist': artist,
+ 'status': status,
+ 'rating': rating,
+ 'chapters': chapters?.map((item) => item.toJson()).toList(),
+ };
+ }
+}
+
+class SourcePage {
+ List chapters;
+
+ SourcePage({required this.chapters});
+
+ factory SourcePage.fromJson(Map json) {
+ return SourcePage(
+ chapters:
+ (json['chapters'] as List?)
+ ?.map((item) => ChapterItem.fromJson(item))
+ .toList() ??
+ [],
+ );
+ }
+
+ Map toJson() {
+ return {'chapters': chapters.map((item) => item.toJson()).toList()};
+ }
+}
diff --git a/lib/eval/lnreader/service.dart b/lib/eval/lnreader/service.dart
new file mode 100644
index 00000000..6eb78da8
--- /dev/null
+++ b/lib/eval/lnreader/service.dart
@@ -0,0 +1,283 @@
+import 'dart:convert';
+import 'package:flutter_qjs/flutter_qjs.dart';
+import 'package:mangayomi/eval/lnreader/http.dart';
+import 'package:mangayomi/eval/lnreader/m_plugin.dart';
+import 'package:mangayomi/eval/model/filter.dart';
+import 'package:mangayomi/eval/model/m_chapter.dart';
+import 'package:mangayomi/eval/model/m_manga.dart';
+import 'package:mangayomi/eval/model/m_pages.dart';
+import 'package:mangayomi/eval/model/source_preference.dart';
+import 'package:mangayomi/models/manga.dart';
+import 'package:mangayomi/models/page.dart';
+import 'package:mangayomi/models/source.dart';
+import 'package:mangayomi/models/video.dart';
+
+import '../interface.dart';
+import 'js_cheerio.dart';
+import 'js_htmlparser.dart';
+import 'js_libs.dart';
+import 'js_polyfills.dart';
+
+JavascriptRuntime getJavascriptRuntime({
+ Map? extraArgs = const {},
+}) {
+ JavascriptRuntime runtime;
+ runtime = QuickJsRuntime2(stackSize: 1024 * 1024 * 4);
+ runtime.enableHandlePromises();
+ return runtime;
+}
+
+class LNReaderExtensionService implements ExtensionService {
+ late JavascriptRuntime runtime;
+ @override
+ late Source source;
+ bool _isInitialized = false;
+
+ LNReaderExtensionService(this.source);
+
+ void _init() {
+ if (_isInitialized) return;
+ runtime = getJavascriptRuntime();
+ runtime.evaluate('''
+module={},exports=Function("return this")(),Object.defineProperties(module,{namespace:{set:function(a){exports=a}},exports:{set:function(a){for(var b in a)a.hasOwnProperty(b)&&(exports[b]=a[b])},get:function(){return exports}}});
+''');
+ JsPolyfills(runtime).init();
+ JsHttpClient(runtime).init();
+ JsLibs(runtime).init();
+ JsHtmlParser(runtime).init();
+ JsCheerio(runtime).init();
+ runtime.evaluate('''
+const require = (package) => {
+ switch (package) {
+ case "htmlparser2":
+ return {Parser: Parser};
+ case "cheerio":
+ return {load: load};
+ case "dayjs":
+ return module.exports.dayjs;
+ case "urlencode":
+ return {encode: urlencode, decode: urldecode};
+ case "@libs/fetch":
+ return {fetchApi: fetchApi};
+ case "@libs/novelStatus":
+ return {NovelStatus: NovelStatus};
+ case "@libs/isAbsoluteUrl":
+ return {isUrlAbsolute: isUrlAbsolute};
+ case "@libs/filterInputs":
+ return {
+ FilterTypes: FilterTypes,
+ isPickerValue: isPickerValue,
+ isCheckboxValue: isCheckboxValue,
+ isSwitchValue: isSwitchValue,
+ isTextValue: isTextValue,
+ isXCheckboxValue: isXCheckboxValue
+ };
+ case "@libs/defaultCover":
+ return {defaultCover: 'https://raw.githubusercontent.com/LNReader/lnreader-plugins/refs/heads/master/public/static/coverNotAvailable.webp'};
+ case "@libs/storage":
+ return {storage: {get: () => null}};
+ default:
+ return {};
+ }
+};
+''');
+ runtime.evaluate('''
+${source.sourceCode}
+const extension = exports.default;
+''');
+ _isInitialized = true;
+ }
+
+ @override
+ Map getHeaders() {
+ return {};
+ }
+
+ @override
+ bool get supportsLatest {
+ return true;
+ }
+
+ @override
+ String get sourceBaseUrl {
+ return source.baseUrl!;
+ }
+
+ @override
+ Future getPopular(int page) async {
+ final items =
+ ((await _extensionCallAsync(
+ 'popularNovels($page, {showLatestNovels: false, filters: extension.filters})',
+ [],
+ )))
+ .map((e) => NovelItem.fromJson(e))
+ .map(
+ (e) => MManga(
+ name: e.name,
+ imageUrl: e.cover,
+ link: e.path,
+ chapters: [],
+ ),
+ )
+ .toList();
+ return MPages(list: items, hasNextPage: true);
+ }
+
+ @override
+ Future getLatestUpdates(int page) async {
+ final items =
+ ((await _extensionCallAsync(
+ 'popularNovels($page, {showLatestNovels: true, filters: extension.filters})',
+ [],
+ )))
+ .map((e) => NovelItem.fromJson(e))
+ .map(
+ (e) => MManga(
+ name: e.name,
+ imageUrl: e.cover,
+ link: e.path,
+ chapters: [],
+ ),
+ )
+ .toList();
+ return MPages(list: items, hasNextPage: true);
+ }
+
+ @override
+ Future search(String query, int page, List filters) async {
+ final items =
+ ((await _extensionCallAsync('searchNovels("$query",$page)', [])))
+ .map((e) => NovelItem.fromJson(e))
+ .map(
+ (e) => MManga(
+ name: e.name,
+ imageUrl: e.cover,
+ link: e.path,
+ chapters: [],
+ ),
+ )
+ .toList();
+ return MPages(list: items, hasNextPage: true);
+ }
+
+ @override
+ Future getDetail(String url) async {
+ final item = SourceNovel.fromJson(
+ await _extensionCallAsync('parseNovel(`$url`)', {}),
+ );
+ final chapters = SourcePage.fromJson(
+ await _extensionCallAsync('parsePage(`${item.path}`, `1`)', {}),
+ );
+ final chaps =
+ ((chapters.chapters.isNotEmpty ? chapters.chapters : item.chapters)
+ ?.map(
+ (e) => MChapter(
+ name: e.name,
+ url: e.path,
+ dateUpload: e.releaseTime != null
+ ? DateTime.tryParse(
+ e.releaseTime!,
+ )?.millisecondsSinceEpoch.toString() ??
+ int.tryParse(e.releaseTime!)?.toString() ??
+ DateTime.now().millisecondsSinceEpoch.toString()
+ : DateTime.now().millisecondsSinceEpoch.toString(),
+ ),
+ )
+ .toList() ??
+ []);
+ return MManga(
+ name: item.name,
+ imageUrl: item.cover,
+ link: item.path,
+ artist: item.artist,
+ author: item.author,
+ description: item.summary,
+ status: switch (item.status) {
+ "Ongoing" => Status.ongoing,
+ "Completed" => Status.completed,
+ _ => Status.unknown,
+ },
+ genre: item.genres?.split(","),
+ chapters: chaps.reversed.toList(),
+ );
+ }
+
+ @override
+ Future> getPageList(String url) async {
+ return [];
+ }
+
+ @override
+ Future> getVideoList(String url) async {
+ return [];
+ }
+
+ @override
+ Future getHtmlContent(String name, String url) async {
+ _init();
+ final res = (await runtime.handlePromise(
+ await runtime.evaluateAsync(
+ 'jsonStringify(() => extension.parseChapter(`$url`))',
+ ),
+ )).stringResult;
+ return res;
+ }
+
+ @override
+ Future cleanHtmlContent(String html) async {
+ return html;
+ }
+
+ @override
+ FilterList getFilterList() {
+ List list;
+
+ try {
+ list = fromJsonFilterValuesToList(_extensionCall('filters', []));
+ } catch (_) {
+ list = [];
+ }
+
+ return FilterList(list);
+ }
+
+ @override
+ List getSourcePreferences() {
+ return _extensionCall(
+ 'pluginSettings',
+ [],
+ ).map((e) => SourcePreference.fromJson(e)..sourceId = source.id).toList();
+ }
+
+ T _extensionCall(String call, T def) {
+ _init();
+
+ try {
+ final res = runtime.evaluate('JSON.stringify(extension.$call)');
+
+ return jsonDecode(res.stringResult) as T;
+ } catch (_) {
+ if (def != null) {
+ return def;
+ }
+ rethrow;
+ }
+ }
+
+ Future _extensionCallAsync(String call, T def) async {
+ _init();
+
+ try {
+ final promised = await runtime.handlePromise(
+ await runtime.evaluateAsync('jsonStringify(() => extension.$call)'),
+ );
+
+ return jsonDecode(promised.stringResult) as T;
+ } catch (e) {
+ if (def != null) {
+ return def;
+ }
+ rethrow;
+ }
+ }
+}
diff --git a/lib/eval/model/source_preference.dart b/lib/eval/model/source_preference.dart
index ff94ef8f..1d8ae361 100644
--- a/lib/eval/model/source_preference.dart
+++ b/lib/eval/model/source_preference.dart
@@ -1,6 +1,6 @@
import 'dart:math';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
part 'source_preference.g.dart';
@collection
diff --git a/lib/eval/model/source_preference.g.dart b/lib/eval/model/source_preference.g.dart
index 0c891c46..8535c4ac 100644
--- a/lib/eval/model/source_preference.g.dart
+++ b/lib/eval/model/source_preference.g.dart
@@ -74,7 +74,7 @@ const SourcePreferenceSchema = CollectionSchema(
getId: _sourcePreferenceGetId,
getLinks: _sourcePreferenceGetLinks,
attach: _sourcePreferenceAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _sourcePreferenceEstimateSize(
@@ -993,7 +993,7 @@ const SourcePreferenceStringValueSchema = CollectionSchema(
getId: _sourcePreferenceStringValueGetId,
getLinks: _sourcePreferenceStringValueGetLinks,
attach: _sourcePreferenceStringValueAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _sourcePreferenceStringValueEstimateSize(
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index 2472367e..a661108b 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -452,6 +452,7 @@
"custom_dns": "Custom DNS (leave blank to use system DNS)",
"android_proxy_server": "Android Proxy Server (ApkBridge)",
"get_apk_bridge": "Get ApkBridge",
+ "get_sync_server": "Get Sync Server here",
"undefined": "undefined",
"empty_extensions_repo": "You don't have any repository urls here. Click on the plus button to add one!",
"add_extensions_repo": "Add repo URL",
diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart
index 764a8b57..c8e48043 100644
--- a/lib/l10n/generated/app_localizations.dart
+++ b/lib/l10n/generated/app_localizations.dart
@@ -2787,6 +2787,12 @@ abstract class AppLocalizations {
/// **'Get ApkBridge'**
String get get_apk_bridge;
+ /// No description provided for @get_sync_server.
+ ///
+ /// In en, this message translates to:
+ /// **'Get Sync Server here'**
+ String get get_sync_server;
+
/// No description provided for @undefined.
///
/// In en, this message translates to:
diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart
index 7548b98f..468ae28d 100644
--- a/lib/l10n/generated/app_localizations_ar.dart
+++ b/lib/l10n/generated/app_localizations_ar.dart
@@ -1430,6 +1430,9 @@ class AppLocalizationsAr extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'غير محدد';
diff --git a/lib/l10n/generated/app_localizations_as.dart b/lib/l10n/generated/app_localizations_as.dart
index d77408b7..24dfda39 100644
--- a/lib/l10n/generated/app_localizations_as.dart
+++ b/lib/l10n/generated/app_localizations_as.dart
@@ -1432,6 +1432,9 @@ class AppLocalizationsAs extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'undefined';
diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart
index 2f0f882c..2f519dbb 100644
--- a/lib/l10n/generated/app_localizations_de.dart
+++ b/lib/l10n/generated/app_localizations_de.dart
@@ -1441,6 +1441,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'Nicht definiert';
diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart
index a3be3dd0..489460c8 100644
--- a/lib/l10n/generated/app_localizations_en.dart
+++ b/lib/l10n/generated/app_localizations_en.dart
@@ -1431,6 +1431,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'undefined';
diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart
index fb161527..c5541f63 100644
--- a/lib/l10n/generated/app_localizations_es.dart
+++ b/lib/l10n/generated/app_localizations_es.dart
@@ -1445,6 +1445,9 @@ class AppLocalizationsEs extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'Indefinido';
diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart
index 1eb185a5..5570d62a 100644
--- a/lib/l10n/generated/app_localizations_fr.dart
+++ b/lib/l10n/generated/app_localizations_fr.dart
@@ -1448,6 +1448,9 @@ class AppLocalizationsFr extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'Indéfini';
diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart
index 65af21f1..2b0cea5f 100644
--- a/lib/l10n/generated/app_localizations_hi.dart
+++ b/lib/l10n/generated/app_localizations_hi.dart
@@ -1433,6 +1433,9 @@ class AppLocalizationsHi extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'undefined';
diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart
index 4fc46362..f3d08bb4 100644
--- a/lib/l10n/generated/app_localizations_id.dart
+++ b/lib/l10n/generated/app_localizations_id.dart
@@ -1437,6 +1437,9 @@ class AppLocalizationsId extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'Tidak terdefinisi';
diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart
index 4d4ba859..965a8aa9 100644
--- a/lib/l10n/generated/app_localizations_it.dart
+++ b/lib/l10n/generated/app_localizations_it.dart
@@ -1445,6 +1445,9 @@ class AppLocalizationsIt extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'Non definito';
diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart
index 585b9116..015c0c86 100644
--- a/lib/l10n/generated/app_localizations_pt.dart
+++ b/lib/l10n/generated/app_localizations_pt.dart
@@ -1442,6 +1442,9 @@ class AppLocalizationsPt extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'Indefinido';
diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart
index 08024fed..8a1dc0a9 100644
--- a/lib/l10n/generated/app_localizations_ru.dart
+++ b/lib/l10n/generated/app_localizations_ru.dart
@@ -1444,6 +1444,9 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'Не определено';
diff --git a/lib/l10n/generated/app_localizations_th.dart b/lib/l10n/generated/app_localizations_th.dart
index e7b1d12b..582d067e 100644
--- a/lib/l10n/generated/app_localizations_th.dart
+++ b/lib/l10n/generated/app_localizations_th.dart
@@ -1431,6 +1431,9 @@ class AppLocalizationsTh extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'ไม่ได้กำหนด';
diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart
index 812671ab..44f1a065 100644
--- a/lib/l10n/generated/app_localizations_tr.dart
+++ b/lib/l10n/generated/app_localizations_tr.dart
@@ -1437,6 +1437,9 @@ class AppLocalizationsTr extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => 'Tanımsız';
diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart
index ef018eb0..59f66528 100644
--- a/lib/l10n/generated/app_localizations_zh.dart
+++ b/lib/l10n/generated/app_localizations_zh.dart
@@ -1405,6 +1405,9 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get get_apk_bridge => 'Get ApkBridge';
+ @override
+ String get get_sync_server => 'Get Sync Server here';
+
@override
String get undefined => '未定义';
diff --git a/lib/main.dart b/lib/main.dart
index 4ad862f4..171087d7 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -12,7 +12,7 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:intl/date_symbol_data_local.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/eval/model/m_bridge.dart';
import 'package:mangayomi/models/custom_button.dart';
import 'package:mangayomi/models/manga.dart';
@@ -73,7 +73,7 @@ void main(List args) async {
await storage.requestPermission();
await _migrateOldLayout();
isar = await storage.initDB(null, inspector: kDebugMode);
- runApp(const ProviderScope(child: MyApp()));
+ runApp(ProviderScope(child: MyApp(), retry: (retryCount, error) => null));
unawaited(_postLaunchInit(storage)); // Defer non-essential async operations
}
@@ -404,7 +404,13 @@ class _MyAppState extends ConsumerState {
status: track.TrackStatus.completed,
);
ref
- .read(trackStateProvider(track: temp, itemType: null).notifier)
+ .read(
+ trackStateProvider(
+ track: temp,
+ itemType: null,
+ widgetRef: ref,
+ ).notifier,
+ )
.checkRefresh();
}
}
diff --git a/lib/models/category.dart b/lib/models/category.dart
index 70ee1421..9abf359f 100644
--- a/lib/models/category.dart
+++ b/lib/models/category.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/models/manga.dart';
part 'category.g.dart';
diff --git a/lib/models/category.g.dart b/lib/models/category.g.dart
index 05aa7bc3..6ad26997 100644
--- a/lib/models/category.g.dart
+++ b/lib/models/category.g.dart
@@ -46,7 +46,7 @@ const CategorySchema = CollectionSchema(
getId: _categoryGetId,
getLinks: _categoryGetLinks,
attach: _categoryAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _categoryEstimateSize(
diff --git a/lib/models/changed.dart b/lib/models/changed.dart
index 483f76a0..c572f4e0 100644
--- a/lib/models/changed.dart
+++ b/lib/models/changed.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
part 'changed.g.dart';
@collection
diff --git a/lib/models/changed.g.dart b/lib/models/changed.g.dart
index 1b2e17ea..832079a6 100644
--- a/lib/models/changed.g.dart
+++ b/lib/models/changed.g.dart
@@ -44,7 +44,7 @@ const ChangedPartSchema = CollectionSchema(
getId: _changedPartGetId,
getLinks: _changedPartGetLinks,
attach: _changedPartAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _changedPartEstimateSize(
diff --git a/lib/models/chapter.dart b/lib/models/chapter.dart
index d2d2c0e7..74d12884 100644
--- a/lib/models/chapter.dart
+++ b/lib/models/chapter.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/models/manga.dart';
part 'chapter.g.dart';
diff --git a/lib/models/chapter.g.dart b/lib/models/chapter.g.dart
index 4fae9ea1..37091ee1 100644
--- a/lib/models/chapter.g.dart
+++ b/lib/models/chapter.g.dart
@@ -93,7 +93,7 @@ const ChapterSchema = CollectionSchema(
getId: _chapterGetId,
getLinks: _chapterGetLinks,
attach: _chapterAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _chapterEstimateSize(
diff --git a/lib/models/custom_button.dart b/lib/models/custom_button.dart
index b0bd3873..f6f783dc 100644
--- a/lib/models/custom_button.dart
+++ b/lib/models/custom_button.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
part 'custom_button.g.dart';
@collection
diff --git a/lib/models/custom_button.g.dart b/lib/models/custom_button.g.dart
index 37b81a20..054e207a 100644
--- a/lib/models/custom_button.g.dart
+++ b/lib/models/custom_button.g.dart
@@ -58,7 +58,7 @@ const CustomButtonSchema = CollectionSchema(
getId: _customButtonGetId,
getLinks: _customButtonGetLinks,
attach: _customButtonAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _customButtonEstimateSize(
diff --git a/lib/models/download.dart b/lib/models/download.dart
index a751c87e..588d693b 100644
--- a/lib/models/download.dart
+++ b/lib/models/download.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/models/chapter.dart';
part 'download.g.dart';
diff --git a/lib/models/download.g.dart b/lib/models/download.g.dart
index 376e2df3..1bfe7503 100644
--- a/lib/models/download.g.dart
+++ b/lib/models/download.g.dart
@@ -55,7 +55,7 @@ const DownloadSchema = CollectionSchema(
getId: _downloadGetId,
getLinks: _downloadGetLinks,
attach: _downloadAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _downloadEstimateSize(
diff --git a/lib/models/history.dart b/lib/models/history.dart
index e590d87b..f42d4d73 100644
--- a/lib/models/history.dart
+++ b/lib/models/history.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
part 'history.g.dart';
diff --git a/lib/models/history.g.dart b/lib/models/history.g.dart
index 2fde9356..9a233915 100644
--- a/lib/models/history.g.dart
+++ b/lib/models/history.g.dart
@@ -57,7 +57,7 @@ const HistorySchema = CollectionSchema(
getId: _historyGetId,
getLinks: _historyGetLinks,
attach: _historyAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _historyEstimateSize(
diff --git a/lib/models/manga.dart b/lib/models/manga.dart
index 2ba33566..7b5e15ee 100644
--- a/lib/models/manga.dart
+++ b/lib/models/manga.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/models/chapter.dart';
part 'manga.g.dart';
diff --git a/lib/models/manga.g.dart b/lib/models/manga.g.dart
index c8d0ce3c..d60c6848 100644
--- a/lib/models/manga.g.dart
+++ b/lib/models/manga.g.dart
@@ -112,7 +112,7 @@ const MangaSchema = CollectionSchema(
getId: _mangaGetId,
getLinks: _mangaGetLinks,
attach: _mangaAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _mangaEstimateSize(
diff --git a/lib/models/settings.dart b/lib/models/settings.dart
index 1b9bd8ac..5a4ec726 100644
--- a/lib/models/settings.dart
+++ b/lib/models/settings.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/utils/constant.dart';
part 'settings.g.dart';
@@ -281,7 +281,7 @@ class Settings {
late AudioChannel audioChannels;
int? volumeBoostCap;
-
+
bool? downloadedOnlyMode;
late AlgorithmWeights? algorithmWeights;
diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart
index 37f87c9d..53bfa3ab 100644
--- a/lib/models/settings.g.dart
+++ b/lib/models/settings.g.dart
@@ -777,7 +777,7 @@ const SettingsSchema = CollectionSchema(
getId: _settingsGetId,
getLinks: _settingsGetLinks,
attach: _settingsAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _settingsEstimateSize(
diff --git a/lib/models/source.dart b/lib/models/source.dart
index 66184ac5..8fab57e9 100644
--- a/lib/models/source.dart
+++ b/lib/models/source.dart
@@ -1,6 +1,6 @@
import 'dart:convert';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/eval/model/filter.dart';
import 'package:mangayomi/eval/model/m_source.dart';
import 'package:mangayomi/models/manga.dart';
@@ -135,7 +135,7 @@ class Source {
filterList = json['filterList'];
preferenceList = json['preferenceList'];
iconUrl = json['iconUrl'];
- id = json['id'];
+ id = json['id'] is int ? json['id'] : null;
isActive = json['isActive'];
isAdded = json['isAdded'];
isFullData = json['isFullData'];
@@ -216,4 +216,4 @@ class Source {
}
}
-enum SourceCodeLanguage { dart, javascript, mihon }
+enum SourceCodeLanguage { dart, javascript, mihon, lnreader }
diff --git a/lib/models/source.g.dart b/lib/models/source.g.dart
index bf2d532c..e5a3a563 100644
--- a/lib/models/source.g.dart
+++ b/lib/models/source.g.dart
@@ -145,7 +145,7 @@ const SourceSchema = CollectionSchema(
getId: _sourceGetId,
getLinks: _sourceGetLinks,
attach: _sourceAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _sourceEstimateSize(
@@ -475,11 +475,13 @@ const _SourcesourceCodeLanguageEnumValueMap = {
'dart': 0,
'javascript': 1,
'mihon': 2,
+ 'lnreader': 3,
};
const _SourcesourceCodeLanguageValueEnumMap = {
0: SourceCodeLanguage.dart,
1: SourceCodeLanguage.javascript,
2: SourceCodeLanguage.mihon,
+ 3: SourceCodeLanguage.lnreader,
};
Id _sourceGetId(Source object) {
diff --git a/lib/models/sync_preference.dart b/lib/models/sync_preference.dart
index 9c8a7767..216e7c86 100644
--- a/lib/models/sync_preference.dart
+++ b/lib/models/sync_preference.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
part 'sync_preference.g.dart';
@collection
diff --git a/lib/models/sync_preference.g.dart b/lib/models/sync_preference.g.dart
index 1248547c..ea08574d 100644
--- a/lib/models/sync_preference.g.dart
+++ b/lib/models/sync_preference.g.dart
@@ -74,7 +74,7 @@ const SyncPreferenceSchema = CollectionSchema(
getId: _syncPreferenceGetId,
getLinks: _syncPreferenceGetLinks,
attach: _syncPreferenceAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _syncPreferenceEstimateSize(
diff --git a/lib/models/track.dart b/lib/models/track.dart
index f66090d9..402d2481 100644
--- a/lib/models/track.dart
+++ b/lib/models/track.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/models/manga.dart';
part 'track.g.dart';
diff --git a/lib/models/track.g.dart b/lib/models/track.g.dart
index c5602505..b3608a7b 100644
--- a/lib/models/track.g.dart
+++ b/lib/models/track.g.dart
@@ -84,7 +84,7 @@ const TrackSchema = CollectionSchema(
getId: _trackGetId,
getLinks: _trackGetLinks,
attach: _trackAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _trackEstimateSize(
diff --git a/lib/models/track_preference.dart b/lib/models/track_preference.dart
index 9018daf2..722a9b0b 100644
--- a/lib/models/track_preference.dart
+++ b/lib/models/track_preference.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
part 'track_preference.g.dart';
@collection
diff --git a/lib/models/track_preference.g.dart b/lib/models/track_preference.g.dart
index 9fb8268d..ca4f802a 100644
--- a/lib/models/track_preference.g.dart
+++ b/lib/models/track_preference.g.dart
@@ -43,7 +43,7 @@ const TrackPreferenceSchema = CollectionSchema(
getId: _trackPreferenceGetId,
getLinks: _trackPreferenceGetLinks,
attach: _trackPreferenceAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _trackPreferenceEstimateSize(
diff --git a/lib/models/update.dart b/lib/models/update.dart
index 05428291..e90fc4c0 100644
--- a/lib/models/update.dart
+++ b/lib/models/update.dart
@@ -1,4 +1,4 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/models/chapter.dart';
part 'update.g.dart';
diff --git a/lib/models/update.g.dart b/lib/models/update.g.dart
index ea5502ed..04896195 100644
--- a/lib/models/update.g.dart
+++ b/lib/models/update.g.dart
@@ -50,7 +50,7 @@ const UpdateSchema = CollectionSchema(
getId: _updateGetId,
getLinks: _updateGetLinks,
attach: _updateAttach,
- version: '3.1.0+1',
+ version: '3.3.0-dev.3',
);
int _updateEstimateSize(
diff --git a/lib/modules/anime/anime_player_view.dart b/lib/modules/anime/anime_player_view.dart
index b8ec1d46..6e6afb7e 100644
--- a/lib/modules/anime/anime_player_view.dart
+++ b/lib/modules/anime/anime_player_view.dart
@@ -986,6 +986,7 @@ mp.register_script_message('call_button_${button.id}_long', button${button.id}lo
_currentPosition.dispose();
_subDelayController.dispose();
_subSpeedController.dispose();
+ _streamController.keepAliveLink?.close();
super.dispose();
}
@@ -2260,17 +2261,19 @@ mp.register_script_message('call_button_${button.id}_long', button${button.id}lo
if (context.mounted) {
final box =
context.findRenderObject() as RenderBox?;
- await Share.shareXFiles(
- [
- XFile.fromData(
- imageBytes!,
- name: name,
- mimeType: 'image/png',
- ),
- ],
- sharePositionOrigin:
- box!.localToGlobal(Offset.zero) &
- box.size,
+ await SharePlus.instance.share(
+ ShareParams(
+ files: [
+ XFile.fromData(
+ imageBytes!,
+ name: name,
+ mimeType: 'image/png',
+ ),
+ ],
+ sharePositionOrigin:
+ box!.localToGlobal(Offset.zero) &
+ box.size,
+ ),
);
}
},
diff --git a/lib/modules/anime/providers/anime_player_controller_provider.dart b/lib/modules/anime/providers/anime_player_controller_provider.dart
index 9105238c..4c8d407d 100644
--- a/lib/modules/anime/providers/anime_player_controller_provider.dart
+++ b/lib/modules/anime/providers/anime_player_controller_provider.dart
@@ -1,5 +1,5 @@
-import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:isar/isar.dart';
+import 'package:flutter_riverpod/misc.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/history.dart';
@@ -10,16 +10,23 @@ import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provi
import 'package:mangayomi/modules/more/settings/player/providers/player_state_provider.dart';
import 'package:mangayomi/services/aniskip.dart';
import 'package:mangayomi/utils/chapter_recognition.dart';
+import 'package:mangayomi/utils/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'anime_player_controller_provider.g.dart';
-final fullscreenProvider = StateProvider((ref) => false);
+final fullscreenProvider = StateProvider(() => false);
@riverpod
class AnimeStreamController extends _$AnimeStreamController {
@override
- void build({required Chapter episode}) {}
+ KeepAliveLink build({required Chapter episode}) {
+ _keepAliveLink = ref.keepAlive();
+ return _keepAliveLink!;
+ }
+ KeepAliveLink? _keepAliveLink;
+
+ KeepAliveLink? get keepAliveLink => _keepAliveLink;
Manga getAnime() {
return episode.manga.value!;
}
diff --git a/lib/modules/anime/providers/anime_player_controller_provider.g.dart b/lib/modules/anime/providers/anime_player_controller_provider.g.dart
index 5ca0995e..9307298d 100644
--- a/lib/modules/anime/providers/anime_player_controller_provider.g.dart
+++ b/lib/modules/anime/providers/anime_player_controller_provider.g.dart
@@ -6,159 +6,104 @@ part of 'anime_player_controller_provider.dart';
// RiverpodGenerator
// **************************************************************************
-String _$animeStreamControllerHash() =>
- r'46cc71afefa3b3c060f7a28c61dc13e1d0b94999';
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint, type=warning
-/// Copied from Dart SDK
-class _SystemHash {
- _SystemHash._();
-
- static int combine(int hash, int value) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + value);
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
- return hash ^ (hash >> 6);
- }
-
- static int finish(int hash) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
- // ignore: parameter_assignments
- hash = hash ^ (hash >> 11);
- return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
- }
-}
-
-abstract class _$AnimeStreamController
- extends BuildlessAutoDisposeNotifier {
- late final Chapter episode;
-
- void build({required Chapter episode});
-}
-
-/// See also [AnimeStreamController].
@ProviderFor(AnimeStreamController)
-const animeStreamControllerProvider = AnimeStreamControllerFamily();
+const animeStreamControllerProvider = AnimeStreamControllerFamily._();
-/// See also [AnimeStreamController].
-class AnimeStreamControllerFamily extends Family {
- /// See also [AnimeStreamController].
- const AnimeStreamControllerFamily();
+final class AnimeStreamControllerProvider
+ extends $NotifierProvider {
+ const AnimeStreamControllerProvider._({
+ required AnimeStreamControllerFamily super.from,
+ required Chapter super.argument,
+ }) : super(
+ retry: null,
+ name: r'animeStreamControllerProvider',
+ isAutoDispose: true,
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ );
- /// See also [AnimeStreamController].
- AnimeStreamControllerProvider call({required Chapter episode}) {
- return AnimeStreamControllerProvider(episode: episode);
+ @override
+ String debugGetCreateSourceHash() => _$animeStreamControllerHash();
+
+ @override
+ String toString() {
+ return r'animeStreamControllerProvider'
+ ''
+ '($argument)';
}
+ @$internal
@override
- AnimeStreamControllerProvider getProviderOverride(
- covariant AnimeStreamControllerProvider provider,
- ) {
- return call(episode: provider.episode);
- }
+ AnimeStreamController create() => AnimeStreamController();
- static const Iterable? _dependencies = null;
-
- @override
- Iterable? get dependencies => _dependencies;
-
- static const Iterable? _allTransitiveDependencies = null;
-
- @override
- Iterable? get allTransitiveDependencies =>
- _allTransitiveDependencies;
-
- @override
- String? get name => r'animeStreamControllerProvider';
-}
-
-/// See also [AnimeStreamController].
-class AnimeStreamControllerProvider
- extends AutoDisposeNotifierProviderImpl {
- /// See also [AnimeStreamController].
- AnimeStreamControllerProvider({required Chapter episode})
- : this._internal(
- () => AnimeStreamController()..episode = episode,
- from: animeStreamControllerProvider,
- name: r'animeStreamControllerProvider',
- debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
- ? null
- : _$animeStreamControllerHash,
- dependencies: AnimeStreamControllerFamily._dependencies,
- allTransitiveDependencies:
- AnimeStreamControllerFamily._allTransitiveDependencies,
- episode: episode,
- );
-
- AnimeStreamControllerProvider._internal(
- super._createNotifier, {
- required super.name,
- required super.dependencies,
- required super.allTransitiveDependencies,
- required super.debugGetCreateSourceHash,
- required super.from,
- required this.episode,
- }) : super.internal();
-
- final Chapter episode;
-
- @override
- void runNotifierBuild(covariant AnimeStreamController notifier) {
- return notifier.build(episode: episode);
- }
-
- @override
- Override overrideWith(AnimeStreamController Function() create) {
- return ProviderOverride(
+ /// {@macro riverpod.override_with_value}
+ Override overrideWithValue(KeepAliveLink value) {
+ return $ProviderOverride(
origin: this,
- override: AnimeStreamControllerProvider._internal(
- () => create()..episode = episode,
- from: from,
- name: null,
- dependencies: null,
- allTransitiveDependencies: null,
- debugGetCreateSourceHash: null,
- episode: episode,
- ),
+ providerOverride: $SyncValueProvider(value),
);
}
- @override
- AutoDisposeNotifierProviderElement
- createElement() {
- return _AnimeStreamControllerProviderElement(this);
- }
-
@override
bool operator ==(Object other) {
- return other is AnimeStreamControllerProvider && other.episode == episode;
+ return other is AnimeStreamControllerProvider && other.argument == argument;
}
@override
int get hashCode {
- var hash = _SystemHash.combine(0, runtimeType.hashCode);
- hash = _SystemHash.combine(hash, episode.hashCode);
-
- return _SystemHash.finish(hash);
+ return argument.hashCode;
}
}
-@Deprecated('Will be removed in 3.0. Use Ref instead')
-// ignore: unused_element
-mixin AnimeStreamControllerRef on AutoDisposeNotifierProviderRef {
- /// The parameter `episode` of this provider.
- Chapter get episode;
-}
+String _$animeStreamControllerHash() =>
+ r'486889b2b9f71759e4d9ff147b039436572cc01e';
-class _AnimeStreamControllerProviderElement
- extends AutoDisposeNotifierProviderElement
- with AnimeStreamControllerRef {
- _AnimeStreamControllerProviderElement(super.provider);
+final class AnimeStreamControllerFamily extends $Family
+ with
+ $ClassFamilyOverride<
+ AnimeStreamController,
+ KeepAliveLink,
+ KeepAliveLink,
+ KeepAliveLink,
+ Chapter
+ > {
+ const AnimeStreamControllerFamily._()
+ : super(
+ retry: null,
+ name: r'animeStreamControllerProvider',
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ isAutoDispose: true,
+ );
+
+ AnimeStreamControllerProvider call({required Chapter episode}) =>
+ AnimeStreamControllerProvider._(argument: episode, from: this);
@override
- Chapter get episode => (origin as AnimeStreamControllerProvider).episode;
+ String toString() => r'animeStreamControllerProvider';
}
-// ignore_for_file: type=lint
-// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
+abstract class _$AnimeStreamController extends $Notifier {
+ late final _$args = ref.$arg as Chapter;
+ Chapter get episode => _$args;
+
+ KeepAliveLink build({required Chapter episode});
+ @$mustCallSuper
+ @override
+ void runBuild() {
+ final created = build(episode: _$args);
+ final ref = this.ref as $Ref;
+ final element =
+ ref.element
+ as $ClassProviderElement<
+ AnyNotifier,
+ KeepAliveLink,
+ Object?,
+ Object?
+ >;
+ element.handleValue(ref, created);
+ }
+}
diff --git a/lib/modules/anime/providers/state_provider.g.dart b/lib/modules/anime/providers/state_provider.g.dart
index b97a147a..ec84074e 100644
--- a/lib/modules/anime/providers/state_provider.g.dart
+++ b/lib/modules/anime/providers/state_provider.g.dart
@@ -6,25 +6,61 @@ part of 'state_provider.dart';
// RiverpodGenerator
// **************************************************************************
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint, type=warning
+
+@ProviderFor(SubtitleSettingsState)
+const subtitleSettingsStateProvider = SubtitleSettingsStateProvider._();
+
+final class SubtitleSettingsStateProvider
+ extends $NotifierProvider {
+ const SubtitleSettingsStateProvider._()
+ : super(
+ from: null,
+ argument: null,
+ retry: null,
+ name: r'subtitleSettingsStateProvider',
+ isAutoDispose: true,
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ );
+
+ @override
+ String debugGetCreateSourceHash() => _$subtitleSettingsStateHash();
+
+ @$internal
+ @override
+ SubtitleSettingsState create() => SubtitleSettingsState();
+
+ /// {@macro riverpod.override_with_value}
+ Override overrideWithValue(PlayerSubtitleSettings value) {
+ return $ProviderOverride(
+ origin: this,
+ providerOverride: $SyncValueProvider(value),
+ );
+ }
+}
+
String _$subtitleSettingsStateHash() =>
r'410485b55561b7a307c7a55f6798bca225f39830';
-/// See also [SubtitleSettingsState].
-@ProviderFor(SubtitleSettingsState)
-final subtitleSettingsStateProvider =
- AutoDisposeNotifierProvider<
- SubtitleSettingsState,
- PlayerSubtitleSettings
- >.internal(
- SubtitleSettingsState.new,
- name: r'subtitleSettingsStateProvider',
- debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
- ? null
- : _$subtitleSettingsStateHash,
- dependencies: null,
- allTransitiveDependencies: null,
- );
-
-typedef _$SubtitleSettingsState = AutoDisposeNotifier;
-// ignore_for_file: type=lint
-// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
+abstract class _$SubtitleSettingsState
+ extends $Notifier {
+ PlayerSubtitleSettings build();
+ @$mustCallSuper
+ @override
+ void runBuild() {
+ final created = build();
+ final ref =
+ this.ref as $Ref;
+ final element =
+ ref.element
+ as $ClassProviderElement<
+ AnyNotifier,
+ PlayerSubtitleSettings,
+ Object?,
+ Object?
+ >;
+ element.handleValue(ref, created);
+ }
+}
diff --git a/lib/modules/anime/widgets/search_subtitles.dart b/lib/modules/anime/widgets/search_subtitles.dart
index f62246f9..266493b1 100644
--- a/lib/modules/anime/widgets/search_subtitles.dart
+++ b/lib/modules/anime/widgets/search_subtitles.dart
@@ -47,7 +47,7 @@ class _SubtitlesWidgetSearchState extends ConsumerState {
_init();
}
- _init() async {
+ Future _init() async {
await Future.delayed(const Duration(microseconds: 100));
try {
titles = await fetchImdbTitles(query);
@@ -392,7 +392,7 @@ class _SubtitlesWidgetSearchState extends ConsumerState {
}
}
-subtitlesSearchraggableMenu(
+Future subtitlesSearchraggableMenu(
BuildContext context, {
required Chapter chapter,
required bool isLocal,
diff --git a/lib/modules/browse/browse_screen.dart b/lib/modules/browse/browse_screen.dart
index bbc493e6..9067e763 100644
--- a/lib/modules/browse/browse_screen.dart
+++ b/lib/modules/browse/browse_screen.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart';
@@ -48,7 +48,7 @@ class _BrowseScreenState extends ConsumerState
});
}
- _chekPermission() async {
+ Future _chekPermission() async {
await StorageProvider().requestPermission();
}
diff --git a/lib/modules/browse/extension/extension_detail.dart b/lib/modules/browse/extension/extension_detail.dart
index 959f7300..32a2b923 100644
--- a/lib/modules/browse/extension/extension_detail.dart
+++ b/lib/modules/browse/extension/extension_detail.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/eval/model/m_bridge.dart';
import 'package:mangayomi/eval/model/source_preference.dart';
import 'package:mangayomi/main.dart';
diff --git a/lib/modules/browse/extension/extension_lang.dart b/lib/modules/browse/extension/extension_lang.dart
index f1c4c5e3..188a97d0 100644
--- a/lib/modules/browse/extension/extension_lang.dart
+++ b/lib/modules/browse/extension/extension_lang.dart
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart';
diff --git a/lib/modules/browse/extension/providers/extension_preferences_providers.dart b/lib/modules/browse/extension/providers/extension_preferences_providers.dart
index b4d0b222..0e2911dd 100644
--- a/lib/modules/browse/extension/providers/extension_preferences_providers.dart
+++ b/lib/modules/browse/extension/providers/extension_preferences_providers.dart
@@ -1,6 +1,6 @@
import 'dart:convert';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/eval/model/source_preference.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
@@ -37,7 +37,7 @@ void setPreferenceSetting(SourcePreference sourcePreference, Source source) {
});
}
-getPreferenceValue(int sourceId, String key) {
+dynamic getPreferenceValue(int sourceId, String key) {
final sourcePreference = getSourcePreferenceEntry(key, sourceId);
if (sourcePreference.listPreference != null) {
diff --git a/lib/modules/browse/extension/providers/extensions_provider.dart b/lib/modules/browse/extension/providers/extensions_provider.dart
index 0d77bf54..5ece8317 100644
--- a/lib/modules/browse/extension/providers/extensions_provider.dart
+++ b/lib/modules/browse/extension/providers/extensions_provider.dart
@@ -1,10 +1,9 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/models/source.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'extensions_provider.g.dart';
@riverpod
diff --git a/lib/modules/browse/extension/providers/extensions_provider.g.dart b/lib/modules/browse/extension/providers/extensions_provider.g.dart
index 92849ad3..ff29fd05 100644
--- a/lib/modules/browse/extension/providers/extensions_provider.g.dart
+++ b/lib/modules/browse/extension/providers/extensions_provider.g.dart
@@ -6,148 +6,81 @@ part of 'extensions_provider.dart';
// RiverpodGenerator
// **************************************************************************
-String _$getExtensionsStreamHash() =>
- r'18790d3d4a7f52e5e7239c8726dcd09bb51d803a';
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint, type=warning
-/// Copied from Dart SDK
-class _SystemHash {
- _SystemHash._();
-
- static int combine(int hash, int value) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + value);
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
- return hash ^ (hash >> 6);
- }
-
- static int finish(int hash) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
- // ignore: parameter_assignments
- hash = hash ^ (hash >> 11);
- return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
- }
-}
-
-/// See also [getExtensionsStream].
@ProviderFor(getExtensionsStream)
-const getExtensionsStreamProvider = GetExtensionsStreamFamily();
+const getExtensionsStreamProvider = GetExtensionsStreamFamily._();
-/// See also [getExtensionsStream].
-class GetExtensionsStreamFamily extends Family>> {
- /// See also [getExtensionsStream].
- const GetExtensionsStreamFamily();
+final class GetExtensionsStreamProvider
+ extends
+ $FunctionalProvider<
+ AsyncValue>,
+ List,
+ Stream>
+ >
+ with $FutureModifier>, $StreamProvider> {
+ const GetExtensionsStreamProvider._({
+ required GetExtensionsStreamFamily super.from,
+ required ItemType super.argument,
+ }) : super(
+ retry: null,
+ name: r'getExtensionsStreamProvider',
+ isAutoDispose: true,
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ );
- /// See also [getExtensionsStream].
- GetExtensionsStreamProvider call(ItemType itemType) {
- return GetExtensionsStreamProvider(itemType);
+ @override
+ String debugGetCreateSourceHash() => _$getExtensionsStreamHash();
+
+ @override
+ String toString() {
+ return r'getExtensionsStreamProvider'
+ ''
+ '($argument)';
}
+ @$internal
@override
- GetExtensionsStreamProvider getProviderOverride(
- covariant GetExtensionsStreamProvider provider,
- ) {
- return call(provider.itemType);
- }
-
- static const Iterable? _dependencies = null;
+ $StreamProviderElement> $createElement(
+ $ProviderPointer pointer,
+ ) => $StreamProviderElement(pointer);
@override
- Iterable? get dependencies => _dependencies;
-
- static const Iterable? _allTransitiveDependencies = null;
-
- @override
- Iterable? get allTransitiveDependencies =>
- _allTransitiveDependencies;
-
- @override
- String? get name => r'getExtensionsStreamProvider';
-}
-
-/// See also [getExtensionsStream].
-class GetExtensionsStreamProvider
- extends AutoDisposeStreamProvider> {
- /// See also [getExtensionsStream].
- GetExtensionsStreamProvider(ItemType itemType)
- : this._internal(
- (ref) => getExtensionsStream(ref as GetExtensionsStreamRef, itemType),
- from: getExtensionsStreamProvider,
- name: r'getExtensionsStreamProvider',
- debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
- ? null
- : _$getExtensionsStreamHash,
- dependencies: GetExtensionsStreamFamily._dependencies,
- allTransitiveDependencies:
- GetExtensionsStreamFamily._allTransitiveDependencies,
- itemType: itemType,
- );
-
- GetExtensionsStreamProvider._internal(
- super._createNotifier, {
- required super.name,
- required super.dependencies,
- required super.allTransitiveDependencies,
- required super.debugGetCreateSourceHash,
- required super.from,
- required this.itemType,
- }) : super.internal();
-
- final ItemType itemType;
-
- @override
- Override overrideWith(
- Stream> Function(GetExtensionsStreamRef provider) create,
- ) {
- return ProviderOverride(
- origin: this,
- override: GetExtensionsStreamProvider._internal(
- (ref) => create(ref as GetExtensionsStreamRef),
- from: from,
- name: null,
- dependencies: null,
- allTransitiveDependencies: null,
- debugGetCreateSourceHash: null,
- itemType: itemType,
- ),
- );
- }
-
- @override
- AutoDisposeStreamProviderElement> createElement() {
- return _GetExtensionsStreamProviderElement(this);
+ Stream> create(Ref ref) {
+ final argument = this.argument as ItemType;
+ return getExtensionsStream(ref, argument);
}
@override
bool operator ==(Object other) {
- return other is GetExtensionsStreamProvider && other.itemType == itemType;
+ return other is GetExtensionsStreamProvider && other.argument == argument;
}
@override
int get hashCode {
- var hash = _SystemHash.combine(0, runtimeType.hashCode);
- hash = _SystemHash.combine(hash, itemType.hashCode);
-
- return _SystemHash.finish(hash);
+ return argument.hashCode;
}
}
-@Deprecated('Will be removed in 3.0. Use Ref instead')
-// ignore: unused_element
-mixin GetExtensionsStreamRef on AutoDisposeStreamProviderRef> {
- /// The parameter `itemType` of this provider.
- ItemType get itemType;
-}
+String _$getExtensionsStreamHash() =>
+ r'18790d3d4a7f52e5e7239c8726dcd09bb51d803a';
-class _GetExtensionsStreamProviderElement
- extends AutoDisposeStreamProviderElement>
- with GetExtensionsStreamRef {
- _GetExtensionsStreamProviderElement(super.provider);
+final class GetExtensionsStreamFamily extends $Family
+ with $FunctionalFamilyOverride>, ItemType> {
+ const GetExtensionsStreamFamily._()
+ : super(
+ retry: null,
+ name: r'getExtensionsStreamProvider',
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ isAutoDispose: true,
+ );
+
+ GetExtensionsStreamProvider call(ItemType itemType) =>
+ GetExtensionsStreamProvider._(argument: itemType, from: this);
@override
- ItemType get itemType => (origin as GetExtensionsStreamProvider).itemType;
+ String toString() => r'getExtensionsStreamProvider';
}
-
-// ignore_for_file: type=lint
-// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
diff --git a/lib/modules/browse/extension/widgets/create_extension.dart b/lib/modules/browse/extension/widgets/create_extension.dart
index 705853af..c038f68b 100644
--- a/lib/modules/browse/extension/widgets/create_extension.dart
+++ b/lib/modules/browse/extension/widgets/create_extension.dart
@@ -26,7 +26,11 @@ class _CreateExtensionState extends State {
int _languageIndex = 0;
final List _sourceTypes = ["single", "multi", "torrent"];
final List _itemTypes = ["Manga", "Anime", "Novel"];
- final List _languages = ["Dart", "JavaScript"];
+ final List _languages = [
+ "Dart",
+ "JavaScript",
+ "LNReader compiled JS",
+ ];
SourceCodeLanguage _sourceCodeLanguage = SourceCodeLanguage.dart;
@override
Widget build(BuildContext context) {
@@ -67,9 +71,11 @@ class _CreateExtensionState extends State {
setState(() {
if (v == 0) {
_sourceCodeLanguage = SourceCodeLanguage.dart;
- } else {
+ } else if (v == 1) {
_sourceCodeLanguage =
SourceCodeLanguage.javascript;
+ } else {
+ _sourceCodeLanguage = SourceCodeLanguage.lnreader;
}
_languageIndex = v!;
});
diff --git a/lib/modules/browse/extension/widgets/extension_list_tile_widget.dart b/lib/modules/browse/extension/widgets/extension_list_tile_widget.dart
index 6da6eb78..f003a9ee 100644
--- a/lib/modules/browse/extension/widgets/extension_list_tile_widget.dart
+++ b/lib/modules/browse/extension/widgets/extension_list_tile_widget.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/eval/model/source_preference.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/changed.dart';
diff --git a/lib/modules/browse/global_search/global_search_screen.dart b/lib/modules/browse/global_search/global_search_screen.dart
index 7b3f2e6a..eb06339d 100644
--- a/lib/modules/browse/global_search/global_search_screen.dart
+++ b/lib/modules/browse/global_search/global_search_screen.dart
@@ -1,7 +1,7 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/eval/model/m_manga.dart';
import 'package:mangayomi/eval/model/m_pages.dart';
import 'package:mangayomi/main.dart';
@@ -143,7 +143,7 @@ class _SourceSearchScreenState extends ConsumerState {
String _errorMessage = "";
bool _isLoading = true;
MPages? pages;
- _init() async {
+ Future _init() async {
try {
_errorMessage = "";
pages = await ref.read(
diff --git a/lib/modules/browse/sources/sources_filter_screen.dart b/lib/modules/browse/sources/sources_filter_screen.dart
index abcd5f8f..ba76d513 100644
--- a/lib/modules/browse/sources/sources_filter_screen.dart
+++ b/lib/modules/browse/sources/sources_filter_screen.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/modules/widgets/custom_sliver_grouped_list_view.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart';
diff --git a/lib/modules/browse/sources/sources_screen.dart b/lib/modules/browse/sources/sources_screen.dart
index 929e60f2..fb0881c1 100644
--- a/lib/modules/browse/sources/sources_screen.dart
+++ b/lib/modules/browse/sources/sources_screen.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/modules/widgets/custom_sliver_grouped_list_view.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart';
diff --git a/lib/modules/browse/sources/widgets/source_list_tile.dart b/lib/modules/browse/sources/widgets/source_list_tile.dart
index 0abcad31..9abb0729 100644
--- a/lib/modules/browse/sources/widgets/source_list_tile.dart
+++ b/lib/modules/browse/sources/widgets/source_list_tile.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/source.dart';
diff --git a/lib/modules/calendar/calendar_screen.dart b/lib/modules/calendar/calendar_screen.dart
index 74eb218d..91a7fe5b 100644
--- a/lib/modules/calendar/calendar_screen.dart
+++ b/lib/modules/calendar/calendar_screen.dart
@@ -3,7 +3,7 @@ import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/calendar/providers/calendar_provider.dart';
diff --git a/lib/modules/calendar/providers/calendar_provider.dart b/lib/modules/calendar/providers/calendar_provider.dart
index 821751d0..c4807ad7 100644
--- a/lib/modules/calendar/providers/calendar_provider.dart
+++ b/lib/modules/calendar/providers/calendar_provider.dart
@@ -1,8 +1,7 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'calendar_provider.g.dart';
@riverpod
diff --git a/lib/modules/calendar/providers/calendar_provider.g.dart b/lib/modules/calendar/providers/calendar_provider.g.dart
index 7c66e3ed..905b6b15 100644
--- a/lib/modules/calendar/providers/calendar_provider.g.dart
+++ b/lib/modules/calendar/providers/calendar_provider.g.dart
@@ -6,147 +6,80 @@ part of 'calendar_provider.dart';
// RiverpodGenerator
// **************************************************************************
-String _$getCalendarStreamHash() => r'850d81742f8ac5ce88175732c0edf57a7a9295d4';
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint, type=warning
-/// Copied from Dart SDK
-class _SystemHash {
- _SystemHash._();
-
- static int combine(int hash, int value) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + value);
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
- return hash ^ (hash >> 6);
- }
-
- static int finish(int hash) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
- // ignore: parameter_assignments
- hash = hash ^ (hash >> 11);
- return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
- }
-}
-
-/// See also [getCalendarStream].
@ProviderFor(getCalendarStream)
-const getCalendarStreamProvider = GetCalendarStreamFamily();
+const getCalendarStreamProvider = GetCalendarStreamFamily._();
-/// See also [getCalendarStream].
-class GetCalendarStreamFamily extends Family>> {
- /// See also [getCalendarStream].
- const GetCalendarStreamFamily();
+final class GetCalendarStreamProvider
+ extends
+ $FunctionalProvider<
+ AsyncValue>,
+ List,
+ Stream>
+ >
+ with $FutureModifier>, $StreamProvider> {
+ const GetCalendarStreamProvider._({
+ required GetCalendarStreamFamily super.from,
+ required ItemType? super.argument,
+ }) : super(
+ retry: null,
+ name: r'getCalendarStreamProvider',
+ isAutoDispose: true,
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ );
- /// See also [getCalendarStream].
- GetCalendarStreamProvider call({ItemType? itemType}) {
- return GetCalendarStreamProvider(itemType: itemType);
+ @override
+ String debugGetCreateSourceHash() => _$getCalendarStreamHash();
+
+ @override
+ String toString() {
+ return r'getCalendarStreamProvider'
+ ''
+ '($argument)';
}
+ @$internal
@override
- GetCalendarStreamProvider getProviderOverride(
- covariant GetCalendarStreamProvider provider,
- ) {
- return call(itemType: provider.itemType);
- }
-
- static const Iterable? _dependencies = null;
+ $StreamProviderElement> $createElement(
+ $ProviderPointer pointer,
+ ) => $StreamProviderElement(pointer);
@override
- Iterable? get dependencies => _dependencies;
-
- static const Iterable? _allTransitiveDependencies = null;
-
- @override
- Iterable? get allTransitiveDependencies =>
- _allTransitiveDependencies;
-
- @override
- String? get name => r'getCalendarStreamProvider';
-}
-
-/// See also [getCalendarStream].
-class GetCalendarStreamProvider extends AutoDisposeStreamProvider> {
- /// See also [getCalendarStream].
- GetCalendarStreamProvider({ItemType? itemType})
- : this._internal(
- (ref) =>
- getCalendarStream(ref as GetCalendarStreamRef, itemType: itemType),
- from: getCalendarStreamProvider,
- name: r'getCalendarStreamProvider',
- debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
- ? null
- : _$getCalendarStreamHash,
- dependencies: GetCalendarStreamFamily._dependencies,
- allTransitiveDependencies:
- GetCalendarStreamFamily._allTransitiveDependencies,
- itemType: itemType,
- );
-
- GetCalendarStreamProvider._internal(
- super._createNotifier, {
- required super.name,
- required super.dependencies,
- required super.allTransitiveDependencies,
- required super.debugGetCreateSourceHash,
- required super.from,
- required this.itemType,
- }) : super.internal();
-
- final ItemType? itemType;
-
- @override
- Override overrideWith(
- Stream> Function(GetCalendarStreamRef provider) create,
- ) {
- return ProviderOverride(
- origin: this,
- override: GetCalendarStreamProvider._internal(
- (ref) => create(ref as GetCalendarStreamRef),
- from: from,
- name: null,
- dependencies: null,
- allTransitiveDependencies: null,
- debugGetCreateSourceHash: null,
- itemType: itemType,
- ),
- );
- }
-
- @override
- AutoDisposeStreamProviderElement> createElement() {
- return _GetCalendarStreamProviderElement(this);
+ Stream> create(Ref ref) {
+ final argument = this.argument as ItemType?;
+ return getCalendarStream(ref, itemType: argument);
}
@override
bool operator ==(Object other) {
- return other is GetCalendarStreamProvider && other.itemType == itemType;
+ return other is GetCalendarStreamProvider && other.argument == argument;
}
@override
int get hashCode {
- var hash = _SystemHash.combine(0, runtimeType.hashCode);
- hash = _SystemHash.combine(hash, itemType.hashCode);
-
- return _SystemHash.finish(hash);
+ return argument.hashCode;
}
}
-@Deprecated('Will be removed in 3.0. Use Ref instead')
-// ignore: unused_element
-mixin GetCalendarStreamRef on AutoDisposeStreamProviderRef> {
- /// The parameter `itemType` of this provider.
- ItemType? get itemType;
-}
+String _$getCalendarStreamHash() => r'850d81742f8ac5ce88175732c0edf57a7a9295d4';
-class _GetCalendarStreamProviderElement
- extends AutoDisposeStreamProviderElement>
- with GetCalendarStreamRef {
- _GetCalendarStreamProviderElement(super.provider);
+final class GetCalendarStreamFamily extends $Family
+ with $FunctionalFamilyOverride>, ItemType?> {
+ const GetCalendarStreamFamily._()
+ : super(
+ retry: null,
+ name: r'getCalendarStreamProvider',
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ isAutoDispose: true,
+ );
+
+ GetCalendarStreamProvider call({ItemType? itemType}) =>
+ GetCalendarStreamProvider._(argument: itemType, from: this);
@override
- ItemType? get itemType => (origin as GetCalendarStreamProvider).itemType;
+ String toString() => r'getCalendarStreamProvider';
}
-
-// ignore_for_file: type=lint
-// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
diff --git a/lib/modules/history/history_screen.dart b/lib/modules/history/history_screen.dart
index 0c8d3c65..2a4d8151 100644
--- a/lib/modules/history/history_screen.dart
+++ b/lib/modules/history/history_screen.dart
@@ -5,7 +5,7 @@ import 'package:go_router/go_router.dart';
import 'package:mangayomi/l10n/generated/app_localizations.dart';
import 'package:mangayomi/modules/widgets/custom_sliver_grouped_list_view.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/changed.dart';
import 'package:mangayomi/models/chapter.dart';
diff --git a/lib/modules/history/providers/isar_providers.dart b/lib/modules/history/providers/isar_providers.dart
index 93433365..d3e44c8b 100644
--- a/lib/modules/history/providers/isar_providers.dart
+++ b/lib/modules/history/providers/isar_providers.dart
@@ -1,11 +1,10 @@
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'isar_providers.g.dart';
@riverpod
diff --git a/lib/modules/history/providers/isar_providers.g.dart b/lib/modules/history/providers/isar_providers.g.dart
index 813a7a40..3b580f9e 100644
--- a/lib/modules/history/providers/isar_providers.g.dart
+++ b/lib/modules/history/providers/isar_providers.g.dart
@@ -6,308 +6,183 @@ part of 'isar_providers.dart';
// RiverpodGenerator
// **************************************************************************
-String _$getAllHistoryStreamHash() =>
- r'1ce5bd0046fbbec46e91b7a486523945699d95f3';
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint, type=warning
-/// Copied from Dart SDK
-class _SystemHash {
- _SystemHash._();
-
- static int combine(int hash, int value) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + value);
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
- return hash ^ (hash >> 6);
- }
-
- static int finish(int hash) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
- // ignore: parameter_assignments
- hash = hash ^ (hash >> 11);
- return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
- }
-}
-
-/// See also [getAllHistoryStream].
@ProviderFor(getAllHistoryStream)
-const getAllHistoryStreamProvider = GetAllHistoryStreamFamily();
+const getAllHistoryStreamProvider = GetAllHistoryStreamFamily._();
-/// See also [getAllHistoryStream].
-class GetAllHistoryStreamFamily extends Family>> {
- /// See also [getAllHistoryStream].
- const GetAllHistoryStreamFamily();
+final class GetAllHistoryStreamProvider
+ extends
+ $FunctionalProvider<
+ AsyncValue>,
+ List,
+ Stream>
+ >
+ with $FutureModifier>, $StreamProvider> {
+ const GetAllHistoryStreamProvider._({
+ required GetAllHistoryStreamFamily super.from,
+ required ({ItemType itemType, String search}) super.argument,
+ }) : super(
+ retry: null,
+ name: r'getAllHistoryStreamProvider',
+ isAutoDispose: true,
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ );
- /// See also [getAllHistoryStream].
- GetAllHistoryStreamProvider call({
- required ItemType itemType,
- String search = "",
- }) {
- return GetAllHistoryStreamProvider(itemType: itemType, search: search);
+ @override
+ String debugGetCreateSourceHash() => _$getAllHistoryStreamHash();
+
+ @override
+ String toString() {
+ return r'getAllHistoryStreamProvider'
+ ''
+ '$argument';
}
+ @$internal
@override
- GetAllHistoryStreamProvider getProviderOverride(
- covariant GetAllHistoryStreamProvider provider,
- ) {
- return call(itemType: provider.itemType, search: provider.search);
- }
-
- static const Iterable? _dependencies = null;
+ $StreamProviderElement> $createElement(
+ $ProviderPointer pointer,
+ ) => $StreamProviderElement(pointer);
@override
- Iterable? get dependencies => _dependencies;
-
- static const Iterable? _allTransitiveDependencies = null;
-
- @override
- Iterable? get allTransitiveDependencies =>
- _allTransitiveDependencies;
-
- @override
- String? get name => r'getAllHistoryStreamProvider';
-}
-
-/// See also [getAllHistoryStream].
-class GetAllHistoryStreamProvider
- extends AutoDisposeStreamProvider> {
- /// See also [getAllHistoryStream].
- GetAllHistoryStreamProvider({required ItemType itemType, String search = ""})
- : this._internal(
- (ref) => getAllHistoryStream(
- ref as GetAllHistoryStreamRef,
- itemType: itemType,
- search: search,
- ),
- from: getAllHistoryStreamProvider,
- name: r'getAllHistoryStreamProvider',
- debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
- ? null
- : _$getAllHistoryStreamHash,
- dependencies: GetAllHistoryStreamFamily._dependencies,
- allTransitiveDependencies:
- GetAllHistoryStreamFamily._allTransitiveDependencies,
- itemType: itemType,
- search: search,
- );
-
- GetAllHistoryStreamProvider._internal(
- super._createNotifier, {
- required super.name,
- required super.dependencies,
- required super.allTransitiveDependencies,
- required super.debugGetCreateSourceHash,
- required super.from,
- required this.itemType,
- required this.search,
- }) : super.internal();
-
- final ItemType itemType;
- final String search;
-
- @override
- Override overrideWith(
- Stream> Function(GetAllHistoryStreamRef provider) create,
- ) {
- return ProviderOverride(
- origin: this,
- override: GetAllHistoryStreamProvider._internal(
- (ref) => create(ref as GetAllHistoryStreamRef),
- from: from,
- name: null,
- dependencies: null,
- allTransitiveDependencies: null,
- debugGetCreateSourceHash: null,
- itemType: itemType,
- search: search,
- ),
+ Stream> create(Ref ref) {
+ final argument = this.argument as ({ItemType itemType, String search});
+ return getAllHistoryStream(
+ ref,
+ itemType: argument.itemType,
+ search: argument.search,
);
}
- @override
- AutoDisposeStreamProviderElement> createElement() {
- return _GetAllHistoryStreamProviderElement(this);
- }
-
@override
bool operator ==(Object other) {
- return other is GetAllHistoryStreamProvider &&
- other.itemType == itemType &&
- other.search == search;
+ return other is GetAllHistoryStreamProvider && other.argument == argument;
}
@override
int get hashCode {
- var hash = _SystemHash.combine(0, runtimeType.hashCode);
- hash = _SystemHash.combine(hash, itemType.hashCode);
- hash = _SystemHash.combine(hash, search.hashCode);
-
- return _SystemHash.finish(hash);
+ return argument.hashCode;
}
}
-@Deprecated('Will be removed in 3.0. Use Ref instead')
-// ignore: unused_element
-mixin GetAllHistoryStreamRef on AutoDisposeStreamProviderRef> {
- /// The parameter `itemType` of this provider.
- ItemType get itemType;
+String _$getAllHistoryStreamHash() =>
+ r'1ce5bd0046fbbec46e91b7a486523945699d95f3';
- /// The parameter `search` of this provider.
- String get search;
+final class GetAllHistoryStreamFamily extends $Family
+ with
+ $FunctionalFamilyOverride<
+ Stream>,
+ ({ItemType itemType, String search})
+ > {
+ const GetAllHistoryStreamFamily._()
+ : super(
+ retry: null,
+ name: r'getAllHistoryStreamProvider',
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ isAutoDispose: true,
+ );
+
+ GetAllHistoryStreamProvider call({
+ required ItemType itemType,
+ String search = '',
+ }) => GetAllHistoryStreamProvider._(
+ argument: (itemType: itemType, search: search),
+ from: this,
+ );
+
+ @override
+ String toString() => r'getAllHistoryStreamProvider';
}
-class _GetAllHistoryStreamProviderElement
- extends AutoDisposeStreamProviderElement>
- with GetAllHistoryStreamRef {
- _GetAllHistoryStreamProviderElement(super.provider);
+@ProviderFor(getAllUpdateStream)
+const getAllUpdateStreamProvider = GetAllUpdateStreamFamily._();
+
+final class GetAllUpdateStreamProvider
+ extends
+ $FunctionalProvider<
+ AsyncValue>,
+ List,
+ Stream>
+ >
+ with $FutureModifier>, $StreamProvider> {
+ const GetAllUpdateStreamProvider._({
+ required GetAllUpdateStreamFamily super.from,
+ required ({ItemType itemType, String search}) super.argument,
+ }) : super(
+ retry: null,
+ name: r'getAllUpdateStreamProvider',
+ isAutoDispose: true,
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ );
@override
- ItemType get itemType => (origin as GetAllHistoryStreamProvider).itemType;
+ String debugGetCreateSourceHash() => _$getAllUpdateStreamHash();
+
@override
- String get search => (origin as GetAllHistoryStreamProvider).search;
+ String toString() {
+ return r'getAllUpdateStreamProvider'
+ ''
+ '$argument';
+ }
+
+ @$internal
+ @override
+ $StreamProviderElement> $createElement(
+ $ProviderPointer pointer,
+ ) => $StreamProviderElement(pointer);
+
+ @override
+ Stream> create(Ref ref) {
+ final argument = this.argument as ({ItemType itemType, String search});
+ return getAllUpdateStream(
+ ref,
+ itemType: argument.itemType,
+ search: argument.search,
+ );
+ }
+
+ @override
+ bool operator ==(Object other) {
+ return other is GetAllUpdateStreamProvider && other.argument == argument;
+ }
+
+ @override
+ int get hashCode {
+ return argument.hashCode;
+ }
}
String _$getAllUpdateStreamHash() =>
r'43369b20d702d12aeae627fcd04ceb61caf0dc74';
-/// See also [getAllUpdateStream].
-@ProviderFor(getAllUpdateStream)
-const getAllUpdateStreamProvider = GetAllUpdateStreamFamily();
-
-/// See also [getAllUpdateStream].
-class GetAllUpdateStreamFamily extends Family>> {
- /// See also [getAllUpdateStream].
- const GetAllUpdateStreamFamily();
-
- /// See also [getAllUpdateStream].
- GetAllUpdateStreamProvider call({
- required ItemType itemType,
- String search = "",
- }) {
- return GetAllUpdateStreamProvider(itemType: itemType, search: search);
- }
-
- @override
- GetAllUpdateStreamProvider getProviderOverride(
- covariant GetAllUpdateStreamProvider provider,
- ) {
- return call(itemType: provider.itemType, search: provider.search);
- }
-
- static const Iterable? _dependencies = null;
-
- @override
- Iterable? get dependencies => _dependencies;
-
- static const Iterable? _allTransitiveDependencies = null;
-
- @override
- Iterable? get allTransitiveDependencies =>
- _allTransitiveDependencies;
-
- @override
- String? get name => r'getAllUpdateStreamProvider';
-}
-
-/// See also [getAllUpdateStream].
-class GetAllUpdateStreamProvider
- extends AutoDisposeStreamProvider> {
- /// See also [getAllUpdateStream].
- GetAllUpdateStreamProvider({required ItemType itemType, String search = ""})
- : this._internal(
- (ref) => getAllUpdateStream(
- ref as GetAllUpdateStreamRef,
- itemType: itemType,
- search: search,
- ),
- from: getAllUpdateStreamProvider,
+final class GetAllUpdateStreamFamily extends $Family
+ with
+ $FunctionalFamilyOverride<
+ Stream>,
+ ({ItemType itemType, String search})
+ > {
+ const GetAllUpdateStreamFamily._()
+ : super(
+ retry: null,
name: r'getAllUpdateStreamProvider',
- debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
- ? null
- : _$getAllUpdateStreamHash,
- dependencies: GetAllUpdateStreamFamily._dependencies,
- allTransitiveDependencies:
- GetAllUpdateStreamFamily._allTransitiveDependencies,
- itemType: itemType,
- search: search,
+ dependencies: null,
+ $allTransitiveDependencies: null,
+ isAutoDispose: true,
);
- GetAllUpdateStreamProvider._internal(
- super._createNotifier, {
- required super.name,
- required super.dependencies,
- required super.allTransitiveDependencies,
- required super.debugGetCreateSourceHash,
- required super.from,
- required this.itemType,
- required this.search,
- }) : super.internal();
-
- final ItemType itemType;
- final String search;
+ GetAllUpdateStreamProvider call({
+ required ItemType itemType,
+ String search = '',
+ }) => GetAllUpdateStreamProvider._(
+ argument: (itemType: itemType, search: search),
+ from: this,
+ );
@override
- Override overrideWith(
- Stream> Function(GetAllUpdateStreamRef provider) create,
- ) {
- return ProviderOverride(
- origin: this,
- override: GetAllUpdateStreamProvider._internal(
- (ref) => create(ref as GetAllUpdateStreamRef),
- from: from,
- name: null,
- dependencies: null,
- allTransitiveDependencies: null,
- debugGetCreateSourceHash: null,
- itemType: itemType,
- search: search,
- ),
- );
- }
-
- @override
- AutoDisposeStreamProviderElement> createElement() {
- return _GetAllUpdateStreamProviderElement(this);
- }
-
- @override
- bool operator ==(Object other) {
- return other is GetAllUpdateStreamProvider &&
- other.itemType == itemType &&
- other.search == search;
- }
-
- @override
- int get hashCode {
- var hash = _SystemHash.combine(0, runtimeType.hashCode);
- hash = _SystemHash.combine(hash, itemType.hashCode);
- hash = _SystemHash.combine(hash, search.hashCode);
-
- return _SystemHash.finish(hash);
- }
+ String toString() => r'getAllUpdateStreamProvider';
}
-
-@Deprecated('Will be removed in 3.0. Use Ref instead')
-// ignore: unused_element
-mixin GetAllUpdateStreamRef on AutoDisposeStreamProviderRef> {
- /// The parameter `itemType` of this provider.
- ItemType get itemType;
-
- /// The parameter `search` of this provider.
- String get search;
-}
-
-class _GetAllUpdateStreamProviderElement
- extends AutoDisposeStreamProviderElement>
- with GetAllUpdateStreamRef {
- _GetAllUpdateStreamProviderElement(super.provider);
-
- @override
- ItemType get itemType => (origin as GetAllUpdateStreamProvider).itemType;
- @override
- String get search => (origin as GetAllUpdateStreamProvider).search;
-}
-
-// ignore_for_file: type=lint
-// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
diff --git a/lib/modules/library/library_screen.dart b/lib/modules/library/library_screen.dart
index bdaa0e0b..6c1363d8 100644
--- a/lib/modules/library/library_screen.dart
+++ b/lib/modules/library/library_screen.dart
@@ -6,7 +6,7 @@ import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:isar/isar.dart';
+import 'package:isar_community/isar.dart';
import 'package:mangayomi/eval/model/m_bridge.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/changed.dart';
@@ -43,6 +43,7 @@ import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/utils/extensions/string_extensions.dart';
import 'package:mangayomi/utils/global_style.dart';
import 'package:path/path.dart' as p;
+import 'package:riverpod_annotation/riverpod_annotation.dart';
class LibraryScreen extends ConsumerStatefulWidget {
final ItemType itemType;
diff --git a/lib/modules/library/providers/add_torrent.dart b/lib/modules/library/providers/add_torrent.dart
index a8f88b1a..8ed28bc9 100644
--- a/lib/modules/library/providers/add_torrent.dart
+++ b/lib/modules/library/providers/add_torrent.dart
@@ -4,7 +4,6 @@ import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/services/torrent_server.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
-import 'package:flutter_riverpod/flutter_riverpod.dart';
part 'add_torrent.g.dart';
@riverpod
diff --git a/lib/modules/library/providers/add_torrent.g.dart b/lib/modules/library/providers/add_torrent.g.dart
index 23b1e14e..fa586232 100644
--- a/lib/modules/library/providers/add_torrent.g.dart
+++ b/lib/modules/library/providers/add_torrent.g.dart
@@ -6,183 +6,92 @@ part of 'add_torrent.dart';
// RiverpodGenerator
// **************************************************************************
-String _$addTorrentFromUrlOrFromFileHash() =>
- r'a54f90b6708b13eeb8fed098691f9a79dbab50fd';
+// GENERATED CODE - DO NOT MODIFY BY HAND
+// ignore_for_file: type=lint, type=warning
-/// Copied from Dart SDK
-class _SystemHash {
- _SystemHash._();
-
- static int combine(int hash, int value) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + value);
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
- return hash ^ (hash >> 6);
- }
-
- static int finish(int hash) {
- // ignore: parameter_assignments
- hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
- // ignore: parameter_assignments
- hash = hash ^ (hash >> 11);
- return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
- }
-}
-
-/// See also [addTorrentFromUrlOrFromFile].
@ProviderFor(addTorrentFromUrlOrFromFile)
-const addTorrentFromUrlOrFromFileProvider = AddTorrentFromUrlOrFromFileFamily();
+const addTorrentFromUrlOrFromFileProvider =
+ AddTorrentFromUrlOrFromFileFamily._();
-/// See also [addTorrentFromUrlOrFromFile].
-class AddTorrentFromUrlOrFromFileFamily extends Family {
- /// See also [addTorrentFromUrlOrFromFile].
- const AddTorrentFromUrlOrFromFileFamily();
-
- /// See also [addTorrentFromUrlOrFromFile].
- AddTorrentFromUrlOrFromFileProvider call(
- Manga? mManga, {
- required bool init,
- String? url,
- }) {
- return AddTorrentFromUrlOrFromFileProvider(mManga, init: init, url: url);
- }
-
- @override
- AddTorrentFromUrlOrFromFileProvider getProviderOverride(
- covariant AddTorrentFromUrlOrFromFileProvider provider,
- ) {
- return call(provider.mManga, init: provider.init, url: provider.url);
- }
-
- static const Iterable? _dependencies = null;
-
- @override
- Iterable? get dependencies => _dependencies;
-
- static const Iterable? _allTransitiveDependencies = null;
-
- @override
- Iterable? get allTransitiveDependencies =>
- _allTransitiveDependencies;
-
- @override
- String? get name => r'addTorrentFromUrlOrFromFileProvider';
-}
-
-/// See also [addTorrentFromUrlOrFromFile].
-class AddTorrentFromUrlOrFromFileProvider
- extends AutoDisposeFutureProvider