5 Commits

Author SHA1 Message Date
9d8ade6fe0 Add log export functionality. 2025-07-23 14:35:27 +08:00
6245399810 Improve UI of comic source page. 2025-07-23 14:28:40 +08:00
c074e7f9d1 Add default source list url. 2025-07-23 14:16:53 +08:00
f822e198ea Update version code. 2025-07-22 17:55:51 +08:00
7035f11eb5 Add optional image parameter to showInputDialog for captcha support. Close #422 2025-07-22 17:51:40 +08:00
11 changed files with 106 additions and 97 deletions

View File

@@ -1322,13 +1322,15 @@ let UI = {
* 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.
* @param image {string?} - Available since 1.4.6. An optional image to show in the dialog. You can use this to show a captcha.
* @returns {Promise<string | null>} - The input value. If the dialog is canceled, return null.
*/
showInputDialog: (title, validator) => {
showInputDialog: (title, validator, image) => {
return sendMessage({
method: 'UI',
function: 'showInputDialog',
title: title,
image: image,
validator: validator
})
},

View File

@@ -404,7 +404,8 @@
"Reload": "重载",
"Disable Length Limitation": "禁用长度限制",
"Only valid for this run": "仅对本次运行有效",
"Logs": "日志"
"Logs": "日志",
"Export logs": "导出日志"
},
"zh_TW": {
"Home": "首頁",
@@ -811,6 +812,7 @@
"Reload": "重載",
"Disable Length Limitation": "禁用長度限制",
"Only valid for this run": "僅對本次運行有效",
"Logs": "日誌"
"Logs": "日誌",
"Export logs": "匯出日誌"
}
}

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:math' as math;
import 'dart:ui' as ui;
@@ -21,11 +22,13 @@ import 'package:venera/foundation/image_provider/cached_image.dart';
import 'package:venera/foundation/image_provider/history_image_provider.dart';
import 'package:venera/foundation/image_provider/local_comic_image.dart';
import 'package:venera/foundation/local.dart';
import 'package:venera/foundation/log.dart';
import 'package:venera/foundation/res.dart';
import 'package:venera/network/cloudflare.dart';
import 'package:venera/pages/comic_details_page/comic_page.dart';
import 'package:venera/pages/favorites/favorites_page.dart';
import 'package:venera/utils/ext.dart';
import 'package:venera/utils/io.dart';
import 'package:venera/utils/tags_translation.dart';
import 'package:venera/utils/translations.dart';

View File

@@ -37,9 +37,11 @@ mixin class JsUiApi {
case 'showInputDialog':
var title = message['title'];
var validator = message['validator'];
var image = message['image'];
if (title is! String) return;
if (validator != null && validator is! JSInvokable) return;
return _showInputDialog(title, validator);
if (image != null && image is! String) return;
return _showInputDialog(title, validator, image);
case 'showSelectDialog':
var title = message['title'];
var options = message['options'];
@@ -124,12 +126,13 @@ mixin class JsUiApi {
controller?.close();
}
Future<String?> _showInputDialog(String title, JSInvokable? validator) async {
Future<String?> _showInputDialog(String title, JSInvokable? validator, String? image) async {
String? result;
var func = validator == null ? null : JSAutoFreeFunction(validator);
await showInputDialog(
context: App.rootContext,
title: title,
image: image,
onConfirm: (v) {
if (func != null) {
var res = func.call([v]);

View File

@@ -41,18 +41,22 @@ class NetworkError extends StatelessWidget {
],
),
),
const SizedBox(
height: 8,
),
const SizedBox(height: 8),
Text(
cfe == null ? message : "Cloudflare verification required".tl,
textAlign: TextAlign.center,
maxLines: 3,
),
if (retry != null)
const SizedBox(
height: 12,
),
TextButton(
onPressed: () {
saveFile(
data: utf8.encode(Log().toString()),
filename: 'log.txt',
);
},
child: Text("Export logs".tl),
),
const SizedBox(height: 8),
if (retry != null)
if (cfe != null)
FilledButton(
@@ -74,15 +78,11 @@ class NetworkError extends StatelessWidget {
body = Column(
children: [
const Appbar(title: Text("")),
Expanded(
child: body,
)
Expanded(child: body),
],
);
}
return Material(
child: body,
);
return Material(child: body);
}
}
@@ -94,9 +94,7 @@ class ListLoadingIndicator extends StatelessWidget {
return const SizedBox(
width: double.infinity,
height: 80,
child: Center(
child: FiveDotLoadingAnimation(),
),
child: Center(child: FiveDotLoadingAnimation()),
);
}
}
@@ -108,10 +106,9 @@ class SliverListLoadingIndicator extends StatelessWidget {
Widget build(BuildContext context) {
// SliverToBoxAdapter can not been lazy loaded.
// Use SliverList to make sure the animation can be lazy loaded.
return SliverList.list(children: const [
SizedBox(),
ListLoadingIndicator(),
]);
return SliverList.list(
children: const [SizedBox(), ListLoadingIndicator()],
);
}
}
@@ -178,10 +175,7 @@ abstract class LoadingState<T extends StatefulWidget, S extends Object>
}
Widget buildError() {
return NetworkError(
message: error!,
retry: retry,
);
return NetworkError(message: error!, retry: retry);
}
@override
@@ -323,11 +317,7 @@ abstract class MultiPageLoadingState<T extends StatefulWidget, S extends Object>
}
Widget buildError(BuildContext context, String error) {
return NetworkError(
withAppbar: false,
message: error,
retry: reset,
);
return NetworkError(withAppbar: false, message: error, retry: reset);
}
@override
@@ -388,7 +378,7 @@ class _FiveDotLoadingAnimationState extends State<FiveDotLoadingAnimation>
Colors.green,
Colors.blue,
Colors.yellow,
Colors.purple
Colors.purple,
];
static const _padding = 12.0;
@@ -400,16 +390,15 @@ class _FiveDotLoadingAnimationState extends State<FiveDotLoadingAnimation>
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return SizedBox(
width: _dotSize * 5 + _padding * 6,
height: _height,
child: Stack(
children: List.generate(5, (index) => buildDot(index)),
),
);
});
animation: _controller,
builder: (context, child) {
return SizedBox(
width: _dotSize * 5 + _padding * 6,
height: _height,
child: Stack(children: List.generate(5, (index) => buildDot(index))),
);
},
);
}
Widget buildDot(int index) {
@@ -417,7 +406,8 @@ class _FiveDotLoadingAnimationState extends State<FiveDotLoadingAnimation>
var startValue = index * 0.8;
return Positioned(
left: index * _dotSize + (index + 1) * _padding,
bottom: (math.sin(math.pi / 2 * (value - startValue).clamp(0, 2))) *
bottom:
(math.sin(math.pi / 2 * (value - startValue).clamp(0, 2))) *
(_height - _dotSize),
child: Container(
width: _dotSize,

View File

@@ -359,6 +359,7 @@ Future<void> showInputDialog({
String confirmText = "Confirm",
String cancelText = "Cancel",
RegExp? inputValidator,
String? image,
}) {
var controller = TextEditingController(text: initialValue);
bool isLoading = false;
@@ -371,14 +372,23 @@ Future<void> showInputDialog({
builder: (context, setState) {
return ContentDialog(
title: title,
content: TextField(
controller: controller,
decoration: InputDecoration(
hintText: hintText,
border: const OutlineInputBorder(),
errorText: error,
),
).paddingHorizontal(12),
content: Column(
children: [
if (image != null)
SizedBox(
height: 108,
child: Image.network(image, fit: BoxFit.none),
).paddingBottom(8),
TextField(
controller: controller,
decoration: InputDecoration(
hintText: hintText,
border: const OutlineInputBorder(),
errorText: error,
),
).paddingHorizontal(12),
],
),
actions: [
Button.filled(
isLoading: isLoading,

View File

@@ -13,7 +13,7 @@ export "widget_utils.dart";
export "context.dart";
class _App {
final version = "1.4.5";
final version = "1.4.6";
bool get isAndroid => Platform.isAndroid;

View File

@@ -189,7 +189,7 @@ class Settings with ChangeNotifier {
'customImageProcessing': defaultCustomImageProcessing,
'sni': true,
'autoAddLanguageFilter': 'none', // none, chinese, english, japanese
'comicSourceListUrl': '',
'comicSourceListUrl': _defaultSourceListUrl,
'preloadImageCount': 4,
'followUpdatesFolder': null,
'initialPage': '0',
@@ -235,3 +235,5 @@ function processImage(image, cid, eid, page, sourceKey) {
return futureImage;
}
''';
const _defaultSourceListUrl = "https://git.nyne.dev/nyne/venera-configs/raw/branch/main/index.json";

View File

@@ -191,13 +191,6 @@ class _BodyState extends State<_Body> {
}
Widget buildCard(BuildContext context) {
Widget buildButton({
required Widget child,
required VoidCallback onPressed,
}) {
return Button.normal(onPressed: onPressed, child: child).fixHeight(32);
}
return SliverToBoxAdapter(
child: SizedBox(
width: double.infinity,
@@ -224,33 +217,33 @@ class _BodyState extends State<_Body> {
},
onSubmitted: handleAddSource,
).paddingHorizontal(16).paddingBottom(8),
ListTile(
title: Text("Comic Source list".tl),
trailing: buildButton(
child: Text("View".tl),
onPressed: () {
showPopUpWidget(
App.rootContext,
_ComicSourceList(handleAddSource),
);
},
),
),
ListTile(
title: Text("Use a config file".tl),
trailing: buildButton(
onPressed: _selectFile,
child: Text("Select".tl),
),
),
ListTile(
title: Text("Help".tl),
trailing: buildButton(onPressed: help, child: Text("Open".tl)),
),
ListTile(
title: Text("Check updates".tl),
trailing: _CheckUpdatesButton(),
),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
FilledButton.tonalIcon(
icon: Icon(Icons.article_outlined),
label: Text("Comic Source list".tl),
onPressed: () {
showPopUpWidget(
App.rootContext,
_ComicSourceList(handleAddSource),
);
},
),
FilledButton.tonalIcon(
icon: Icon(Icons.file_open_outlined),
label: Text("Use a config file".tl),
onPressed: _selectFile,
),
FilledButton.tonalIcon(
icon: Icon(Icons.help_outline),
label: Text("Help".tl),
onPressed: help,
),
_CheckUpdatesButton(),
],
).paddingHorizontal(12).paddingVertical(8),
const SizedBox(height: 8),
],
),
@@ -699,11 +692,15 @@ class _CheckUpdatesButtonState extends State<_CheckUpdatesButton> {
@override
Widget build(BuildContext context) {
return Button.normal(
return FilledButton.tonalIcon(
icon: isLoading ? SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
) : Icon(Icons.update),
label: Text("Check updates".tl),
onPressed: check,
isLoading: isLoading,
child: Text("Check".tl),
).fixHeight(32);
);
}
}

View File

@@ -1116,4 +1116,4 @@ packages:
version: "0.0.12"
sdks:
dart: ">=3.8.0 <4.0.0"
flutter: ">=3.32.4"
flutter: ">=3.32.6"

View File

@@ -2,11 +2,11 @@ name: venera
description: "A comic app."
publish_to: 'none'
version: 1.4.5+145
version: 1.4.6+146
environment:
sdk: '>=3.8.0 <4.0.0'
flutter: 3.32.4
flutter: 3.32.6
dependencies:
flutter: