From 66c6f17b9994b9a3b17b6191ba5e18536f408188 Mon Sep 17 00:00:00 2001 From: ksenia312 Date: Tue, 6 Feb 2024 22:24:58 +0100 Subject: [PATCH] feat(lib): create responses to text messages --- example_full/lib/domain/app_service.dart | 41 ++++---- .../presentation/listener/files_listener.dart | 17 ++++ .../listener/messages_listener.dart | 56 +++++++++++ .../presentation/view/communication_view.dart | 2 +- .../lib/presentation/view/connected_view.dart | 58 ++--------- example_full/lib/uikit/app_snack_bar.dart | 4 +- ios/Classes/Models/NearbyMessageContent.swift | 97 ++++++++++--------- ios/Classes/NearbyNotificationReceiver.swift | 4 + lib/src/base/nearby_message_content_base.dart | 36 ++++--- lib/src/model/nearby_message_content.dart | 85 ++++++---------- .../model/nearby_message_content_type.dart | 18 +++- .../socket_service/file_sockets_manager.dart | 9 +- .../socket_service/nearby_socket_service.dart | 50 +++++----- lib/src/platforms/ios/nearby_ios_service.dart | 22 +++-- lib/src/utils/stream_mapper.dart | 19 ++-- 15 files changed, 285 insertions(+), 233 deletions(-) create mode 100644 example_full/lib/presentation/listener/files_listener.dart create mode 100644 example_full/lib/presentation/listener/messages_listener.dart diff --git a/example_full/lib/domain/app_service.dart b/example_full/lib/domain/app_service.dart index 88d08b0..c7a9d65 100644 --- a/example_full/lib/domain/app_service.dart +++ b/example_full/lib/domain/app_service.dart @@ -314,20 +314,14 @@ extension CommunicationChannelExtension on AppService { } extension MessagingExtension on AppService { - void sendMessage(String message) { - try { - if (connectedDevice == null) return; - _nearbyService.send( - OutgoingNearbyMessage( - content: NearbyMessageTextContent(value: message), - receiver: connectedDevice!.info, - ), - ); - } catch (e) { - if (kDebugMode) { - print(e); - } - } + void sendTextRequest(String message) { + if (connectedDevice == null) return; + _nearbyService.send( + OutgoingNearbyMessage( + content: NearbyMessageTextRequest.create(value: message), + receiver: connectedDevice!.info, + ), + ); } void sendFilesRequest(List paths) { @@ -344,15 +338,24 @@ extension MessagingExtension on AppService { ); } - void sendFilesResponse(String requestId, {required bool response}) { + void sendTextResponse(String requestId) { if (connectedDevice == null) return; + _nearbyService.send( OutgoingNearbyMessage( receiver: connectedDevice!.info, - content: NearbyMessageFilesResponse( - id: requestId, - response: response, - ), + content: NearbyMessageTextResponse(id: requestId), + ), + ); + } + + void sendFilesResponse(String requestId, {required bool response}) { + if (connectedDevice == null) return; + print('send'); + _nearbyService.send( + OutgoingNearbyMessage( + receiver: connectedDevice!.info, + content: NearbyMessageFilesResponse(id: requestId, isAccepted: response), ), ); } diff --git a/example_full/lib/presentation/listener/files_listener.dart b/example_full/lib/presentation/listener/files_listener.dart new file mode 100644 index 0000000..7154085 --- /dev/null +++ b/example_full/lib/presentation/listener/files_listener.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'package:nearby_service/nearby_service.dart'; +import 'package:nearby_service_example_full/uikit/uikit.dart'; + +class FilesListener { + FilesListener._(); + + static void call(BuildContext context, ReceivedNearbyFilesPack pack) { + final senderSubtitle = 'From ${pack.sender.displayName} ' + '(ID: ${pack.sender.id})'; + AppShackBar.show( + Scaffold.of(context).context, + '${pack.files.length} files saved! \n${pack.files.map((e) => e.name).join('\n')}', + subtitle: senderSubtitle, + ); + } +} diff --git a/example_full/lib/presentation/listener/messages_listener.dart b/example_full/lib/presentation/listener/messages_listener.dart new file mode 100644 index 0000000..1b332af --- /dev/null +++ b/example_full/lib/presentation/listener/messages_listener.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:nearby_service/nearby_service.dart'; +import 'package:nearby_service_example_full/domain/app_service.dart'; +import 'package:nearby_service_example_full/uikit/uikit.dart'; +import 'package:provider/provider.dart'; + +class MessagesListener { + MessagesListener._(); + + static void call(BuildContext context, ReceivedNearbyMessage message) { + final senderSubtitle = 'From ${message.sender.displayName} ' + '(ID: ${message.sender.id})'; + message.content.byType( + onTextRequest: (textRequest) { + AppShackBar.show( + Scaffold.of(context).context, + '${textRequest.value} (Message ID=${textRequest.id})', + subtitle: senderSubtitle, + )?.closed.whenComplete(() { + // mark as read + context.read().sendTextResponse(textRequest.id); + }); + }, + onTextResponse: (textResponse) { + AppShackBar.show( + Scaffold.of(context).context, + 'Your message with ID=${textResponse.id} was delivered to ${message.sender.displayName}', + ); + }, + onFilesRequest: (filesRequest) { + ActionDialog.show( + context, + title: 'Request to send ${filesRequest.files.length} files', + subtitle: senderSubtitle, + ).then( + // accept or dismiss the files request + (isAccepted) => context.read().sendFilesResponse( + filesRequest.id, + response: isAccepted ?? false, + ), + ); + }, + onFilesResponse: (filesResponse) { + AppShackBar.show( + Scaffold.of(context).context, + filesResponse.isAccepted + ? 'Request is accepted!' + : 'Request was denied :(', + subtitle: senderSubtitle, + actionType: + filesResponse.isAccepted ? ActionType.idle : ActionType.warning, + ); + }, + ); + } +} diff --git a/example_full/lib/presentation/view/communication_view.dart b/example_full/lib/presentation/view/communication_view.dart index b645195..09f075d 100644 --- a/example_full/lib/presentation/view/communication_view.dart +++ b/example_full/lib/presentation/view/communication_view.dart @@ -69,7 +69,7 @@ class _CommunicationViewState extends State { Flexible( child: ActionButton( title: 'Send', - onTap: () => service.sendMessage(message), + onTap: () => service.sendTextRequest(message), ), ), ], diff --git a/example_full/lib/presentation/view/connected_view.dart b/example_full/lib/presentation/view/connected_view.dart index d2201e0..f3eefde 100644 --- a/example_full/lib/presentation/view/connected_view.dart +++ b/example_full/lib/presentation/view/connected_view.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:nearby_service/nearby_service.dart'; import 'package:nearby_service_example_full/domain/app_service.dart'; +import 'package:nearby_service_example_full/presentation/listener/files_listener.dart'; +import 'package:nearby_service_example_full/presentation/listener/messages_listener.dart'; import 'package:nearby_service_example_full/uikit/uikit.dart'; import 'package:provider/provider.dart'; @@ -48,8 +50,14 @@ class ConnectedView extends StatelessWidget { ActionButton( title: 'Start communicate', onTap: () => service.startCommunicationChannel( - listener: (event) => _listener(context, event), - onFilesSaved: (files) => _onFileSaved(context, files), + listener: (event) => MessagesListener.call( + context, + event, + ), + onFilesSaved: (files) => FilesListener.call( + context, + files, + ), ), ) else @@ -64,50 +72,4 @@ class ConnectedView extends StatelessWidget { }, ); } - - void _listener(BuildContext context, ReceivedNearbyMessage message) { - final senderSubtitle = 'From ${message.sender.displayName} ' - '(ID: ${message.sender.id})'; - message.content.byType( - onText: (content) { - AppShackBar.show( - Scaffold.of(context).context, - content.value, - subtitle: senderSubtitle, - ); - }, - onFilesRequest: (content) { - ActionDialog.show( - context, - title: 'Request to send ${content.files.length} files', - subtitle: senderSubtitle, - ).then((value) { - if (value is bool) { - context.read().sendFilesResponse( - content.id, - response: value, - ); - } - }); - }, - onFilesResponse: (content) { - AppShackBar.show( - Scaffold.of(context).context, - content.response ? 'Request is accepted!' : 'Request was denied :(', - subtitle: senderSubtitle, - actionType: content.response ? ActionType.idle : ActionType.warning, - ); - }, - ); - } - - void _onFileSaved(BuildContext context, ReceivedNearbyFilesPack pack) { - final senderSubtitle = 'From ${pack.sender.displayName} ' - '(ID: ${pack.sender.id})'; - AppShackBar.show( - Scaffold.of(context).context, - '${pack.files.length} files saved! \n${pack.files.map((e) => e.name).join('\n')}', - subtitle: senderSubtitle, - ); - } } diff --git a/example_full/lib/uikit/app_snack_bar.dart b/example_full/lib/uikit/app_snack_bar.dart index 56cda1c..68ab527 100644 --- a/example_full/lib/uikit/app_snack_bar.dart +++ b/example_full/lib/uikit/app_snack_bar.dart @@ -15,12 +15,12 @@ class AppShackBar { SnackBar( content: RichText( text: TextSpan( - text: '$title \n', + text: title, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), children: [ if (subtitle != null) TextSpan( - text: subtitle, + text: '\n$subtitle', style: const TextStyle( fontWeight: FontWeight.normal, fontSize: 14, diff --git a/ios/Classes/Models/NearbyMessageContent.swift b/ios/Classes/Models/NearbyMessageContent.swift index 99058a6..9da4ab4 100644 --- a/ios/Classes/Models/NearbyMessageContent.swift +++ b/ios/Classes/Models/NearbyMessageContent.swift @@ -10,8 +10,9 @@ import MultipeerConnectivity class NearbyMessageContent { - init(type: MessageContentType) { + init(id: String, type: MessageContentType) { self.type = type + self.id = id } let type: MessageContentType @@ -19,8 +20,10 @@ class NearbyMessageContent { static func typedFromJson(json: [String: Any]) -> NearbyMessageContent? { if let typeString: String = json["type"] as? String { let type = MessageContentType.fromString(value: typeString) - if (type == MessageContentType.text) { - return NearbyMessageTextContent.fromJson(json: json) + if (type == MessageContentType.textRequest) { + return NearbyMessageTextRequest.fromJson(json: json) + } else if (type == MessageContentType.textResponse) { + return NearbyMessageTextResponse.fromJson(json: json) } else if (type == MessageContentType.filesRequest) { return NearbyMessageFilesRequest.fromJson(json: json) } else if (type == MessageContentType.filesResponse) { @@ -30,21 +33,30 @@ class NearbyMessageContent { return nil; } + static func fromJsonRaw(type: MessageContentType, json: [String: Any]) -> NearbyMessageContent? { + if let id: String = json["id"] as? String { + return NearbyMessageContent(id: id, type: type) + } + return nil; + } func toJson() -> [String : Any] { - return ["type": type.name] - } -} - -class NearbyMessageTextContent : NearbyMessageContent { - init(value: String) { - self.value = value - super.init(type: MessageContentType.text) + return ["type": type.name, "id": id] } - static func fromJson(json:[String: Any]) -> NearbyMessageTextContent? { - if let message: String = json["value"] as? String { - return NearbyMessageTextContent(value: message) + let id: String +} + +class NearbyMessageTextRequest : NearbyMessageContent { + init(id: String, value: String) { + self.value = value + super.init(id: id, type: MessageContentType.textRequest) + } + + static func fromJson(json:[String: Any]) -> NearbyMessageTextRequest? { + if let value: String = json["value"] as? String, + let content = NearbyMessageContent.fromJsonRaw(type: MessageContentType.textRequest, json:json) { + return NearbyMessageTextRequest(id: content.id, value: value) } return nil; } @@ -56,42 +68,33 @@ class NearbyMessageTextContent : NearbyMessageContent { let value: String } -class NearbyMessageFilesContent : NearbyMessageContent { +class NearbyMessageTextResponse :NearbyMessageContent { - init(id: String, type: MessageContentType) { - self.id = id - super.init(type: type) + init(id: String) { + super.init(id: id, type: MessageContentType.textResponse) } - static func fromJsonRaw(type: MessageContentType, json: [String: Any]) -> NearbyMessageFilesContent? { - if let id: String = json["id"] as? String{ - return NearbyMessageFilesContent(id: id, type: type) + static func fromJson( json: [String: Any]) -> NearbyMessageTextResponse? { + let content = NearbyMessageContent.fromJsonRaw(type: MessageContentType.textResponse, json: json) + if let requireContent = content { + return NearbyMessageTextResponse(id: requireContent.id) } - return nil; + return nil } - - override func toJson() -> [String : Any] { - return [ - "id": id, - ].merging( super.toJson()) { (current, _) in current} - } - - - let id: String } -class NearbyMessageFilesRequest : NearbyMessageFilesContent { +class NearbyMessageFilesRequest : NearbyMessageContent { init(files: Array, id: String) { self.files = files super.init(id: id, type: MessageContentType.filesRequest) } static func fromJson(json: [String: Any]) -> NearbyMessageFilesRequest? { - let message = NearbyMessageFilesContent.fromJsonRaw(type: MessageContentType.filesRequest, json: json) + let content = NearbyMessageContent.fromJsonRaw(type: MessageContentType.filesRequest, json: json) if let filesObjects: Array = json["files"] as? Array> { let files : [String]? = filesObjects.map({ $0["path"] as? String }).compactMap({$0}) - if let requireMessage = message { + if let requireContent = content { if let requireFiles = files { - return NearbyMessageFilesRequest(files: requireFiles, id: requireMessage.id) + return NearbyMessageFilesRequest(files: requireFiles, id: requireContent.id) } } } @@ -106,22 +109,22 @@ class NearbyMessageFilesRequest : NearbyMessageFilesContent { } } -class NearbyMessageFilesResponse : NearbyMessageFilesContent { +class NearbyMessageFilesResponse : NearbyMessageContent { init(id: String, response: Bool) { self.response = response super.init(id: id, type: MessageContentType.filesResponse) } static func fromJson( json: [String: Any]) -> NearbyMessageFilesResponse? { - let message = NearbyMessageFilesContent.fromJsonRaw(type: MessageContentType.filesResponse, json: json) + let message = NearbyMessageContent.fromJsonRaw(type: MessageContentType.filesResponse, json: json) if let requireMessage = message, - let response = json["response"] as? Bool { + let response = json["isAccepted"] as? Bool { return NearbyMessageFilesResponse(id: requireMessage.id, response: response) } return nil } override func toJson() -> [String : Any] { return [ - "response": response + "isAccepted": response ].merging( super.toJson()) { (current, _) in current} } @@ -130,25 +133,29 @@ class NearbyMessageFilesResponse : NearbyMessageFilesContent { enum MessageContentType { - case text + case textRequest + case textResponse case filesRequest case filesResponse static func fromString(value: String) -> MessageContentType { - if (value == text.name) { - return text - } else if (value == filesRequest.name) { + if (value == textRequest.name) { + return textRequest + } else if (value == textResponse.name) { + return textResponse + } else if (value == filesRequest.name) { return filesRequest } else if (value == filesResponse.name) { return filesResponse } else { - return text + return textRequest } } var name : String { switch self { - case .text: return "text" + case .textRequest: return "textRequest" + case .textResponse: return "textResponse" case .filesRequest: return "filesRequest" case .filesResponse: return "filesResponse" } diff --git a/ios/Classes/NearbyNotificationReceiver.swift b/ios/Classes/NearbyNotificationReceiver.swift index ee11241..aef686a 100644 --- a/ios/Classes/NearbyNotificationReceiver.swift +++ b/ios/Classes/NearbyNotificationReceiver.swift @@ -13,11 +13,15 @@ extension NearbyServicePlugin { @objc func onMessageReceived(notification: Notification) { DispatchQueue.main.async { if let userInfo = NearbyUserInfo.fromDictionary(userInfo: notification.userInfo) { + print(userInfo) if let message = NearbyMessage.fromUserInfo(userInfo: userInfo) { + print(message) if message.content is NearbyMessageFilesResponse { + print(message.content) let response = message.content as! NearbyMessageFilesResponse let cachedRequest = NearbyRequestsStore.instance.find(for: response.id) if (response.response && cachedRequest != nil) { + print("send") self.manager.sendFiles( id: cachedRequest!.id, paths: cachedRequest!.files, diff --git a/lib/src/base/nearby_message_content_base.dart b/lib/src/base/nearby_message_content_base.dart index 8c3922a..8a5d3fc 100644 --- a/lib/src/base/nearby_message_content_base.dart +++ b/lib/src/base/nearby_message_content_base.dart @@ -1,4 +1,5 @@ import 'package:nearby_service/nearby_service.dart'; +import 'package:nearby_service/src/utils/random.dart'; /// /// Abstraction for the message content. @@ -6,11 +7,14 @@ import 'package:nearby_service/nearby_service.dart'; /// determine, what type of content is it. /// abstract base class NearbyMessageContent { - const NearbyMessageContent(); + const NearbyMessageContent({required this.id}); + + NearbyMessageContent.create() + : id = RandomUtils.instance.nextInt(1000000, 9999999).toString(); /// /// Contains the conditional logic of creating [NearbyMessageFilesRequest], - /// [NearbyMessageFilesResponse] or [NearbyMessageTextContent] + /// [NearbyMessageFilesResponse] or [NearbyMessageTextRequest] /// by `type` field of [json]. /// static C fromJson( @@ -20,8 +24,10 @@ abstract base class NearbyMessageContent { final type = NearbyMessageContentType.values.firstWhere( (e) => e.name == json?['type'], ); - if (type.isText) { - return NearbyMessageTextContent.fromJson(json) as C; + if (type.isTextRequest) { + return NearbyMessageTextRequest.fromJson(json) as C; + } else if (type.isTextResponse) { + return NearbyMessageTextResponse.fromJson(json) as C; } else if (type.isFilesRequest) { return NearbyMessageFilesRequest.fromJson(json) as C; } else if (type.isFilesResponse) { @@ -34,9 +40,12 @@ abstract base class NearbyMessageContent { } } + final String id; + NearbyMessageContentType get _type { final type = byType( - onText: (_) => NearbyMessageContentType.text, + onTextRequest: (_) => NearbyMessageContentType.textRequest, + onTextResponse: (_) => NearbyMessageContentType.textResponse, onFilesRequest: (_) => NearbyMessageContentType.filesRequest, onFilesResponse: (_) => NearbyMessageContentType.filesResponse, ); @@ -51,11 +60,11 @@ abstract base class NearbyMessageContent { /// /// Check for the content if it is valid for sending or receiving. /// - bool get isValid; + bool get isValid => id.isNotEmpty; /// - /// * The [onText] callback returns this instance of [NearbyMessageContent], - /// cast as [NearbyMessageTextContent] if is a text. + /// * The [onTextRequest] callback returns this instance of [NearbyMessageContent], + /// cast as [NearbyMessageTextRequest] if is a text. /// /// * The [onFilesRequest] callback returns this instance of [NearbyMessageContent], /// cast as [NearbyMessageFilesRequest] if is a files pack request. @@ -64,12 +73,15 @@ abstract base class NearbyMessageContent { /// cast as [NearbyMessageFilesResponse] if is a files pack response. /// T? byType({ - T Function(NearbyMessageTextContent)? onText, + T Function(NearbyMessageTextRequest)? onTextRequest, + T Function(NearbyMessageTextResponse)? onTextResponse, T Function(NearbyMessageFilesRequest)? onFilesRequest, T Function(NearbyMessageFilesResponse)? onFilesResponse, }) { - if (this is NearbyMessageTextContent && onText != null) { - return onText(this as NearbyMessageTextContent); + if (this is NearbyMessageTextRequest && onTextRequest != null) { + return onTextRequest(this as NearbyMessageTextRequest); + } else if (this is NearbyMessageTextResponse && onTextResponse != null) { + return onTextResponse(this as NearbyMessageTextResponse); } else if (this is NearbyMessageFilesRequest && onFilesRequest != null) { return onFilesRequest(this as NearbyMessageFilesRequest); } else if (this is NearbyMessageFilesResponse && onFilesResponse != null) { @@ -82,6 +94,6 @@ abstract base class NearbyMessageContent { /// Gets [Map] from [NearbyMessageContent] /// Map toJson() { - return {'type': _type.name}; + return {'type': _type.name, 'id': id}; } } diff --git a/lib/src/model/nearby_message_content.dart b/lib/src/model/nearby_message_content.dart index 6975b05..e2eee9b 100644 --- a/lib/src/model/nearby_message_content.dart +++ b/lib/src/model/nearby_message_content.dart @@ -1,20 +1,25 @@ import 'package:nearby_service/nearby_service.dart'; -import 'package:nearby_service/src/utils/random.dart'; /// /// Nearby message Text content. /// /// Contains [value] - the message to be sent or received. /// -final class NearbyMessageTextContent extends NearbyMessageContent { - const NearbyMessageTextContent({required this.value}); +final class NearbyMessageTextRequest extends NearbyMessageContent { + const NearbyMessageTextRequest._({ + required this.value, + required super.id, + }); + + NearbyMessageTextRequest.create({required this.value}) : super.create(); /// - /// Gets [NearbyMessageTextContent] from [json] + /// Gets [NearbyMessageTextRequest] from [json] /// - factory NearbyMessageTextContent.fromJson(Map? json) { - return NearbyMessageTextContent( - value: json?['value'] ?? '', + factory NearbyMessageTextRequest.fromJson(Map? json) { + return NearbyMessageTextRequest._( + id: json?['id'], + value: json?['value'], ); } @@ -29,7 +34,7 @@ final class NearbyMessageTextContent extends NearbyMessageContent { @override bool operator ==(Object other) => identical(this, other) || - other is NearbyMessageTextContent && + other is NearbyMessageTextRequest && runtimeType == other.runtimeType && value == other.value; @@ -38,7 +43,7 @@ final class NearbyMessageTextContent extends NearbyMessageContent { @override String toString() { - return 'NearbyMessageTextContent{value: $value}'; + return 'NearbyMessageTextRequest{id: $id, value: $value}'; } @override @@ -50,55 +55,24 @@ final class NearbyMessageTextContent extends NearbyMessageContent { } } -/// -/// Sealed class for files content in NearbyMessage. -/// -sealed class NearbyMessageFilesContent extends NearbyMessageContent { - /// - /// Here type is [NearbyMessageContentType.filesResponse] or - /// [NearbyMessageContentType.filesRequest] - /// - /// Also [NearbyMessageFilesContent] contains [id] of the files pack. - /// - const NearbyMessageFilesContent({required this.id}); +final class NearbyMessageTextResponse extends NearbyMessageContent { + const NearbyMessageTextResponse({required super.id}); - /// - /// ID of this files pack - /// - final String id; - - @override - Map toJson() { - return { - 'id': id, - ...super.toJson(), - }; + factory NearbyMessageTextResponse.fromJson(Map? json) { + return NearbyMessageTextResponse(id: json?['id']); } - @override - bool operator ==(Object other) => - identical(this, other) || - other is NearbyMessageFilesContent && - runtimeType == other.runtimeType && - id == other.id; - - @override - int get hashCode => id.hashCode; - @override String toString() { - return 'NearbyMessageFilesContent{id: $id}'; + return 'NearbyMessageTextResponse{id: $id}'; } - - @override - bool get isValid => id.isNotEmpty; } /// /// Nearby message File Request. Used for files sending requests. /// Contains info about the [files]. /// -final class NearbyMessageFilesRequest extends NearbyMessageFilesContent { +final class NearbyMessageFilesRequest extends NearbyMessageContent { /// /// Adds a [NearbyFileInfo] list to [id] to identify files. /// @@ -111,17 +85,14 @@ final class NearbyMessageFilesRequest extends NearbyMessageFilesContent { /// Basic constructor with [files] to be sent or received. /// Generates [id] in constructor. /// - NearbyMessageFilesRequest.create({required this.files}) - : super( - id: RandomUtils.instance.nextInt(1000000, 9999999).toString(), - ); + NearbyMessageFilesRequest.create({required this.files}) : super.create(); /// /// Gets [NearbyMessageFilesRequest] from [json]. /// factory NearbyMessageFilesRequest.fromJson(Map? json) { return NearbyMessageFilesRequest._( - id: json?['id'] ?? '', + id: json?['id'], files: [ ...?(json?['files'] as List?)?.map( (e) => NearbyFileInfo.fromJson(e), @@ -171,14 +142,14 @@ final class NearbyMessageFilesRequest extends NearbyMessageFilesContent { /// /// Nearby message File Response. Used for file sending responses. /// -final class NearbyMessageFilesResponse extends NearbyMessageFilesContent { +final class NearbyMessageFilesResponse extends NearbyMessageContent { /// /// Used to send a response to a previously received request. /// Provide [id] from [NearbyMessageFilesRequest]. /// NearbyMessageFilesResponse({ required super.id, - required this.response, + required this.isAccepted, }); /// @@ -187,25 +158,25 @@ final class NearbyMessageFilesResponse extends NearbyMessageFilesContent { factory NearbyMessageFilesResponse.fromJson(Map? json) { return NearbyMessageFilesResponse( id: json?['id'] ?? '', - response: json?['response'] ?? false, + isAccepted: json?['isAccepted'] ?? false, ); } /// /// The main response to the received [NearbyMessageFilesRequest]. /// - final bool response; + final bool isAccepted; @override Map toJson() { return { - 'response': response, + 'isAccepted': isAccepted, ...super.toJson(), }; } @override String toString() { - return 'NearbyMessageFileResponse{response: $response, id: $id}'; + return 'NearbyMessageFileResponse{response: $isAccepted, id: $id}'; } } diff --git a/lib/src/model/nearby_message_content_type.dart b/lib/src/model/nearby_message_content_type.dart index 143f084..70f5c9a 100644 --- a/lib/src/model/nearby_message_content_type.dart +++ b/lib/src/model/nearby_message_content_type.dart @@ -1,21 +1,29 @@ /// /// Type of the message. /// -/// If [text], it will be a text message. +/// If [textRequest], it will be a text message. /// If [filesRequest], it will be a files pack request. /// After accepting the request, /// user can get files bytes stream from the connected device. /// enum NearbyMessageContentType { - text, + textRequest, + textResponse, filesRequest, filesResponse; /// - /// Checks if this is [NearbyMessageContentType.text] + /// Checks if this is [NearbyMessageContentType.textRequest] /// - bool get isText { - return this == NearbyMessageContentType.text; + bool get isTextRequest { + return this == NearbyMessageContentType.textRequest; + } + + /// + /// Checks if this is [NearbyMessageContentType.textResponse] + /// + bool get isTextResponse { + return this == NearbyMessageContentType.textResponse; } /// diff --git a/lib/src/platforms/android/socket_service/file_sockets_manager.dart b/lib/src/platforms/android/socket_service/file_sockets_manager.dart index fc1599b..ea24b82 100644 --- a/lib/src/platforms/android/socket_service/file_sockets_manager.dart +++ b/lib/src/platforms/android/socket_service/file_sockets_manager.dart @@ -34,10 +34,15 @@ class FileSocketsManager { } Future handleFileMessageContent( - NearbyMessageFilesContent content, { + NearbyMessageContent content, { required NearbyDeviceInfo? sender, required bool isReceived, }) async { + assert( + content is NearbyMessageFilesResponse || + content is NearbyMessageFilesRequest, + "Provide NearbyMessageFilesResponse or NearbyMessageFilesRequest to handleFileMessageContent()", + ); if (sender != null) { _sender = sender; Logger.debug('Sender was set to $_sender'); @@ -47,7 +52,7 @@ class FileSocketsManager { final isRequest = content is NearbyMessageFilesRequest; final isPositiveResponse = - content is NearbyMessageFilesResponse && content.response; + content is NearbyMessageFilesResponse && content.isAccepted; if (isRequest) { _cachedFilesRequest = content; diff --git a/lib/src/platforms/android/socket_service/nearby_socket_service.dart b/lib/src/platforms/android/socket_service/nearby_socket_service.dart index 6aca2e9..e047c0f 100644 --- a/lib/src/platforms/android/socket_service/nearby_socket_service.dart +++ b/lib/src/platforms/android/socket_service/nearby_socket_service.dart @@ -98,7 +98,7 @@ class NearbySocketService { }, ), ); - _handleMessage(message); + _handleFilesMessage(message); } return true; } @@ -203,28 +203,27 @@ class NearbySocketService { ?.where((e) => e != null) .map(MessagesStreamMapper.toMessage) .cast() - .map((e) => MessagesStreamMapper.replaceId(e, _connectedDeviceId!)) + .map((e) => MessagesStreamMapper.replaceId(e, _connectedDeviceId)) .listen( - (message) async { - try { - _handleMessage(message); - socketListener.onData(message); - } catch (e) { - Logger.error(e); - } - // } - }, - onDone: () { - state.value = CommunicationChannelState.notConnected; - socketListener.onDone?.call(); - }, - onError: (e, s) { - Logger.error(e); - state.value = CommunicationChannelState.notConnected; - socketListener.onError?.call(e, s); - }, - cancelOnError: socketListener.cancelOnError, - ); + (message) async { + try { + _handleFilesMessage(message); + socketListener.onData(message); + } catch (e) { + Logger.error(e); + } + }, + onDone: () { + state.value = CommunicationChannelState.notConnected; + socketListener.onDone?.call(); + }, + onError: (e, s) { + Logger.error(e); + state.value = CommunicationChannelState.notConnected; + socketListener.onError?.call(e, s); + }, + cancelOnError: socketListener.cancelOnError, + ); } if (_messagesSubscription != null) { state.value = CommunicationChannelState.connected; @@ -235,10 +234,11 @@ class NearbySocketService { } } - void _handleMessage(NearbyMessage message) { - if (message.content is NearbyMessageFilesContent) { + void _handleFilesMessage(NearbyMessage message) { + if (message.content is NearbyMessageFilesRequest || + message.content is NearbyMessageFilesResponse) { _fileSocketsManager.handleFileMessageContent( - message.content as NearbyMessageFilesContent, + message.content, isReceived: message is ReceivedNearbyMessage, sender: message is ReceivedNearbyMessage ? message.sender : null, ); diff --git a/lib/src/platforms/ios/nearby_ios_service.dart b/lib/src/platforms/ios/nearby_ios_service.dart index 8ff9bd1..6e8730e 100644 --- a/lib/src/platforms/ios/nearby_ios_service.dart +++ b/lib/src/platforms/ios/nearby_ios_service.dart @@ -186,19 +186,23 @@ class NearbyIOSService extends NearbyService { cancelOnError: eventListener.cancelOnError, ); _resourcesSubscription = NearbyServiceIOSPlatform.instance.resourcesStream + .map((event) { + print(event); + return event; + }) .map(ResourcesStreamMapper.toFilesPack) .where((event) => event != null) .cast() .listen( - (e) => filesListener?.onData.call(e), - onDone: filesListener?.onDone, - onError: (e, s) { - Logger.error(e); - _state.value = CommunicationChannelState.notConnected; - filesListener?.onError?.call(e, s); - }, - cancelOnError: filesListener?.cancelOnError, - ); + (e) => filesListener?.onData.call(e), + onDone: filesListener?.onDone, + onError: (e, s) { + Logger.error(e); + _state.value = CommunicationChannelState.notConnected; + filesListener?.onError?.call(e, s); + }, + cancelOnError: filesListener?.cancelOnError, + ); if (_messagesSubscription != null) { Logger.info('Messages subscription was created successfully'); eventListener.onCreated?.call(); diff --git a/lib/src/utils/stream_mapper.dart b/lib/src/utils/stream_mapper.dart index e18c6d6..b7f2e6c 100644 --- a/lib/src/utils/stream_mapper.dart +++ b/lib/src/utils/stream_mapper.dart @@ -4,15 +4,18 @@ import 'package:nearby_service/src/utils/json_decoder.dart'; abstract class MessagesStreamMapper { static ReceivedNearbyMessage replaceId( ReceivedNearbyMessage message, - String id, + String? id, ) { - return ReceivedNearbyMessage( - content: message.content, - sender: NearbyDeviceInfo( - id: id, - displayName: message.sender.displayName, - ), - ); + if (id != null) { + return ReceivedNearbyMessage( + content: message.content, + sender: NearbyDeviceInfo( + id: id, + displayName: message.sender.displayName, + ), + ); + } + throw NearbyServiceException('The provided ID does not exist'); } static ReceivedNearbyMessage? toMessage(dynamic event) {