Forgot password & Webdav histories sync

This commit is contained in:
niuhuan 2023-02-13 15:38:26 +08:00
parent d01d0a7cc7
commit bfcb1f6a0e
8 changed files with 659 additions and 113 deletions

View File

@ -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<String, dynamic> json){
PkzComicViewLog.fromJson(Map<String, dynamic> 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<String, dynamic> json) {
question1 = json['question1'];
question2 = json['question2'];
question3 = json['question3'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['question1'] = question1;
_data['question2'] = question2;
_data['question3'] = question3;
return _data;
}
}
class ResetPasswordResult {
ResetPasswordResult({
required this.password,
});
late final String password;
ResetPasswordResult.fromJson(Map<String, dynamic> json) {
password = json['password'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['password'] = password;
return _data;
}
}

View File

@ -569,10 +569,10 @@ class Method {
/// HTML+JPG (使)
Future<dynamic> 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<dynamic> 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<String> iosGetDocumentDir() async {
return await _channel.invokeMethod('iosGetDocumentDir', '');
}
/// 1
Future<ForgotPasswordResult> forgotPassword(email) async {
String data = await _flatInvoke("forgotPassword", email);
return ForgotPasswordResult.fromJson(jsonDecode(data));
}
/// 2
Future<ResetPasswordResult> 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,
});
}
}

View File

@ -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<Widget> 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<String>(
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);
}),
];
}

View File

@ -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<AccountScreen> {
versionPop(context);
}
Future _loadProperties() async {
var username = await method.getUsername();
var password = await method.getPassword();
@ -103,8 +100,7 @@ class _AccountScreenState extends State<AccountScreen> {
Navigator.push(
context,
mixRoute(
builder: (context) => const AboutScreen(
),
builder: (context) => const AboutScreen(),
),
);
},
@ -160,28 +156,39 @@ class _AccountScreenState extends State<AccountScreen> {
},
),
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()),
)),
),
],
),

View File

@ -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<StatefulWidget> createState() => _ForgotPasswordScreenState();
}
class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
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);
},
),
]);
}
}

View File

@ -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<InitScreen> {
await initShowCommentAtDownload();
await initDownloadCachePath();
await initUseApiLoadImage();
await initWebDav();
String? initUrl;
if (Platform.isAndroid || Platform.isIOS) {
@ -154,6 +156,7 @@ class _InitScreenState extends State<InitScreen> {
if (_authenticating) {
_goAuthentication();
} else {
syncWebDavIfAuto(context);
_goApplication();
}
}

View File

@ -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<SettingsScreen> {
),
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)),
]),

View File

@ -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: