websocket apply/add/delete friend v1
parent
f75cccd28e
commit
5da249e4fc
|
@ -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)
|
||||
|
|
|
@ -21,13 +21,14 @@ class ChatSettingAdapter extends TypeAdapter<ChatSetting> {
|
|||
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<ChatSetting> {
|
|||
..writeByte(2)
|
||||
..write(obj.isOpen)
|
||||
..writeByte(3)
|
||||
..write(obj.isHideMsg);
|
||||
..write(obj.isHideMsg)
|
||||
..writeByte(4)
|
||||
..write(obj.latestDateTime);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -15,7 +15,7 @@ void initDatabase() async {
|
|||
|
||||
Box<ChatSetting> chatSettingBox =
|
||||
await Hive.openBox<ChatSetting>('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<ChatSetting>('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,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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<String, dynamic> 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() {
|
||||
|
|
|
@ -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<String, dynamic> json) {
|
||||
friends.addAll({friendId: FriendAccountProfile.fromJson(json)});
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void removeFriend(String friendId) {
|
||||
friends.remove(friendId);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,14 @@ class UserAccount extends ChangeNotifier {
|
|||
email = data['email']!;
|
||||
}
|
||||
|
||||
Map<String, String> 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<String, String> toMap() {
|
||||
return {
|
||||
'nickname': nickname,
|
||||
'gender': gender,
|
||||
'birthday': birthday,
|
||||
'location': location,
|
||||
'status': status,
|
||||
'sign': sign,
|
||||
'avatar': avatar,
|
||||
};
|
||||
}
|
||||
|
||||
void updateBasic(Map<String, String> newBasic) {
|
||||
nickname = newBasic['nickname']!;
|
||||
location = newBasic['location']!;
|
||||
|
|
|
@ -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<String, dynamic> msg) async {
|
|||
}
|
||||
|
||||
Box<ChatSetting> chatSettingBox = Hive.box<ChatSetting>('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<String> 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<String, dynamic> msg) {
|
||||
getIt.get<ApplyList>().addJson(msg);
|
||||
}
|
||||
|
||||
void receiveFriendAdded(Map<String, dynamic> msg) {
|
||||
print('=================收到了申请好友通过事件==================');
|
||||
print(msg);
|
||||
print('=======================================');
|
||||
getIt.get<Contact>().addFriend(msg['friendId'], msg['setting']);
|
||||
getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.addAccountProfile(msg['friendId'], msg['accountProfile']);
|
||||
}
|
||||
|
||||
void receiveFriendDeleted(Map<String, dynamic> msg) {
|
||||
print('=================收到了解除好友事件==================');
|
||||
print(msg);
|
||||
print('=======================================');
|
||||
getIt.get<Contact>().removeFriend(msg['friendId']);
|
||||
getIt.get<ContactAccountProfile>().removeFriend(msg['friendId']);
|
||||
}
|
||||
|
|
|
@ -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<ChatScreen> {
|
|||
itemCount: openedChat.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
String contactId = openedChat[index].contactId;
|
||||
String showedTime = formatTileDateTime(
|
||||
openedChat[index].latestDateTime!,
|
||||
);
|
||||
|
||||
return ValueListenableBuilder(
|
||||
valueListenable:
|
||||
Hive.box<MessageT>('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,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
|
|
|
@ -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<ChatTile> createState() => _ChatTileState();
|
||||
}
|
||||
|
||||
class _ChatTileState extends State<ChatTile> {
|
||||
Future<Map<String, dynamic>> _getLatestMsg() async {
|
||||
LazyBox<MessageT> messageTBox =
|
||||
Hive.lazyBox<MessageT>('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<ContactAccountProfile>()
|
||||
.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<ContactAccountProfile>().friends[widget.contactId]!.avatar}',
|
||||
),
|
||||
),
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
// friend remark or nickname
|
||||
child: Text(
|
||||
getIt
|
||||
.get<Contact>()
|
||||
.friends[widget.contactId]!
|
||||
.friendRemark
|
||||
.isEmpty
|
||||
? getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.friends[widget.contactId]!
|
||||
.nickname
|
||||
: getIt
|
||||
.get<Contact>()
|
||||
.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'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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<String> attachments;
|
||||
final bool isShowTime;
|
||||
|
||||
@override
|
||||
State<ChatTile> createState() => _ChatTileState();
|
||||
}
|
||||
|
||||
class _ChatTileState extends State<ChatTile> {
|
||||
late Map<String, dynamic> _latestMsg;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Box<MessageT> messageTBox =
|
||||
Hive.box<MessageT>('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<ChatTile> {
|
|||
endActionPane: ActionPane(
|
||||
motion: const BehindMotion(),
|
||||
dismissible: DismissiblePane(
|
||||
onDismissed: () {},
|
||||
onDismissed: () {
|
||||
Box<ChatSetting> 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<ChatTile> {
|
|||
),
|
||||
// latest msg datetime
|
||||
Text(
|
||||
_latestMsg['dateTime']!,
|
||||
widget.dateTime,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: kUnActivatedColor,
|
||||
|
@ -144,7 +127,7 @@ class _ChatTileState extends State<ChatTile> {
|
|||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
_latestMsg['text'],
|
||||
widget.text,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: kUnActivatedColor,
|
||||
|
@ -152,7 +135,6 @@ class _ChatTileState extends State<ChatTile> {
|
|||
),
|
||||
),
|
||||
),
|
||||
// Text('10:13'),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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<FriendGroup> createState() => _FriendGroupState();
|
||||
}
|
||||
|
||||
class _FriendGroupState extends State<FriendGroup> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExpansionTile(
|
||||
title: Text(widget.groupName),
|
||||
title: Text(groupName),
|
||||
trailing: Text(
|
||||
getIt
|
||||
.get<Contact>()
|
||||
.filterGroupFriends(widget.groupName)
|
||||
.filterGroupFriends(groupName)
|
||||
.length
|
||||
.toString(),
|
||||
),
|
||||
children: List.generate(
|
||||
getIt.get<Contact>().filterGroupFriends(widget.groupName).length,
|
||||
getIt.get<Contact>().filterGroupFriends(groupName).length,
|
||||
(index) => FriendTile(
|
||||
key: ValueKey(
|
||||
getIt.get<Contact>().friends.keys.toList()[index],
|
||||
),
|
||||
friendId: getIt
|
||||
.get<Contact>()
|
||||
.filterGroupFriends(widget.groupName)
|
||||
.filterGroupFriends(groupName)
|
||||
.keys
|
||||
.toList()[index],
|
||||
),
|
||||
|
|
|
@ -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<ApplyListScreen> {
|
|||
Map<String, dynamic> res =
|
||||
await getApplicantProfile(getIt.get<ApplyList>().applicantIds);
|
||||
|
||||
List<String> avatars = [];
|
||||
// List<String> 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<UserAccount>().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<UserAccount>().id}/images/avatars',
|
||||
// );
|
||||
// await zipFile.delete();
|
||||
// }
|
||||
|
||||
return Future(() => res['data']);
|
||||
}
|
||||
|
|
|
@ -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<ApplyBottomSheet> {
|
|||
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<UserAccount>().toMap());
|
||||
accountProfile.addAll(getIt.get<UserProfile>().toMap());
|
||||
|
||||
getIt.get<WebSocketManager>().channel.sink.add(json.encode({
|
||||
'event': 'friend-added',
|
||||
'friendId': widget.apply.recipient,
|
||||
'receiverId': widget.apply.applicant,
|
||||
'setting': widget.apply.setting,
|
||||
'accountProfile': accountProfile,
|
||||
}));
|
||||
|
||||
getIt.get<ApplyList>().removeAt(widget.index);
|
||||
widget.refreshCallback();
|
||||
getIt.get<Contact>().addFriend(widget.apply.applicant!, recipientSetting);
|
||||
getIt.get<ContactAccountProfile>().addAccountProfile(
|
||||
widget.apply.applicant!,
|
||||
widget.accountProfile,
|
||||
);
|
||||
widget.refreshCallback();
|
||||
} else {
|
||||
// ignore: use_build_context_synchronously
|
||||
CherryToast.error(
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -36,6 +36,10 @@ class _ContactScreenState extends State<ContactScreen> with GetItStateMixin {
|
|||
List<String> 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<ContactScreen> with GetItStateMixin {
|
|||
SliverFixedExtentList(
|
||||
delegate: SliverChildListDelegate(
|
||||
[
|
||||
// apply list
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
// await getApplicantInfo(get<ApplyList>().applicantIds);
|
||||
|
@ -96,13 +101,13 @@ class _ContactScreenState extends State<ContactScreen> with GetItStateMixin {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
badges.Badge(
|
||||
showBadge: get<ApplyList>().count > 0,
|
||||
showBadge: applyCount > 0,
|
||||
badgeStyle: const badges.BadgeStyle(
|
||||
badgeColor: kErrorColor,
|
||||
elevation: 12,
|
||||
),
|
||||
badgeContent: Text(
|
||||
get<ApplyList>().count.toString(),
|
||||
applyCount.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color:
|
||||
|
@ -169,20 +174,22 @@ class _ContactScreenState extends State<ContactScreen> 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<Contact>().friendGroups.length
|
||||
? friendGroups.length
|
||||
: _shows['allFriends']!
|
||||
? get<Contact>().friends.length
|
||||
? friendCount
|
||||
: get<Contact>().groupChats.length,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<AddBottomSheet> {
|
|||
// ignore: use_build_context_synchronously
|
||||
context.pop();
|
||||
|
||||
getIt.get<WebSocketManager>().channel.sink.add(
|
||||
json.encode(
|
||||
{
|
||||
'event': 'apply-friend',
|
||||
'relation': 0,
|
||||
'applicant': getIt.get<UserAccount>().id,
|
||||
'recipient': widget.friendId,
|
||||
'hello': hello,
|
||||
'groupChatId': '',
|
||||
'setting': {
|
||||
'friendRemark': friendRemark,
|
||||
'friendGroup': _selectedGroup,
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// ignore: use_build_context_synchronously
|
||||
CherryToast.success(
|
||||
title: const Text(
|
||||
|
|
|
@ -179,16 +179,14 @@ class _SearchNewScreenState extends State<SearchNewScreen> {
|
|||
: 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);
|
||||
}
|
||||
|
|
|
@ -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<FriendSettingScreen> {
|
|||
'Contact',
|
||||
queryParameters: {'deletedFriendId': widget.friendId},
|
||||
);
|
||||
|
||||
getIt.get<WebSocketManager>().channel.sink.add(json.encode({
|
||||
'event': 'friend-deleted',
|
||||
'friendId': getIt.get<UserAccount>().id,
|
||||
'receiverId': widget.friendId,
|
||||
}));
|
||||
|
||||
// ignore: use_build_context_synchronously
|
||||
CherryToast.success(
|
||||
title: const Text(
|
||||
|
|
|
@ -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<ContactAccountProfile>()
|
||||
.friends[contactId]!
|
||||
.avatar
|
||||
.isEmpty
|
||||
? CircleAvatar(
|
||||
child: Image.asset('assets/images/user_2.png'),
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/${getIt.get<ContactAccountProfile>().friends[contactId]!.avatar}',
|
||||
),
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/${getIt.get<UserProfile>().avatar}',
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
|
|
|
@ -192,7 +192,7 @@ class _MessageInputBoxState extends State<MessageInputBox> {
|
|||
if (chatSetting == null) {
|
||||
_chatBox.put(
|
||||
widget.contactId,
|
||||
ChatSetting(widget.contactId, false, true, false),
|
||||
ChatSetting(widget.contactId, false, true, false, now),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,17 @@ class _MessageScreenState extends State<MessageScreen> {
|
|||
valueListenable: Hive.box<MessageT>('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(),
|
||||
|
|
|
@ -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<UserAccount>().clean();
|
||||
getIt.get<UserProfile>().clean();
|
||||
getIt.get<ApplyList>().clean();
|
||||
Hive.close();
|
||||
// ignore: use_build_context_synchronously
|
||||
context.go('/welcome');
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue