mirror of
https://github.com/Linloir/Simple-TCP-Client.git
synced 2025-12-18 17:28:11 +08:00
New Feature:
- Unread message bubble!
This commit is contained in:
parent
ed10d0aec4
commit
7023271fe9
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-13 14:03:56
|
* @Date : 2022-10-13 14:03:56
|
||||||
* @LastEditTime : 2022-10-23 13:07:08
|
* @LastEditTime : 2022-10-23 17:22:46
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -209,6 +209,14 @@ class ChatCubit extends Cubit<ChatState> {
|
|||||||
if(response.type == TCPResponseType.forwardMessage) {
|
if(response.type == TCPResponseType.forwardMessage) {
|
||||||
response as ForwardMessageResponse;
|
response as ForwardMessageResponse;
|
||||||
if(response.message.senderID == userID || response.message.recieverID == userID) {
|
if(response.message.senderID == userID || response.message.recieverID == userID) {
|
||||||
|
if(response.message.senderID == userID) {
|
||||||
|
//Update read history
|
||||||
|
localServiceRepository.setReadHistory(
|
||||||
|
userid: response.message.recieverID,
|
||||||
|
targetid: userID,
|
||||||
|
timestamp: response.message.timeStamp
|
||||||
|
);
|
||||||
|
}
|
||||||
// Message storage will be handled by home bloc listener
|
// Message storage will be handled by home bloc listener
|
||||||
//Emit new state
|
//Emit new state
|
||||||
var newHistory = ChatHistory(
|
var newHistory = ChatHistory(
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import 'package:tcp_client/home/cubit/home_cubit.dart';
|
|||||||
import 'package:tcp_client/home/cubit/home_state.dart';
|
import 'package:tcp_client/home/cubit/home_state.dart';
|
||||||
import 'package:tcp_client/home/view/contact_page/contact_page.dart';
|
import 'package:tcp_client/home/view/contact_page/contact_page.dart';
|
||||||
import 'package:tcp_client/home/view/contact_page/cubit/contact_cubit.dart';
|
import 'package:tcp_client/home/view/contact_page/cubit/contact_cubit.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/cubit/msg_list_cubit.dart';
|
import 'package:tcp_client/home/view/message_page/cubit/msg_list/msg_list_cubit.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/mesage_page.dart';
|
import 'package:tcp_client/home/view/message_page/mesage_page.dart';
|
||||||
import 'package:tcp_client/home/view/profile_page/profile_page.dart';
|
import 'package:tcp_client/home/view/profile_page/profile_page.dart';
|
||||||
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import 'package:tcp_client/home/cubit/home_cubit.dart';
|
|||||||
import 'package:tcp_client/home/cubit/home_state.dart';
|
import 'package:tcp_client/home/cubit/home_state.dart';
|
||||||
import 'package:tcp_client/home/view/contact_page/cubit/contact_cubit.dart';
|
import 'package:tcp_client/home/view/contact_page/cubit/contact_cubit.dart';
|
||||||
import 'package:tcp_client/home/view/contact_page/models/contact_model.dart';
|
import 'package:tcp_client/home/view/contact_page/models/contact_model.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/cubit/msg_list_cubit.dart';
|
import 'package:tcp_client/home/view/message_page/cubit/msg_list/msg_list_cubit.dart';
|
||||||
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
||||||
import 'package:tcp_client/repositories/tcp_repository/models/tcp_request.dart';
|
import 'package:tcp_client/repositories/tcp_repository/models/tcp_request.dart';
|
||||||
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-12 23:38:31
|
* @Date : 2022-10-12 23:38:31
|
||||||
* @LastEditTime : 2022-10-21 23:14:02
|
* @LastEditTime : 2022-10-23 16:30:24
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/cubit/msg_list_state.dart';
|
import 'package:tcp_client/home/view/message_page/cubit/msg_list/msg_list_state.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/models/message_info.dart';
|
import 'package:tcp_client/home/view/message_page/models/message_info.dart';
|
||||||
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
||||||
import 'package:tcp_client/repositories/tcp_repository/models/tcp_request.dart';
|
import 'package:tcp_client/repositories/tcp_repository/models/tcp_request.dart';
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-23 16:30:45
|
||||||
|
* @LastEditTime : 2022-10-23 17:46:28
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:tcp_client/home/view/message_page/cubit/msg_tile/msg_tile_state.dart';
|
||||||
|
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
||||||
|
import 'package:tcp_client/repositories/tcp_repository/models/tcp_response.dart';
|
||||||
|
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
||||||
|
|
||||||
|
class MessageTileCubit extends Cubit<MessageTileState> {
|
||||||
|
MessageTileCubit({
|
||||||
|
required this.tcpRepository,
|
||||||
|
required this.localServiceRepository,
|
||||||
|
required this.targetID
|
||||||
|
}): super(const MessageTileState(unreadCount: 0)) {
|
||||||
|
Future<int>(() async {
|
||||||
|
return await localServiceRepository.getUnreadCount(
|
||||||
|
userid: (await SharedPreferences.getInstance()).getInt('userid')!,
|
||||||
|
targetid: targetID
|
||||||
|
);
|
||||||
|
}).then((value) => emit(state + value));
|
||||||
|
subscription = tcpRepository.responseStreamBroadcast.listen(_onResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
final TCPRepository tcpRepository;
|
||||||
|
final LocalServiceRepository localServiceRepository;
|
||||||
|
final int targetID;
|
||||||
|
late final StreamSubscription subscription;
|
||||||
|
|
||||||
|
Future<void> _onResponse(TCPResponse response) async {
|
||||||
|
var pref = await SharedPreferences.getInstance();
|
||||||
|
var userID = pref.getInt('userid');
|
||||||
|
if(userID == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var readHistoryTimestamp = await localServiceRepository.fetchReadHistory(
|
||||||
|
userid: userID,
|
||||||
|
targetid: targetID
|
||||||
|
);
|
||||||
|
if(response.type == TCPResponseType.fetchMessage) {
|
||||||
|
//Count unread incoming message count
|
||||||
|
response as FetchMessageResponse;
|
||||||
|
var addCnt = 0;
|
||||||
|
for(var message in response.messages) {
|
||||||
|
if(message.senderID == targetID && message.recieverID == userID) {
|
||||||
|
if(readHistoryTimestamp < message.timeStamp) {
|
||||||
|
addCnt += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!isClosed) {
|
||||||
|
emit(state + addCnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(response.type == TCPResponseType.forwardMessage) {
|
||||||
|
//Count unread incoming message count
|
||||||
|
response as ForwardMessageResponse;
|
||||||
|
if(response.message.senderID == targetID && response.message.recieverID == userID) {
|
||||||
|
if(readHistoryTimestamp < response.message.timeStamp) {
|
||||||
|
if(!isClosed) {
|
||||||
|
emit(state + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(!isClosed) {
|
||||||
|
emit(const MessageTileState(unreadCount: 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearUnread() {
|
||||||
|
emit(const MessageTileState(unreadCount: 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
subscription.cancel();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* @Author : Linloir
|
||||||
|
* @Date : 2022-10-23 16:30:52
|
||||||
|
* @LastEditTime : 2022-10-23 16:40:47
|
||||||
|
* @Description :
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
||||||
|
class MessageTileState extends Equatable {
|
||||||
|
final int unreadCount;
|
||||||
|
|
||||||
|
const MessageTileState({required this.unreadCount});
|
||||||
|
|
||||||
|
MessageTileState operator +(int other) {
|
||||||
|
return MessageTileState(unreadCount: unreadCount + other);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [unreadCount];
|
||||||
|
}
|
||||||
@ -1,15 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-11 11:05:18
|
* @Date : 2022-10-11 11:05:18
|
||||||
* @LastEditTime : 2022-10-17 13:35:35
|
* @LastEditTime : 2022-10-23 17:38:30
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
|
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/cubit/msg_list_cubit.dart';
|
import 'package:tcp_client/home/view/message_page/cubit/msg_list/msg_list_cubit.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/cubit/msg_list_state.dart';
|
import 'package:tcp_client/home/view/message_page/cubit/msg_list/msg_list_state.dart';
|
||||||
import 'package:tcp_client/home/view/message_page/view/message_tile.dart';
|
import 'package:tcp_client/home/view/message_page/view/message_tile.dart';
|
||||||
|
|
||||||
class MessagePage extends StatelessWidget {
|
class MessagePage extends StatelessWidget {
|
||||||
@ -31,6 +31,7 @@ class MessagePage extends StatelessWidget {
|
|||||||
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return MessageTile(
|
return MessageTile(
|
||||||
|
key: ValueKey(state.messageList[index].targetUser),
|
||||||
userID: state.messageList[index].targetUser,
|
userID: state.messageList[index].targetUser,
|
||||||
message: state.messageList[index].message,
|
message: state.messageList[index].message,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-12 23:48:54
|
* @Date : 2022-10-12 23:48:54
|
||||||
* @LastEditTime : 2022-10-18 11:25:36
|
* @LastEditTime : 2022-10-23 16:30:08
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -14,9 +14,20 @@ class MessageInfo extends Equatable {
|
|||||||
|
|
||||||
const MessageInfo({
|
const MessageInfo({
|
||||||
this.message,
|
this.message,
|
||||||
required this.targetUser
|
required this.targetUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MessageInfo copyWith({
|
||||||
|
Message? message,
|
||||||
|
int? targetUser,
|
||||||
|
int? unreadCount
|
||||||
|
}) {
|
||||||
|
return MessageInfo(
|
||||||
|
message: message ?? this.message,
|
||||||
|
targetUser: targetUser ?? this.targetUser,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [message?.contentmd5 ?? '', targetUser];
|
List<Object> get props => [message?.contentmd5 ?? '', targetUser];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-13 13:17:52
|
* @Date : 2022-10-13 13:17:52
|
||||||
* @LastEditTime : 2022-10-23 10:09:09
|
* @LastEditTime : 2022-10-23 17:55:44
|
||||||
* @Description :
|
* @Description :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -10,6 +10,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:tcp_client/chat/chat_page.dart';
|
import 'package:tcp_client/chat/chat_page.dart';
|
||||||
import 'package:tcp_client/common/avatar/avatar.dart';
|
import 'package:tcp_client/common/avatar/avatar.dart';
|
||||||
import 'package:tcp_client/common/username/username.dart';
|
import 'package:tcp_client/common/username/username.dart';
|
||||||
|
import 'package:tcp_client/home/view/message_page/cubit/msg_tile/msg_tile_cubit.dart';
|
||||||
|
import 'package:tcp_client/home/view/message_page/cubit/msg_tile/msg_tile_state.dart';
|
||||||
import 'package:tcp_client/repositories/common_models/message.dart';
|
import 'package:tcp_client/repositories/common_models/message.dart';
|
||||||
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
|
||||||
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
||||||
@ -27,118 +29,168 @@ class MessageTile extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return IntrinsicHeight(
|
return BlocProvider<MessageTileCubit>(
|
||||||
child: Stack(
|
key: ValueKey(userID),
|
||||||
fit: StackFit.expand,
|
create: (context) {
|
||||||
children: [
|
return MessageTileCubit(
|
||||||
InkWell(
|
tcpRepository: context.read<TCPRepository>(),
|
||||||
onTap: () {
|
localServiceRepository: context.read<LocalServiceRepository>(),
|
||||||
Navigator.of(context).push(ChatPage.route(
|
targetID: userID
|
||||||
userRepository: context.read<UserRepository>(),
|
);
|
||||||
localServiceRepository: context.read<LocalServiceRepository>(),
|
},
|
||||||
tcpRepository: context.read<TCPRepository>(),
|
child: Builder(
|
||||||
userID: userID
|
key: ValueKey(userID),
|
||||||
));
|
builder: (context) => IntrinsicHeight(
|
||||||
},
|
child: Stack(
|
||||||
),
|
fit: StackFit.expand,
|
||||||
Padding(
|
children: [
|
||||||
padding: const EdgeInsets.symmetric(
|
InkWell(
|
||||||
vertical: 8.0,
|
onTap: () {
|
||||||
horizontal: 24.0
|
if(message != null) {
|
||||||
),
|
context.read<LocalServiceRepository>().setReadHistory(
|
||||||
child: Row(
|
userid: message!.recieverID == userID ? message!.senderID : message!.recieverID,
|
||||||
mainAxisSize: MainAxisSize.max,
|
targetid: userID,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
timestamp: message!.timeStamp
|
||||||
children: [
|
);
|
||||||
IgnorePointer(
|
}
|
||||||
child: UserAvatar(userid: userID),
|
context.read<MessageTileCubit>().clearUnread();
|
||||||
|
Navigator.of(context).push(ChatPage.route(
|
||||||
|
userRepository: context.read<UserRepository>(),
|
||||||
|
localServiceRepository: context.read<LocalServiceRepository>(),
|
||||||
|
tcpRepository: context.read<TCPRepository>(),
|
||||||
|
userID: userID
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 8.0,
|
||||||
|
horizontal: 24.0
|
||||||
),
|
),
|
||||||
// if(userInfo.avatarEncoded != null && userInfo.avatarEncoded!.isEmpty)
|
child: Row(
|
||||||
// Container(
|
mainAxisSize: MainAxisSize.max,
|
||||||
// decoration: BoxDecoration(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
// borderRadius: BorderRadius.circular(5.0),
|
children: [
|
||||||
// border: Border.all(
|
IgnorePointer(
|
||||||
// color: Colors.grey[700]!,
|
child: UserAvatar(userid: userID),
|
||||||
// width: 1.0
|
),
|
||||||
// )
|
// if(userInfo.avatarEncoded != null && userInfo.avatarEncoded!.isEmpty)
|
||||||
// ),
|
// Container(
|
||||||
// child: ClipRRect(
|
// decoration: BoxDecoration(
|
||||||
// borderRadius: BorderRadius.circular(5.0),
|
// borderRadius: BorderRadius.circular(5.0),
|
||||||
// child: OverflowBox(
|
// border: Border.all(
|
||||||
// alignment: Alignment.center,
|
// color: Colors.grey[700]!,
|
||||||
// child: FittedBox(
|
// width: 1.0
|
||||||
// fit: BoxFit.fitWidth,
|
// )
|
||||||
// child: Image.memory(base64Decode(userInfo.avatarEncoded!)),
|
// ),
|
||||||
// ),
|
// child: ClipRRect(
|
||||||
// )
|
// borderRadius: BorderRadius.circular(5.0),
|
||||||
// ),
|
// child: OverflowBox(
|
||||||
// ),
|
// alignment: Alignment.center,
|
||||||
// if(userInfo.avatarEncoded == null || userInfo.avatarEncoded!.isEmpty)
|
// child: FittedBox(
|
||||||
// Container(
|
// fit: BoxFit.fitWidth,
|
||||||
// color: Colors.grey,
|
// child: Image.memory(base64Decode(userInfo.avatarEncoded!)),
|
||||||
// decoration: BoxDecoration(
|
// ),
|
||||||
// borderRadius: BorderRadius.circular(5.0),
|
// )
|
||||||
// border: Border.all(
|
// ),
|
||||||
// color: Colors.grey[700]!,
|
// ),
|
||||||
// width: 1.0
|
// if(userInfo.avatarEncoded == null || userInfo.avatarEncoded!.isEmpty)
|
||||||
// )
|
// Container(
|
||||||
// ),
|
// color: Colors.grey,
|
||||||
// ),
|
// decoration: BoxDecoration(
|
||||||
const SizedBox(width: 16,),
|
// borderRadius: BorderRadius.circular(5.0),
|
||||||
Expanded(
|
// border: Border.all(
|
||||||
child: Column(
|
// color: Colors.grey[700]!,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
// width: 1.0
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
// )
|
||||||
children: [
|
// ),
|
||||||
const SizedBox(height: 6,),
|
// ),
|
||||||
Padding(
|
const SizedBox(width: 16,),
|
||||||
padding: const EdgeInsets.symmetric(
|
Expanded(
|
||||||
vertical: 2.0,
|
child: Column(
|
||||||
horizontal: 0
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
child: IgnorePointer(
|
children: [
|
||||||
child: UserNameText(userid: userID, fontWeight: FontWeight.bold,),
|
const SizedBox(height: 6,),
|
||||||
),
|
Padding(
|
||||||
),
|
padding: const EdgeInsets.symmetric(
|
||||||
Padding(
|
vertical: 2.0,
|
||||||
padding: const EdgeInsets.symmetric(
|
horizontal: 0
|
||||||
vertical: 2.0
|
),
|
||||||
),
|
child: IgnorePointer(
|
||||||
child: IgnorePointer(
|
child: UserNameText(userid: userID, fontWeight: FontWeight.bold,),
|
||||||
child: Text(
|
|
||||||
message?.type == MessageType.image ? '[Image]' : message?.contentDecoded ?? '',
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 2.0
|
||||||
|
),
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: Text(
|
||||||
|
message?.type == MessageType.image ? '[Image]' : message?.contentDecoded ?? '',
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 6,),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6,),
|
),
|
||||||
],
|
Column(
|
||||||
),
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
if(message != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 8.0,
|
||||||
|
bottom: 8.0
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: Text(
|
||||||
|
getTimeStamp(message!.timeStamp)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BlocBuilder<MessageTileCubit, MessageTileState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return state.unreadCount == 0 ? Container() : Container(
|
||||||
|
margin: const EdgeInsets.only(
|
||||||
|
bottom: 8.0
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 10.0,
|
||||||
|
vertical: 4.0
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(50),
|
||||||
|
color: Colors.blue.withOpacity(0.9)
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'${state.unreadCount > 99 ? '99+' : state.unreadCount}',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
if(message != null)
|
),
|
||||||
Padding(
|
],
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
vertical: 8.0,
|
|
||||||
horizontal: 0
|
|
||||||
),
|
|
||||||
child: Align(
|
|
||||||
alignment: Alignment.topCenter,
|
|
||||||
child: IgnorePointer(
|
|
||||||
child: Text(
|
|
||||||
getTimeStamp(message!.timeStamp)
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : Linloir
|
* @Author : Linloir
|
||||||
* @Date : 2022-10-11 10:56:02
|
* @Date : 2022-10-11 10:56:02
|
||||||
* @LastEditTime : 2022-10-23 13:49:23
|
* @LastEditTime : 2022-10-23 17:10:13
|
||||||
* @Description : Local Service Repository
|
* @Description : Local Service Repository
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -73,29 +73,38 @@ class LocalServiceRepository {
|
|||||||
);
|
);
|
||||||
'''
|
'''
|
||||||
);
|
);
|
||||||
|
await txn.execute(
|
||||||
|
'''
|
||||||
|
create table readhistory (
|
||||||
|
userid int not null,
|
||||||
|
targetid int not null,
|
||||||
|
timestamp int not null,
|
||||||
|
primary key (userid, targetid)
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
);
|
||||||
});
|
});
|
||||||
// await db.execute(
|
}
|
||||||
// '''
|
|
||||||
// create table msgs (
|
static Future<void> _updateDatabaseToVer2(Database db) async {
|
||||||
// userid integer not null,
|
await db.transaction((txn) async {
|
||||||
// targetid integer not null,
|
db.execute(
|
||||||
// contenttype text not null,
|
'''
|
||||||
// content text not null,
|
create table readhistory (
|
||||||
// timestamp int not null,
|
userid int not null,
|
||||||
// md5encoded text primary key,
|
targetid int not null,
|
||||||
// filemd5 text
|
timestamp int not null,
|
||||||
// );
|
primary key (userid, targetid)
|
||||||
// create table users (
|
)
|
||||||
// userid integer primary key,
|
'''
|
||||||
// username text not null,
|
);
|
||||||
// avatar text
|
});
|
||||||
// );
|
}
|
||||||
// create table files (
|
|
||||||
// filemd5 text primary key,
|
static FutureOr<void> _onDatabaseUpgrade(Database db, int curVer, int newVer) async {
|
||||||
// dir text not null
|
if(curVer == 1 && newVer == 2) {
|
||||||
// );
|
await _updateDatabaseToVer2(db);
|
||||||
// '''
|
}
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<LocalServiceRepository> create({
|
static Future<LocalServiceRepository> create({
|
||||||
@ -104,8 +113,9 @@ class LocalServiceRepository {
|
|||||||
}) async {
|
}) async {
|
||||||
var database = await openDatabase(
|
var database = await openDatabase(
|
||||||
databaseFilePath,
|
databaseFilePath,
|
||||||
version: 1,
|
version: 2,
|
||||||
onCreate: _onDatabaseCreate
|
onCreate: _onDatabaseCreate,
|
||||||
|
onUpgrade: _onDatabaseUpgrade,
|
||||||
);
|
);
|
||||||
return LocalServiceRepository._internal(database: database);
|
return LocalServiceRepository._internal(database: database);
|
||||||
}
|
}
|
||||||
@ -457,4 +467,94 @@ class LocalServiceRepository {
|
|||||||
var imageContent = await image.readAsBytes();
|
var imageContent = await image.readAsBytes();
|
||||||
return imageContent;
|
return imageContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> setReadHistory({
|
||||||
|
required int userid,
|
||||||
|
required int targetid,
|
||||||
|
required int timestamp
|
||||||
|
}) async {
|
||||||
|
await _database.transaction((txn) async {
|
||||||
|
var result = await txn.query(
|
||||||
|
'readhistory',
|
||||||
|
where: 'userid = ? and targetid = ?',
|
||||||
|
whereArgs: [
|
||||||
|
userid,
|
||||||
|
targetid
|
||||||
|
]
|
||||||
|
);
|
||||||
|
if(result.isEmpty) {
|
||||||
|
await txn.insert(
|
||||||
|
'readhistory',
|
||||||
|
{
|
||||||
|
'userid': userid,
|
||||||
|
'targetid': targetid,
|
||||||
|
'timestamp': timestamp
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(result[0]['timestamp'] as int > timestamp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await txn.update(
|
||||||
|
'readhistory',
|
||||||
|
{
|
||||||
|
'timestamp': timestamp
|
||||||
|
},
|
||||||
|
where: 'userid = ? and targetid = ?',
|
||||||
|
whereArgs: [
|
||||||
|
userid,
|
||||||
|
targetid
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> fetchReadHistory({
|
||||||
|
required int userid,
|
||||||
|
required int targetid
|
||||||
|
}) async {
|
||||||
|
return await _database.transaction<int>((txn) async {
|
||||||
|
var result = await txn.query(
|
||||||
|
'readhistory',
|
||||||
|
where: 'userid = ? and targetid = ?',
|
||||||
|
whereArgs: [
|
||||||
|
userid,
|
||||||
|
targetid,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
if(result.isEmpty) {
|
||||||
|
txn.insert(
|
||||||
|
'readhistory',
|
||||||
|
{
|
||||||
|
'userid': userid,
|
||||||
|
'targetid': targetid,
|
||||||
|
'timestamp': 0
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return result[0]['timestamp'] as int;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> getUnreadCount({
|
||||||
|
required int userid,
|
||||||
|
required int targetid
|
||||||
|
}) async {
|
||||||
|
return await _database.transaction<int>((txn) async {
|
||||||
|
var result = await txn.query(
|
||||||
|
'msgs left outer join readhistory on msgs.userid = readhistory.targetid and msgs.targetid = readhistory.userid',
|
||||||
|
columns: [
|
||||||
|
'msgs.md5encoded'
|
||||||
|
],
|
||||||
|
where: 'msgs.userid = ? and msgs.targetid = ? and msgs.timestamp > readhistory.timestamp',
|
||||||
|
whereArgs: [
|
||||||
|
targetid,
|
||||||
|
userid
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return result.length;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 2.0.1
|
version: 2.2.0
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.18.2 <3.0.0'
|
sdk: '>=2.18.2 <3.0.0'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user