diff --git a/lib/basic/Entities.dart b/lib/basic/Entities.dart index 179d1c5..690d8d6 100644 --- a/lib/basic/Entities.dart +++ b/lib/basic/Entities.dart @@ -979,6 +979,7 @@ class PkzComicViewLog { required this.lastViewPictureRank, required this.lastViewTime, }); + late final String fileName; late final String lastViewComicId; late final String filePath; @@ -988,7 +989,7 @@ class PkzComicViewLog { late final int lastViewPictureRank; late final String lastViewTime; - PkzComicViewLog.fromJson(Map json){ + PkzComicViewLog.fromJson(Map json) { fileName = json['fileName']; lastViewComicId = json['lastViewComicId']; filePath = json['filePath']; @@ -1022,3 +1023,47 @@ class IsPro { this.expire = json["expire"]; } } + +class ForgotPasswordResult { + ForgotPasswordResult({ + required this.question1, + required this.question2, + required this.question3, + }); + + late final String question1; + late final String question2; + late final String question3; + + ForgotPasswordResult.fromJson(Map json) { + question1 = json['question1']; + question2 = json['question2']; + question3 = json['question3']; + } + + Map toJson() { + final _data = {}; + _data['question1'] = question1; + _data['question2'] = question2; + _data['question3'] = question3; + return _data; + } +} + +class ResetPasswordResult { + ResetPasswordResult({ + required this.password, + }); + + late final String password; + + ResetPasswordResult.fromJson(Map json) { + password = json['password']; + } + + Map toJson() { + final _data = {}; + _data['password'] = password; + return _data; + } +} diff --git a/lib/basic/Method.dart b/lib/basic/Method.dart index 18406fd..6da2933 100644 --- a/lib/basic/Method.dart +++ b/lib/basic/Method.dart @@ -569,10 +569,10 @@ class Method { /// 导出下载的图片到HTML+JPG (即使没有下载完成) Future exportComicJpegsEvenNotFinish( - String comicId, - String dir, - String name, - ) { + String comicId, + String dir, + String name, + ) { return _flatInvoke("exportComicJpegsEvenNotFinish", { "comicId": comicId, "dir": dir, @@ -582,10 +582,10 @@ class Method { /// 导出下载的图片到HTML+JPG Future exportComicDownloadToJPG( - String comicId, - String dir, - String name, - ) { + String comicId, + String dir, + String name, + ) { return _flatInvoke("exportComicDownloadToJPG", { "comicId": comicId, "dir": dir, @@ -920,4 +920,38 @@ class Method { Future iosGetDocumentDir() async { return await _channel.invokeMethod('iosGetDocumentDir', ''); } + + /// 找回密码1 + Future forgotPassword(email) async { + String data = await _flatInvoke("forgotPassword", email); + return ForgotPasswordResult.fromJson(jsonDecode(data)); + } + + /// 找回密码2 + Future resetPassword( + String email, + int questionNo, + String answer, + ) async { + String data = await _flatInvoke("resetPassword", { + "email": email, + "questionNo": questionNo, + "answer": answer, + }); + return ResetPasswordResult.fromJson(jsonDecode(data)); + } + + Future mergeHistoriesFromWebDav( + String root, + String username, + String password, + String file, + ) { + return _flatInvoke("mergeHistoriesFromWebDav", { + "root": root, + "username": username, + "password": password, + "file": file, + }); + } } diff --git a/lib/basic/config/WebDav.dart b/lib/basic/config/WebDav.dart new file mode 100644 index 0000000..9338594 --- /dev/null +++ b/lib/basic/config/WebDav.dart @@ -0,0 +1,186 @@ +import 'package:flutter/material.dart'; + +import '../Common.dart'; +import '../Method.dart'; +import 'IsPro.dart'; + +const _webdavRootPropertyName = "webdavRoot"; +const _webdavUsernamePropertyName = "webdavUsername"; +const _webdavPasswordPropertyName = "webdavPassword"; +const _autoSyncHistoryToWebdavPropertyName = "autoSyncHistoryToWebdav"; + +late String _webdavRoot; +late String _webdavUsername; +late String _webdavPassword; +late bool _autoSyncHistoryToWebdav; + +Future initWebDav() async { + _webdavRoot = await method.loadProperty( + _webdavRootPropertyName, + "https://your.dav.host/folder", + ); + _webdavUsername = await method.loadProperty( + _webdavUsernamePropertyName, + "", + ); + _webdavPassword = await method.loadProperty( + _webdavPasswordPropertyName, + "", + ); + if (!isPro) { + _autoSyncHistoryToWebdav = false; + return; + } + _autoSyncHistoryToWebdav = await method.loadProperty( + _autoSyncHistoryToWebdavPropertyName, + "false", + ) == + "true"; +} + +Future syncWebDavIfAuto(BuildContext context) async { + if (_autoSyncHistoryToWebdav) { + try { + await method.mergeHistoriesFromWebDav( + _webdavRoot, + _webdavUsername, + _webdavPassword, + "pk.histories", + ); + } catch (e, s) { + print("$e\n$s"); + defaultToast(context, "WebDav没有同步成功\n$e"); + } + } +} + +Future syncHistoryToWebdav(BuildContext context) async { + try { + await method.mergeHistoriesFromWebDav( + _webdavRoot, + _webdavUsername, + _webdavPassword, + "pk.histories", + ); + defaultToast(context, "同步成功"); + } catch (e, s) { + print("$e\n$s"); + defaultToast(context, "没有同步成功\n$e"); + } +} + +List webDavSettings(BuildContext context) { + return [ + // + StatefulBuilder( + builder: (BuildContext context, void Function(void Function()) setState) { + return ListTile( + title: const Text( + "WebDav 路径 (文件夹)", + ), + subtitle: Text(_webdavRoot), + onTap: () async { + String? input = await displayTextInputDialog( + context, + src: _webdavRoot, + title: 'WebDav 路径', + hint: '请输入WebDav 路径', + ); + if (input != null) { + await method.saveProperty(_webdavRootPropertyName, input); + setState(() { + _webdavRoot = input; + }); + } + }); + }, + ), + // + StatefulBuilder( + builder: (BuildContext context, void Function(void Function()) setState) { + return ListTile( + title: const Text( + "WebDav 用户名", + ), + subtitle: Text(_webdavUsername), + onTap: () async { + String? input = await displayTextInputDialog( + context, + src: _webdavUsername, + title: 'WebDav 用户名', + hint: '请输入WebDav 用户名', + ); + if (input != null) { + await method.saveProperty(_webdavUsernamePropertyName, input); + setState(() { + _webdavUsername = input; + }); + } + }); + }, + ), + // + StatefulBuilder( + builder: (BuildContext context, void Function(void Function()) setState) { + return ListTile( + title: const Text( + "WebDav 密码", + ), + subtitle: Text(_webdavPassword), + onTap: () async { + String? input = await displayTextInputDialog( + context, + src: _webdavPassword, + title: 'WebDav 密码', + hint: '请输入WebDav 密码', + ); + if (input != null) { + await method.saveProperty(_webdavPasswordPropertyName, input); + setState(() { + _webdavPassword = input; + }); + } + }); + }, + ), + // + StatefulBuilder( + builder: (BuildContext context, void Function(void Function()) setState) { + return ListTile( + title: Text( + "开启时自动同步浏览记录到WebDav" + (isPro ? "" : "(发电)"), + style: TextStyle( + color: !isPro ? Colors.grey : null, + ), + ), + subtitle: Text( + _autoSyncHistoryToWebdav ? "是" : "否", + style: TextStyle( + color: !isPro ? Colors.grey : null, + ), + ), + onTap: () async { + if (!isPro) { + return; + } + String? result = await chooseListDialog( + context, "开启时自动同步浏览记录到WebDav", ["是", "否"]); + if (result != null) { + var target = result == "是"; + await method.saveProperty( + _autoSyncHistoryToWebdavPropertyName, "$target"); + _autoSyncHistoryToWebdav = target; + } + setState(() {}); + }, + ); + }, + ), + // + ListTile( + title: const Text("立即同步浏览记录"), + onTap: () async { + await syncHistoryToWebdav(context); + }), + ]; +} diff --git a/lib/screens/AccountScreen.dart b/lib/screens/AccountScreen.dart index 8e847d3..d67d420 100644 --- a/lib/screens/AccountScreen.dart +++ b/lib/screens/AccountScreen.dart @@ -1,12 +1,10 @@ import 'dart:async'; -import 'dart:io'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:pikapika/basic/Common.dart'; import 'package:pikapika/basic/Method.dart'; import 'package:pikapika/basic/config/IsPro.dart'; -import 'package:pikapika/basic/config/Themes.dart'; import 'package:pikapika/basic/enum/ErrorTypes.dart'; import 'package:pikapika/screens/AboutScreen.dart'; import 'package:pikapika/screens/RegisterScreen.dart'; @@ -17,7 +15,7 @@ import '../basic/config/IconLoading.dart'; import '../basic/config/Version.dart'; import 'AppScreen.dart'; import 'DownloadListScreen.dart'; -import 'ThemeScreen.dart'; +import 'ForgotPasswordScreen.dart'; import 'components/ContentLoading.dart'; // 账户设置 @@ -56,7 +54,6 @@ class _AccountScreenState extends State { versionPop(context); } - Future _loadProperties() async { var username = await method.getUsername(); var password = await method.getPassword(); @@ -103,8 +100,7 @@ class _AccountScreenState extends State { Navigator.push( context, mixRoute( - builder: (context) => const AboutScreen( - ), + builder: (context) => const AboutScreen(), ), ); }, @@ -160,28 +156,39 @@ class _AccountScreenState extends State { }, ), const NetworkSetting(), - Row( - children: [ - Expanded( - child: Container( - padding: const EdgeInsets.all(15), - child: Text.rich(TextSpan( - text: '没有账号,我要注册', - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - decoration: TextDecoration.underline, - ), - recognizer: TapGestureRecognizer() - ..onTap = () => Navigator.push( - context, - mixRoute( - builder: (BuildContext context) => - const RegisterScreen()), - ).then((value) => _loadProperties()), - )), - ), + Container( + padding: const EdgeInsets.all(15), + child: Text.rich(TextSpan( + text: '没有账号,我要注册', + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + decoration: TextDecoration.underline, ), - ], + recognizer: TapGestureRecognizer() + ..onTap = () => Navigator.push( + context, + mixRoute( + builder: (BuildContext context) => + const RegisterScreen()), + ).then((value) => _loadProperties()), + )), + ), + Container( + padding: const EdgeInsets.all(15), + child: Text.rich(TextSpan( + text: '密码找回', + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + decoration: TextDecoration.underline, + ), + recognizer: TapGestureRecognizer() + ..onTap = () => Navigator.push( + context, + mixRoute( + builder: (BuildContext context) => + const ForgotPasswordScreen()), + ).then((value) => _loadProperties()), + )), ), ], ), diff --git a/lib/screens/ForgotPasswordScreen.dart b/lib/screens/ForgotPasswordScreen.dart new file mode 100644 index 0000000..f4329cd --- /dev/null +++ b/lib/screens/ForgotPasswordScreen.dart @@ -0,0 +1,264 @@ +import 'package:flutter/material.dart'; + +import '../basic/Common.dart'; +import '../basic/Cross.dart'; +import '../basic/Method.dart'; +import 'components/ContentLoading.dart'; + +class ForgotPasswordScreen extends StatefulWidget { + const ForgotPasswordScreen({Key? key}) : super(key: key); + + @override + State createState() => _ForgotPasswordScreenState(); +} + +class _ForgotPasswordScreenState extends State { + bool _loading = false; + int _state = 0; // 0 输入账号,1 回答问题,2 密码已经找回 + String _email = ""; + String _question1 = ""; + String _question2 = ""; + String _question3 = ""; + String _answer1 = "回答1"; + String _answer2 = "回答2"; + String _answer3 = "回答3"; + String _password = ""; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("找回密码"), + ), + body: _stateScreen(), + ); + } + + Widget _stateScreen() { + if (_loading) { + return const ContentLoading(label: '加载中'); + } + switch (_state) { + case 0: + return _inputEmailScreen(); + case 1: + return _inputAnswerScreen(); + case 2: + return _showNewPasswordScreen(); + } + throw ''; + } + + Widget _inputEmailScreen() { + return ListView(children: [ + ListTile( + title: const Text("账号"), + subtitle: Text(_email == "" ? "未设置" : _email), + onTap: () async { + String? input = await displayTextInputDialog( + context, + src: _email, + title: '账号', + hint: '请输入账号', + ); + if (input != null) { + setState(() { + _email = input; + }); + } + }, + ), + Container( + margin: const EdgeInsets.all(10), + color: Colors.grey.shade500.withAlpha(18), + child: MaterialButton( + onPressed: _confirmEmail, + child: const Text("确认"), + ), + ), + ]); + } + + void _confirmEmail() async { + if (_email.isEmpty) { + defaultToast(context, "请输入账号"); + return; + } + try { + setState(() { + _loading = true; + }); + var result = await method.forgotPassword(_email); + _question1 = result.question1; + _question2 = result.question2; + _question3 = result.question3; + _state = 1; + } catch (e, s) { + print("$e\n$s"); + defaultToast(context, '$e'); + } finally { + setState(() { + _loading = false; + }); + } + } + + Widget _inputAnswerScreen() { + return ListView(children: [ + Container(height: 10), + ListTile( + title: const Text("账号"), + subtitle: Text(_email.isEmpty ? "未设置" : _email), + ), + Container(height: 10), + const Divider(), + Container(height: 10), + ListTile( + title: const Text("问题1"), + subtitle: Text(_question1), + ), + ListTile( + title: const Text("回答1"), + subtitle: Text(_answer1.isEmpty ? "未设置" : _answer1), + onTap: () async { + String? input = await displayTextInputDialog( + context, + src: _answer1, + title: '回答1', + hint: '请输入回答1', + ); + if (input != null) { + setState(() { + _answer1 = input; + }); + } + }, + ), + Container( + margin: const EdgeInsets.all(10), + color: Colors.grey.shade500.withAlpha(18), + child: MaterialButton( + onPressed: () { + _confirmAnswer(1, _answer1); + }, + child: const Text("使用回答1找回密码"), + ), + ), + Container(height: 10), + const Divider(), + Container(height: 10), + ListTile( + title: const Text("问题2"), + subtitle: Text(_question2), + ), + ListTile( + title: const Text("回答2"), + subtitle: Text(_answer2.isEmpty ? "未设置" : _answer2), + onTap: () async { + String? input = await displayTextInputDialog( + context, + src: _answer2, + title: '回答2', + hint: '请输入回答2', + ); + if (input != null) { + setState(() { + _answer2 = input; + }); + } + }, + ), + Container( + margin: const EdgeInsets.all(10), + color: Colors.grey.shade500.withAlpha(18), + child: MaterialButton( + onPressed: () { + _confirmAnswer(2, _answer2); + }, + child: const Text("使用回答2找回密码"), + ), + ), + Container(height: 10), + const Divider(), + Container(height: 10), + ListTile( + title: const Text("问题3"), + subtitle: Text(_question3), + ), + ListTile( + title: const Text("回答3"), + subtitle: Text(_answer3.isEmpty ? "未设置" : _answer3), + onTap: () async { + String? input = await displayTextInputDialog( + context, + src: _answer3, + title: '回答3', + hint: '请输入回答3', + ); + if (input != null) { + setState(() { + _answer3 = input; + }); + } + }, + ), + Container( + margin: const EdgeInsets.all(10), + color: Colors.grey.shade500.withAlpha(18), + child: MaterialButton( + onPressed: () { + _confirmAnswer(3, _answer3); + }, + child: const Text("使用回答3找回密码"), + ), + ), + ///////// + Container(height: 20), + ]); + } + + _confirmAnswer(int answerNo, String answer) async { + if (answer.isEmpty) { + defaultToast(context, "请输入答案"); + return; + } + try { + setState(() { + _loading = true; + }); + var result = await method.resetPassword(_email, answerNo, answer); + _password = result.password; + _state = 2; + defaultToast(context, "新密码正在复制到剪切板"); + copyToClipBoard(context, _password); + } catch (e, s) { + print("$e\n$s"); + if ("$e".contains("invalid request")) { + defaultToast(context, '答案不正确'); + } else { + defaultToast(context, '$e'); + } + } finally { + setState(() { + _loading = false; + }); + } + } + + Widget _showNewPasswordScreen() { + return ListView(children: [ + ListTile( + title: const Text("账号"), + subtitle: Text(_email.isEmpty ? "未设置" : _email), + ), + ListTile( + title: const Text("密码"), + subtitle: Text(_password.isEmpty ? "未设置" : _password), + onTap: () { + defaultToast(context, "新密码正在复制到剪切板"); + copyToClipBoard(context, _password); + }, + ), + ]); + } +} diff --git a/lib/screens/InitScreen.dart b/lib/screens/InitScreen.dart index ffb43a4..8b1c525 100644 --- a/lib/screens/InitScreen.dart +++ b/lib/screens/InitScreen.dart @@ -45,6 +45,7 @@ import '../basic/config/DownloadCachePath.dart'; import '../basic/config/ExportRename.dart'; import '../basic/config/IconLoading.dart'; import '../basic/config/IsPro.dart'; +import '../basic/config/WebDav.dart'; import 'AccountScreen.dart'; import 'AppScreen.dart'; import 'DownloadOnlyImportScreen.dart'; @@ -109,6 +110,7 @@ class _InitScreenState extends State { await initShowCommentAtDownload(); await initDownloadCachePath(); await initUseApiLoadImage(); + await initWebDav(); String? initUrl; if (Platform.isAndroid || Platform.isIOS) { @@ -154,6 +156,7 @@ class _InitScreenState extends State { if (_authenticating) { _goAuthentication(); } else { + syncWebDavIfAuto(context); _goApplication(); } } diff --git a/lib/screens/SettingsScreen.dart b/lib/screens/SettingsScreen.dart index 62d3348..f677292 100644 --- a/lib/screens/SettingsScreen.dart +++ b/lib/screens/SettingsScreen.dart @@ -35,6 +35,7 @@ import '../basic/config/Authentication.dart'; import '../basic/config/CategoriesColumnCount.dart'; import '../basic/config/DownloadCachePath.dart'; import '../basic/config/UsingRightClickPop.dart'; +import '../basic/config/WebDav.dart'; import '../basic/config/WillPopNotice.dart'; import 'CleanScreen.dart'; import 'MigrateScreen.dart'; @@ -87,6 +88,12 @@ class _SettingsScreenState extends State { ), const Divider(), const NetworkSetting(), + const Padding(padding: EdgeInsets.only(top: 15)), + const Divider(), + const ListTile( + subtitle: Text("同步"), + ), + ...webDavSettings(context), const Divider(), const Padding(padding: EdgeInsets.only(top: 15)), ]), diff --git a/pubspec.lock b/pubspec.lock index 0667864..325f835 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -6,7 +6,7 @@ packages: description: name: another_xlider sha256: "1446d10af1aefd8fe527e62054214967684773c0c2bb3dd2a8d506983a1d2279" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.1.2" archive: @@ -14,7 +14,7 @@ packages: description: name: archive sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.3.6" async: @@ -22,7 +22,7 @@ packages: description: name: async sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.10.0" boolean_selector: @@ -30,7 +30,7 @@ packages: description: name: boolean_selector sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.1.1" characters: @@ -38,7 +38,7 @@ packages: description: name: characters sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.2.1" clipboard: @@ -46,7 +46,7 @@ packages: description: name: clipboard sha256: "2ec38f0e59878008ceca0ab122e4bfde98847f88ef0f83331362ba4521f565a9" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.1.3" clock: @@ -54,7 +54,7 @@ packages: description: name: clock sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.1.1" collection: @@ -62,7 +62,7 @@ packages: description: name: collection sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.17.0" convert: @@ -70,7 +70,7 @@ packages: description: name: convert sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.1.1" crop_image: @@ -78,7 +78,7 @@ packages: description: name: crop_image sha256: "78715179b0d3cd1e9e0a5c4a7846851acf33db346c657674b9abc358e84a511d" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.0.3" cross_file: @@ -86,7 +86,7 @@ packages: description: name: cross_file sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.3.3+4" crypto: @@ -94,7 +94,7 @@ packages: description: name: crypto sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.0.2" cupertino_icons: @@ -102,7 +102,7 @@ packages: description: name: cupertino_icons sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.0.5" event: @@ -110,7 +110,7 @@ packages: description: name: event sha256: eb4814de94cbf6a10da9c4f652bc654087d7066e33566b5036822e6c0b24befb - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.1.2" fake_async: @@ -118,7 +118,7 @@ packages: description: name: fake_async sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.3.1" ffi: @@ -126,7 +126,7 @@ packages: description: name: ffi sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.0.1" file_picker: @@ -134,7 +134,7 @@ packages: description: name: file_picker sha256: d090ae03df98b0247b82e5928f44d1b959867049d18d73635e2e0bc3f49542b9 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "5.2.5" filesystem_picker: @@ -142,7 +142,7 @@ packages: description: name: filesystem_picker sha256: cf790e033b3e0c07b5bc9f71458b39f1f45017641aae508ffdfb86a59baa0c1d - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.1.0" flutter: @@ -155,7 +155,7 @@ packages: description: name: flutter_datetime_picker sha256: "8e695c63c769350e541951227c2775190ec73ceda774a315b1dc9a99d5facfe5" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.5.1" flutter_lints: @@ -163,7 +163,7 @@ packages: description: name: flutter_lints sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_localizations: @@ -176,7 +176,7 @@ packages: description: name: flutter_plugin_android_lifecycle sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.0.7" flutter_search_bar: @@ -184,7 +184,7 @@ packages: description: name: flutter_search_bar sha256: "80c00de27e2fbb852550d6f0319135af191e5ba7ab7e61cd5173fd4e29611eb3" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.0.0-dev.1" flutter_styled_toast: @@ -192,7 +192,7 @@ packages: description: name: flutter_styled_toast sha256: cc32aed2a49ce77a1ed5844073c6c0f5e381c81fd6d694e0ba3c5dc2a645963d - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.1.3" flutter_svg: @@ -200,7 +200,7 @@ packages: description: name: flutter_svg sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.1.6" flutter_test: @@ -218,7 +218,7 @@ packages: description: name: http sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.13.5" http_parser: @@ -226,7 +226,7 @@ packages: description: name: http_parser sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "4.0.2" image: @@ -234,7 +234,7 @@ packages: description: name: image sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.3.0" image_cropper: @@ -242,7 +242,7 @@ packages: description: name: image_cropper sha256: "60542ffd03436e6f80a1d7c9839f75b6a62b0a290cd98624fa29d150fdf672c8" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.5.1" image_picker: @@ -250,7 +250,7 @@ packages: description: name: image_picker sha256: f98d76672d309c8b7030c323b3394669e122d52b307d2bbd8d06bd70f5b2aabe - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.8.6+1" image_picker_android: @@ -258,7 +258,7 @@ packages: description: name: image_picker_android sha256: "385f12ee9c7288575572c7873a332016ec45ebd092e1c2f6bd421b4a9ad21f1d" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.8.5+6" image_picker_for_web: @@ -266,7 +266,7 @@ packages: description: name: image_picker_for_web sha256: "7d319fb74955ca46d9bf7011497860e3923bb67feebcf068f489311065863899" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.1.10" image_picker_ios: @@ -274,7 +274,7 @@ packages: description: name: image_picker_ios sha256: "8ffb14b43713d7c43fb21299cc18181cc5b39bd3ea1cc427a085c6400fe5aa52" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.8.6+7" image_picker_platform_interface: @@ -282,7 +282,7 @@ packages: description: name: image_picker_platform_interface sha256: "7cef2f28f4f2fef99180f636c3d446b4ccbafd6ba0fad2adc9a80c4040f656b8" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.6.2" intl: @@ -290,7 +290,7 @@ packages: description: name: intl sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.17.0" isolate: @@ -298,7 +298,7 @@ packages: description: name: isolate sha256: "3554ab10fdeec965d27e0074c913ccb2229887633da080d2b35a6322da14938b" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.1.1" js: @@ -306,7 +306,7 @@ packages: description: name: js sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.6.5" lints: @@ -314,7 +314,7 @@ packages: description: name: lints sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.0.1" matcher: @@ -322,7 +322,7 @@ packages: description: name: matcher sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.12.13" material_color_utilities: @@ -330,7 +330,7 @@ packages: description: name: material_color_utilities sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.2.0" meta: @@ -338,7 +338,7 @@ packages: description: name: meta sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.8.0" modal_bottom_sheet: @@ -346,7 +346,7 @@ packages: description: name: modal_bottom_sheet sha256: "3bba63c62d35c931bce7f8ae23a47f9a05836d8cb3c11122ada64e0b2f3d718f" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.0.0-pre" multi_select_flutter: @@ -354,7 +354,7 @@ packages: description: name: multi_select_flutter sha256: "503857b415d390d29159df8a9d92d83c6aac17aaf1c307fb7bcfc77d097d20ed" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "4.1.3" path: @@ -362,7 +362,7 @@ packages: description: name: path sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.8.2" path_drawing: @@ -370,7 +370,7 @@ packages: description: name: path_drawing sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.0.1" path_parsing: @@ -378,7 +378,7 @@ packages: description: name: path_parsing sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.0.1" permission_handler: @@ -386,7 +386,7 @@ packages: description: name: permission_handler sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "10.2.0" permission_handler_android: @@ -394,7 +394,7 @@ packages: description: name: permission_handler_android sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "10.2.0" permission_handler_apple: @@ -402,7 +402,7 @@ packages: description: name: permission_handler_apple sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "9.0.7" permission_handler_platform_interface: @@ -410,7 +410,7 @@ packages: description: name: permission_handler_platform_interface sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.9.0" permission_handler_windows: @@ -418,7 +418,7 @@ packages: description: name: permission_handler_windows sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.1.2" petitparser: @@ -426,7 +426,7 @@ packages: description: name: petitparser sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "5.1.0" photo_view: @@ -434,7 +434,7 @@ packages: description: name: photo_view sha256: "26cb153080a2673bebccaf72d3283e82f8f41a47fe5f9bc5ba8634d2e8a9fc8e" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.13.0" plugin_platform_interface: @@ -442,7 +442,7 @@ packages: description: name: plugin_platform_interface sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.1.3" pointycastle: @@ -450,7 +450,7 @@ packages: description: name: pointycastle sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.6.2" scrollable_positioned_list: @@ -458,7 +458,7 @@ packages: description: name: scrollable_positioned_list sha256: "9566352ab9ba05794ee6c8864f154afba5d36c5637d0e3e32c615ba4ceb92772" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.2.3" sky_engine: @@ -471,7 +471,7 @@ packages: description: name: source_span sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.9.1" stack_trace: @@ -479,7 +479,7 @@ packages: description: name: stack_trace sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.11.0" stream_channel: @@ -487,7 +487,7 @@ packages: description: name: stream_channel sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.1.1" string_scanner: @@ -495,7 +495,7 @@ packages: description: name: string_scanner sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.2.0" term_glyph: @@ -503,7 +503,7 @@ packages: description: name: term_glyph sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: @@ -511,7 +511,7 @@ packages: description: name: test_api sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.4.16" typed_data: @@ -519,7 +519,7 @@ packages: description: name: typed_data sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.3.1" uni_links: @@ -527,7 +527,7 @@ packages: description: name: uni_links sha256: "051098acfc9e26a9fde03b487bef5d3d228ca8f67693480c6f33fd4fbb8e2b6e" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.5.1" uni_links_platform_interface: @@ -535,7 +535,7 @@ packages: description: name: uni_links_platform_interface sha256: "929cf1a71b59e3b7c2d8a2605a9cf7e0b125b13bc858e55083d88c62722d4507" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "1.0.0" uni_links_web: @@ -543,7 +543,7 @@ packages: description: name: uni_links_web sha256: "7539db908e25f67de2438e33cc1020b30ab94e66720b5677ba6763b25f6394df" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.1.0" uri_to_file: @@ -551,7 +551,7 @@ packages: description: name: uri_to_file sha256: "84afd633b1492fc465c768141e1a29edd519061bf99935b6b4d0d5de8ec7c108" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "0.2.0" url_launcher: @@ -559,7 +559,7 @@ packages: description: name: url_launcher sha256: e8f2efc804810c0f2f5b485f49e7942179f56eabcfe81dce3387fec4bb55876b - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "6.1.9" url_launcher_android: @@ -567,7 +567,7 @@ packages: description: name: url_launcher_android sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "6.0.23" url_launcher_ios: @@ -575,7 +575,7 @@ packages: description: name: url_launcher_ios sha256: "0a5af0aefdd8cf820dd739886efb1637f1f24489900204f50984634c07a54815" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "6.1.0" url_launcher_linux: @@ -583,7 +583,7 @@ packages: description: name: url_launcher_linux sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.0.2" url_launcher_macos: @@ -591,7 +591,7 @@ packages: description: name: url_launcher_macos sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.0.2" url_launcher_platform_interface: @@ -599,7 +599,7 @@ packages: description: name: url_launcher_platform_interface sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.1.1" url_launcher_web: @@ -607,7 +607,7 @@ packages: description: name: url_launcher_web sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.0.14" url_launcher_windows: @@ -615,7 +615,7 @@ packages: description: name: url_launcher_windows sha256: b6217370f8eb1fd85c8890c539f5a639a01ab209a36db82c921ebeacefc7a615 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.0.3" vector_math: @@ -623,7 +623,7 @@ packages: description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "2.1.4" win32: @@ -631,7 +631,7 @@ packages: description: name: win32 sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "3.1.3" xml: @@ -639,7 +639,7 @@ packages: description: name: xml sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" - url: "https://pub.dartlang.org" + url: "https://pub.dev" source: hosted version: "6.2.2" sdks: