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
|
||||
* @Date : 2022-10-13 14:03:56
|
||||
* @LastEditTime : 2022-10-23 13:07:08
|
||||
* @LastEditTime : 2022-10-23 17:22:46
|
||||
* @Description :
|
||||
*/
|
||||
|
||||
@ -209,6 +209,14 @@ class ChatCubit extends Cubit<ChatState> {
|
||||
if(response.type == TCPResponseType.forwardMessage) {
|
||||
response as ForwardMessageResponse;
|
||||
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
|
||||
//Emit new state
|
||||
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/view/contact_page/contact_page.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/profile_page/profile_page.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/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/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/tcp_repository/models/tcp_request.dart';
|
||||
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author : Linloir
|
||||
* @Date : 2022-10-12 23:38:31
|
||||
* @LastEditTime : 2022-10-21 23:14:02
|
||||
* @LastEditTime : 2022-10-23 16:30:24
|
||||
* @Description :
|
||||
*/
|
||||
|
||||
@ -9,7 +9,7 @@ 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_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/repositories/local_service_repository/local_service_repository.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
|
||||
* @Date : 2022-10-11 11:05:18
|
||||
* @LastEditTime : 2022-10-17 13:35:35
|
||||
* @LastEditTime : 2022-10-23 17:38:30
|
||||
* @Description :
|
||||
*/
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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_state.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/msg_list_state.dart';
|
||||
import 'package:tcp_client/home/view/message_page/view/message_tile.dart';
|
||||
|
||||
class MessagePage extends StatelessWidget {
|
||||
@ -31,6 +31,7 @@ class MessagePage extends StatelessWidget {
|
||||
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
itemBuilder: (context, index) {
|
||||
return MessageTile(
|
||||
key: ValueKey(state.messageList[index].targetUser),
|
||||
userID: state.messageList[index].targetUser,
|
||||
message: state.messageList[index].message,
|
||||
);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author : Linloir
|
||||
* @Date : 2022-10-12 23:48:54
|
||||
* @LastEditTime : 2022-10-18 11:25:36
|
||||
* @LastEditTime : 2022-10-23 16:30:08
|
||||
* @Description :
|
||||
*/
|
||||
|
||||
@ -14,9 +14,20 @@ class MessageInfo extends Equatable {
|
||||
|
||||
const MessageInfo({
|
||||
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
|
||||
List<Object> get props => [message?.contentmd5 ?? '', targetUser];
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author : Linloir
|
||||
* @Date : 2022-10-13 13:17:52
|
||||
* @LastEditTime : 2022-10-23 10:09:09
|
||||
* @LastEditTime : 2022-10-23 17:55:44
|
||||
* @Description :
|
||||
*/
|
||||
|
||||
@ -10,6 +10,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:tcp_client/chat/chat_page.dart';
|
||||
import 'package:tcp_client/common/avatar/avatar.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/local_service_repository/local_service_repository.dart';
|
||||
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
|
||||
@ -27,118 +29,168 @@ class MessageTile extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IntrinsicHeight(
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
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
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
IgnorePointer(
|
||||
child: UserAvatar(userid: userID),
|
||||
return BlocProvider<MessageTileCubit>(
|
||||
key: ValueKey(userID),
|
||||
create: (context) {
|
||||
return MessageTileCubit(
|
||||
tcpRepository: context.read<TCPRepository>(),
|
||||
localServiceRepository: context.read<LocalServiceRepository>(),
|
||||
targetID: userID
|
||||
);
|
||||
},
|
||||
child: Builder(
|
||||
key: ValueKey(userID),
|
||||
builder: (context) => IntrinsicHeight(
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if(message != null) {
|
||||
context.read<LocalServiceRepository>().setReadHistory(
|
||||
userid: message!.recieverID == userID ? message!.senderID : message!.recieverID,
|
||||
targetid: userID,
|
||||
timestamp: message!.timeStamp
|
||||
);
|
||||
}
|
||||
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)
|
||||
// Container(
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(5.0),
|
||||
// border: Border.all(
|
||||
// color: Colors.grey[700]!,
|
||||
// width: 1.0
|
||||
// )
|
||||
// ),
|
||||
// child: ClipRRect(
|
||||
// borderRadius: BorderRadius.circular(5.0),
|
||||
// child: OverflowBox(
|
||||
// alignment: Alignment.center,
|
||||
// child: FittedBox(
|
||||
// fit: BoxFit.fitWidth,
|
||||
// child: Image.memory(base64Decode(userInfo.avatarEncoded!)),
|
||||
// ),
|
||||
// )
|
||||
// ),
|
||||
// ),
|
||||
// if(userInfo.avatarEncoded == null || userInfo.avatarEncoded!.isEmpty)
|
||||
// Container(
|
||||
// color: Colors.grey,
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(5.0),
|
||||
// border: Border.all(
|
||||
// color: Colors.grey[700]!,
|
||||
// width: 1.0
|
||||
// )
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(width: 16,),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 6,),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 2.0,
|
||||
horizontal: 0
|
||||
),
|
||||
child: IgnorePointer(
|
||||
child: UserNameText(userid: userID, fontWeight: FontWeight.bold,),
|
||||
),
|
||||
),
|
||||
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,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
IgnorePointer(
|
||||
child: UserAvatar(userid: userID),
|
||||
),
|
||||
// if(userInfo.avatarEncoded != null && userInfo.avatarEncoded!.isEmpty)
|
||||
// Container(
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(5.0),
|
||||
// border: Border.all(
|
||||
// color: Colors.grey[700]!,
|
||||
// width: 1.0
|
||||
// )
|
||||
// ),
|
||||
// child: ClipRRect(
|
||||
// borderRadius: BorderRadius.circular(5.0),
|
||||
// child: OverflowBox(
|
||||
// alignment: Alignment.center,
|
||||
// child: FittedBox(
|
||||
// fit: BoxFit.fitWidth,
|
||||
// child: Image.memory(base64Decode(userInfo.avatarEncoded!)),
|
||||
// ),
|
||||
// )
|
||||
// ),
|
||||
// ),
|
||||
// if(userInfo.avatarEncoded == null || userInfo.avatarEncoded!.isEmpty)
|
||||
// Container(
|
||||
// color: Colors.grey,
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(5.0),
|
||||
// border: Border.all(
|
||||
// color: Colors.grey[700]!,
|
||||
// width: 1.0
|
||||
// )
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(width: 16,),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 6,),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 2.0,
|
||||
horizontal: 0
|
||||
),
|
||||
child: IgnorePointer(
|
||||
child: UserNameText(userid: userID, fontWeight: FontWeight.bold,),
|
||||
),
|
||||
),
|
||||
),
|
||||
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
|
||||
* @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
|
||||
*/
|
||||
|
||||
@ -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 (
|
||||
// userid integer not null,
|
||||
// targetid integer not null,
|
||||
// contenttype text not null,
|
||||
// content text not null,
|
||||
// timestamp int not null,
|
||||
// md5encoded text primary key,
|
||||
// filemd5 text
|
||||
// );
|
||||
// create table users (
|
||||
// userid integer primary key,
|
||||
// username text not null,
|
||||
// avatar text
|
||||
// );
|
||||
// create table files (
|
||||
// filemd5 text primary key,
|
||||
// dir text not null
|
||||
// );
|
||||
// '''
|
||||
// );
|
||||
}
|
||||
|
||||
static Future<void> _updateDatabaseToVer2(Database db) async {
|
||||
await db.transaction((txn) async {
|
||||
db.execute(
|
||||
'''
|
||||
create table readhistory (
|
||||
userid int not null,
|
||||
targetid int not null,
|
||||
timestamp int not null,
|
||||
primary key (userid, targetid)
|
||||
)
|
||||
'''
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
static FutureOr<void> _onDatabaseUpgrade(Database db, int curVer, int newVer) async {
|
||||
if(curVer == 1 && newVer == 2) {
|
||||
await _updateDatabaseToVer2(db);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<LocalServiceRepository> create({
|
||||
@ -104,8 +113,9 @@ class LocalServiceRepository {
|
||||
}) async {
|
||||
var database = await openDatabase(
|
||||
databaseFilePath,
|
||||
version: 1,
|
||||
onCreate: _onDatabaseCreate
|
||||
version: 2,
|
||||
onCreate: _onDatabaseCreate,
|
||||
onUpgrade: _onDatabaseUpgrade,
|
||||
);
|
||||
return LocalServiceRepository._internal(database: database);
|
||||
}
|
||||
@ -457,4 +467,94 @@ class LocalServiceRepository {
|
||||
var imageContent = await image.readAsBytes();
|
||||
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
|
||||
# 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.
|
||||
version: 2.0.1
|
||||
version: 2.2.0
|
||||
|
||||
environment:
|
||||
sdk: '>=2.18.2 <3.0.0'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user