implement hiding msg

main
htylight 2023-09-17 17:45:32 +08:00
parent 5c2022d107
commit fa81ae090d
11 changed files with 98 additions and 257 deletions

View File

@ -1,227 +0,0 @@
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:together_mobile/database/hive_database.dart';
import 'package:together_mobile/request/message.dart';
import 'package:together_mobile/screens/chat/components/group_chat_chat_tile.dart';
import 'components/friend_chat_tile.dart';
import 'components/add_menu.dart';
import 'package:together_mobile/database/box_type.dart';
import 'package:together_mobile/models/websocket_model.dart';
import 'package:together_mobile/utils/format_datetime.dart';
import 'package:together_mobile/models/contact_model.dart';
import 'package:together_mobile/models/apply_list_model.dart';
import 'package:together_mobile/request/apply.dart';
import 'package:together_mobile/request/server.dart';
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';
class ChatScreen extends StatefulWidget {
const ChatScreen({super.key});
@override
State<ChatScreen> createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
Future<bool> _initData() async {
if (!getIt.get<UserProfile>().isInitialised) {
await HiveDatabase.init();
getIt.get<WebSocketManager>().connect(getIt.get<UserAccount>().id, false);
String userId = getIt.get<UserAccount>().id;
List<Map<String, dynamic>> res = await Future.wait([
getMyProfile(userId),
getApplyList(userId),
getContact(userId),
]);
await getIt.get<UserProfile>().init(res[0]['data']);
if (res[1]['code'] == 10600) {
getIt.get<ApplyList>().init(res[1]['data']);
}
if (res[2]['code'] == 10700) {
getIt.get<Contact>().init(res[2]['data']);
}
Map<String, dynamic> contactAcctProfRes = await getContactAccountProfiles(
getIt.get<Contact>().friends.keys.toList(),
getIt.get<Contact>().groupChats.keys.toList(),
);
if (contactAcctProfRes['code'] == 10700) {
getIt.get<ContactAccountProfile>().init(contactAcctProfRes['data']);
}
await _getUnreceivedMsg(userId);
}
return Future(() => true);
}
Future<void> _getUnreceivedMsg(String userId) async {
print('触发了获取信息事件..................');
final res = await getUnreceivedMsg(userId);
if (res['code'] == 10900) {
for (var msg in res['data'] as List<Map<String, dynamic>>) {
if (msg['event'] == 'friend-chat-msg') {
receiveFriendMsg(msg, false);
} else if (msg['event'] == 'group-chat-msg') {
receiveGroupChatMsg(msg, false);
}
}
}
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initData(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.hasData) {
return Scaffold(
appBar: AppBar(
leading: getIt.get<UserProfile>().avatar.isEmpty
? const CircleAvatar(
backgroundImage: AssetImage('assets/images/user_2.png'),
)
: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(
'$userAvatarsUrl/${getIt.get<UserProfile>().avatar}',
),
),
title: Text(getIt.get<UserProfile>().nickname),
centerTitle: true,
actions: [
IconButton(
onPressed: () {},
splashRadius: 20,
icon: const Icon(Icons.search),
),
const AddMenu(),
],
),
// Use ListView.builder because it renders list element on demand
body: RefreshIndicator(
onRefresh: () async {
String userId = getIt.get<UserAccount>().id;
if (getIt.get<WebSocketManager>().socketStatus ==
SocketStatus.closed) {
getIt.get<WebSocketManager>().connect(userId, false);
}
await _getUnreceivedMsg(userId);
},
child: ValueListenableBuilder(
valueListenable:
Hive.box<ChatSetting>('chat_setting').listenable(),
builder: (context, Box<ChatSetting> box, _) {
final List<ChatSetting> 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(
'没有最新消息',
style: TextStyle(
fontSize: 18,
letterSpacing: 5.0,
),
),
);
} else {
return ListView.builder(
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
itemCount: openedChat.length,
itemBuilder: (BuildContext context, int index) {
String contactId = openedChat[index].contactId;
String showedTime = formatTileDateTime(
openedChat[index].latestDateTime,
);
int unreadCount = openedChat[index].unreadCount;
return ValueListenableBuilder(
valueListenable:
Hive.box<MessageT>('message_$contactId')
.listenable(),
builder: (context, messageTBox, _) {
int length = messageTBox.length;
if (length > 0) {
MessageT messageT =
messageTBox.getAt(length - 1)!;
if (openedChat[index].type == 0) {
return FriendChatTile(
key: ValueKey(contactId),
index: index,
contactId: contactId,
senderId: messageT.senderId,
messageType: messageT.type,
text: messageT.text,
attachments: messageT.attachments,
dateTime: showedTime,
isShowTime: messageT.isShowTime,
unreadCount: unreadCount,
);
} else {
return GroupChatChatTile(
key: ValueKey(contactId),
index: index,
contactId: contactId,
senderId: messageT.senderId,
messageType: messageT.type,
text: messageT.text,
attachments: messageT.attachments,
dateTime: showedTime,
isShowTime: messageT.isShowTime,
unreadCount: unreadCount,
);
}
} else {
return const SizedBox();
}
},
);
},
);
}
},
),
),
);
} else {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 60,
height: 60,
child: CircularProgressIndicator(),
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Text('Loading data....'),
)
],
),
);
}
},
);
}
}

View File

@ -205,7 +205,6 @@ class _ChatScreenState extends State<ChatScreen> with GetItStateMixin {
if (openedChat[index].type == 0) {
return FriendChatTile(
key: ValueKey(contactId),
index: index,
contactId: contactId,
senderId: messageT.senderId,
messageType: messageT.type,

View File

@ -15,7 +15,6 @@ import 'badge_avatar.dart';
class FriendChatTile extends StatefulWidget {
const FriendChatTile({
super.key,
required this.index,
required this.contactId,
required this.senderId,
required this.messageType,
@ -26,7 +25,7 @@ class FriendChatTile extends StatefulWidget {
required this.unreadCount,
});
final int index, unreadCount;
final int unreadCount;
final String contactId, senderId, messageType, text, dateTime;
final List<String> attachments;
final bool isShowTime;
@ -38,14 +37,14 @@ class FriendChatTile extends StatefulWidget {
class _FriendChatTileState extends State<FriendChatTile> {
@override
Widget build(BuildContext context) {
Box<ChatSetting> chatSettingBox = Hive.box<ChatSetting>('chat_setting');
ChatSetting chatSetting = chatSettingBox.get(widget.contactId)!;
return Slidable(
key: const ValueKey(0),
endActionPane: ActionPane(
motion: const BehindMotion(),
dismissible: DismissiblePane(
onDismissed: () {
Box<ChatSetting> chatSettingBox = Hive.box('chat_setting');
ChatSetting chatSetting = chatSettingBox.getAt(widget.index)!;
chatSetting.isOpen = false;
chatSettingBox.put(widget.contactId, chatSetting);
},
@ -59,11 +58,14 @@ class _FriendChatTileState extends State<FriendChatTile> {
label: '置顶',
),
SlidableAction(
onPressed: (BuildContext context) {},
onPressed: (BuildContext context) {
chatSetting.isHideMsg = !chatSetting.isHideMsg;
chatSettingBox.put(widget.contactId, chatSetting);
},
foregroundColor: kContentColorDark,
backgroundColor: kPrimaryColor,
icon: Icons.remove_red_eye,
label: '隐藏消息',
label: chatSetting.isHideMsg ? '显示消息' : '隐藏消息',
flex: 1,
),
],

View File

@ -9,7 +9,6 @@ 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/models/route_state_model.dart';
import 'package:together_mobile/request/server.dart';
import 'badge_avatar.dart';

View File

@ -82,7 +82,7 @@ class RowFloatingButtons extends StatelessWidget {
}
// ignore: use_build_context_synchronously
context.goNamed(
context.pushReplacementNamed(
'Message',
queryParameters: {'friendId': friendId, 'type': '0'},
);

View File

@ -40,7 +40,6 @@ class FriendProfileScreen extends StatelessWidget {
actions: [
TextButton(
onPressed: () {
getIt.get<RouteState>().changeRoute('FriendSetting');
context.pushNamed(
'FriendSetting',
queryParameters: {'friendId': friendId},

View File

@ -8,6 +8,7 @@ import 'package:go_router/go_router.dart';
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/route_state_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';
@ -49,6 +50,11 @@ class _FriendSettingScreenState extends State<FriendSettingScreen> {
@override
Widget build(BuildContext context) {
Timer(
const Duration(milliseconds: 300),
() => getIt.get<RouteState>().changeRoute('FriendProfile'),
);
return Scaffold(
appBar: AppBar(
centerTitle: true,

View File

@ -3,8 +3,10 @@ import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.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/models/user_model.dart';
@ -13,6 +15,8 @@ import 'package:together_mobile/request/server.dart';
class FriendMessageBubble extends StatefulWidget {
const FriendMessageBubble({
super.key,
required this.index,
required this.length,
required this.contactId,
required this.senderId,
required this.type,
@ -22,6 +26,7 @@ class FriendMessageBubble extends StatefulWidget {
required this.attachments,
});
final int index, length;
final String contactId, senderId, type, dateTime, text;
final bool isShowTime;
final List<String> attachments;
@ -34,11 +39,13 @@ class _FriendMessageBubbleState extends State<FriendMessageBubble> {
// add late here so you can access widget instance
List<bool> _isImagesLoaded = [];
final List<Timer> _timerList = [];
late bool _isHideMsg;
@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<UserProfile>().baseImageDir}/${widget.attachments[i]}';
@ -47,7 +54,8 @@ class _FriendMessageBubbleState extends State<FriendMessageBubble> {
_isImagesLoaded[i] = true;
} else {
_isImagesLoaded[i] = false;
_timerList.add(Timer.periodic(
_timerList.add(
Timer.periodic(
const Duration(milliseconds: 200),
(timer) {
if ((file.existsSync())) {
@ -57,17 +65,37 @@ class _FriendMessageBubbleState extends State<FriendMessageBubble> {
timer.cancel();
}
},
));
),
);
}
}
final chatSettingBox = Hive.box<ChatSetting>('chat_setting');
late final chatSetting = chatSettingBox.get(widget.contactId);
_isHideMsg = chatSetting!.isHideMsg;
if (_isHideMsg) {
if (widget.index + 1 == widget.length) {
_isHideMsg = false;
Timer(
const Duration(milliseconds: 3500),
() {
setState(() {
_isHideMsg = true;
});
},
);
}
}
}
@override
void dispose() {
super.dispose();
for (var element in _timerList) {
element.cancel();
}
super.dispose();
}
@override
@ -137,8 +165,10 @@ class _FriendMessageBubbleState extends State<FriendMessageBubble> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (_isHideMsg) const Text('消息已隐藏'),
// text message content
if (widget.text.isNotEmpty)
if (widget.text.isNotEmpty && !_isHideMsg)
Text(
widget.text,
textWidthBasis: TextWidthBasis.longestLine,
@ -147,7 +177,7 @@ class _FriendMessageBubbleState extends State<FriendMessageBubble> {
height: 10,
),
// image content if have
if (widget.attachments.isNotEmpty)
if (widget.attachments.isNotEmpty && !_isHideMsg)
...List.generate(
widget.attachments.length,
(int index) {
@ -187,13 +217,18 @@ class _FriendMessageBubbleState extends State<FriendMessageBubble> {
),
],
),
if (_isHideMsg)
TextButton(
onPressed: () {},
onPressed: () {
setState(() {
_isHideMsg = false;
});
},
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
child: const Text('显示'),
child: const Text('显示'),
),
],
),

View File

@ -3,8 +3,10 @@ import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.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/models/user_model.dart';
@ -14,6 +16,8 @@ import 'package:together_mobile/request/server.dart';
class GroupChatMessageBubble extends StatefulWidget {
const GroupChatMessageBubble({
super.key,
required this.index,
required this.length,
required this.contactId,
required this.senderId,
required this.type,
@ -23,6 +27,7 @@ class GroupChatMessageBubble extends StatefulWidget {
required this.attachments,
});
final int index, length;
final String contactId, senderId, type, dateTime, text;
final bool isShowTime;
final List<String> attachments;
@ -35,6 +40,7 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
// add late here so you can access widget instance
List<bool> _isImagesLoaded = [];
final List<Timer> _timerList = [];
late bool _isHideMsg;
Future<bool> _getMemberGroupChatProfile() async {
if (widget.senderId == getIt.get<UserAccount>().id) {
@ -100,6 +106,24 @@ class _GroupChatMessageBubbleState extends State<GroupChatMessageBubble> {
));
}
}
final chatSettingBox = Hive.box<ChatSetting>('chat_setting');
late final chatSetting = chatSettingBox.get(widget.contactId);
_isHideMsg = chatSetting!.isHideMsg;
if (_isHideMsg) {
if (widget.index + 1 == widget.length) {
_isHideMsg = false;
Timer(
const Duration(milliseconds: 3500),
() {
setState(() {
_isHideMsg = true;
});
},
);
}
}
}
@override

View File

@ -123,6 +123,8 @@ class _FriendMessageScreenState extends State<FriendMessageScreen> {
return FriendMessageBubble(
key: ValueKey(i),
index: i,
length: length,
contactId: widget.friendId,
senderId: messageT.senderId,
dateTime: formatMessageDateTime(messageT.dateTime),

View File

@ -134,6 +134,8 @@ class _GroupChatMessageScreenState extends State<GroupChatMessageScreen> {
return GroupChatMessageBubble(
key: ValueKey(i),
index: i,
length: length,
contactId: widget.groupChatId,
senderId: messageT.senderId,
dateTime: formatMessageDateTime(messageT.dateTime),