import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_styled_toast/flutter_styled_toast.dart'; import 'package:uni_links/uni_links.dart'; import 'package:uri_to_file/uri_to_file.dart'; import '../screens/ComicInfoScreen.dart'; import '../screens/DownloadOnlyImportScreen.dart'; import '../screens/PkzArchiveScreen.dart'; import 'config/TimeOffsetHour.dart'; /// 默认的图片尺寸 double coverWidth = 210; double coverHeight = 315; String categoryTitle(String? categoryTitle) { return categoryTitle ?? "全分类"; } /// 显示一个toast void defaultToast(BuildContext context, String title) { showToast( title, context: context, position: StyledToastPosition.center, animation: StyledToastAnimation.scale, reverseAnimation: StyledToastAnimation.fade, duration: const Duration(seconds: 4), animDuration: const Duration(seconds: 1), curve: Curves.elasticOut, reverseCurve: Curves.linear, ); } /// 显示一个确认框, 用户关闭弹窗以及选择否都会返回false, 仅当用户选择确定时返回true Future confirmDialog( BuildContext context, String title, String content) async { return await showDialog( context: context, builder: (context) => AlertDialog( title: Text(title), content: SingleChildScrollView( child: ListBody( children: [Text(content)], ), ), actions: [ MaterialButton( child: const Text('取消'), onPressed: () { Navigator.of(context).pop(false); }, ), MaterialButton( child: const Text('确定'), onPressed: () { Navigator.of(context).pop(true); }, ), ], )) ?? false; } /// 显示一个消息提示框 Future alertDialog(BuildContext context, String title, String content) { return showDialog( context: context, builder: (context) => AlertDialog( title: Text(title), content: SingleChildScrollView( child: ListBody( children: [ Text(content), ], ), ), actions: [ MaterialButton( child: const Text('确定'), onPressed: () { Navigator.of(context).pop(); }, ), ], ), ); } /// stream-filter的替代方法 List filteredList(List list, bool Function(T) filter) { List result = []; for (var element in list) { if (filter(element)) { result.add(element); } } return result; } /// 创建一个单选对话框, 用户取消选择返回null, 否则返回所选内容 Future chooseListDialog( BuildContext context, String title, List items, {String? tips}) async { return showDialog( context: context, builder: (BuildContext context) { return SimpleDialog( title: Text(title), children: [ ...items.map((e) => SimpleDialogOption( onPressed: () { Navigator.of(context).pop(e); }, child: Text('$e'), )), ...tips != null ? [ Container( padding: const EdgeInsets.fromLTRB(15, 5, 15, 15), child: Text(tips), ), ] : [], ], ); }, ); } /// 创建一个单选对话框, 用户取消选择返回null, 否则返回所选内容(value) Future chooseMapDialog( BuildContext buildContext, Map values, String title) async { return await showDialog( context: buildContext, builder: (BuildContext context) { return SimpleDialog( title: Text(title), children: values.entries .map((e) => SimpleDialogOption( child: Text(e.key), onPressed: () { Navigator.of(context).pop(e.value); }, )) .toList(), ); }, ); } /// 输入对话框1 var _controller = TextEditingController.fromValue(const TextEditingValue(text: '')); Future displayTextInputDialog(BuildContext context, {String? title, String src = "", String? hint, String? desc, bool isPasswd = false}) { _controller.text = src; return showDialog( context: context, builder: (context) { return AlertDialog( title: title == null ? null : Text(title), content: SingleChildScrollView( child: ListBody( children: [ TextField( controller: _controller, decoration: InputDecoration(hintText: hint), obscureText: isPasswd, obscuringCharacter: '\u2022', ), ...(desc == null ? [] : [ Container( padding: const EdgeInsets.only(top: 20, bottom: 10), child: Text( desc, style: TextStyle( fontSize: 12, color: Theme.of(context) .textTheme .bodyText1 ?.color ?.withOpacity(.5)), ), ) ]), ], ), ), actions: [ MaterialButton( child: const Text('取消'), onPressed: () { Navigator.of(context).pop(); }, ), MaterialButton( child: const Text('确认'), onPressed: () { Navigator.of(context).pop(_controller.text); }, ), ], ); }, ); } /// 将字符串前面加0直至满足len位 String add0(int num, int len) { var rsp = "$num"; while (rsp.length < len) { rsp = "0$rsp"; } return rsp; } /// 格式化时间 2012-34-56 String formatTimeToDate(String str) { try { var c = DateTime.parse(str).add(Duration(hours: currentTimeOffsetHour())); return "${add0(c.year, 4)}-${add0(c.month, 2)}-${add0(c.day, 2)}"; } catch (e) { return "-"; } } /// 格式化时间 2012-34-56 12:34:56 String formatTimeToDateTime(String str) { try { var c = DateTime.parse(str).add(Duration(hours: currentTimeOffsetHour())); return "${add0(c.year, 4)}-${add0(c.month, 2)}-${add0(c.day, 2)} ${add0(c.hour, 2)}:${add0(c.minute, 2)}"; } catch (e) { return "-"; } } /// 输入对话框2 final TextEditingController _textEditController = TextEditingController(text: ''); Future inputString(BuildContext context, String title, {String hint = "", String? defaultValue}) async { if (defaultValue != null) { _textEditController.text = defaultValue; } else { _textEditController.clear(); } return showDialog( context: context, builder: (context) { return AlertDialog( content: Card( child: SingleChildScrollView( child: ListBody( children: [ Text(title), TextField( controller: _textEditController, decoration: InputDecoration( labelText: hint, ), ), ], ), ), ), actions: [ MaterialButton( onPressed: () { Navigator.pop(context); }, child: const Text('取消'), ), MaterialButton( onPressed: () { Navigator.pop(context, _textEditController.text); }, child: const Text('确定'), ), ], ); }, ); } StreamSubscription linkSubscript(BuildContext context) { return linkStream.listen((uri) async { if (uri == null) return; if (RegExp(r"^pika://comic/([0-9A-z]+)/$").allMatches(uri).isNotEmpty) { String comicId = RegExp(r"^pika://comic/([0-9A-z]+)/$") .allMatches(uri) .first .group(1)!; Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) => ComicInfoScreen(comicId: comicId), ), ); } else if (RegExp(r"^.*\.pkz$").allMatches(uri).isNotEmpty) { File file = await toFile(uri); Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) => PkzArchiveScreen(pkzPath: file.path), ), ); } else if (RegExp(r"^.*\.((pki)|(zip))$").allMatches(uri).isNotEmpty) { File file = await toFile(uri); Navigator.of(context).push( MaterialPageRoute( builder: (BuildContext context) => DownloadOnlyImportScreen(path: file.path), ), ); } }); }