mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
Add input dialog
This commit is contained in:
@@ -1276,5 +1276,20 @@ let UI = {
|
||||
function: 'cancelLoading',
|
||||
id: id
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Show an input dialog
|
||||
* @param title {string}
|
||||
* @param validator {(string) => string | null | undefined} - A function that validates the input. If the function returns a string, the dialog will show the error message.
|
||||
* @returns {string | null} - The input value. If the dialog is canceled, return null.
|
||||
*/
|
||||
showInputDialog: (title, validator) => {
|
||||
return sendMessage({
|
||||
method: 'UI',
|
||||
function: 'showInputDialog',
|
||||
title: title,
|
||||
validator: validator
|
||||
})
|
||||
}
|
||||
}
|
@@ -34,6 +34,12 @@ mixin class JsUiApi {
|
||||
if (id is int) {
|
||||
cancelLoading(id);
|
||||
}
|
||||
case 'showInputDialog':
|
||||
var title = message['title'];
|
||||
var validator = message['validator'];
|
||||
if (title is! String) return;
|
||||
if (validator != null && validator is! JSInvokable) return;
|
||||
return _showInputDialog(title, validator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +53,6 @@ mixin class JsUiApi {
|
||||
continue;
|
||||
}
|
||||
var callback = action['callback'] as JSInvokable;
|
||||
// [message] will be released after the method call, causing the action to be invalid, so we need to duplicate it
|
||||
callback.dup();
|
||||
var text = action['text'].toString();
|
||||
var style = (action['style'] ?? 'text').toString();
|
||||
actions.add(_JSCallbackButton(
|
||||
@@ -84,15 +88,16 @@ mixin class JsUiApi {
|
||||
}
|
||||
|
||||
int showLoading(JSInvokable? onCancel) {
|
||||
onCancel?.dup();
|
||||
var func = onCancel == null ? null : JSAutoFreeFunction(onCancel);
|
||||
var controller = showLoadingDialog(
|
||||
App.rootContext,
|
||||
barrierDismissible: onCancel != null,
|
||||
allowCancel: onCancel != null,
|
||||
onCancel: onCancel == null ? null : () {
|
||||
func?.call([]);
|
||||
},
|
||||
onCancel: onCancel == null
|
||||
? null
|
||||
: () {
|
||||
func?.call([]);
|
||||
},
|
||||
);
|
||||
var i = 0;
|
||||
while (_loadingDialogControllers.containsKey(i)) {
|
||||
@@ -106,6 +111,29 @@ mixin class JsUiApi {
|
||||
var controller = _loadingDialogControllers.remove(id);
|
||||
controller?.close();
|
||||
}
|
||||
|
||||
Future<String?> _showInputDialog(String title, JSInvokable? validator) async {
|
||||
String? result;
|
||||
var func = validator == null ? null : JSAutoFreeFunction(validator);
|
||||
await showInputDialog(
|
||||
context: App.rootContext,
|
||||
title: title,
|
||||
onConfirm: (v) {
|
||||
if (func != null) {
|
||||
var res = func.call([v]);
|
||||
if (res != null) {
|
||||
return res.toString();
|
||||
} else {
|
||||
result = v;
|
||||
}
|
||||
} else {
|
||||
result = v;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class _JSCallbackButton extends StatefulWidget {
|
||||
|
@@ -63,7 +63,8 @@ class ReaderImageProvider
|
||||
})()
|
||||
''');
|
||||
if (func is JSInvokable) {
|
||||
var result = func.invoke([imageBytes, cid, eid, page, sourceKey]);
|
||||
var autoFreeFunc = JSAutoFreeFunction(func);
|
||||
var result = autoFreeFunc([imageBytes, cid, eid, page, sourceKey]);
|
||||
if (result is Uint8List) {
|
||||
imageBytes = result;
|
||||
} else if (result is Future) {
|
||||
@@ -76,9 +77,9 @@ class ReaderImageProvider
|
||||
if (image is Uint8List) {
|
||||
imageBytes = image;
|
||||
} else if (image is Future) {
|
||||
JSInvokable? onCancel;
|
||||
JSAutoFreeFunction? onCancel;
|
||||
if (result['onCancel'] is JSInvokable) {
|
||||
onCancel = result['onCancel'];
|
||||
onCancel = JSAutoFreeFunction(result['onCancel']);
|
||||
}
|
||||
if (onCancel == null) {
|
||||
var futureImage = await image;
|
||||
@@ -96,9 +97,7 @@ class ReaderImageProvider
|
||||
checkStop();
|
||||
}
|
||||
catch(e) {
|
||||
onCancel.invoke([]);
|
||||
onCancel.free();
|
||||
func.free();
|
||||
onCancel([]);
|
||||
rethrow;
|
||||
}
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
@@ -107,10 +106,8 @@ class ReaderImageProvider
|
||||
imageBytes = futureImage;
|
||||
}
|
||||
}
|
||||
onCancel?.free();
|
||||
}
|
||||
}
|
||||
func.free();
|
||||
}
|
||||
}
|
||||
return imageBytes!;
|
||||
|
@@ -677,6 +677,7 @@ class JSAutoFreeFunction {
|
||||
|
||||
/// Automatically free the function when it's not used anymore
|
||||
JSAutoFreeFunction(this.func) {
|
||||
func.dup();
|
||||
finalizer.attach(this, func);
|
||||
}
|
||||
|
||||
@@ -685,6 +686,6 @@ class JSAutoFreeFunction {
|
||||
}
|
||||
|
||||
static final finalizer = Finalizer<JSInvokable>((func) {
|
||||
func.free();
|
||||
func.destroy();
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user