mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
Add callback setting
This commit is contained in:
@@ -6,6 +6,7 @@ import 'dart:convert';
|
|||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_qjs/flutter_qjs.dart';
|
||||||
import 'package:venera/foundation/app.dart';
|
import 'package:venera/foundation/app.dart';
|
||||||
import 'package:venera/foundation/comic_type.dart';
|
import 'package:venera/foundation/comic_type.dart';
|
||||||
import 'package:venera/foundation/history.dart';
|
import 'package:venera/foundation/history.dart';
|
||||||
@@ -203,7 +204,7 @@ class ComicSource {
|
|||||||
|
|
||||||
final LikeCommentFunc? likeCommentFunc;
|
final LikeCommentFunc? likeCommentFunc;
|
||||||
|
|
||||||
final Map<String, dynamic>? settings;
|
final Map<String, Map<String, dynamic>>? settings;
|
||||||
|
|
||||||
final Map<String, Map<String, String>>? translations;
|
final Map<String, Map<String, String>>? translations;
|
||||||
|
|
||||||
|
@@ -923,8 +923,30 @@ class ComicSourceParser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _parseSettings() {
|
Map<String, Map<String, dynamic>> _parseSettings() {
|
||||||
return _getValue("settings") ?? {};
|
var value = _getValue("settings");
|
||||||
|
if (value is Map) {
|
||||||
|
var newMap = <String, Map<String, dynamic>>{};
|
||||||
|
for (var e in value.entries) {
|
||||||
|
if (e.key is! String) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var v = <String, dynamic>{};
|
||||||
|
for (var e2 in e.value.entries) {
|
||||||
|
if (e2.key is! String) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var v2 = e2.value;
|
||||||
|
if (v2 is JSInvokable) {
|
||||||
|
v2 = JSAutoFreeFunction(v2);
|
||||||
|
}
|
||||||
|
v[e2.key] = v2;
|
||||||
|
}
|
||||||
|
newMap[e.key] = v;
|
||||||
|
}
|
||||||
|
return newMap;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
RegExp? _parseIdMatch() {
|
RegExp? _parseIdMatch() {
|
||||||
|
@@ -165,7 +165,7 @@ class JsEngine with _JSEngineApi {
|
|||||||
String settingKey = message["setting_key"];
|
String settingKey = message["setting_key"];
|
||||||
var source = ComicSource.find(key)!;
|
var source = ComicSource.find(key)!;
|
||||||
return source.data["settings"]?[settingKey] ??
|
return source.data["settings"]?[settingKey] ??
|
||||||
source.settings?[settingKey]['default'] ??
|
source.settings?[settingKey]!['default'] ??
|
||||||
(throw "Setting not found: $settingKey");
|
(throw "Setting not found: $settingKey");
|
||||||
}
|
}
|
||||||
case "isLogged":
|
case "isLogged":
|
||||||
@@ -688,3 +688,20 @@ class DocumentWrapper {
|
|||||||
return elements.length - 1;
|
return elements.length - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class JSAutoFreeFunction {
|
||||||
|
final JSInvokable func;
|
||||||
|
|
||||||
|
/// Automatically free the function when it's not used anymore
|
||||||
|
JSAutoFreeFunction(this.func) {
|
||||||
|
finalizer.attach(this, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic call(List<dynamic> args) {
|
||||||
|
return func(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final finalizer = Finalizer<JSInvokable>((func) {
|
||||||
|
func.free();
|
||||||
|
});
|
||||||
|
}
|
@@ -244,6 +244,8 @@ class _BodyState extends State<_Body> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
} else if (type == "callback") {
|
||||||
|
yield _CallbackSetting(setting: item);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Log.error("ComicSourcePage", "Failed to build a setting\n$e\n$s");
|
Log.error("ComicSourcePage", "Failed to build a setting\n$e\n$s");
|
||||||
@@ -677,3 +679,48 @@ class _CheckUpdatesButtonState extends State<_CheckUpdatesButton> {
|
|||||||
).fixHeight(32);
|
).fixHeight(32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _CallbackSetting extends StatefulWidget {
|
||||||
|
const _CallbackSetting({required this.setting});
|
||||||
|
|
||||||
|
final MapEntry<String, Map<String, dynamic>> setting;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_CallbackSetting> createState() => _CallbackSettingState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CallbackSettingState extends State<_CallbackSetting> {
|
||||||
|
String get key => widget.setting.key;
|
||||||
|
|
||||||
|
String get buttonText => widget.setting.value['buttonText'] ?? "Click";
|
||||||
|
|
||||||
|
String get title => widget.setting.value['title'] ?? key;
|
||||||
|
|
||||||
|
bool isLoading = false;
|
||||||
|
|
||||||
|
Future<void> onClick() async {
|
||||||
|
var func = widget.setting.value['callback'];
|
||||||
|
var result = func([]);
|
||||||
|
if (result is Future) {
|
||||||
|
setState(() {
|
||||||
|
isLoading = true;
|
||||||
|
});
|
||||||
|
await result;
|
||||||
|
setState(() {
|
||||||
|
isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(title.ts(key)),
|
||||||
|
trailing: Button.normal(
|
||||||
|
onPressed: onClick,
|
||||||
|
isLoading: isLoading,
|
||||||
|
child: Text(buttonText.ts(key)),
|
||||||
|
).fixHeight(32),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user