From 22f66d36a2e210dd0274489be5cdccd30164e95a Mon Sep 17 00:00:00 2001 From: jyuesong <425698907@qq.com> Date: Thu, 20 Jan 2022 10:25:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=84=9A=E6=9C=AC=E7=9A=84?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 + lib/base/http/api.dart | 31 +++ lib/base/http/http.dart | 2 +- lib/base/http/url.dart | 6 + lib/base/routes.dart | 20 +- lib/module/others/other_page.dart | 69 ++++-- .../others/scripts/script_detail_page.dart | 188 +++++++++++++-- .../others/scripts/script_edit_page.dart | 93 ++++++++ lib/module/others/scripts/script_page.dart | 12 +- lib/module/others/update_password_page.dart | 207 +++++++++++++++++ pubspec.lock | 216 +++++++++--------- 11 files changed, 703 insertions(+), 147 deletions(-) create mode 100644 lib/module/others/scripts/script_edit_page.dart create mode 100644 lib/module/others/update_password_page.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 76a2d47..5d57a98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.0.2 + +* 支持脚本的编辑删除 +* 支持client_id登录之后只启用部分模块 + + ## 1.0.1 * 增加任务详情页 diff --git a/lib/base/http/api.dart b/lib/base/http/api.dart index 7d69608..8629278 100644 --- a/lib/base/http/api.dart +++ b/lib/base/http/api.dart @@ -66,6 +66,16 @@ class Api { ); } + static Future> updatePassword(String name, String password) async { + return await Http.put( + Url.updatePassword, + { + "username": name, + "password": password, + }, + ); + } + static Future> inTimeLog(String cron) async { return await Http.get( Url.intimeLog(cron), @@ -225,6 +235,27 @@ class Api { ); } + static Future> updateScript(String name, String path, String content) async { + return await Http.put( + Url.scriptDetail, + { + "filename": name, + "path": path, + "content": content, + }, + ); + } + + static Future> delScript(String name, String path) async { + return await Http.delete( + Url.scriptDetail, + { + "filename": name, + "path": path, + }, + ); + } + static Future> scriptDetail(String name, String? path) async { return await Http.get( Url.scriptDetail + name, diff --git a/lib/base/http/http.dart b/lib/base/http/http.dart index a598f09..c1ed0c5 100644 --- a/lib/base/http/http.dart +++ b/lib/base/http/http.dart @@ -117,7 +117,7 @@ class Http { if (!pushedLoginPage) { "身份已过期,请重新登录".toast(); pushedLoginPage = true; - navigatorState.currentState?.pushReplacementNamed(Routes.routeLogin); + navigatorState.currentState?.pushNamedAndRemoveUntil(Routes.routeLogin, (route) => false); } } diff --git a/lib/base/http/url.dart b/lib/base/http/url.dart index 63617f8..f3c0788 100644 --- a/lib/base/http/url.dart +++ b/lib/base/http/url.dart @@ -6,6 +6,8 @@ class Url { static const loginByClientId = "/open/auth/token"; static const user = "/api/user"; + static const updatePassword = "/api/user"; + static get tasks => getIt().useSecretLogined ? "/open/crons" : "/api/crons"; static get runTasks => getIt().useSecretLogined ? "/open/crons/run" : "/api/crons/run"; @@ -47,6 +49,7 @@ class Url { static get taskLogDetail => getIt().useSecretLogined ? "/open/logs/" : "/api/logs/"; static get scripts => getIt().useSecretLogined ? "/open/scripts/files" : "/api/scripts/files"; + static get scriptUpdate => getIt().useSecretLogined ? "/open/scripts" : "/api/scripts"; static get scriptDetail => getIt().useSecretLogined ? "/open/scripts/" : "/api/scripts/"; @@ -54,6 +57,9 @@ class Url { static get dependencyReinstall => getIt().useSecretLogined ? "/open/dependencies/reinstall" : "/api/dependencies/reinstall"; + + + static intimeLog(String cronId) { return getIt().useSecretLogined ? "/open/crons/$cronId/log" : "/api/crons/$cronId/log"; } diff --git a/lib/base/routes.dart b/lib/base/routes.dart index c12e4fe..e4c3953 100644 --- a/lib/base/routes.dart +++ b/lib/base/routes.dart @@ -10,9 +10,11 @@ import 'package:qinglong_app/module/others/dependencies/add_dependency_page.dart import 'package:qinglong_app/module/others/dependencies/dependency_page.dart'; import 'package:qinglong_app/module/others/login_log/login_log_page.dart'; import 'package:qinglong_app/module/others/scripts/script_detail_page.dart'; +import 'package:qinglong_app/module/others/scripts/script_edit_page.dart'; import 'package:qinglong_app/module/others/scripts/script_page.dart'; import 'package:qinglong_app/module/others/task_log/task_log_detail_page.dart'; import 'package:qinglong_app/module/others/task_log/task_log_page.dart'; +import 'package:qinglong_app/module/others/update_password_page.dart'; import 'package:qinglong_app/module/task/add_task_page.dart'; import 'package:qinglong_app/module/task/task_bean.dart'; import 'package:qinglong_app/module/task/task_detail/task_detail_page.dart'; @@ -31,7 +33,10 @@ class Routes { static const String routeTaskLogDetail = "/log/taskDetail"; static const String routeScript = "/script"; static const String routeScriptDetail = "/script/detail"; + static const String routeScriptUpdate = "/script/update"; + static const String routeScriptAdd = "/script/add"; static const String routeDependency = "/Dependency"; + static const String routeUpdatePassword = "/updatePassword"; static Route? generateRoute(RouteSettings settings) { switch (settings.name) { @@ -100,12 +105,25 @@ class Routes { builder: (context) => TaskDetailPage( settings.arguments as TaskBean, ), - ); case routeEnvDetail: + ); + case routeEnvDetail: return CupertinoPageRoute( builder: (context) => EnvDetailPage( settings.arguments as EnvBean, ), ); + case routeUpdatePassword: + return CupertinoPageRoute( + builder: (context) => const UpdatePasswordPage(), + ); + case routeScriptUpdate: + return CupertinoPageRoute( + builder: (context) => ScriptEditPage( + (settings.arguments as Map)["title"], + (settings.arguments as Map)["path"], + (settings.arguments as Map)["content"], + ), + ); } return null; diff --git a/lib/module/others/other_page.dart b/lib/module/others/other_page.dart index 15df6ca..94c0e32 100644 --- a/lib/module/others/other_page.dart +++ b/lib/module/others/other_page.dart @@ -6,6 +6,7 @@ import 'package:qinglong_app/base/theme.dart'; import 'package:qinglong_app/base/userinfo_viewmodel.dart'; import 'package:qinglong_app/main.dart'; import 'package:qinglong_app/utils/extension.dart'; + class OtherPage extends ConsumerStatefulWidget { const OtherPage({Key? key}) : super(key: key); @@ -57,10 +58,7 @@ class _OtherPageState extends ConsumerState { Text( "脚本管理", style: TextStyle( - color: ref - .watch(themeProvider) - .themeColor - .titleColor(), + color: ref.watch(themeProvider).themeColor.titleColor(), fontSize: 16, ), ), @@ -93,10 +91,7 @@ class _OtherPageState extends ConsumerState { Text( "依赖管理", style: TextStyle( - color: ref - .watch(themeProvider) - .themeColor - .titleColor(), + color: ref.watch(themeProvider).themeColor.titleColor(), fontSize: 16, ), ), @@ -129,10 +124,7 @@ class _OtherPageState extends ConsumerState { Text( "任务日志", style: TextStyle( - color: ref - .watch(themeProvider) - .themeColor - .titleColor(), + color: ref.watch(themeProvider).themeColor.titleColor(), fontSize: 16, ), ), @@ -170,10 +162,7 @@ class _OtherPageState extends ConsumerState { Text( "登录日志", style: TextStyle( - color: ref - .watch(themeProvider) - .themeColor - .titleColor(), + color: ref.watch(themeProvider).themeColor.titleColor(), fontSize: 16, ), ), @@ -192,6 +181,7 @@ class _OtherPageState extends ConsumerState { Container( margin: const EdgeInsets.symmetric( horizontal: 15, + vertical: 15, ), decoration: BoxDecoration( color: ref.watch(themeProvider).themeColor.settingBgColor(), @@ -203,10 +193,47 @@ class _OtherPageState extends ConsumerState { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ + GestureDetector( + onTap: () { + if (getIt().useSecretLogined) { + "使用client_id方式登录无法修改密码".toast(); + } else { + Navigator.of(context).pushNamed( + Routes.routeUpdatePassword, + ); + } + }, + behavior: HitTestBehavior.opaque, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 15, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "修改密码", + style: TextStyle( + color: ref.watch(themeProvider).themeColor.titleColor(), + fontSize: 16, + ), + ), + const Spacer(), + const Icon( + CupertinoIcons.right_chevron, + size: 16, + ), + ], + ), + ), + ), + const Divider( + indent: 15, + ), Padding( padding: const EdgeInsets.only( - top: 5, - bottom: 5, left: 15, right: 15, ), @@ -217,8 +244,7 @@ class _OtherPageState extends ConsumerState { Text( "夜间模式", style: TextStyle( - color: - ref.watch(themeProvider).themeColor.titleColor(), + color: ref.watch(themeProvider).themeColor.titleColor(), fontSize: 16, ), ), @@ -267,8 +293,7 @@ class _OtherPageState extends ConsumerState { child: const Text("确定"), onPressed: () { getIt().updateToken(""); - Navigator.of(context) - .pushReplacementNamed(Routes.routeLogin); + Navigator.of(context).pushReplacementNamed(Routes.routeLogin); }, ), ], diff --git a/lib/module/others/scripts/script_detail_page.dart b/lib/module/others/scripts/script_detail_page.dart index aa5a0b8..648c815 100644 --- a/lib/module/others/scripts/script_detail_page.dart +++ b/lib/module/others/scripts/script_detail_page.dart @@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:qinglong_app/base/http/api.dart'; import 'package:qinglong_app/base/http/http.dart'; import 'package:qinglong_app/base/ql_app_bar.dart'; +import 'package:qinglong_app/base/routes.dart'; import 'package:qinglong_app/base/theme.dart'; import 'package:qinglong_app/base/ui/lazy_load_state.dart'; import 'package:qinglong_app/utils/extension.dart'; @@ -27,6 +28,105 @@ class ScriptDetailPage extends ConsumerStatefulWidget { class _ScriptDetailPageState extends ConsumerState with LazyLoadState { String? content; + List actions = []; + + @override + void initState() { + super.initState(); + actions.addAll( + [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.of(context).pop(); + if (content == null || content!.isEmpty) { + "未获取到脚本内容,请稍候重试".toast(); + return; + } + Navigator.of(context).pushNamed( + Routes.routeScriptUpdate, + arguments: { + "title": widget.title, + "path": widget.path, + "content": content, + }, + ).then((value) { + if (value != null && value == true) { + Navigator.of(context).pop(true); + } + }); + }, + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 15, + ), + alignment: Alignment.center, + child: const Material( + color: Colors.transparent, + child: Text( + "编辑", + style: TextStyle( + fontSize: 16, + ), + ), + ), + ), + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () async { + Navigator.of(context).pop(); + + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: const Text("确认删除"), + content: const Text("确认删除该脚本吗"), + actions: [ + CupertinoDialogAction( + child: const Text("取消"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + CupertinoDialogAction( + child: const Text("确定"), + onPressed: () async { + Navigator.of(context).pop(); + HttpResponse result = await Api.delScript(widget.title, widget.path ?? ""); + if (result.success) { + "删除成功".toast(); + Navigator.of(context).pop(true); + } else { + result.message?.toast(); + } + }, + ), + ], + ), + ); + }, + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 15, + ), + alignment: Alignment.center, + child: const Material( + color: Colors.transparent, + child: Text( + "删除", + style: TextStyle( + color: Colors.red, + fontSize: 16, + ), + ), + ), + ), + ), + ], + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -36,22 +136,82 @@ class _ScriptDetailPageState extends ConsumerState with LazyLo Navigator.of(context).pop(); }, title: "脚本详情", - ), - body:content == null - ? const Center( - child: CupertinoActivityIndicator(), - ) - : SingleChildScrollView( - child: HighlightView( - content ?? "", - language: getLanguageType(widget.title), - padding: const EdgeInsets.symmetric( - horizontal: 15, + actions: [ + InkWell( + onTap: () { + showCupertinoModalPopup( + context: context, + builder: (context) { + return CupertinoActionSheet( + title: Container( + alignment: Alignment.center, + child: const Material( + color: Colors.transparent, + child: Text( + "更多操作", + style: TextStyle( + fontSize: 16, + ), + ), + ), + ), + actions: actions, + cancelButton: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Navigator.pop(context); + }, + child: Container( + alignment: Alignment.center, + padding: const EdgeInsets.symmetric( + vertical: 10, + ), + child: const Material( + color: Colors.transparent, + child: Text( + "取消", + style: TextStyle( + color: Colors.red, + fontSize: 16, + ), + ), + ), + ), + ), + ); + }, + ); + }, + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 15, + ), + child: Center( + child: Icon( + Icons.more_horiz, + color: Colors.white, + size: 26, + ), + ), + ), ), - theme: ref.watch(themeProvider).themeColor.codeEditorTheme(), - tabSize: 14, - ), + ], ), + body: content == null + ? const Center( + child: CupertinoActivityIndicator(), + ) + : SingleChildScrollView( + child: HighlightView( + content ?? "", + language: getLanguageType(widget.title), + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + theme: ref.watch(themeProvider).themeColor.codeEditorTheme(), + tabSize: 14, + ), + ), ); } diff --git a/lib/module/others/scripts/script_edit_page.dart b/lib/module/others/scripts/script_edit_page.dart new file mode 100644 index 0000000..8c9dc45 --- /dev/null +++ b/lib/module/others/scripts/script_edit_page.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:qinglong_app/base/http/api.dart'; +import 'package:qinglong_app/base/http/http.dart'; +import 'package:qinglong_app/base/ql_app_bar.dart'; +import 'package:qinglong_app/base/theme.dart'; +import 'package:qinglong_app/module/config/config_viewmodel.dart'; +import 'package:qinglong_app/utils/extension.dart'; + +class ScriptEditPage extends ConsumerStatefulWidget { + final String content; + final String title; + final String path; + + const ScriptEditPage(this.title, this.path, this.content, {Key? key}) : super(key: key); + + @override + _ScriptEditPageState createState() => _ScriptEditPageState(); +} + +class _ScriptEditPageState extends ConsumerState { + late TextEditingController _controller; + FocusNode node = FocusNode(); + + @override + void initState() { + _controller = TextEditingController(text: widget.content); + super.initState(); + WidgetsBinding.instance?.addPostFrameCallback( + (timeStamp) { + node.requestFocus(); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: QlAppBar( + canBack: true, + backCall: () { + Navigator.of(context).pop(); + }, + title: '编辑${widget.title}', + actions: [ + InkWell( + onTap: () async { + HttpResponse response = await Api.updateScript(widget.title, widget.path, _controller.text); + if (response.success) { + "提交成功".toast(); + Navigator.of(context).pop(true); + } else { + (response.message ?? "").toast(); + } + }, + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 15, + ), + child: Center( + child: Text( + "提交", + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ), + ), + ), + ) + ], + ), + body: Container( + padding: const EdgeInsets.only( + left: 15, + right: 15, + ), + child: SingleChildScrollView( + child: TextField( + focusNode: node, + style: TextStyle( + color: ref.read(themeProvider).themeColor.descColor(), + fontSize: 14, + ), + controller: _controller, + minLines: 1, + maxLines: 100, + ), + ), + ), + ); + } +} diff --git a/lib/module/others/scripts/script_page.dart b/lib/module/others/scripts/script_page.dart index bfc9f62..4d36b28 100644 --- a/lib/module/others/scripts/script_page.dart +++ b/lib/module/others/scripts/script_page.dart @@ -60,7 +60,11 @@ class _ScriptPageState extends ConsumerState with LazyLoadState with LazyLoadState createState() => _UpdatePasswordPageState(); +} + +class _UpdatePasswordPageState extends ConsumerState { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + final TextEditingController _passwordAgainController = TextEditingController(); + + FocusNode focusNode = FocusNode(); + + @override + void initState() { + super.initState(); + WidgetsBinding.instance?.addPostFrameCallback( + (timeStamp) { + focusNode.requestFocus(); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: QlAppBar( + canBack: true, + backCall: () { + Navigator.of(context).pop(); + }, + title: "修改用户名密码", + actions: [ + InkWell( + onTap: () { + submit(); + }, + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 15, + ), + child: Center( + child: Text( + "提交", + style: TextStyle( + color: Colors.white, + fontSize: 16, + ), + ), + ), + ), + ) + ], + ), + body: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 15, + ), + const Text( + "用户名:", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + TextField( + focusNode: focusNode, + controller: _nameController, + decoration: const InputDecoration( + contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "请输入用户名", + ), + autofocus: false, + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 15, + ), + const Text( + "新密码:", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + TextField( + obscureText: true, + controller: _passwordController, + maxLines: 1, + decoration: const InputDecoration( + contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "请输入新密码", + ), + autofocus: false, + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 15, + ), + const Text( + "再次输入新密码:", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + TextField( + obscureText: true, + maxLines: 1, + controller: _passwordAgainController, + decoration: const InputDecoration( + contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5), + hintText: "再次输入新密码", + ), + autofocus: false, + ), + ], + ), + ), + ], + ), + ); + } + + void submit() async { + if (_nameController.text.isEmpty) { + "用户名不能为空".toast(); + return; + } + if (_passwordController.text.isEmpty || _passwordAgainController.text.isEmpty) { + "密码不能为空".toast(); + return; + } + + if (_passwordAgainController.text != _passwordController.text) { + "两次输入的密码不一致".toast(); + return; + } + + commitReal(); + } + + void commitReal() async { + String name = _nameController.text; + String password = _passwordController.text; + HttpResponse response = await Api.updatePassword(name, password); + + if (response.success) { + "更新成功".toast(); + + if (!getIt().useSecretLogined) { + getIt().updateUserName(name, password); + } + Navigator.of(context).pushNamedAndRemoveUntil(Routes.routeLogin, (route) => false); + } else { + response.message.toast(); + } + } +} diff --git a/pubspec.lock b/pubspec.lock index 13bdfaa..da0ad75 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,245 +5,245 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "22.0.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.7.2" archive: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.8" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.8.2" back_button_interceptor: dependency: "direct main" description: name: back_button_interceptor - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "5.0.2" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.1" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.7" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "7.2.3" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "8.1.4" change_app_package_name: dependency: "direct dev" description: name: change_app_package_name - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.3" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" cli_util: dependency: transitive description: name: cli_util - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.5" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.1.0" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.15.0" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" dio: dependency: "direct main" description: name: dio - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.4" dio_log: dependency: "direct main" description: name: dio_log - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.2" drag_and_drop_lists: dependency: "direct main" description: name: drag_and_drop_lists - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.2+2" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.2" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" flip_card: dependency: "direct main" description: name: flip_card - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.0" flutter: @@ -255,49 +255,49 @@ packages: dependency: "direct dev" description: name: flutter_app_name - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.1" flutter_highlight: dependency: "direct main" description: name: flutter_highlight - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.0" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.2" flutter_lints: dependency: "direct dev" description: name: flutter_lints - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" flutter_native_splash: dependency: "direct dev" description: name: flutter_native_splash - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.3" flutter_riverpod: dependency: "direct main" description: name: flutter_riverpod - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.3" flutter_slidable: dependency: "direct main" description: name: flutter_slidable - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" flutter_test: @@ -314,322 +314,322 @@ packages: dependency: "direct main" description: name: fluttertoast - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "8.0.8" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" get_it: dependency: "direct main" description: name: get_it - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "7.2.0" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.2" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" highlight: dependency: transitive description: name: highlight - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.0" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.0" image: dependency: transitive description: name: image - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.1" intl: dependency: "direct main" description: name: intl - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.17.0" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.3" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.3" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.4.0" json_conversion: dependency: "direct dev" description: name: json_conversion - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.0.4" json_conversion_annotation: dependency: "direct main" description: name: json_conversion_annotation - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.0.4" lints: dependency: transitive description: name: lints - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" logger: dependency: "direct main" description: name: logger - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.12.11" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.7.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" move_to_background: dependency: "direct main" description: name: move_to_background - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.2" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.8.0" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.5" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.5" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.11.1" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.4.0" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.5.0" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "4.2.4" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" riverpod: dependency: transitive description: name: riverpod - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.3" shared_preferences: dependency: "direct main" description: name: shared_preferences - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.12" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.10" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.9" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.2" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" sky_engine: @@ -641,140 +641,140 @@ packages: dependency: transitive description: name: source_gen - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.3" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.10.0" state_notifier: dependency: transitive description: name: state_notifier - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.2+1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" synchronized: dependency: "direct main" description: name: synchronized - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.4.3" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" universal_io: dependency: transitive description: name: universal_io - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.6" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.0" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "5.3.1" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" sdks: