From a4daec8f103dbcfaf670eed226c9256628a4ca95 Mon Sep 17 00:00:00 2001 From: htylight Date: Tue, 15 Aug 2023 10:53:30 +0800 Subject: [PATCH] order chat tile by time, image message can be sent and showed on message screen --- lib/common/theme.dart | 2 + lib/database/box_type.dart | 6 +- lib/database/box_type.g.dart | 9 +- lib/database/hive_database.dart | 6 +- lib/models/user_model.dart | 6 +- lib/models/websocket_model.dart | 26 +- lib/router/contact_router.dart | 2 +- lib/screens/chat/chat_screen.dart | 48 ++- lib/screens/chat/components/badge_avatar.dart | 16 +- lib/screens/chat/components/chat_tile.dart | 13 +- .../message/components/input_icon_button.dart | 0 .../message/components/message_bubble.dart | 149 ++++++-- .../message/components/message_input_box.dart | 120 ++++-- lib/screens/message/message_screen.dart | 105 +++--- lib/utils/app_dir.dart | 18 +- lib/utils/format_datetime.dart | 9 + pubspec.lock | 354 +++++++++--------- 17 files changed, 562 insertions(+), 327 deletions(-) mode change 100755 => 100644 lib/screens/message/components/input_icon_button.dart diff --git a/lib/common/theme.dart b/lib/common/theme.dart index d43ad99..3ebda44 100755 --- a/lib/common/theme.dart +++ b/lib/common/theme.dart @@ -5,6 +5,7 @@ import './constants.dart'; ThemeData lightThemeData(BuildContext context) { return ThemeData( + useMaterial3: true, primaryColor: kPrimaryColor, scaffoldBackgroundColor: Colors.white, appBarTheme: appBarThemeLight, @@ -32,6 +33,7 @@ ThemeData lightThemeData(BuildContext context) { ThemeData darkThemeData(BuildContext context) { return ThemeData( + useMaterial3: true, primaryColor: kPrimaryColor, scaffoldBackgroundColor: Colors.black, appBarTheme: appBarThemeDark, diff --git a/lib/database/box_type.dart b/lib/database/box_type.dart index 46bbf6a..c5a6905 100644 --- a/lib/database/box_type.dart +++ b/lib/database/box_type.dart @@ -17,7 +17,10 @@ class ChatSetting { bool isHideMsg; @HiveField(4) - DateTime? latestDateTime; + DateTime latestDateTime; + + @HiveField(5) + int unreadCount; ChatSetting( this.contactId, @@ -25,6 +28,7 @@ class ChatSetting { this.isOpen, this.isHideMsg, this.latestDateTime, + this.unreadCount, ); } diff --git a/lib/database/box_type.g.dart b/lib/database/box_type.g.dart index e35decf..748c994 100644 --- a/lib/database/box_type.g.dart +++ b/lib/database/box_type.g.dart @@ -21,14 +21,15 @@ class ChatSettingAdapter extends TypeAdapter { fields[1] == null ? false : fields[1] as bool, fields[2] == null ? true : fields[2] as bool, fields[3] == null ? false : fields[3] as bool, - fields[4] as DateTime?, + fields[4] as DateTime, + fields[5] as int, ); } @override void write(BinaryWriter writer, ChatSetting obj) { writer - ..writeByte(5) + ..writeByte(6) ..writeByte(0) ..write(obj.contactId) ..writeByte(1) @@ -38,7 +39,9 @@ class ChatSettingAdapter extends TypeAdapter { ..writeByte(3) ..write(obj.isHideMsg) ..writeByte(4) - ..write(obj.latestDateTime); + ..write(obj.latestDateTime) + ..writeByte(5) + ..write(obj.unreadCount); } @override diff --git a/lib/database/hive_database.dart b/lib/database/hive_database.dart index 68fde70..72b7194 100644 --- a/lib/database/hive_database.dart +++ b/lib/database/hive_database.dart @@ -11,7 +11,7 @@ import 'package:together_mobile/utils/app_dir.dart'; void initDatabase() async { List encryptionKeyUint8List = await getEncryptKey(); - await Hive.initFlutter(await getBoxPath()); + await Hive.initFlutter(await getBoxDir()); Box chatSettingBox = await Hive.openBox('chat_setting'); @@ -54,11 +54,11 @@ void openNewMessageBox(String contactId) async { var chatSettingBox = Hive.box('chat_setting'); chatSettingBox - .add(ChatSetting(contactId, false, true, false, DateTime.now())); + .add(ChatSetting(contactId, false, true, false, DateTime.now(), 0)); await Hive.openLazyBox( 'message_$contactId', encryptionCipher: HiveAesCipher(encryptionKeyUint8List), compactionStrategy: (entries, deletedEntries) => entries > 200, ); -} \ No newline at end of file +} diff --git a/lib/models/user_model.dart b/lib/models/user_model.dart index 88971f7..ff094a2 100755 --- a/lib/models/user_model.dart +++ b/lib/models/user_model.dart @@ -44,7 +44,7 @@ class UserProfile extends ChangeNotifier { String status = ''; String sign = ''; String avatar = ''; - String baseAvatarPath = ''; + String baseImageDir = ''; bool isInitialised = false; Future init(Map json) async { @@ -54,7 +54,7 @@ class UserProfile extends ChangeNotifier { status = json['status'] ?? ''; sign = json['sign'] ?? ''; avatar = json['avatar'] ?? ''; - baseAvatarPath = await getAvatarDir(); + baseImageDir = await getChatImageDir(); gender = _genderEn2Cn(json['gender'] ?? ''); isInitialised = true; } @@ -94,7 +94,7 @@ class UserProfile extends ChangeNotifier { status = ''; sign = ''; avatar = ''; - baseAvatarPath = ''; + baseImageDir = ''; isInitialised = false; } diff --git a/lib/models/websocket_model.dart b/lib/models/websocket_model.dart index c9e5f71..d5c54b0 100644 --- a/lib/models/websocket_model.dart +++ b/lib/models/websocket_model.dart @@ -1,13 +1,16 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'package:flutter/material.dart'; + import 'package:hive_flutter/hive_flutter.dart'; + import 'package:together_mobile/database/box_type.dart'; import 'package:together_mobile/models/apply_list_model.dart'; import 'package:together_mobile/models/contact_model.dart'; import 'package:together_mobile/models/init_get_it.dart'; - +import 'package:together_mobile/models/user_model.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:web_socket_channel/status.dart' as status; @@ -51,6 +54,8 @@ class WebSocketManager extends ChangeNotifier { receiveFriendAdded(data); case 'friend-deleted': receiveFriendDeleted(data); + case 'chat-image': + receiveImages(data); } } @@ -130,6 +135,9 @@ enum SocketStatus { } void receiveFriendMsg(Map msg) async { + print('=================收到了好友信息事件=================='); + print(msg); + print('======================================='); String senderId = msg['senderId'] as String; late Box messageTBox; try { @@ -151,11 +159,13 @@ void receiveFriendMsg(Map msg) async { true, false, dateTime, + 1, ), ); } else { chatSetting.isOpen = true; chatSetting.latestDateTime = dateTime; + chatSetting.unreadCount++; chatSettingBox.put(senderId, chatSetting); } @@ -174,6 +184,9 @@ void receiveFriendMsg(Map msg) async { } void receiveApplyFriend(Map msg) { + print('=================收到了申请好友事件=================='); + print(msg); + print('======================================='); getIt.get().addJson(msg); } @@ -194,3 +207,14 @@ void receiveFriendDeleted(Map msg) { getIt.get().removeFriend(msg['friendId']); getIt.get().removeFriend(msg['friendId']); } + +void receiveImages(Map msg) async { + print('=================收到了聊天图片事件=================='); + print(msg); + print('======================================='); + String chatImageDir = getIt.get().baseImageDir; + File file = await File('$chatImageDir/${msg['filename']}').create( + recursive: true, + ); + await file.writeAsBytes(msg['bytes']); +} diff --git a/lib/router/contact_router.dart b/lib/router/contact_router.dart index 10cdca6..aa81bcf 100644 --- a/lib/router/contact_router.dart +++ b/lib/router/contact_router.dart @@ -31,7 +31,7 @@ final contactRouter = GoRoute( path: 'add', name: 'AddContact', parentNavigatorKey: rootNavigatorKey, - builder: (context, state) => const SearchNewScreen(), + builder: (context, state) => const SearchNewScreen() , routes: [ GoRoute( path: 'friend', diff --git a/lib/screens/chat/chat_screen.dart b/lib/screens/chat/chat_screen.dart index b3b5e88..b4c0a2a 100755 --- a/lib/screens/chat/chat_screen.dart +++ b/lib/screens/chat/chat_screen.dart @@ -27,24 +27,25 @@ class ChatScreen extends StatefulWidget { class _ChatScreenState extends State { Future _initData() async { - List encryptionKeyUint8List = await getEncryptKey(); - - await Hive.initFlutter(await getBoxPath()); - - Box chatSettingBox = - await Hive.openBox('chat_setting'); - - final openedChats = - chatSettingBox.values.where((element) => element.isOpen); - - for (var chatBox in openedChats) { - Hive.openBox( - 'message_${chatBox.contactId}', - encryptionCipher: HiveAesCipher(encryptionKeyUint8List), - compactionStrategy: (entries, deletedEntries) => entries > 200, - ); - } if (!getIt.get().isInitialised) { + List encryptionKeyUint8List = await getEncryptKey(); + + await Hive.initFlutter(await getBoxDir()); + + Box chatSettingBox = + await Hive.openBox('chat_setting'); + + final openedChats = + chatSettingBox.values.where((element) => element.isOpen); + + for (var chatBox in openedChats) { + await Hive.openBox( + 'message_${chatBox.contactId}', + encryptionCipher: HiveAesCipher(encryptionKeyUint8List), + compactionStrategy: (entries, deletedEntries) => entries > 200, + ); + } + getIt.get().connect(getIt.get().id); List> res = await Future.wait([ @@ -120,8 +121,14 @@ class _ChatScreenState extends State { valueListenable: Hive.box('chat_setting').listenable(), builder: (context, Box box, _) { - final openedChat = + final List openedChat = box.values.where((element) => element.isOpen).toList(); + + // latestMsg on the top + openedChat.sort( + (a, b) => b.latestDateTime.compareTo(a.latestDateTime), + ); + if (openedChat.isEmpty) { return const Center( child: Text( @@ -141,8 +148,9 @@ class _ChatScreenState extends State { itemBuilder: (BuildContext context, int index) { String contactId = openedChat[index].contactId; String showedTime = formatTileDateTime( - openedChat[index].latestDateTime!, + openedChat[index].latestDateTime, ); + int unreadCount = openedChat[index].unreadCount; return ValueListenableBuilder( valueListenable: @@ -162,6 +170,7 @@ class _ChatScreenState extends State { attachments: messageT.attachments, dateTime: showedTime, isShowTime: messageT.isShowTime, + unreadCount: unreadCount, ); } else { return ChatTile( @@ -173,6 +182,7 @@ class _ChatScreenState extends State { attachments: const [], dateTime: showedTime, isShowTime: false, + unreadCount: 0, ); } }, diff --git a/lib/screens/chat/components/badge_avatar.dart b/lib/screens/chat/components/badge_avatar.dart index 0c67496..4fbbc96 100755 --- a/lib/screens/chat/components/badge_avatar.dart +++ b/lib/screens/chat/components/badge_avatar.dart @@ -3,32 +3,28 @@ import 'package:flutter/material.dart'; import 'package:badges/badges.dart' as badges; import 'package:together_mobile/common/constants.dart'; -class BadgeAvatar extends StatefulWidget { +class BadgeAvatar extends StatelessWidget { const BadgeAvatar({ super.key, - required this.count, + required this.unreadCount, required this.radius, required this.backgroundImage, }); - final int count; + final int unreadCount; final double radius; final ImageProvider backgroundImage; - @override - State createState() => _BadgeAvatarState(); -} - -class _BadgeAvatarState extends State { @override Widget build(BuildContext context) { return badges.Badge( + showBadge: unreadCount > 0, badgeStyle: const badges.BadgeStyle( badgeColor: kErrorColor, elevation: 12, ), badgeContent: Text( - '${widget.count}+', + unreadCount > 99 ? '$unreadCount+' : '$unreadCount', style: TextStyle( fontSize: 11, color: Theme.of(context).colorScheme.inversePrimary, @@ -37,7 +33,7 @@ class _BadgeAvatarState extends State { badgeAnimation: const badges.BadgeAnimation.scale(), position: badges.BadgePosition.topEnd(top: -12, end: -16), child: CircleAvatar( - backgroundImage: widget.backgroundImage, + backgroundImage: backgroundImage, ), ); } diff --git a/lib/screens/chat/components/chat_tile.dart b/lib/screens/chat/components/chat_tile.dart index d8c5667..d82e618 100755 --- a/lib/screens/chat/components/chat_tile.dart +++ b/lib/screens/chat/components/chat_tile.dart @@ -23,9 +23,10 @@ class ChatTile extends StatefulWidget { required this.attachments, required this.dateTime, required this.isShowTime, + required this.unreadCount, }); - final int index; + final int index, unreadCount; final String contactId, senderId, type, text, dateTime; final List attachments; final bool isShowTime; @@ -62,7 +63,7 @@ class _ChatTileState extends State { foregroundColor: kContentColorDark, backgroundColor: kPrimaryColor, icon: Icons.remove_red_eye, - label: '隐藏信息', + label: '隐藏消息', flex: 1, ), ], @@ -78,13 +79,13 @@ class _ChatTileState extends State { .friends[widget.contactId]! .avatar .isEmpty - ? const BadgeAvatar( - count: 99, + ? BadgeAvatar( + unreadCount: widget.unreadCount, radius: 25, - backgroundImage: AssetImage('assets/images/user_3.png'), + backgroundImage: const AssetImage('assets/images/user_3.png'), ) : BadgeAvatar( - count: 99, + unreadCount: widget.unreadCount, radius: 25, backgroundImage: CachedNetworkImageProvider( '$avatarsUrl/${getIt.get().friends[widget.contactId]!.avatar}', diff --git a/lib/screens/message/components/input_icon_button.dart b/lib/screens/message/components/input_icon_button.dart old mode 100755 new mode 100644 diff --git a/lib/screens/message/components/message_bubble.dart b/lib/screens/message/components/message_bubble.dart index 181ac54..a642b95 100755 --- a/lib/screens/message/components/message_bubble.dart +++ b/lib/screens/message/components/message_bubble.dart @@ -1,3 +1,6 @@ +import 'dart:async'; +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; @@ -7,7 +10,7 @@ import 'package:together_mobile/models/init_get_it.dart'; import 'package:together_mobile/models/user_model.dart'; import 'package:together_mobile/request/server.dart'; -class MessageBubble extends StatelessWidget { +class MessageBubble extends StatefulWidget { const MessageBubble({ super.key, required this.contactId, @@ -23,6 +26,70 @@ class MessageBubble extends StatelessWidget { final bool isShowTime; final List attachments; + @override + State createState() => _MessageBubbleState(); +} + +class _MessageBubbleState extends State { + // add late here so you can access widget instance + List _isImagesLoaded = []; + final List _timerList = []; + + @override + void initState() { + super.initState(); + _isImagesLoaded = List.filled(widget.attachments.length, false); + for (var i = 0; i < widget.attachments.length; i++) { + String imagePath = + '${getIt.get().baseImageDir}/${widget.attachments[i]}'; + File file = File(imagePath); + if (file.existsSync()) { + _isImagesLoaded[i] = true; + } else { + _isImagesLoaded[i] = false; + _timerList.add(Timer.periodic( + const Duration(milliseconds: 200), + (timer) { + if ((file.existsSync())) { + setState(() { + _isImagesLoaded[i] = true; + }); + timer.cancel(); + } + }, + )); + } + } + // _isImagesLoaded = List.filled(widget.attachments.length, false); + // _timerList = List.generate( + // widget.attachments.length, + // (index) { + // return Timer.periodic( + // const Duration(milliseconds: 200), + // (timer) async { + // String imagePath = + // '${getIt.get().baseImageDir}/${widget.attachments[index]}'; + // File file = File(imagePath); + // if ((await file.exists())) { + // setState(() { + // _isImagesLoaded[index] = true; + // }); + // timer.cancel(); + // } + // }, + // ); + // }, + // ); + } + + @override + void dispose() { + super.dispose(); + for (var element in _timerList) { + element.cancel(); + } + } + @override Widget build(BuildContext context) { return Container( @@ -33,25 +100,26 @@ class MessageBubble extends StatelessWidget { child: Column( children: [ // message date time - if (isShowTime) + if (widget.isShowTime) SizedBox( height: 35.0, child: Text( - dateTime, + widget.dateTime, style: const TextStyle( color: kUnActivatedColor, ), ), ), Row( - textDirection: - senderId == contactId ? TextDirection.ltr : TextDirection.rtl, + textDirection: widget.senderId == widget.contactId + ? TextDirection.ltr + : TextDirection.rtl, crossAxisAlignment: CrossAxisAlignment.start, children: [ - senderId == contactId + widget.senderId == widget.contactId ? getIt .get() - .friends[contactId]! + .friends[widget.contactId]! .avatar .isEmpty ? CircleAvatar( @@ -59,7 +127,7 @@ class MessageBubble extends StatelessWidget { ) : CircleAvatar( backgroundImage: CachedNetworkImageProvider( - '$avatarsUrl/${getIt.get().friends[contactId]!.avatar}', + '$avatarsUrl/${getIt.get().friends[widget.contactId]!.avatar}', ), ) : CircleAvatar( @@ -72,7 +140,7 @@ class MessageBubble extends StatelessWidget { ), Expanded( child: Column( - crossAxisAlignment: senderId == contactId + crossAxisAlignment: widget.senderId == widget.contactId ? CrossAxisAlignment.start : CrossAxisAlignment.end, children: [ @@ -83,12 +151,12 @@ class MessageBubble extends StatelessWidget { // height: 5, // ), - if (type == 'text/multipart') + if (widget.type == 'text/multipart') // message box Container( padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), decoration: BoxDecoration( - color: senderId == contactId + color: widget.senderId == widget.contactId ? const Color.fromARGB(255, 241, 241, 241) : kPrimaryColor, borderRadius: BorderRadius.circular(10.0), @@ -97,31 +165,46 @@ class MessageBubble extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ // text message content - Text( - text, - textWidthBasis: TextWidthBasis.longestLine, - ), + if (widget.text.isNotEmpty) + Text( + widget.text, + textWidthBasis: TextWidthBasis.longestLine, + ), const SizedBox( height: 10, ), - // image content if has - if (attachments.isNotEmpty) - ...List.filled( - attachments.length, - Container( - margin: const EdgeInsets.only( - bottom: 10, - ), - constraints: const BoxConstraints( - maxHeight: 100, - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - ), - child: Image.asset( - 'assets/images/Logo_dark.png', - ), - ), + // image content if have + if (widget.attachments.isNotEmpty) + ...List.generate( + widget.attachments.length, + (int index) { + return Container( + margin: const EdgeInsets.only( + bottom: 15, + ), + constraints: const BoxConstraints( + maxHeight: 120, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + ), + child: _isImagesLoaded[index] + ? Image.file(File( + '${getIt.get().baseImageDir}/${widget.attachments[index]}', + )) + : Container( + width: 20, + height: 40, + padding: const EdgeInsets.symmetric( + vertical: 10), + child: + const CircularProgressIndicator( + color: kSecondaryColor, + strokeWidth: 3.0, + ), + ), + ); + }, ), ], ), diff --git a/lib/screens/message/components/message_input_box.dart b/lib/screens/message/components/message_input_box.dart index 0ba8335..d6a845a 100755 --- a/lib/screens/message/components/message_input_box.dart +++ b/lib/screens/message/components/message_input_box.dart @@ -1,14 +1,20 @@ import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:hive_flutter/hive_flutter.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:badges/badges.dart' as badges; import 'package:together_mobile/common/constants.dart'; import 'package:together_mobile/database/box_type.dart'; import 'package:together_mobile/models/init_get_it.dart'; import 'package:together_mobile/models/user_model.dart'; import 'package:together_mobile/models/websocket_model.dart'; +import 'package:together_mobile/utils/app_dir.dart'; +import 'package:together_mobile/utils/format_datetime.dart'; import 'input_icon_button.dart'; class MessageInputBox extends StatefulWidget { @@ -27,11 +33,14 @@ class MessageInputBox extends StatefulWidget { class _MessageInputBoxState extends State { final TextEditingController _controller = TextEditingController(); + final ImagePicker _picker = ImagePicker(); bool _hasMsg = false; late Box _chatBox; late Box _messageTBox; + List _imageFileList = []; + @override void initState() { super.initState(); @@ -85,9 +94,11 @@ class _MessageInputBoxState extends State { _hasMsg = true; }); } else { - setState(() { - _hasMsg = false; - }); + if (_imageFileList.isEmpty) { + setState(() { + _hasMsg = false; + }); + } } }, minLines: null, @@ -132,15 +143,26 @@ class _MessageInputBoxState extends State { children: [ InputIconButton( onPressed: () {}, - icon: const Icon(Icons.insert_photo), + icon: const Icon(Icons.mic), ), InputIconButton( onPressed: () {}, icon: const Icon(Icons.call), ), - InputIconButton( - onPressed: () {}, - icon: const Icon(Icons.mic), + badges.Badge( + showBadge: _imageFileList.isNotEmpty, + badgeStyle: const badges.BadgeStyle( + badgeColor: kSecondaryColor, + elevation: 12, + ), + badgeContent: Text(_imageFileList.length.toString()), + position: badges.BadgePosition.topEnd(top: 0, end: 0), + child: InputIconButton( + onPressed: () { + _pickImages(context); + }, + icon: const Icon(Icons.insert_photo), + ), ), InputIconButton( onPressed: () {}, @@ -157,13 +179,37 @@ class _MessageInputBoxState extends State { ); } - void _sendMsg() { + void _pickImages(BuildContext context) async { + try { + List pickedImages = await _picker.pickMultiImage(); + if (pickedImages.isNotEmpty) { + setState(() { + _imageFileList = pickedImages; + _hasMsg = true; + }); + } else { + setState(() { + _imageFileList = []; + }); + if (_controller.text.isEmpty) { + setState(() { + _hasMsg = false; + }); + } + } + } catch (e) { + print(e); + } + } + + void _sendMsg() async { if (!_hasMsg) { return; } DateTime now = DateTime.now(); late bool isShowTime; + List attachments = []; int messageCount = _messageTBox.length; if (messageCount == 0) { @@ -174,28 +220,25 @@ class _MessageInputBoxState extends State { var differenceInMinutes = now.difference(lastTime).inMinutes; isShowTime = differenceInMinutes > 8 ? true : false; } + + if (_imageFileList.isNotEmpty) { + String dirTime = formatDirTime(now); + for (var i = 0; i < _imageFileList.length; i++) { + attachments.add('$dirTime/${getRandomFilename()}'); + } + } + final msg = { 'event': 'one-to-one-chat', 'type': 'text/multipart', 'senderId': getIt.get().id, 'receiverId': widget.contactId, 'text': _controller.text, - 'attachments': [], + 'attachments': attachments, 'dateTime': now.toString(), 'isShowTime': isShowTime, }; - getIt.get().channel.sink.add(json.encode(msg)); - _controller.text = ''; - - var chatSetting = _chatBox.get(widget.contactId); - if (chatSetting == null) { - _chatBox.put( - widget.contactId, - ChatSetting(widget.contactId, false, true, false, now), - ); - } - _messageTBox.add( MessageT( msg['senderId']! as String, @@ -203,17 +246,50 @@ class _MessageInputBoxState extends State { msg['type']! as String, now, isShowTime, - [], + attachments, ), ); Future.delayed( const Duration(milliseconds: 50), () => widget.scrollController.animateTo( - widget.scrollController.position.maxScrollExtent, + 0, duration: const Duration(milliseconds: 500), curve: Curves.linear, ), ); + + getIt.get().channel.sink.add(json.encode(msg)); + + if (attachments.isNotEmpty) { + String baseImageDir = getIt.get().baseImageDir; + for (var i = 0; i < attachments.length; i++) { + Uint8List bytes = await _imageFileList[i].readAsBytes(); + File file = File('$baseImageDir/${attachments[i]}'); + file.createSync(recursive: true); + file.writeAsBytes(bytes); + getIt.get().channel.sink.add(json.encode( + { + 'event': 'chat-image', + 'receiverId': widget.contactId, + 'filename': attachments[i], + 'bytes': bytes, + }, + )); + } + } + _controller.text = ''; + setState(() { + _imageFileList = []; + _hasMsg = false; + }); + + var chatSetting = _chatBox.get(widget.contactId); + if (chatSetting == null) { + _chatBox.put( + widget.contactId, + ChatSetting(widget.contactId, false, true, false, now, 0), + ); + } } } diff --git a/lib/screens/message/message_screen.dart b/lib/screens/message/message_screen.dart index f54b734..ae4de53 100755 --- a/lib/screens/message/message_screen.dart +++ b/lib/screens/message/message_screen.dart @@ -23,16 +23,9 @@ class MessageScreen extends StatefulWidget { } class _MessageScreenState extends State { - ScrollController _controller = ScrollController(); - - @override - void initState() { - super.initState(); - Future.delayed( - const Duration(microseconds: 500), - () => _controller.jumpTo(_controller.position.maxScrollExtent), - ); - } + final ScrollController _controller = ScrollController(); + final Box _chatSettingBox = + Hive.box('chat_setting'); @override void dispose() { @@ -77,46 +70,64 @@ class _MessageScreenState extends State { body: Column( children: [ Expanded( - child: ValueListenableBuilder( - valueListenable: Hive.box('message_${widget.contactId}') - .listenable(), - builder: (context, value, _) { - Future.delayed( - const Duration( - milliseconds: 50, - ), - () => _controller.animateTo( - _controller.position.maxScrollExtent, - duration: const Duration(milliseconds: 500), - curve: Curves.linear, - ), - ); + child: Align( + alignment: Alignment.topCenter, + child: ValueListenableBuilder( + valueListenable: + Hive.box('message_${widget.contactId}') + .listenable(), + builder: (context, value, _) { + // Set unreadCount to 0 when at message screen + ChatSetting? chatSetting = + _chatSettingBox.get(widget.contactId); - return ListView.builder( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics(), - ), - controller: _controller, - itemCount: - Hive.box('message_${widget.contactId}').length, - itemBuilder: (context, index) { - Box messageTBox = - Hive.box('message_${widget.contactId}'); + // whethe it is a brand new chat + if (chatSetting != null) { + chatSetting.unreadCount = 0; + _chatSettingBox.put(widget.contactId, chatSetting); + } - MessageT messageT = messageTBox.getAt(index)!; + Future.delayed( + const Duration( + milliseconds: 100, + ), + () => _controller.animateTo( + 0, + duration: const Duration(milliseconds: 500), + curve: Curves.linear, + ), + ); - return MessageBubble( - contactId: widget.contactId, - senderId: messageT.senderId, - dateTime: formatMessageDateTime(messageT.dateTime), - isShowTime: messageT.isShowTime, - type: messageT.type, - text: messageT.text, - attachments: messageT.attachments, - ); - }, - ); - }, + return ListView.builder( + physics: const BouncingScrollPhysics( + parent: AlwaysScrollableScrollPhysics(), + ), + controller: _controller, + shrinkWrap: true, + reverse: true, + itemCount: Hive.box('message_${widget.contactId}') + .length, + itemBuilder: (context, index) { + Box messageTBox = + Hive.box('message_${widget.contactId}'); + int length = messageTBox.length; + int i = length - index - 1; + MessageT messageT = messageTBox.getAt(i)!; + + return MessageBubble( + key: ValueKey(i), + contactId: widget.contactId, + senderId: messageT.senderId, + dateTime: formatMessageDateTime(messageT.dateTime), + isShowTime: messageT.isShowTime, + type: messageT.type, + text: messageT.text, + attachments: messageT.attachments, + ); + }, + ); + }, + ), ), ), MessageInputBox( diff --git a/lib/utils/app_dir.dart b/lib/utils/app_dir.dart index 852875d..b7a5cd8 100644 --- a/lib/utils/app_dir.dart +++ b/lib/utils/app_dir.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:math'; import 'package:path_provider/path_provider.dart'; @@ -15,7 +16,22 @@ Future getAvatarDir() async { return '${appDirectory.path}/${getIt.get().id}/images/avatars'; } -Future getBoxPath() async { +Future getBoxDir() async { Directory appDirectory = await getApplicationDocumentsDirectory(); return '${appDirectory.path}/${getIt.get().id}/ChatBox'; } + +Future getChatImageDir() async { + Directory appDirectory = await getApplicationDocumentsDirectory(); + return '${appDirectory.path}/${getIt.get().id}/images'; +} + +String getRandomFilename() { + final random = Random(); + const availableChars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'; + String randomString = List.generate( + 11, (index) => availableChars[random.nextInt(availableChars.length)]) + .join(); + + return '$randomString.png'; +} diff --git a/lib/utils/format_datetime.dart b/lib/utils/format_datetime.dart index 560daeb..d4a3276 100644 --- a/lib/utils/format_datetime.dart +++ b/lib/utils/format_datetime.dart @@ -78,3 +78,12 @@ String formatMessageDateTime(DateTime dateTime) { return '$year-$month-$day $hour:$minute'; } } + +String formatDirTime(DateTime dateTime) { + int year = dateTime.year; + String month = + dateTime.month < 0 ? '0${dateTime.month}' : '${dateTime.month}'; + String day = dateTime.day < 0 ? '0${dateTime.day}' : '${dateTime.day}'; + + return '$year$month$day'; +} diff --git a/pubspec.lock b/pubspec.lock index 7d11184..2ca9cbc 100755 --- a/pubspec.lock +++ b/pubspec.lock @@ -6,7 +6,7 @@ packages: description: name: _fe_analyzer_shared sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "61.0.0" analyzer: @@ -14,7 +14,7 @@ packages: description: name: analyzer sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.13.0" archive: @@ -22,7 +22,7 @@ packages: description: name: archive sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.3.7" args: @@ -30,7 +30,7 @@ packages: description: name: args sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.2" async: @@ -38,7 +38,7 @@ packages: description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.11.0" badges: @@ -46,7 +46,7 @@ packages: description: name: badges sha256: "6e7f3ec561ec08f47f912cfe349d4a1707afdc8dda271e17b046aa6d42c89e77" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.1" boolean_selector: @@ -54,7 +54,7 @@ packages: description: name: boolean_selector sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" build: @@ -62,7 +62,7 @@ packages: description: name: build sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" build_config: @@ -70,7 +70,7 @@ packages: description: name: build_config sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" build_daemon: @@ -78,7 +78,7 @@ packages: description: name: build_daemon sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.0" build_resolvers: @@ -86,7 +86,7 @@ packages: description: name: build_resolvers sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.1" build_runner: @@ -94,7 +94,7 @@ packages: description: name: build_runner sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.6" build_runner_core: @@ -102,7 +102,7 @@ packages: description: name: build_runner_core sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.2.10" built_collection: @@ -110,7 +110,7 @@ packages: description: name: built_collection sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.1.1" built_value: @@ -118,7 +118,7 @@ packages: description: name: built_value sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "8.6.1" cached_network_image: @@ -126,7 +126,7 @@ packages: description: name: cached_network_image sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.3" cached_network_image_platform_interface: @@ -134,7 +134,7 @@ packages: description: name: cached_network_image_platform_interface sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" cached_network_image_web: @@ -142,7 +142,7 @@ packages: description: name: cached_network_image_web sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" characters: @@ -150,7 +150,7 @@ packages: description: name: characters sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" checked_yaml: @@ -158,7 +158,7 @@ packages: description: name: checked_yaml sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3" cherry_toast: @@ -166,7 +166,7 @@ packages: description: name: cherry_toast sha256: "5724acebea4544697994e47a180295657b48d7468224c4c6296f230706a9a4a5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.1" clock: @@ -174,7 +174,7 @@ packages: description: name: clock sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" code_builder: @@ -182,7 +182,7 @@ packages: description: name: code_builder sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.5.0" collection: @@ -190,7 +190,7 @@ packages: description: name: collection sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.17.1" colorfilter_generator: @@ -198,7 +198,7 @@ packages: description: name: colorfilter_generator sha256: ccc2995e440b1d828d55d99150e7cad64624f3cb4a1e235000de3f93cf10d35c - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.0.8" convert: @@ -206,7 +206,7 @@ packages: description: name: convert sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.1" cross_file: @@ -214,7 +214,7 @@ packages: description: name: cross_file sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.3+4" crypto: @@ -222,7 +222,7 @@ packages: description: name: crypto sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.3" csslib: @@ -230,7 +230,7 @@ packages: description: name: csslib sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" cupertino_icons: @@ -238,7 +238,7 @@ packages: description: name: cupertino_icons sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.5" dart_style: @@ -246,7 +246,7 @@ packages: description: name: dart_style sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.2" dbus: @@ -254,7 +254,7 @@ packages: description: name: dbus sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.8" device_info_plus: @@ -262,7 +262,7 @@ packages: description: name: device_info_plus sha256: "86add5ef97215562d2e090535b0a16f197902b10c369c558a100e74ea06e8659" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "9.0.3" device_info_plus_platform_interface: @@ -270,7 +270,7 @@ packages: description: name: device_info_plus_platform_interface sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.0.0" dio: @@ -278,7 +278,7 @@ packages: description: name: dio sha256: ce75a1b40947fea0a0e16ce73337122a86762e38b982e1ccb909daa3b9bc4197 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.3.2" extended_image: @@ -286,7 +286,7 @@ packages: description: name: extended_image sha256: e77d18f956649ba6e5ecebd0cb68542120886336a75ee673788145bd4c3f0767 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "8.0.2" extended_image_library: @@ -294,7 +294,7 @@ packages: description: name: extended_image_library sha256: bb8d08c504ebc73d476ec1c99451a61f12e95538869e734fc4f55a3a2d5c98ec - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.5.3" fake_async: @@ -302,31 +302,31 @@ packages: description: name: fake_async sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.1" fast_rsa: dependency: "direct main" description: name: fast_rsa - sha256: "79bc5398e69d226497d926e85fab944e5d07bb8a9dd747129cf7be33009e386d" - url: "https://pub.dev" + sha256: "2619f8869c0245919fc8f3695f786bf7a7e75e4bb87a7f13ad3b3223fa35bdf0" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.5.7" + version: "3.6.1" ffi: dependency: transitive description: name: ffi - sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 - url: "https://pub.dev" + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.2" + version: "2.1.0" file: dependency: transitive description: name: file sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.4" file_selector_linux: @@ -334,7 +334,7 @@ packages: description: name: file_selector_linux sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.2" file_selector_macos: @@ -342,7 +342,7 @@ packages: description: name: file_selector_macos sha256: "4ada532862917bf16e3adb3891fe3a5917a58bae03293e497082203a80909412" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.3+1" file_selector_platform_interface: @@ -350,7 +350,7 @@ packages: description: name: file_selector_platform_interface sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.6.0" file_selector_windows: @@ -358,7 +358,7 @@ packages: description: name: file_selector_windows sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.3" fixnum: @@ -366,7 +366,7 @@ packages: description: name: fixnum sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" flat_buffers: @@ -374,7 +374,7 @@ packages: description: name: flat_buffers sha256: "23e2ced0d8e8ecdffbd9f267f49a668c74438393b9acaeac1c724123e3764263" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.5" flutter: @@ -387,7 +387,7 @@ packages: description: name: flutter_blurhash sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.0" flutter_cache_manager: @@ -395,7 +395,7 @@ packages: description: name: flutter_cache_manager sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.3.1" flutter_colorpicker: @@ -403,7 +403,7 @@ packages: description: name: flutter_colorpicker sha256: "458a6ed8ea480eb16ff892aedb4b7092b2804affd7e046591fb03127e8d8ef8b" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.3" flutter_image_compress: @@ -411,7 +411,7 @@ packages: description: name: flutter_image_compress sha256: "2725cce5c58fdeaf1db8f4203688228bb67e3523a66305ccaa6f99071beb6dc2" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.4" flutter_image_compress_common: @@ -419,7 +419,7 @@ packages: description: name: flutter_image_compress_common sha256: "8e7299afe109dc4b97fda34bf0f4967cc1fc10bc8050c374d449cab262d095b3" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" flutter_image_compress_platform_interface: @@ -427,7 +427,7 @@ packages: description: name: flutter_image_compress_platform_interface sha256: "3c7e86da7540b1adfa919b461885a41a018d4a26544d0fcbeaa769f6542e603d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" flutter_image_compress_web: @@ -435,7 +435,7 @@ packages: description: name: flutter_image_compress_web sha256: e879189dc7f246dcf8f06c07ee849231341508bf51e8ed7d5dcbe778ddde0e81 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.1.3+1" flutter_lints: @@ -443,7 +443,7 @@ packages: description: name: flutter_lints sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.2" flutter_local_notifications: @@ -451,7 +451,7 @@ packages: description: name: flutter_local_notifications sha256: aea96b3b78556c97607d9bee59fcec515bc3ec1b6e905f14d72906ae055033fa - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "14.1.2" flutter_local_notifications_linux: @@ -459,7 +459,7 @@ packages: description: name: flutter_local_notifications_linux sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.0+1" flutter_local_notifications_platform_interface: @@ -467,7 +467,7 @@ packages: description: name: flutter_local_notifications_platform_interface sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.0.0+1" flutter_pickers: @@ -475,7 +475,7 @@ packages: description: name: flutter_pickers sha256: f38a9d9229afed75f76bae64e628b78b9c20194873e3c141783523cf21ac8a95 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.9" flutter_plugin_android_lifecycle: @@ -483,7 +483,7 @@ packages: description: name: flutter_plugin_android_lifecycle sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.15" flutter_secure_storage: @@ -491,7 +491,7 @@ packages: description: name: flutter_secure_storage sha256: "98352186ee7ad3639ccc77ad7924b773ff6883076ab952437d20f18a61f0a7c5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "8.0.0" flutter_secure_storage_linux: @@ -499,7 +499,7 @@ packages: description: name: flutter_secure_storage_linux sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.3" flutter_secure_storage_macos: @@ -507,7 +507,7 @@ packages: description: name: flutter_secure_storage_macos sha256: "083add01847fc1c80a07a08e1ed6927e9acd9618a35e330239d4422cd2a58c50" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" flutter_secure_storage_platform_interface: @@ -515,7 +515,7 @@ packages: description: name: flutter_secure_storage_platform_interface sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" flutter_secure_storage_web: @@ -523,7 +523,7 @@ packages: description: name: flutter_secure_storage_web sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" flutter_secure_storage_windows: @@ -531,7 +531,7 @@ packages: description: name: flutter_secure_storage_windows sha256: fc2910ec9b28d60598216c29ea763b3a96c401f0ce1d13cdf69ccb0e5c93c3ee - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" flutter_slidable: @@ -539,7 +539,7 @@ packages: description: name: flutter_slidable sha256: cc4231579e3eae41ae166660df717f4bad1359c87f4a4322ad8ba1befeb3d2be - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" flutter_test: @@ -552,7 +552,7 @@ packages: description: name: flutter_timezone sha256: "4508018aba499c837f723e2e718259eb677410490638b7ea669b11113d083e68" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.7" flutter_web_plugins: @@ -565,7 +565,7 @@ packages: description: name: font_awesome_flutter sha256: "5fb789145cae1f4c3245c58b3f8fb287d055c26323879eab57a7bf0cfd1e45f3" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "10.5.0" frontend_server_client: @@ -573,7 +573,7 @@ packages: description: name: frontend_server_client sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.0" functional_listener: @@ -581,7 +581,7 @@ packages: description: name: functional_listener sha256: "026d1bd4f66367f11d9ec9f1f1ddb42b89e4484b356972c76d983266cf82f33f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.1" get_it: @@ -589,7 +589,7 @@ packages: description: name: get_it sha256: "529de303c739fca98cd7ece5fca500d8ff89649f1bb4b4e94fb20954abcd7468" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.6.0" get_it_mixin: @@ -597,7 +597,7 @@ packages: description: name: get_it_mixin sha256: d59fe7e49e258ddf9f10580b50cce5c129d3f2f6a340b684847615128c641261 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.2.0" glob: @@ -605,7 +605,7 @@ packages: description: name: glob sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" go_router: @@ -613,7 +613,7 @@ packages: description: name: go_router sha256: "00d1b67d6e9fa443331da229084dd3eb04407f5a2dff22940bd7bba6af5722c3" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.1.1" google_fonts: @@ -621,7 +621,7 @@ packages: description: name: google_fonts sha256: "2776c66b3e97c6cdd58d1bd3281548b074b64f1fd5c8f82391f7456e38849567" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.5" graphs: @@ -629,7 +629,7 @@ packages: description: name: graphs sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.1" hand_signature: @@ -637,7 +637,7 @@ packages: description: name: hand_signature sha256: "69cc5a978a5a15dfc1fabb01c097efcf91e9af2006475e48bb8f2560db368a97" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" hive: @@ -645,7 +645,7 @@ packages: description: name: hive sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.3" hive_flutter: @@ -653,7 +653,7 @@ packages: description: name: hive_flutter sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" hive_generator: @@ -661,7 +661,7 @@ packages: description: name: hive_generator sha256: "65998cc4d2cd9680a3d9709d893d2f6bb15e6c1f92626c3f1fa650b4b3281521" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" html: @@ -669,7 +669,7 @@ packages: description: name: html sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.15.4" http: @@ -677,7 +677,7 @@ packages: description: name: http sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" http_client_helper: @@ -685,7 +685,7 @@ packages: description: name: http_client_helper sha256: "8a9127650734da86b5c73760de2b404494c968a3fd55602045ffec789dac3cb1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" http_multi_server: @@ -693,7 +693,7 @@ packages: description: name: http_multi_server sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.1" http_parser: @@ -701,7 +701,7 @@ packages: description: name: http_parser sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.2" image: @@ -709,7 +709,7 @@ packages: description: name: image sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.17" image_editor: @@ -717,7 +717,7 @@ packages: description: name: image_editor sha256: "9877a057b0cd2fafcd9a3dce5279948bd850d53ce76231a83c9678a2c9f186e9" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" image_editor_common: @@ -725,7 +725,7 @@ packages: description: name: image_editor_common sha256: "07fc9bcc16918a8230e132b9d9a9f66bb1cef3ac99f5e2939cf2ad7a6775b511" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" image_editor_platform_interface: @@ -733,7 +733,7 @@ packages: description: name: image_editor_platform_interface sha256: ee01ec5e228e10c40f96d7f822c176d4140c15b6706e4a701866ee0cdd1c2b72 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" image_editor_plus: @@ -741,7 +741,7 @@ packages: description: name: image_editor_plus sha256: "1a79038294402ac058488f6f619e62fc78ed857393512912d896da778f5f7e8d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.5" image_picker: @@ -749,7 +749,7 @@ packages: description: name: image_picker sha256: "841837258e0b42c80946c43443054fc726f5e8aa84a97f363eb9ef0d45b33c14" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" image_picker_android: @@ -757,7 +757,7 @@ packages: description: name: image_picker_android sha256: "8179b54039b50eee561676232304f487602e2950ffb3e8995ed9034d6505ca34" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.7+4" image_picker_for_web: @@ -765,7 +765,7 @@ packages: description: name: image_picker_for_web sha256: "8b6c160cdbe572199103a091c783685b236110e4a0fd7a4947f32ff5b7da8765" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.0" image_picker_ios: @@ -773,7 +773,7 @@ packages: description: name: image_picker_ios sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.8" image_picker_linux: @@ -781,7 +781,7 @@ packages: description: name: image_picker_linux sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.1" image_picker_macos: @@ -789,7 +789,7 @@ packages: description: name: image_picker_macos sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.1" image_picker_platform_interface: @@ -797,7 +797,7 @@ packages: description: name: image_picker_platform_interface sha256: c1134543ae2187e85299996d21c526b2f403854994026d575ae4cf30d7bb2a32 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.9.0" image_picker_windows: @@ -805,7 +805,7 @@ packages: description: name: image_picker_windows sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.1" io: @@ -813,7 +813,7 @@ packages: description: name: io sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" js: @@ -821,7 +821,7 @@ packages: description: name: js sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.7" json_annotation: @@ -829,7 +829,7 @@ packages: description: name: json_annotation sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.8.1" lints: @@ -837,7 +837,7 @@ packages: description: name: lints sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" logging: @@ -845,7 +845,7 @@ packages: description: name: logging sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" matcher: @@ -853,7 +853,7 @@ packages: description: name: matcher sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.12.15" material_color_utilities: @@ -861,7 +861,7 @@ packages: description: name: material_color_utilities sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.0" matrix2d: @@ -869,7 +869,7 @@ packages: description: name: matrix2d sha256: "188718dd3bc2a31e372cfd0791b0f77f4f13ea76164147342cc378d9132949e7" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" meta: @@ -877,7 +877,7 @@ packages: description: name: meta sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.9.1" mime: @@ -885,7 +885,7 @@ packages: description: name: mime sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" octo_image: @@ -893,7 +893,7 @@ packages: description: name: octo_image sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" package_config: @@ -901,7 +901,7 @@ packages: description: name: package_config sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" path: @@ -909,23 +909,23 @@ packages: description: name: path sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.8.3" path_provider: dependency: "direct main" description: name: path_provider - sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" - url: "https://pub.dev" + sha256: "909b84830485dbcd0308edf6f7368bc8fd76afa26a270420f34cabea2a6467a0" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.15" + version: "2.1.0" path_provider_android: dependency: transitive description: name: path_provider_android sha256: "5d44fc3314d969b84816b569070d7ace0f1dea04bd94a83f74c4829615d22ad8" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" path_provider_foundation: @@ -933,7 +933,7 @@ packages: description: name: path_provider_foundation sha256: "1b744d3d774e5a879bb76d6cd1ecee2ba2c6960c03b1020cd35212f6aa267ac5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" path_provider_linux: @@ -941,7 +941,7 @@ packages: description: name: path_provider_linux sha256: ba2b77f0c52a33db09fc8caf85b12df691bf28d983e84cf87ff6d693cfa007b3 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" path_provider_platform_interface: @@ -949,7 +949,7 @@ packages: description: name: path_provider_platform_interface sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" path_provider_windows: @@ -957,7 +957,7 @@ packages: description: name: path_provider_windows sha256: ee0e0d164516b90ae1f970bdf29f726f1aa730d7cfc449ecc74c495378b705da - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" petitparser: @@ -965,7 +965,7 @@ packages: description: name: petitparser sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.4.0" photo_view: @@ -973,7 +973,7 @@ packages: description: name: photo_view sha256: "8036802a00bae2a78fc197af8a158e3e2f7b500561ed23b4c458107685e645bb" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.14.0" platform: @@ -981,7 +981,7 @@ packages: description: name: platform sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" plugin_platform_interface: @@ -989,7 +989,7 @@ packages: description: name: plugin_platform_interface sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.5" pointycastle: @@ -997,7 +997,7 @@ packages: description: name: pointycastle sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.7.3" pool: @@ -1005,7 +1005,7 @@ packages: description: name: pool sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.5.1" pub_semver: @@ -1013,7 +1013,7 @@ packages: description: name: pub_semver sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.4" pubspec_parse: @@ -1021,7 +1021,7 @@ packages: description: name: pubspec_parse sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.3" reorderables: @@ -1029,7 +1029,7 @@ packages: description: name: reorderables sha256: "004a886e4878df1ee27321831c838bc1c976311f4ca6a74ce7d561e506540a77" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.0" rxdart: @@ -1037,7 +1037,7 @@ packages: description: name: rxdart sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.27.7" screenshot: @@ -1045,7 +1045,7 @@ packages: description: name: screenshot sha256: "455284ff1f5b911d94a43c25e1385485cf6b4f288293eba68f15dad711c7b81c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" shared_preferences: @@ -1053,7 +1053,7 @@ packages: description: name: shared_preferences sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" shared_preferences_android: @@ -1061,23 +1061,23 @@ packages: description: name: shared_preferences_android sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 - url: "https://pub.dev" + sha256: d29753996d8eb8f7619a1f13df6ce65e34bc107bef6330739ed76f18b22310ef + url: "https://pub.flutter-io.cn" source: hosted - version: "2.3.2" + version: "2.3.3" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" shared_preferences_platform_interface: @@ -1085,7 +1085,7 @@ packages: description: name: shared_preferences_platform_interface sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" shared_preferences_web: @@ -1093,7 +1093,7 @@ packages: description: name: shared_preferences_web sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" shared_preferences_windows: @@ -1101,7 +1101,7 @@ packages: description: name: shared_preferences_windows sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" shelf: @@ -1109,7 +1109,7 @@ packages: description: name: shelf sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.1" shelf_web_socket: @@ -1117,7 +1117,7 @@ packages: description: name: shelf_web_socket sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" sky_engine: @@ -1130,7 +1130,7 @@ packages: description: name: source_gen sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" source_helper: @@ -1138,7 +1138,7 @@ packages: description: name: source_helper sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.4" source_span: @@ -1146,7 +1146,7 @@ packages: description: name: source_span sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.9.1" sqflite: @@ -1154,7 +1154,7 @@ packages: description: name: sqflite sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" sqflite_common: @@ -1162,7 +1162,7 @@ packages: description: name: sqflite_common sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.5.0" stack_trace: @@ -1170,7 +1170,7 @@ packages: description: name: stack_trace sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.11.0" stream_channel: @@ -1178,7 +1178,7 @@ packages: description: name: stream_channel sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" stream_transform: @@ -1186,7 +1186,7 @@ packages: description: name: stream_transform sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" string_scanner: @@ -1194,7 +1194,7 @@ packages: description: name: string_scanner sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" synchronized: @@ -1202,7 +1202,7 @@ packages: description: name: synchronized sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" term_glyph: @@ -1210,7 +1210,7 @@ packages: description: name: term_glyph sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.1" test_api: @@ -1218,7 +1218,7 @@ packages: description: name: test_api sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.5.1" timezone: @@ -1226,7 +1226,7 @@ packages: description: name: timezone sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.2" timing: @@ -1234,7 +1234,7 @@ packages: description: name: timing sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" typed_data: @@ -1242,7 +1242,7 @@ packages: description: name: typed_data sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.2" uuid: @@ -1250,7 +1250,7 @@ packages: description: name: uuid sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.7" vector_math: @@ -1258,7 +1258,7 @@ packages: description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.4" video_player: @@ -1266,7 +1266,7 @@ packages: description: name: video_player sha256: "3fd106c74da32f336dc7feb65021da9b0207cb3124392935f1552834f7cce822" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.7.0" video_player_android: @@ -1274,7 +1274,7 @@ packages: description: name: video_player_android sha256: f338a5a396c845f4632959511cad3542cdf3167e1b2a1a948ef07f7123c03608 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.9" video_player_avfoundation: @@ -1282,7 +1282,7 @@ packages: description: name: video_player_avfoundation sha256: f5f5b7fe8c865be8a57fe80c2dca130772e1db775b7af4e5c5aa1905069cfc6c - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.9" video_player_platform_interface: @@ -1290,7 +1290,7 @@ packages: description: name: video_player_platform_interface sha256: "1ca9acd7a0fb15fb1a990cb554e6f004465c6f37c99d2285766f08a4b2802988" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.2.0" video_player_web: @@ -1298,7 +1298,7 @@ packages: description: name: video_player_web sha256: "44ce41424d104dfb7cf6982cc6b84af2b007a24d126406025bf40de5d481c74c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.16" watcher: @@ -1306,7 +1306,7 @@ packages: description: name: watcher sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" web_socket_channel: @@ -1314,7 +1314,7 @@ packages: description: name: web_socket_channel sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.0" win32: @@ -1322,7 +1322,7 @@ packages: description: name: win32 sha256: f2add6fa510d3ae152903412227bda57d0d5a8da61d2c39c1fb022c9429a41c0 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.0.6" win32_registry: @@ -1330,23 +1330,23 @@ packages: description: name: win32_registry sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff - url: "https://pub.dev" + sha256: f0c26453a2d47aa4c2570c6a033246a3fc62da2fe23c7ffdd0a7495086dc0247 + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.1" + version: "1.0.2" xml: dependency: transitive description: name: xml sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.3.0" yaml: @@ -1354,7 +1354,7 @@ packages: description: name: yaml sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.2" sdks: