diff --git a/lib/database/box_type.dart b/lib/database/box_type.dart index 65bd9ea..46bbf6a 100644 --- a/lib/database/box_type.dart +++ b/lib/database/box_type.dart @@ -16,7 +16,16 @@ class ChatSetting { @HiveField(3, defaultValue: false) bool isHideMsg; - ChatSetting(this.contactId, this.isTop, this.isOpen, this.isHideMsg); + @HiveField(4) + DateTime? latestDateTime; + + ChatSetting( + this.contactId, + this.isTop, + this.isOpen, + this.isHideMsg, + this.latestDateTime, + ); } @HiveType(typeId: 1) diff --git a/lib/database/box_type.g.dart b/lib/database/box_type.g.dart index f98a531..e35decf 100644 --- a/lib/database/box_type.g.dart +++ b/lib/database/box_type.g.dart @@ -21,13 +21,14 @@ 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?, ); } @override void write(BinaryWriter writer, ChatSetting obj) { writer - ..writeByte(4) + ..writeByte(5) ..writeByte(0) ..write(obj.contactId) ..writeByte(1) @@ -35,7 +36,9 @@ class ChatSettingAdapter extends TypeAdapter { ..writeByte(2) ..write(obj.isOpen) ..writeByte(3) - ..write(obj.isHideMsg); + ..write(obj.isHideMsg) + ..writeByte(4) + ..write(obj.latestDateTime); } @override diff --git a/lib/database/init_database.dart b/lib/database/hive_database.dart similarity index 95% rename from lib/database/init_database.dart rename to lib/database/hive_database.dart index efab0cd..68fde70 100644 --- a/lib/database/init_database.dart +++ b/lib/database/hive_database.dart @@ -15,7 +15,7 @@ void initDatabase() async { Box chatSettingBox = await Hive.openBox('chat_setting'); - + final openedChats = chatSettingBox.values.where((element) => element.isOpen); for (var chatBox in openedChats) { @@ -53,11 +53,12 @@ void openNewMessageBox(String contactId) async { final encryptionKeyUint8List = await getEncryptKey(); var chatSettingBox = Hive.box('chat_setting'); - chatSettingBox.add(ChatSetting(contactId, false, true, false)); + chatSettingBox + .add(ChatSetting(contactId, false, true, false, DateTime.now())); await Hive.openLazyBox( 'message_$contactId', encryptionCipher: HiveAesCipher(encryptionKeyUint8List), compactionStrategy: (entries, deletedEntries) => entries > 200, ); -} +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 1a9bcbb..0f8b993 100755 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:together_mobile/common/theme.dart'; -import 'package:together_mobile/database/init_database.dart'; +import 'package:together_mobile/database/hive_database.dart'; import 'package:together_mobile/router/router.dart'; import 'package:together_mobile/models/init_get_it.dart'; diff --git a/lib/models/apply_list_model.dart b/lib/models/apply_list_model.dart index 41db135..c3a3f93 100644 --- a/lib/models/apply_list_model.dart +++ b/lib/models/apply_list_model.dart @@ -11,7 +11,6 @@ class Apply { applicant = json['applicant']; recipient = json['recipient']; hello = json['hello']; - createdAt = json['createdAt']; groupChatId = json['groupChatId']; setting = json['setting']; } @@ -33,13 +32,22 @@ class ApplyList extends ChangeNotifier { void removeAt(int index) { applyList.removeAt(index); + applicantIds.removeAt(index); count--; + notifyListeners(); } void addJson(Map json) { Apply apply = Apply.fromJson(json); + int index = applicantIds.indexOf(json['applicant']); + if (index != -1) { + applyList.removeAt(index); + count--; + } applyList.add(apply); + applicantIds.add(json['applicant']); count++; + notifyListeners(); } void clean() { diff --git a/lib/models/contact_model.dart b/lib/models/contact_model.dart index b68101c..3c506dd 100644 --- a/lib/models/contact_model.dart +++ b/lib/models/contact_model.dart @@ -53,7 +53,7 @@ class Contact extends ChangeNotifier { } void addFriend(String friendId, Map friendSetting) { - friends[friendId] = FriendSetting.fromJson(friendSetting); + friends.addAll({friendId: FriendSetting.fromJson(friendSetting)}); notifyListeners(); } @@ -121,7 +121,13 @@ class ContactAccountProfile extends ChangeNotifier { return friendId.isNotEmpty ? (true, friendId) : (false, ''); } + void addAccountProfile(String friendId, Map json) { + friends.addAll({friendId: FriendAccountProfile.fromJson(json)}); + notifyListeners(); + } + void removeFriend(String friendId) { friends.remove(friendId); + notifyListeners(); } } diff --git a/lib/models/user_model.dart b/lib/models/user_model.dart index 60e57b9..88971f7 100755 --- a/lib/models/user_model.dart +++ b/lib/models/user_model.dart @@ -13,6 +13,14 @@ class UserAccount extends ChangeNotifier { email = data['email']!; } + Map toMap() { + return { + 'id': id, + 'username': username, + 'email': email, + }; + } + void updateUsername(String newUsername) { username = newUsername; } @@ -51,6 +59,18 @@ class UserProfile extends ChangeNotifier { isInitialised = true; } + Map toMap() { + return { + 'nickname': nickname, + 'gender': gender, + 'birthday': birthday, + 'location': location, + 'status': status, + 'sign': sign, + 'avatar': avatar, + }; + } + void updateBasic(Map newBasic) { nickname = newBasic['nickname']!; location = newBasic['location']!; diff --git a/lib/models/websocket_model.dart b/lib/models/websocket_model.dart index 852c99f..c9e5f71 100644 --- a/lib/models/websocket_model.dart +++ b/lib/models/websocket_model.dart @@ -4,6 +4,9 @@ import 'dart:convert'; 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:web_socket_channel/web_socket_channel.dart'; import 'package:web_socket_channel/status.dart' as status; @@ -42,6 +45,12 @@ class WebSocketManager extends ChangeNotifier { switch (data['event']) { case 'one-to-one-chat': receiveFriendMsg(data); + case 'apply-friend': + receiveApplyFriend(data); + case 'friend-added': + receiveFriendAdded(data); + case 'friend-deleted': + receiveFriendDeleted(data); } } @@ -130,24 +139,58 @@ void receiveFriendMsg(Map msg) async { } Box chatSettingBox = Hive.box('chat_setting'); - ChatSetting? chatSetting = chatSettingBox.get(senderId); + DateTime dateTime = DateTime.parse(msg['dateTime'] as String); if (chatSetting == null) { - chatSettingBox.put(senderId, ChatSetting(senderId, false, true, false)); + chatSettingBox.put( + senderId, + ChatSetting( + senderId, + false, + true, + false, + dateTime, + ), + ); } else { chatSetting.isOpen = true; + chatSetting.latestDateTime = dateTime; chatSettingBox.put(senderId, chatSetting); } + List attachments = List.from(msg['attachments']); + messageTBox.add( MessageT( senderId, msg['text'], msg['type'], - DateTime.parse(msg['dateTime']), + DateTime.parse(msg['dateTime'] as String), msg['isShowTime'], - msg['attachments'], + attachments, ), ); } + +void receiveApplyFriend(Map msg) { + getIt.get().addJson(msg); +} + +void receiveFriendAdded(Map msg) { + print('=================收到了申请好友通过事件=================='); + print(msg); + print('======================================='); + getIt.get().addFriend(msg['friendId'], msg['setting']); + getIt + .get() + .addAccountProfile(msg['friendId'], msg['accountProfile']); +} + +void receiveFriendDeleted(Map msg) { + print('=================收到了解除好友事件=================='); + print(msg); + print('======================================='); + getIt.get().removeFriend(msg['friendId']); + getIt.get().removeFriend(msg['friendId']); +} diff --git a/lib/screens/chat/chat_screen.dart b/lib/screens/chat/chat_screen.dart index 9fb0a84..b3b5e88 100755 --- a/lib/screens/chat/chat_screen.dart +++ b/lib/screens/chat/chat_screen.dart @@ -6,6 +6,7 @@ import 'package:hive_flutter/hive_flutter.dart'; import 'package:together_mobile/database/box_type.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 'components/chat_tile.dart'; import 'package:together_mobile/models/contact_model.dart'; import 'package:together_mobile/models/apply_list_model.dart'; @@ -15,7 +16,7 @@ import 'package:together_mobile/request/contact.dart'; import 'package:together_mobile/models/user_model.dart'; import 'package:together_mobile/models/init_get_it.dart'; import 'package:together_mobile/request/user_profile.dart'; -import 'package:together_mobile/database/init_database.dart'; +import 'package:together_mobile/database/hive_database.dart'; class ChatScreen extends StatefulWidget { const ChatScreen({super.key}); @@ -139,14 +140,41 @@ class _ChatScreenState extends State { itemCount: openedChat.length, itemBuilder: (BuildContext context, int index) { String contactId = openedChat[index].contactId; + String showedTime = formatTileDateTime( + openedChat[index].latestDateTime!, + ); + return ValueListenableBuilder( valueListenable: Hive.box('message_$contactId') .listenable(), - builder: (context, value, _) { - return ChatTile( - contactId: contactId, - ); + builder: (context, messageTBox, _) { + int length = messageTBox.length; + if (length > 0) { + MessageT messageT = + messageTBox.getAt(length - 1)!; + return ChatTile( + index: index, + contactId: contactId, + senderId: messageT.senderId, + type: messageT.type, + text: messageT.text, + attachments: messageT.attachments, + dateTime: showedTime, + isShowTime: messageT.isShowTime, + ); + } else { + return ChatTile( + index: index, + contactId: contactId, + senderId: '', + type: '', + text: '', + attachments: const [], + dateTime: showedTime, + isShowTime: false, + ); + } }, ); }, diff --git a/lib/screens/chat/components/chat_tile copy.dart b/lib/screens/chat/components/chat_tile copy.dart deleted file mode 100755 index 387221c..0000000 --- a/lib/screens/chat/components/chat_tile copy.dart +++ /dev/null @@ -1,138 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:flutter_slidable/flutter_slidable.dart'; -import 'package:go_router/go_router.dart'; -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:hive_flutter/hive_flutter.dart'; - -import 'package:together_mobile/common/constants.dart'; -import 'package:together_mobile/database/box_type.dart'; -import 'package:together_mobile/models/contact_model.dart'; -import 'package:together_mobile/models/init_get_it.dart'; -import 'package:together_mobile/request/server.dart'; -import 'badge_avatar.dart'; - -class ChatTile extends StatefulWidget { - const ChatTile({ - super.key, - required this.contactId, - }); - - final String contactId; - - @override - State createState() => _ChatTileState(); -} - -class _ChatTileState extends State { - Future> _getLatestMsg() async { - LazyBox messageTBox = - Hive.lazyBox('message_${widget.contactId}'); - int messageCount = messageTBox.length; - - if (messageCount > 0) { - MessageT messageT = (await messageTBox.getAt(messageCount - 1))!; - return Future(() => { - 'text': messageT.text, - 'dateTime': messageT.dateTime, - 'attachments': messageT.attachments, - }); - } else { - return Future(() => {}); - } - } - - @override - Widget build(BuildContext context) { - return Slidable( - key: const ValueKey(0), - endActionPane: ActionPane( - motion: const BehindMotion(), - dismissible: DismissiblePane( - onDismissed: () {}, - ), - children: [ - SlidableAction( - onPressed: (BuildContext context) {}, - backgroundColor: kSecondaryColor, - foregroundColor: kContentColorDark, - icon: Icons.arrow_upward_rounded, - label: '置顶', - ), - SlidableAction( - onPressed: (BuildContext context) {}, - foregroundColor: kContentColorDark, - backgroundColor: kPrimaryColor, - icon: Icons.remove_red_eye, - label: '隐藏信息', - flex: 1, - ), - ], - ), - child: ListTile( - // Must have a onTap callback or Ink won't work - onTap: () => context.goNamed( - 'Message', - queryParameters: {'contactId': widget.contactId}, - ), - leading: getIt - .get() - .friends[widget.contactId]! - .avatar - .isEmpty - ? const BadgeAvatar( - count: 99, - radius: 25, - backgroundImage: AssetImage('assets/images/user_3.png'), - ) - : BadgeAvatar( - count: 99, - radius: 25, - backgroundImage: CachedNetworkImageProvider( - '$avatarsUrl/${getIt.get().friends[widget.contactId]!.avatar}', - ), - ), - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - // friend remark or nickname - child: Text( - getIt - .get() - .friends[widget.contactId]! - .friendRemark - .isEmpty - ? getIt - .get() - .friends[widget.contactId]! - .nickname - : getIt - .get() - .friends[widget.contactId]! - .friendRemark, - overflow: TextOverflow.ellipsis, - ), - ), - // latest msg datetime - Text('10:13'), - ], - ), - subtitle: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - 'How are you today, you look not very well, whats happended to you', - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: Theme.of(context).textTheme.displayLarge?.color), - ), - ), - // Text('10:13'), - ], - ), - ), - ); - } -} diff --git a/lib/screens/chat/components/chat_tile.dart b/lib/screens/chat/components/chat_tile.dart index bb4824a..d8c5667 100755 --- a/lib/screens/chat/components/chat_tile.dart +++ b/lib/screens/chat/components/chat_tile.dart @@ -10,53 +10,31 @@ import 'package:together_mobile/database/box_type.dart'; import 'package:together_mobile/models/contact_model.dart'; import 'package:together_mobile/models/init_get_it.dart'; import 'package:together_mobile/request/server.dart'; -import 'package:together_mobile/utils/format_datetime.dart'; import 'badge_avatar.dart'; class ChatTile extends StatefulWidget { const ChatTile({ super.key, + required this.index, required this.contactId, + required this.senderId, + required this.type, + required this.text, + required this.attachments, + required this.dateTime, + required this.isShowTime, }); - final String contactId; + final int index; + final String contactId, senderId, type, text, dateTime; + final List attachments; + final bool isShowTime; @override State createState() => _ChatTileState(); } class _ChatTileState extends State { - late Map _latestMsg; - - @override - void initState() { - super.initState(); - Box messageTBox = - Hive.box('message_${widget.contactId}'); - int length = messageTBox.length; - - if (length > 0) { - MessageT messageT = messageTBox.getAt(length - 1)!; - _latestMsg = { - 'senderId': messageT.senderId, - 'type': messageT.type, - 'text': messageT.text, - 'attachments': messageT.attachments, - 'dateTime': formatMessageDateTime(messageT.dateTime), - 'isShowTime': messageT.isShowTime, - }; - } else { - _latestMsg = { - 'senderId': '', - 'type': '', - 'text': '', - 'attachments': [], - 'dateTime': [], - 'isShowTime': false, - }; - } - } - @override Widget build(BuildContext context) { return Slidable( @@ -64,7 +42,12 @@ class _ChatTileState extends State { endActionPane: ActionPane( motion: const BehindMotion(), dismissible: DismissiblePane( - onDismissed: () {}, + onDismissed: () { + Box chatSettingBox = Hive.box('chat_setting'); + ChatSetting chatSetting = chatSettingBox.getAt(widget.index)!; + chatSetting.isOpen = false; + chatSettingBox.put(widget.contactId, chatSetting); + }, ), children: [ SlidableAction( @@ -131,7 +114,7 @@ class _ChatTileState extends State { ), // latest msg datetime Text( - _latestMsg['dateTime']!, + widget.dateTime, style: const TextStyle( fontSize: 14, color: kUnActivatedColor, @@ -144,7 +127,7 @@ class _ChatTileState extends State { children: [ Expanded( child: Text( - _latestMsg['text'], + widget.text, overflow: TextOverflow.ellipsis, style: const TextStyle( color: kUnActivatedColor, @@ -152,7 +135,6 @@ class _ChatTileState extends State { ), ), ), - // Text('10:13'), ], ), ), diff --git a/lib/screens/contact/components/friend_group.dart b/lib/screens/contact/components/friend_group.dart index ee74c87..94d3082 100755 --- a/lib/screens/contact/components/friend_group.dart +++ b/lib/screens/contact/components/friend_group.dart @@ -5,7 +5,7 @@ import 'package:together_mobile/models/init_get_it.dart'; import 'friend_tile.dart'; -class FriendGroup extends StatefulWidget { +class FriendGroup extends StatelessWidget { const FriendGroup({ super.key, required this.groupName, @@ -13,31 +13,26 @@ class FriendGroup extends StatefulWidget { final String groupName; - @override - State createState() => _FriendGroupState(); -} - -class _FriendGroupState extends State { @override Widget build(BuildContext context) { return ExpansionTile( - title: Text(widget.groupName), + title: Text(groupName), trailing: Text( getIt .get() - .filterGroupFriends(widget.groupName) + .filterGroupFriends(groupName) .length .toString(), ), children: List.generate( - getIt.get().filterGroupFriends(widget.groupName).length, + getIt.get().filterGroupFriends(groupName).length, (index) => FriendTile( key: ValueKey( getIt.get().friends.keys.toList()[index], ), friendId: getIt .get() - .filterGroupFriends(widget.groupName) + .filterGroupFriends(groupName) .keys .toList()[index], ), diff --git a/lib/screens/contact/contact_apply_screen/apply_list_screen.dart b/lib/screens/contact/contact_apply_screen/apply_list_screen.dart index 714a477..42517a8 100755 --- a/lib/screens/contact/contact_apply_screen/apply_list_screen.dart +++ b/lib/screens/contact/contact_apply_screen/apply_list_screen.dart @@ -1,16 +1,9 @@ -import 'dart:io'; -import 'dart:typed_data'; - import 'package:flutter/material.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:archive/archive_io.dart'; import 'package:together_mobile/models/apply_list_model.dart'; import 'package:together_mobile/models/init_get_it.dart'; -import 'package:together_mobile/models/user_model.dart'; import 'package:together_mobile/request/apply.dart'; import 'package:together_mobile/screens/contact/contact_apply_screen/components/apply_list_tile.dart'; -import 'package:together_mobile/utils/app_dir.dart'; class ApplyListScreen extends StatefulWidget { const ApplyListScreen({super.key}); @@ -28,30 +21,30 @@ class _ApplyListScreenState extends State { Map res = await getApplicantProfile(getIt.get().applicantIds); - List avatars = []; + // List avatars = []; - for (var profile in res['data'].values) { - if (profile['avatar'] != null) { - String avatarPath = await getAvatarPath(profile['avatar']); - if (!File(avatarPath).existsSync()) { - avatars.add(profile['avatar']); - } - } - } + // for (var profile in res['data'].values) { + // if (profile['avatar'] != null) { + // String avatarPath = await getAvatarPath(profile['avatar']); + // if (!File(avatarPath).existsSync()) { + // avatars.add(profile['avatar']); + // } + // } + // } - if (avatars.isNotEmpty) { - Uint8List res = await downloadApplicantAvatars(avatars); - Directory tempDir = await getTemporaryDirectory(); - Directory appDir = await getApplicationDocumentsDirectory(); - String zipFilePath = - '${tempDir.path}/temp_avatars_${DateTime.now().millisecondsSinceEpoch}.zip'; - File zipFile = await File(zipFilePath).writeAsBytes(res); - extractFileToDisk( - zipFilePath, - '${appDir.path}/${getIt.get().id}/images/avatars', - ); - await zipFile.delete(); - } + // if (avatars.isNotEmpty) { + // Uint8List res = await downloadApplicantAvatars(avatars); + // Directory tempDir = await getTemporaryDirectory(); + // Directory appDir = await getApplicationDocumentsDirectory(); + // String zipFilePath = + // '${tempDir.path}/temp_avatars_${DateTime.now().millisecondsSinceEpoch}.zip'; + // File zipFile = await File(zipFilePath).writeAsBytes(res); + // extractFileToDisk( + // zipFilePath, + // '${appDir.path}/${getIt.get().id}/images/avatars', + // ); + // await zipFile.delete(); + // } return Future(() => res['data']); } diff --git a/lib/screens/contact/contact_apply_screen/components/apply_bottom_sheet.dart b/lib/screens/contact/contact_apply_screen/components/apply_bottom_sheet.dart index 9260c77..071e2e2 100755 --- a/lib/screens/contact/contact_apply_screen/components/apply_bottom_sheet.dart +++ b/lib/screens/contact/contact_apply_screen/components/apply_bottom_sheet.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; @@ -10,6 +11,7 @@ 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:together_mobile/models/websocket_model.dart'; import 'package:together_mobile/request/apply.dart'; import 'package:together_mobile/request/server.dart'; @@ -215,15 +217,33 @@ class _ApplyBottomSheetState extends State { if (res['code'] == 10600) { // ignore: use_build_context_synchronously CherryToast.success( - title: const Text( - '添加好友成功', - style: TextStyle( - color: kContentColorLight, + title: const Text( + '添加好友成功', + style: TextStyle( + color: kContentColorLight, + ), ), - )).show(context); + ).show(context); + + final accountProfile = {}; + accountProfile.addAll(getIt.get().toMap()); + accountProfile.addAll(getIt.get().toMap()); + + getIt.get().channel.sink.add(json.encode({ + 'event': 'friend-added', + 'friendId': widget.apply.recipient, + 'receiverId': widget.apply.applicant, + 'setting': widget.apply.setting, + 'accountProfile': accountProfile, + })); + getIt.get().removeAt(widget.index); - widget.refreshCallback(); getIt.get().addFriend(widget.apply.applicant!, recipientSetting); + getIt.get().addAccountProfile( + widget.apply.applicant!, + widget.accountProfile, + ); + widget.refreshCallback(); } else { // ignore: use_build_context_synchronously CherryToast.error( diff --git a/lib/screens/contact/contact_apply_screen/components/apply_list_tile.dart b/lib/screens/contact/contact_apply_screen/components/apply_list_tile.dart index 07fe4d0..700cbaf 100755 --- a/lib/screens/contact/contact_apply_screen/components/apply_list_tile.dart +++ b/lib/screens/contact/contact_apply_screen/components/apply_list_tile.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:cached_network_image/cached_network_image.dart'; import 'package:cherry_toast/cherry_toast.dart'; import 'package:flutter/material.dart'; diff --git a/lib/screens/contact/contact_screen.dart b/lib/screens/contact/contact_screen.dart index 9a6f817..b6cb0ba 100755 --- a/lib/screens/contact/contact_screen.dart +++ b/lib/screens/contact/contact_screen.dart @@ -36,6 +36,10 @@ class _ContactScreenState extends State with GetItStateMixin { List friendGroups = watchOnly( (Contact contact) => contact.friendGroups, ); + int applyCount = watchOnly( + (ApplyList applyList) => applyList.count, + ); + int friendCount = friends.length; // Create a localkey, use to generate the custom scroll view, // or there will be a error: "Duplicate GlobalKey detected in widget tree." @@ -84,6 +88,7 @@ class _ContactScreenState extends State with GetItStateMixin { SliverFixedExtentList( delegate: SliverChildListDelegate( [ + // apply list TextButton( onPressed: () async { // await getApplicantInfo(get().applicantIds); @@ -96,13 +101,13 @@ class _ContactScreenState extends State with GetItStateMixin { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ badges.Badge( - showBadge: get().count > 0, + showBadge: applyCount > 0, badgeStyle: const badges.BadgeStyle( badgeColor: kErrorColor, elevation: 12, ), badgeContent: Text( - get().count.toString(), + applyCount.toString(), style: TextStyle( fontSize: 11, color: @@ -169,20 +174,22 @@ class _ContactScreenState extends State with GetItStateMixin { groupName: friendGroups[index], ); } else if (_shows['allFriends']!) { + String friendId = friends.keys.toList()[index]; + // print(friends); return FriendTile( key: ValueKey( - friends.keys.toList()[index], + friendId, ), - friendId: friends.keys.toList()[index], + friendId: friendId, ); } else { return GroupChatTile(); } }, childCount: _shows['friendGroups']! - ? get().friendGroups.length + ? friendGroups.length : _shows['allFriends']! - ? get().friends.length + ? friendCount : get().groupChats.length, ), ), diff --git a/lib/screens/contact_add/contact_add_friend_screen/add_friend_screen.dart b/lib/screens/contact_add/contact_add_friend_screen/add_friend_screen.dart index c4d261f..c4f9875 100755 --- a/lib/screens/contact_add/contact_add_friend_screen/add_friend_screen.dart +++ b/lib/screens/contact_add/contact_add_friend_screen/add_friend_screen.dart @@ -1,10 +1,10 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; -import 'package:together_mobile/common/constants.dart'; -import 'package:together_mobile/screens/contact_add/contact_add_friend_screen/components/add_bottom_sheet.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:together_mobile/common/constants.dart'; +import 'package:together_mobile/request/server.dart'; +import 'package:together_mobile/screens/contact_add/contact_add_friend_screen/components/add_bottom_sheet.dart'; import 'package:together_mobile/screens/friend_profile/components/friend_profile_card.dart'; class AddFriendScreen extends StatelessWidget { @@ -43,8 +43,9 @@ class AddFriendScreen extends StatelessWidget { radius: 60, ) : CircleAvatar( - backgroundImage: - FileImage(File(accountProfile['avatar']!)), + backgroundImage: CachedNetworkImageProvider( + '$avatarsUrl/${accountProfile['avatar']!}', + ), radius: 60, ), const Chip( diff --git a/lib/screens/contact_add/contact_add_friend_screen/components/add_bottom_sheet.dart b/lib/screens/contact_add/contact_add_friend_screen/components/add_bottom_sheet.dart index b2c1140..2ad1515 100755 --- a/lib/screens/contact_add/contact_add_friend_screen/components/add_bottom_sheet.dart +++ b/lib/screens/contact_add/contact_add_friend_screen/components/add_bottom_sheet.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -8,6 +10,7 @@ import 'package:together_mobile/common/constants.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:together_mobile/models/websocket_model.dart'; import 'package:together_mobile/request/apply.dart'; import 'package:together_mobile/request/server.dart'; @@ -208,6 +211,23 @@ class _AddBottomSheetState extends State { // ignore: use_build_context_synchronously context.pop(); + getIt.get().channel.sink.add( + json.encode( + { + 'event': 'apply-friend', + 'relation': 0, + 'applicant': getIt.get().id, + 'recipient': widget.friendId, + 'hello': hello, + 'groupChatId': '', + 'setting': { + 'friendRemark': friendRemark, + 'friendGroup': _selectedGroup, + }, + }, + ), + ); + // ignore: use_build_context_synchronously CherryToast.success( title: const Text( diff --git a/lib/screens/contact_add/search_new_screen.dart b/lib/screens/contact_add/search_new_screen.dart index 513b042..7ecf0f1 100755 --- a/lib/screens/contact_add/search_new_screen.dart +++ b/lib/screens/contact_add/search_new_screen.dart @@ -179,16 +179,14 @@ class _SearchNewScreenState extends State { : res['data']['gender'] == 'man' ? '男' : '女', - 'avatar': res['data']['avatar'] == null - ? '' - : await getAvatarPath(res['data']['avatar']), + 'avatar': res['data']['avatar'] ?? '', }; - if (accountProfile['avatar']!.isNotEmpty) { - if (!File(accountProfile['avatar']!).existsSync()) { - var data = await downloadAvatar(res['data']['avatar']); - await File(accountProfile['avatar']!).writeAsBytes(data); - } - } + // if (accountProfile['avatar']!.isNotEmpty) { + // if (!File(accountProfile['avatar']!).existsSync()) { + // var data = await downloadAvatar(res['data']['avatar']); + // await File(accountProfile['avatar']!).writeAsBytes(data); + // } + // } // ignore: use_build_context_synchronously context.pushNamed('AddFriend', queryParameters: accountProfile); } diff --git a/lib/screens/friend_profile/friend_setting_screen/friend_setting_screen.dart b/lib/screens/friend_profile/friend_setting_screen/friend_setting_screen.dart index 7769817..cf9eeb9 100644 --- a/lib/screens/friend_profile/friend_setting_screen/friend_setting_screen.dart +++ b/lib/screens/friend_profile/friend_setting_screen/friend_setting_screen.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:cherry_toast/cherry_toast.dart'; import 'package:flutter/material.dart'; @@ -8,6 +9,7 @@ import 'package:together_mobile/common/constants.dart'; import 'package:together_mobile/models/init_get_it.dart'; import 'package:together_mobile/models/contact_model.dart'; import 'package:together_mobile/models/user_model.dart'; +import 'package:together_mobile/models/websocket_model.dart'; import 'package:together_mobile/request/contact.dart'; class FriendSettingScreen extends StatefulWidget { @@ -355,6 +357,13 @@ class _FriendSettingScreenState extends State { 'Contact', queryParameters: {'deletedFriendId': widget.friendId}, ); + + getIt.get().channel.sink.add(json.encode({ + 'event': 'friend-deleted', + 'friendId': getIt.get().id, + 'receiverId': widget.friendId, + })); + // ignore: use_build_context_synchronously CherryToast.success( title: const Text( diff --git a/lib/screens/message/components/message_bubble.dart b/lib/screens/message/components/message_bubble.dart index 34504de..181ac54 100755 --- a/lib/screens/message/components/message_bubble.dart +++ b/lib/screens/message/components/message_bubble.dart @@ -1,6 +1,11 @@ +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:together_mobile/common/constants.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:together_mobile/request/server.dart'; class MessageBubble extends StatelessWidget { const MessageBubble({ @@ -43,9 +48,25 @@ class MessageBubble extends StatelessWidget { senderId == contactId ? TextDirection.ltr : TextDirection.rtl, crossAxisAlignment: CrossAxisAlignment.start, children: [ - CircleAvatar( - child: Image.asset('assets/images/user_2.png'), - ), + senderId == contactId + ? getIt + .get() + .friends[contactId]! + .avatar + .isEmpty + ? CircleAvatar( + child: Image.asset('assets/images/user_2.png'), + ) + : CircleAvatar( + backgroundImage: CachedNetworkImageProvider( + '$avatarsUrl/${getIt.get().friends[contactId]!.avatar}', + ), + ) + : CircleAvatar( + backgroundImage: CachedNetworkImageProvider( + '$avatarsUrl/${getIt.get().avatar}', + ), + ), const SizedBox( width: 10, ), diff --git a/lib/screens/message/components/message_input_box.dart b/lib/screens/message/components/message_input_box.dart index 3079f91..0ba8335 100755 --- a/lib/screens/message/components/message_input_box.dart +++ b/lib/screens/message/components/message_input_box.dart @@ -192,7 +192,7 @@ class _MessageInputBoxState extends State { if (chatSetting == null) { _chatBox.put( widget.contactId, - ChatSetting(widget.contactId, false, true, false), + ChatSetting(widget.contactId, false, true, false, now), ); } diff --git a/lib/screens/message/message_screen.dart b/lib/screens/message/message_screen.dart index 1f4e32f..f54b734 100755 --- a/lib/screens/message/message_screen.dart +++ b/lib/screens/message/message_screen.dart @@ -81,6 +81,17 @@ class _MessageScreenState extends State { 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, + ), + ); + return ListView.builder( physics: const BouncingScrollPhysics( parent: AlwaysScrollableScrollPhysics(), diff --git a/lib/screens/more/setting_screen/setting_screen.dart b/lib/screens/more/setting_screen/setting_screen.dart index cacbff2..1638a78 100644 --- a/lib/screens/more/setting_screen/setting_screen.dart +++ b/lib/screens/more/setting_screen/setting_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:hive_flutter/hive_flutter.dart'; import 'package:together_mobile/models/apply_list_model.dart'; import 'package:together_mobile/models/init_get_it.dart'; import 'package:together_mobile/models/token_model.dart'; @@ -24,6 +25,7 @@ class SettingScreen extends StatelessWidget { getIt.get().clean(); getIt.get().clean(); getIt.get().clean(); + Hive.close(); // ignore: use_build_context_synchronously context.go('/welcome'); },