mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
Add log export functionality.
This commit is contained in:
@@ -404,7 +404,8 @@
|
|||||||
"Reload": "重载",
|
"Reload": "重载",
|
||||||
"Disable Length Limitation": "禁用长度限制",
|
"Disable Length Limitation": "禁用长度限制",
|
||||||
"Only valid for this run": "仅对本次运行有效",
|
"Only valid for this run": "仅对本次运行有效",
|
||||||
"Logs": "日志"
|
"Logs": "日志",
|
||||||
|
"Export logs": "导出日志"
|
||||||
},
|
},
|
||||||
"zh_TW": {
|
"zh_TW": {
|
||||||
"Home": "首頁",
|
"Home": "首頁",
|
||||||
@@ -811,6 +812,7 @@
|
|||||||
"Reload": "重載",
|
"Reload": "重載",
|
||||||
"Disable Length Limitation": "禁用長度限制",
|
"Disable Length Limitation": "禁用長度限制",
|
||||||
"Only valid for this run": "僅對本次運行有效",
|
"Only valid for this run": "僅對本次運行有效",
|
||||||
"Logs": "日誌"
|
"Logs": "日誌",
|
||||||
|
"Export logs": "匯出日誌"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
import 'dart:ui' as ui;
|
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/history_image_provider.dart';
|
||||||
import 'package:venera/foundation/image_provider/local_comic_image.dart';
|
import 'package:venera/foundation/image_provider/local_comic_image.dart';
|
||||||
import 'package:venera/foundation/local.dart';
|
import 'package:venera/foundation/local.dart';
|
||||||
|
import 'package:venera/foundation/log.dart';
|
||||||
import 'package:venera/foundation/res.dart';
|
import 'package:venera/foundation/res.dart';
|
||||||
import 'package:venera/network/cloudflare.dart';
|
import 'package:venera/network/cloudflare.dart';
|
||||||
import 'package:venera/pages/comic_details_page/comic_page.dart';
|
import 'package:venera/pages/comic_details_page/comic_page.dart';
|
||||||
import 'package:venera/pages/favorites/favorites_page.dart';
|
import 'package:venera/pages/favorites/favorites_page.dart';
|
||||||
import 'package:venera/utils/ext.dart';
|
import 'package:venera/utils/ext.dart';
|
||||||
|
import 'package:venera/utils/io.dart';
|
||||||
import 'package:venera/utils/tags_translation.dart';
|
import 'package:venera/utils/tags_translation.dart';
|
||||||
import 'package:venera/utils/translations.dart';
|
import 'package:venera/utils/translations.dart';
|
||||||
|
|
||||||
|
@@ -41,18 +41,22 @@ class NetworkError extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(height: 8),
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Text(
|
Text(
|
||||||
cfe == null ? message : "Cloudflare verification required".tl,
|
cfe == null ? message : "Cloudflare verification required".tl,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
),
|
),
|
||||||
if (retry != null)
|
TextButton(
|
||||||
const SizedBox(
|
onPressed: () {
|
||||||
height: 12,
|
saveFile(
|
||||||
),
|
data: utf8.encode(Log().toString()),
|
||||||
|
filename: 'log.txt',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text("Export logs".tl),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
if (retry != null)
|
if (retry != null)
|
||||||
if (cfe != null)
|
if (cfe != null)
|
||||||
FilledButton(
|
FilledButton(
|
||||||
@@ -74,15 +78,11 @@ class NetworkError extends StatelessWidget {
|
|||||||
body = Column(
|
body = Column(
|
||||||
children: [
|
children: [
|
||||||
const Appbar(title: Text("")),
|
const Appbar(title: Text("")),
|
||||||
Expanded(
|
Expanded(child: body),
|
||||||
child: body,
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Material(
|
return Material(child: body);
|
||||||
child: body,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,9 +94,7 @@ class ListLoadingIndicator extends StatelessWidget {
|
|||||||
return const SizedBox(
|
return const SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 80,
|
height: 80,
|
||||||
child: Center(
|
child: Center(child: FiveDotLoadingAnimation()),
|
||||||
child: FiveDotLoadingAnimation(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,10 +106,9 @@ class SliverListLoadingIndicator extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// SliverToBoxAdapter can not been lazy loaded.
|
// SliverToBoxAdapter can not been lazy loaded.
|
||||||
// Use SliverList to make sure the animation can be lazy loaded.
|
// Use SliverList to make sure the animation can be lazy loaded.
|
||||||
return SliverList.list(children: const [
|
return SliverList.list(
|
||||||
SizedBox(),
|
children: const [SizedBox(), ListLoadingIndicator()],
|
||||||
ListLoadingIndicator(),
|
);
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,10 +175,7 @@ abstract class LoadingState<T extends StatefulWidget, S extends Object>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildError() {
|
Widget buildError() {
|
||||||
return NetworkError(
|
return NetworkError(message: error!, retry: retry);
|
||||||
message: error!,
|
|
||||||
retry: retry,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -323,11 +317,7 @@ abstract class MultiPageLoadingState<T extends StatefulWidget, S extends Object>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildError(BuildContext context, String error) {
|
Widget buildError(BuildContext context, String error) {
|
||||||
return NetworkError(
|
return NetworkError(withAppbar: false, message: error, retry: reset);
|
||||||
withAppbar: false,
|
|
||||||
message: error,
|
|
||||||
retry: reset,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -388,7 +378,7 @@ class _FiveDotLoadingAnimationState extends State<FiveDotLoadingAnimation>
|
|||||||
Colors.green,
|
Colors.green,
|
||||||
Colors.blue,
|
Colors.blue,
|
||||||
Colors.yellow,
|
Colors.yellow,
|
||||||
Colors.purple
|
Colors.purple,
|
||||||
];
|
];
|
||||||
|
|
||||||
static const _padding = 12.0;
|
static const _padding = 12.0;
|
||||||
@@ -400,16 +390,15 @@ class _FiveDotLoadingAnimationState extends State<FiveDotLoadingAnimation>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedBuilder(
|
return AnimatedBuilder(
|
||||||
animation: _controller,
|
animation: _controller,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: _dotSize * 5 + _padding * 6,
|
width: _dotSize * 5 + _padding * 6,
|
||||||
height: _height,
|
height: _height,
|
||||||
child: Stack(
|
child: Stack(children: List.generate(5, (index) => buildDot(index))),
|
||||||
children: List.generate(5, (index) => buildDot(index)),
|
);
|
||||||
),
|
},
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildDot(int index) {
|
Widget buildDot(int index) {
|
||||||
@@ -417,7 +406,8 @@ class _FiveDotLoadingAnimationState extends State<FiveDotLoadingAnimation>
|
|||||||
var startValue = index * 0.8;
|
var startValue = index * 0.8;
|
||||||
return Positioned(
|
return Positioned(
|
||||||
left: index * _dotSize + (index + 1) * _padding,
|
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),
|
(_height - _dotSize),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: _dotSize,
|
width: _dotSize,
|
||||||
|
Reference in New Issue
Block a user