fix group chat bubble bug: flash
parent
6367125961
commit
3f3f898d2c
|
@ -105,6 +105,15 @@ class Contact extends ChangeNotifier {
|
|||
groupChatCount--;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void clean() {
|
||||
friends = {};
|
||||
friendGroups = [];
|
||||
defaultGroup = '';
|
||||
groupChats = {};
|
||||
friendCount = 0;
|
||||
groupChatCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
class FriendAccountProfile {
|
||||
|
@ -272,4 +281,10 @@ class ContactAccountProfile extends ChangeNotifier {
|
|||
grouChatMemberProfiles.remove(groupChatId);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void clean() {
|
||||
friends = {};
|
||||
groupChats = {};
|
||||
grouChatMemberProfiles = {};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,11 +14,17 @@ 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;
|
||||
|
||||
enum SocketStatus {
|
||||
connected,
|
||||
closed,
|
||||
error,
|
||||
}
|
||||
|
||||
class WebSocketManager extends ChangeNotifier {
|
||||
late Uri wsUrl;
|
||||
late WebSocketChannel channel;
|
||||
String id = '';
|
||||
SocketStatus? socketStatus;
|
||||
SocketStatus socketStatus = SocketStatus.closed;
|
||||
Timer? heartBeatTimer;
|
||||
Timer? serverTimer;
|
||||
Timer? reconnectTimer;
|
||||
|
@ -42,6 +48,20 @@ class WebSocketManager extends ChangeNotifier {
|
|||
channel.stream.listen(onData, onError: onError, onDone: onDone);
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
channel.sink.close();
|
||||
wsUrl = Uri();
|
||||
id = '';
|
||||
socketStatus = SocketStatus.closed;
|
||||
heartBeatTimer?.cancel();
|
||||
serverTimer?.cancel();
|
||||
reconnectTimer?.cancel();
|
||||
heartBeatTimer = null;
|
||||
serverTimer = null;
|
||||
reconnectTimer = null;
|
||||
reconnectTimes = 0;
|
||||
}
|
||||
|
||||
void onData(jsonData) {
|
||||
heartBeatInspect();
|
||||
Map<String, dynamic> data = json.decode(jsonData);
|
||||
|
@ -65,6 +85,9 @@ class WebSocketManager extends ChangeNotifier {
|
|||
|
||||
void onDone() {
|
||||
print('websocket disconnected <$channel>');
|
||||
if (socketStatus == SocketStatus.closed) {
|
||||
return;
|
||||
}
|
||||
reconnect();
|
||||
}
|
||||
|
||||
|
@ -132,12 +155,6 @@ class WebSocketManager extends ChangeNotifier {
|
|||
}
|
||||
}
|
||||
|
||||
enum SocketStatus {
|
||||
connected,
|
||||
closed,
|
||||
error,
|
||||
}
|
||||
|
||||
void receiveFriendMsg(Map<String, dynamic> msg) async {
|
||||
print('=================收到了好友信息事件==================');
|
||||
print(msg);
|
||||
|
@ -252,10 +269,10 @@ void receiveGroupChatMsg(Map<String, dynamic> msg) async {
|
|||
|
||||
if (chatSetting == null) {
|
||||
chatSettingBox.put(
|
||||
senderId,
|
||||
groupChatId,
|
||||
ChatSetting(
|
||||
groupChatId,
|
||||
0,
|
||||
1,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
|
@ -271,7 +288,6 @@ void receiveGroupChatMsg(Map<String, dynamic> msg) async {
|
|||
}
|
||||
|
||||
List<String> attachments = List.from(msg['attachments']);
|
||||
|
||||
messageTBox.add(
|
||||
MessageT(
|
||||
senderId,
|
||||
|
|
|
@ -162,6 +162,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
messageTBox.getAt(length - 1)!;
|
||||
if (openedChat[index].type == 0) {
|
||||
return FriendChatTile(
|
||||
key: ValueKey(contactId),
|
||||
index: index,
|
||||
contactId: contactId,
|
||||
senderId: messageT.senderId,
|
||||
|
@ -174,6 +175,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
);
|
||||
} else {
|
||||
return GroupChatChatTile(
|
||||
key: ValueKey(contactId),
|
||||
index: index,
|
||||
contactId: contactId,
|
||||
senderId: messageT.senderId,
|
||||
|
|
|
@ -37,12 +37,18 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
|
|||
final List<Timer> _timerList = [];
|
||||
|
||||
Future<bool> _getMemberGroupChatProfile() async {
|
||||
if (widget.senderId == getIt.get<UserAccount>().id ||
|
||||
getIt
|
||||
if (widget.senderId == getIt.get<UserAccount>().id) {
|
||||
// myself or already have profile
|
||||
return Future(() => true);
|
||||
}
|
||||
if (getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles
|
||||
.containsKey(widget.contactId) &&
|
||||
getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]!
|
||||
.containsKey(widget.senderId)) {
|
||||
// myself or already have profile
|
||||
return Future(() => true);
|
||||
} else {
|
||||
Map<String, dynamic> res;
|
||||
|
@ -136,50 +142,19 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
|
|||
? FutureBuilder(
|
||||
future: _getMemberGroupChatProfile(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
if (isFriend) {
|
||||
return getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.friends[widget.senderId]!
|
||||
.avatar
|
||||
.isEmpty
|
||||
? CircleAvatar(
|
||||
child:
|
||||
Image.asset('assets/images/user_2.png'),
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/${getIt.get<ContactAccountProfile>().friends[widget.senderId]!.avatar}',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.groupChats[widget.senderId]!
|
||||
.avatar
|
||||
.isEmpty
|
||||
? CircleAvatar(
|
||||
child:
|
||||
Image.asset('assets/images/user_2.png'),
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/${getIt.get<ContactAccountProfile>().groupChats[widget.senderId]!.avatar}',
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return CircleAvatar(
|
||||
child: Image.asset('assets/images/user_2.png'),
|
||||
);
|
||||
}
|
||||
return _showAvatar(snapshot, isFriend);
|
||||
},
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/${getIt.get<UserProfile>().avatar}',
|
||||
),
|
||||
),
|
||||
: getIt.get<UserProfile>().avatar.isNotEmpty
|
||||
? CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/${getIt.get<UserProfile>().avatar}',
|
||||
),
|
||||
)
|
||||
: const CircleAvatar(
|
||||
backgroundImage:
|
||||
AssetImage('assets/images/user_4.png'),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
|
@ -190,8 +165,6 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
|
|||
? CrossAxisAlignment.start
|
||||
: CrossAxisAlignment.end,
|
||||
children: [
|
||||
// nickname
|
||||
// used in group chat only
|
||||
widget.senderId == getIt.get<UserAccount>().id
|
||||
? getIt
|
||||
.get<Contact>()
|
||||
|
@ -208,70 +181,12 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
|
|||
: FutureBuilder(
|
||||
future: _getMemberGroupChatProfile(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
if (isFriend) {
|
||||
return getIt
|
||||
.get<Contact>()
|
||||
.friends[widget.senderId]!
|
||||
.friendRemark
|
||||
.isEmpty
|
||||
? getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget
|
||||
.contactId]![widget.senderId]!
|
||||
.remark
|
||||
.isEmpty
|
||||
? Text(
|
||||
getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.friends[widget.senderId]!
|
||||
.nickname,
|
||||
)
|
||||
: Text(
|
||||
getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[
|
||||
widget.contactId]![
|
||||
widget.senderId]!
|
||||
.remark,
|
||||
)
|
||||
: Text(
|
||||
getIt
|
||||
.get<Contact>()
|
||||
.friends[widget.senderId]!
|
||||
.friendRemark,
|
||||
);
|
||||
} else {
|
||||
return getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget
|
||||
.contactId]![widget.senderId]!
|
||||
.remark
|
||||
.isEmpty
|
||||
? Text(
|
||||
getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget
|
||||
.contactId]![widget.senderId]!
|
||||
.nickname,
|
||||
)
|
||||
: Text(
|
||||
getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget
|
||||
.contactId]![widget.senderId]!
|
||||
.remark,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return Text(widget.senderId);
|
||||
}
|
||||
return _showName(snapshot, isFriend);
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
|
||||
if (widget.type == 'text/multipart')
|
||||
// message box
|
||||
Container(
|
||||
|
@ -347,4 +262,191 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
CircleAvatar _showAvatar(AsyncSnapshot snapshot, bool isFriend) {
|
||||
if (snapshot.hasData) {
|
||||
if (isFriend) {
|
||||
String avatar =
|
||||
getIt.get<ContactAccountProfile>().friends[widget.senderId]!.avatar;
|
||||
return avatar.isEmpty
|
||||
? CircleAvatar(
|
||||
child: Image.asset('assets/images/user_4.png'),
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/$avatar',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
String avatar = getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]![widget.senderId]!
|
||||
.avatar;
|
||||
return avatar.isEmpty
|
||||
? CircleAvatar(
|
||||
child: Image.asset('assets/images/user_4.png'),
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/$avatar',
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// fix the bug that when the future return, the avatar will flash
|
||||
if (isFriend) {
|
||||
String avatar =
|
||||
getIt.get<ContactAccountProfile>().friends[widget.senderId]!.avatar;
|
||||
return avatar.isEmpty
|
||||
? CircleAvatar(
|
||||
child: Image.asset('assets/images/user_4.png'),
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/$avatar',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
if (getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles
|
||||
.containsKey(widget.contactId)) {
|
||||
if (getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]!
|
||||
.containsKey(widget.senderId)) {
|
||||
String avatar = getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]![widget.senderId]!
|
||||
.avatar;
|
||||
return avatar.isNotEmpty
|
||||
? CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(
|
||||
'$avatarsUrl/$avatar',
|
||||
),
|
||||
)
|
||||
: const CircleAvatar(
|
||||
backgroundImage: AssetImage(
|
||||
'assets/images/user_4.png',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const CircleAvatar(
|
||||
backgroundImage: AssetImage(
|
||||
'assets/images/user_4.png',
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return const CircleAvatar(
|
||||
backgroundImage: AssetImage(
|
||||
'assets/images/user_4.png',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text _showName(AsyncSnapshot snapshot, bool isFriend) {
|
||||
if (snapshot.hasData) {
|
||||
if (isFriend) {
|
||||
String friendRemark =
|
||||
getIt.get<Contact>().friends[widget.senderId]!.friendRemark;
|
||||
String remarkInGroupChat = getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]![widget.senderId]!
|
||||
.remark;
|
||||
|
||||
return friendRemark.isEmpty
|
||||
? remarkInGroupChat.isEmpty
|
||||
? Text(
|
||||
getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.friends[widget.senderId]!
|
||||
.nickname,
|
||||
)
|
||||
: Text(remarkInGroupChat)
|
||||
: Text(friendRemark);
|
||||
} else {
|
||||
String remarkInGroupChat = getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]![widget.senderId]!
|
||||
.remark;
|
||||
|
||||
return remarkInGroupChat.isEmpty
|
||||
? Text(
|
||||
getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]![widget.senderId]!
|
||||
.nickname,
|
||||
)
|
||||
: Text(remarkInGroupChat);
|
||||
}
|
||||
} else {
|
||||
// fix the bug that when the future return, the name will flash
|
||||
if (isFriend) {
|
||||
String friendRemark =
|
||||
getIt.get<Contact>().friends[widget.senderId]!.friendRemark;
|
||||
|
||||
if (friendRemark.isNotEmpty) {
|
||||
return Text(friendRemark);
|
||||
} else {
|
||||
if (getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles
|
||||
.containsKey(widget.contactId) &&
|
||||
getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]!
|
||||
.containsKey(widget.senderId)) {
|
||||
String remarkInGroupChat = getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]![widget.senderId]!
|
||||
.remark;
|
||||
String nickname = getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.friends[widget.senderId]!
|
||||
.nickname;
|
||||
|
||||
return remarkInGroupChat.isEmpty
|
||||
? Text(nickname)
|
||||
: Text(remarkInGroupChat);
|
||||
} else {
|
||||
return Text(widget.senderId.substring(0, 5));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles
|
||||
.containsKey(widget.contactId)) {
|
||||
if (getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]!
|
||||
.containsKey(widget.senderId)) {
|
||||
String remarkInGroupChat = getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]![widget.senderId]!
|
||||
.remark;
|
||||
String nickname = getIt
|
||||
.get<ContactAccountProfile>()
|
||||
.grouChatMemberProfiles[widget.contactId]![widget.senderId]!
|
||||
.nickname;
|
||||
return remarkInGroupChat.isNotEmpty
|
||||
? Text(remarkInGroupChat)
|
||||
: Text(nickname);
|
||||
} else {
|
||||
return Text(
|
||||
widget.senderId.substring(0, 5),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return Text(
|
||||
widget.senderId.substring(0, 5),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@ 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/contact_model.dart';
|
||||
import 'package:together_mobile/models/init_get_it.dart';
|
||||
import 'package:together_mobile/models/token_model.dart';
|
||||
import 'package:together_mobile/models/user_model.dart';
|
||||
import 'package:together_mobile/models/websocket_model.dart';
|
||||
|
||||
class SettingScreen extends StatelessWidget {
|
||||
const SettingScreen({super.key});
|
||||
|
@ -22,9 +24,12 @@ class SettingScreen extends StatelessWidget {
|
|||
child: TextButton(
|
||||
onPressed: () async {
|
||||
await getIt.get<Token>().clean();
|
||||
getIt.get<WebSocketManager>().disconnect();
|
||||
getIt.get<UserAccount>().clean();
|
||||
getIt.get<UserProfile>().clean();
|
||||
getIt.get<ApplyList>().clean();
|
||||
getIt.get<Contact>().clean();
|
||||
getIt.get<ContactAccountProfile>().clean();
|
||||
// Hive.deleteFromDisk();
|
||||
Hive.close();
|
||||
// ignore: use_build_context_synchronously
|
||||
|
|
|
@ -30,6 +30,13 @@ class _UsernameSigninBodyState extends State<UsernameSigninBody> {
|
|||
'password': false,
|
||||
};
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
usernameController.dispose();
|
||||
passwordController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _isInputError(String type, bool error) {
|
||||
setState(() {
|
||||
_isError[type] = error;
|
||||
|
@ -139,11 +146,4 @@ class _UsernameSigninBodyState extends State<UsernameSigninBody> {
|
|||
CherryToast.error(title: const Text('用户名或密码错误')).show(context);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
usernameController.dispose();
|
||||
passwordController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue