diff --git a/lib/constants/socket_events.dart b/lib/constants/socket_events.dart index ef8a7e8..6361829 100644 --- a/lib/constants/socket_events.dart +++ b/lib/constants/socket_events.dart @@ -32,4 +32,8 @@ class SocketEvent { static const String sendPodNameSSC = 'SEND_POD_NAME_SSC'; static const String reconnect = 'reconnect_CSS'; static const String destroy = 'destroy'; + + static const String sendMessageSSC = 'SEND_MESSAGE_SSC'; + static const String updateMessageSSC = 'UPDATE_MESSAGE_SSC'; + static const String deleteMessageSSC = 'DELETE_MESSAGE_SSC'; } diff --git a/lib/core/api/meetings/repositories/meeting_repository.dart b/lib/core/api/meetings/repositories/meeting_repository.dart index 833d6ff..7ed4bcf 100644 --- a/lib/core/api/meetings/repositories/meeting_repository.dart +++ b/lib/core/api/meetings/repositories/meeting_repository.dart @@ -107,7 +107,7 @@ class MeetingRepositoryImpl extends MeetingRepository { final int indexOfMyParticipant = participants.lastIndexWhere( (participant) => participantId != null ? participant.id == participantId - : participant.user.id == userId, + : participant.user?.id == userId, ); if (indexOfMyParticipant == -1) return meeting; diff --git a/lib/core/api/messages/datasources/message_remote_datasource.dart b/lib/core/api/messages/datasources/message_remote_datasource.dart index 5fc8fb4..a4a47a4 100644 --- a/lib/core/api/messages/datasources/message_remote_datasource.dart +++ b/lib/core/api/messages/datasources/message_remote_datasource.dart @@ -17,11 +17,11 @@ abstract class MessageRemoteDataSource { required int meetingId, required String data, }); - Future editMessage({ + Future editMessage({ required int messageId, required String data, }); - Future deleteMessage({required int messageId}); + Future deleteMessage({required int messageId}); } @LazySingleton(as: MessageRemoteDataSource) @@ -70,7 +70,7 @@ class MessageRemoteDataSourceImpl extends MessageRemoteDataSource { } @override - Future editMessage({ + Future editMessage({ required int messageId, required String data, }) async { @@ -79,15 +79,23 @@ class MessageRemoteDataSourceImpl extends MessageRemoteDataSource { {"data": data}, ); - return [StatusCode.ok, StatusCode.created].contains(response.statusCode); + if ([StatusCode.ok, StatusCode.created].contains(response.statusCode)) { + return MessageModel.fromMap(response.data); + } + + return null; } @override - Future deleteMessage({required int messageId}) async { + Future deleteMessage({required int messageId}) async { final Response response = await _remoteData.deleteRoute( "${ApiEndpoints.chats}/$messageId", ); - return [StatusCode.ok, StatusCode.created].contains(response.statusCode); + if ([StatusCode.ok, StatusCode.created].contains(response.statusCode)) { + return MessageModel.fromMap(response.data); + } + + return null; } } diff --git a/lib/core/api/messages/repositories/message_repository.dart b/lib/core/api/messages/repositories/message_repository.dart index d7d4732..4ddbdbb 100644 --- a/lib/core/api/messages/repositories/message_repository.dart +++ b/lib/core/api/messages/repositories/message_repository.dart @@ -14,8 +14,11 @@ abstract class MessageRepository { required int meetingId, required String data, }); - Future editMessage({required int messageId, required String data}); - Future deleteMessage({required int messageId}); + Future editMessage({ + required int messageId, + required String data, + }); + Future deleteMessage({required int messageId}); } @LazySingleton(as: MessageRepository) @@ -27,22 +30,22 @@ class MessageRepositoryImpl extends MessageRepository { ); @override - Future deleteMessage({required int messageId}) async { - final bool isSucceed = + Future deleteMessage({required int messageId}) async { + final MessageModel? messageModel = await _remoteDataSource.deleteMessage(messageId: messageId); - return isSucceed; + return messageModel; } @override - Future editMessage({ + Future editMessage({ required int messageId, required String data, }) async { - final bool isSucceed = + final MessageModel? messageModel = await _remoteDataSource.editMessage(messageId: messageId, data: data); - return isSucceed; + return messageModel; } @override diff --git a/lib/core/websocket/socket_handler.dart b/lib/core/websocket/socket_handler.dart index 8821548..3fb140d 100644 --- a/lib/core/websocket/socket_handler.dart +++ b/lib/core/websocket/socket_handler.dart @@ -277,6 +277,30 @@ class SocketHandlerImpl extends SocketHandler { ); } }); + + _socket?.on(SocketEvent.sendMessageSSC, (data) { + if (data == null) return; + + WaterbusSdk.onMesssageChanged?.call( + MessageSocketEvent(event: MessageEventEnum.create, data: data), + ); + }); + + _socket?.on(SocketEvent.updateMessageSSC, (data) { + if (data == null) return; + + WaterbusSdk.onMesssageChanged?.call( + MessageSocketEvent(event: MessageEventEnum.update, data: data), + ); + }); + + _socket?.on(SocketEvent.deleteMessageSSC, (data) { + if (data == null) return; + + WaterbusSdk.onMesssageChanged?.call( + MessageSocketEvent(event: MessageEventEnum.delete, data: data), + ); + }); }); } diff --git a/lib/flutter_waterbus_sdk.dart b/lib/flutter_waterbus_sdk.dart index feecabc..0d3acec 100644 --- a/lib/flutter_waterbus_sdk.dart +++ b/lib/flutter_waterbus_sdk.dart @@ -19,9 +19,15 @@ class WaterbusSdk { static String apiUrl = ''; static String wsUrl = ''; static String apiKey = ''; + static String privateMessageKey = ''; static Function(CallbackPayload)? onEventChanged; static Function(VideoSenderStats)? onStatsChanged; static Function(Subtitle)? onSubtitle; + static Function(MessageSocketEvent)? onMesssageChanged; + + set onMessageSocketChanged(Function(MessageSocketEvent) onMesssageChanged) { + WaterbusSdk.onMesssageChanged = onMesssageChanged; + } set onEventChangedRegister(Function(CallbackPayload) onEventChanged) { WaterbusSdk.onEventChanged = onEventChanged; @@ -38,11 +44,13 @@ class WaterbusSdk { Future initializeApp({ required String wsUrl, required String apiUrl, + required String privateMessageKey, String apiKey = 'waterbus@2024', }) async { WaterbusSdk.wsUrl = wsUrl; WaterbusSdk.apiUrl = apiUrl; WaterbusSdk.apiKey = apiKey; + WaterbusSdk.privateMessageKey = privateMessageKey; // Init dependency injection if needed if (!getIt.isRegistered()) { @@ -268,14 +276,14 @@ class WaterbusSdk { return await _sdk.sendMessage(meetingId: meetingId, data: data); } - Future editMessage({ + Future editMessage({ required int messageId, required String data, }) async { return await _sdk.editMessage(messageId: messageId, data: data); } - Future deleteMessage({required int messageId}) async { + Future deleteMessage({required int messageId}) async { return await _sdk.deleteMessage(messageId: messageId); } diff --git a/lib/types/models/index.dart b/lib/types/models/index.dart index 3a6bac3..35b85d1 100644 --- a/lib/types/models/index.dart +++ b/lib/types/models/index.dart @@ -16,3 +16,4 @@ export 'status_seen_message.dart'; export 'message_model.dart'; export 'media_source.dart'; export 'subtitle.dart'; +export 'message_socket_event.dart'; diff --git a/lib/types/models/meeting_model.dart b/lib/types/models/meeting_model.dart index a16a171..c9e05c3 100644 --- a/lib/types/models/meeting_model.dart +++ b/lib/types/models/meeting_model.dart @@ -148,14 +148,14 @@ class Meeting { final int numberOfPaticipants = participants.length; if (numberOfPaticipants == 1) { - return '${participants[0].user.fullName} is in the room'; + return '${participants[0].user?.fullName} is in the room'; } else if (numberOfPaticipants == 2) { - return '${participants[0].user.fullName} and ${participants[1].user.fullName} are in the room'; + return '${participants[0].user?.fullName} and ${participants[1].user?.fullName} are in the room'; } else { final int otherParticipants = numberOfPaticipants - 2; final String participantList = participants .sublist(0, 2) - .map((participant) => participant.user.fullName) + .map((participant) => participant.user?.fullName ?? "") .join(', '); return '$participantList and $otherParticipants others are in the room'; } diff --git a/lib/types/models/message_model.dart b/lib/types/models/message_model.dart index 3b40256..d58c29d 100644 --- a/lib/types/models/message_model.dart +++ b/lib/types/models/message_model.dart @@ -4,12 +4,14 @@ import 'dart:convert'; import 'package:waterbus_sdk/types/index.dart'; import 'package:waterbus_sdk/types/models/message_status_enum.dart'; +import 'package:waterbus_sdk/types/models/sending_status_enum.dart'; class MessageModel { final int id; String data; final int meeting; final User? createdBy; + SendingStatusEnum sendingStatus; MessageStatusEnum status; final int type; final DateTime createdAt; @@ -19,7 +21,8 @@ class MessageModel { required this.data, required this.meeting, required this.createdBy, - this.status = MessageStatusEnum.sent, + this.sendingStatus = SendingStatusEnum.sent, + required this.status, required this.type, required this.createdAt, required this.updatedAt, @@ -30,6 +33,7 @@ class MessageModel { String? data, int? meeting, User? createdBy, + SendingStatusEnum? sendingStatus, MessageStatusEnum? status, int? type, DateTime? createdAt, @@ -40,6 +44,7 @@ class MessageModel { data: data ?? this.data, meeting: meeting ?? this.meeting, createdBy: createdBy ?? this.createdBy, + sendingStatus: sendingStatus ?? this.sendingStatus, status: status ?? this.status, type: type ?? this.type, createdAt: createdAt ?? this.createdAt, @@ -53,7 +58,8 @@ class MessageModel { 'data': data, 'meeting': meeting, 'createdBy': createdBy, - 'status': status, + 'sendingStatus': sendingStatus.status, + 'status': status.status, 'type': type, 'createdAt': createdAt.toString(), 'updatedAt': updatedAt.toString(), @@ -68,6 +74,8 @@ class MessageModel { ? map['meeting']['id'] : map['meeting']) ?? 0, + status: + (int.tryParse(map['status']?.toString() ?? "") ?? 0).getMessageStatus, createdBy: map['createdBy'] != null && map['createdBy'] is Map ? User.fromMap(map['createdBy']) @@ -83,6 +91,8 @@ class MessageModel { factory MessageModel.fromMapSocket(Map map) { return MessageModel( id: map['id'] ?? 0, + status: + (int.tryParse(map['status']?.toString() ?? "") ?? 0).getMessageStatus, data: map['data'] ?? "", meeting: (map['meeting'] is Map ? map['meeting']['id'] @@ -109,7 +119,7 @@ class MessageModel { @override String toString() { - return 'MessageModel(id: $id, data: $data, meeting: $meeting, type: $type, createdAt: $createdAt, updatedAt: $updatedAt, createdBy: $createdBy, status: $status)'; + return 'MessageModel(id: $id, data: $data, meeting: $meeting, type: $type, createdAt: $createdAt, updatedAt: $updatedAt, createdBy: $createdBy, status: $sendingStatus)'; } @override @@ -123,7 +133,7 @@ class MessageModel { other.type == type && other.updatedAt == updatedAt && other.createdAt == createdAt && - other.status == status; + other.sendingStatus == sendingStatus; } @override @@ -135,6 +145,8 @@ class MessageModel { type.hashCode ^ updatedAt.hashCode ^ createdAt.hashCode ^ - status.hashCode; + sendingStatus.hashCode; } + + bool get isDeleted => status == MessageStatusEnum.inactive; } diff --git a/lib/types/models/message_socket_event.dart b/lib/types/models/message_socket_event.dart new file mode 100644 index 0000000..1572063 --- /dev/null +++ b/lib/types/models/message_socket_event.dart @@ -0,0 +1,10 @@ +enum MessageEventEnum { create, update, delete } + +class MessageSocketEvent { + final MessageEventEnum event; + final Map data; + MessageSocketEvent({ + required this.event, + required this.data, + }); +} diff --git a/lib/types/models/message_status_enum.dart b/lib/types/models/message_status_enum.dart index 35323a2..68f215d 100644 --- a/lib/types/models/message_status_enum.dart +++ b/lib/types/models/message_status_enum.dart @@ -1,7 +1,6 @@ enum MessageStatusEnum { - error(-1), - sending(0), - sent(1); + inactive(1), + active(0); const MessageStatusEnum(this.status); @@ -13,7 +12,7 @@ extension MessageStatusEnumX on int { final int index = MessageStatusEnum.values.indexWhere((status) => status.status == this); - if (index == -1) return MessageStatusEnum.sending; + if (index == -1) return MessageStatusEnum.inactive; return MessageStatusEnum.values[index]; } diff --git a/lib/types/models/participant_model.dart b/lib/types/models/participant_model.dart index cd696b3..bda0eb2 100644 --- a/lib/types/models/participant_model.dart +++ b/lib/types/models/participant_model.dart @@ -8,7 +8,7 @@ import 'package:waterbus_sdk/types/models/user_model.dart'; class Participant extends Equatable { final int id; - final User user; + final User? user; final bool isMe; const Participant({ required this.id, @@ -31,7 +31,7 @@ class Participant extends Equatable { Map toMap() { return { 'id': id, - 'user': user.toMap(), + 'user': user?.toMap(), 'isMe': isMe, }; } @@ -39,7 +39,9 @@ class Participant extends Equatable { factory Participant.fromMap(Map map) { return Participant( id: map['id'] as int, - user: User.fromMap(map['user'] as Map), + user: map['user'] != null && map['user'] is Map + ? User.fromMap(map['user']) + : null, isMe: map['isMe'] ?? false, ); } @@ -64,10 +66,6 @@ class Participant extends Equatable { @override List get props { - return [ - id, - user, - isMe, - ]; + return [id, isMe]; } } diff --git a/lib/types/models/sending_status_enum.dart b/lib/types/models/sending_status_enum.dart new file mode 100644 index 0000000..8317e2f --- /dev/null +++ b/lib/types/models/sending_status_enum.dart @@ -0,0 +1,20 @@ +enum SendingStatusEnum { + error(-1), + sending(0), + sent(1); + + const SendingStatusEnum(this.status); + + final int status; +} + +extension SendingStatusEnumX on int { + SendingStatusEnum get getSendingStatus { + final int index = + SendingStatusEnum.values.indexWhere((status) => status.status == this); + + if (index == -1) return SendingStatusEnum.sending; + + return SendingStatusEnum.values[index]; + } +} diff --git a/lib/waterbus_sdk_impl.dart b/lib/waterbus_sdk_impl.dart index 4b969eb..3920d61 100644 --- a/lib/waterbus_sdk_impl.dart +++ b/lib/waterbus_sdk_impl.dart @@ -317,7 +317,7 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future editMessage({ + Future editMessage({ required int messageId, required String data, }) async { @@ -328,7 +328,7 @@ class SdkCore extends WaterbusSdkInterface { } @override - Future deleteMessage({required int messageId}) async { + Future deleteMessage({required int messageId}) async { return await _messageRepository.deleteMessage(messageId: messageId); } diff --git a/lib/waterbus_sdk_interface.dart b/lib/waterbus_sdk_interface.dart index 6ce6857..2945cd5 100644 --- a/lib/waterbus_sdk_interface.dart +++ b/lib/waterbus_sdk_interface.dart @@ -49,8 +49,11 @@ abstract class WaterbusSdkInterface { required int meetingId, required String data, }); - Future editMessage({required int messageId, required String data}); - Future deleteMessage({required int messageId}); + Future editMessage({ + required int messageId, + required String data, + }); + Future deleteMessage({required int messageId}); // Meeting Future createRoom({