refactor(lib): create structure with base and interface
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
///
|
||||
/// The status of the communication channel for data exchange.
|
||||
/// Use it to determine if you can send data over the communication channel or not.
|
||||
///
|
||||
enum CommunicationChannelState { notConnected, loading, connected }
|
||||
@@ -0,0 +1,7 @@
|
||||
export 'nearby_device_info.dart';
|
||||
export 'nearby_device_status.dart';
|
||||
export 'nearby_message.dart';
|
||||
export 'nearby_message_content.dart';
|
||||
export 'communication_channel_state.dart';
|
||||
export 'nearby_file.dart';
|
||||
export 'nearby_message_content_type.dart';
|
||||
@@ -0,0 +1,67 @@
|
||||
import 'package:nearby_service/src/utils/unknown.dart';
|
||||
|
||||
///
|
||||
/// Minimal information about the device.
|
||||
///
|
||||
final class NearbyDeviceInfo {
|
||||
///
|
||||
/// Used to connect to the device via [id].
|
||||
/// Depending on the platform, [id] means different parameters.
|
||||
///
|
||||
/// * For Android [id] is the MAC address of the device.
|
||||
/// * For IOS [id] is the [MCPeerID](https://developer.apple.com/documentation/multipeerconnectivity/mcpeerid) passed from the IOS platform.
|
||||
///
|
||||
const NearbyDeviceInfo({
|
||||
required this.displayName,
|
||||
required this.id,
|
||||
});
|
||||
|
||||
///
|
||||
/// Get [NearbyDeviceInfo] from [Map].
|
||||
///
|
||||
factory NearbyDeviceInfo.fromJson(Map<String, dynamic>? json) {
|
||||
return NearbyDeviceInfo(
|
||||
displayName: json?['displayName'] ?? kNearbyUnknown,
|
||||
id: json?['id'],
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// The name of the device in the context of a P2P network.
|
||||
///
|
||||
final String displayName;
|
||||
|
||||
///
|
||||
/// Depending on the platform, [id] means different parameters.
|
||||
///
|
||||
/// * For Android [id] is the MAC address of the device.
|
||||
/// * For IOS [id] is the [MCPeerID](https://developer.apple.com/documentation/multipeerconnectivity/mcpeerid) passed from the IOS platform.
|
||||
///
|
||||
final String id;
|
||||
|
||||
///
|
||||
/// Get [Map] from [NearbyDeviceInfo].
|
||||
///
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'displayName': displayName,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is NearbyDeviceInfo &&
|
||||
runtimeType == other.runtimeType &&
|
||||
displayName == other.displayName &&
|
||||
id == other.id;
|
||||
|
||||
@override
|
||||
int get hashCode => displayName.hashCode ^ id.hashCode;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NearbyDeviceInfo{displayName: $displayName, id: $id}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
///
|
||||
/// Status of device connection.
|
||||
///
|
||||
enum NearbyDeviceStatus {
|
||||
available,
|
||||
connected,
|
||||
failed,
|
||||
connecting,
|
||||
unavailable;
|
||||
|
||||
///
|
||||
/// Checks if status is [NearbyDeviceStatus.connected]
|
||||
///
|
||||
bool get isConnected => this == NearbyDeviceStatus.connected;
|
||||
|
||||
///
|
||||
/// Checks if status is [NearbyDeviceStatus.available]
|
||||
///
|
||||
bool get isAvailable => this == NearbyDeviceStatus.available;
|
||||
|
||||
///
|
||||
/// Checks if status is [NearbyDeviceStatus.failed]
|
||||
///
|
||||
bool get isFailed => this == NearbyDeviceStatus.failed;
|
||||
|
||||
///
|
||||
/// Checks if status is [NearbyDeviceStatus.connecting]
|
||||
///
|
||||
bool get isConnecting => this == NearbyDeviceStatus.connecting;
|
||||
|
||||
///
|
||||
/// Checks if status is [NearbyDeviceStatus.unavailable]
|
||||
///
|
||||
bool get isUnavailable => this == NearbyDeviceStatus.unavailable;
|
||||
|
||||
///
|
||||
/// Get [NearbyDeviceStatus] from the Android platform code.
|
||||
///
|
||||
/// You can read about it on the [Android developer site](https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pDevice#constants_1).
|
||||
///
|
||||
static NearbyDeviceStatus fromAndroidCode(num? code) {
|
||||
if (code == null) {
|
||||
return NearbyDeviceStatus.failed;
|
||||
}
|
||||
return switch (code) {
|
||||
(0) => NearbyDeviceStatus.connected,
|
||||
(1) => NearbyDeviceStatus.connecting,
|
||||
(2) => NearbyDeviceStatus.failed,
|
||||
(3) => NearbyDeviceStatus.available,
|
||||
(4) => NearbyDeviceStatus.unavailable,
|
||||
(_) => NearbyDeviceStatus.failed,
|
||||
};
|
||||
}
|
||||
|
||||
///
|
||||
/// Get [NearbyDeviceStatus] from the IOS platform code.
|
||||
///
|
||||
/// You can read about it on the [IOS developer site](https://developer.apple.com/documentation/multipeerconnectivity/mcsessionstate).
|
||||
///
|
||||
static NearbyDeviceStatus fromIosCode(String? code) {
|
||||
if (code == null) {
|
||||
return NearbyDeviceStatus.failed;
|
||||
}
|
||||
final value = num.tryParse(code);
|
||||
return switch (value) {
|
||||
(0) => NearbyDeviceStatus.available,
|
||||
(1) => NearbyDeviceStatus.connecting,
|
||||
(2) => NearbyDeviceStatus.connected,
|
||||
(_) => NearbyDeviceStatus.failed,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import 'dart:io';
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
|
||||
///
|
||||
/// A representation of a file that can be got from the Nearby Service's
|
||||
/// communication channel.
|
||||
///
|
||||
/// From the communication channel, you usually get
|
||||
/// the [NearbyMessageFilesRequest] request first.
|
||||
/// After that, you can send positive [NearbyMessageFilesResponse] and
|
||||
/// get the list of [NearbyFile].
|
||||
///
|
||||
final class NearbyFile {
|
||||
///
|
||||
/// Pass [info] assigned to file to be sent.
|
||||
///
|
||||
const NearbyFile({
|
||||
required this.info,
|
||||
required this.file,
|
||||
});
|
||||
|
||||
///
|
||||
/// Quick info about the file
|
||||
///
|
||||
final NearbyFileInfo info;
|
||||
|
||||
///
|
||||
/// A file that you can save in your phone if needed
|
||||
///
|
||||
final File file;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is NearbyFile &&
|
||||
runtimeType == other.runtimeType &&
|
||||
info == other.info &&
|
||||
file == other.file;
|
||||
|
||||
@override
|
||||
int get hashCode => info.hashCode ^ file.hashCode;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NearbyFile{info: $info, file: $file}';
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Quick info about the file
|
||||
///
|
||||
class NearbyFileInfo {
|
||||
///
|
||||
/// Contains the file [path] to get the file from it.
|
||||
///
|
||||
const NearbyFileInfo({required this.path});
|
||||
|
||||
factory NearbyFileInfo.fromJson(Map<String, dynamic>? json) {
|
||||
return NearbyFileInfo(
|
||||
path: json?['path'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Path of the representing file
|
||||
///
|
||||
final String path;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is NearbyFileInfo &&
|
||||
runtimeType == other.runtimeType &&
|
||||
path == other.path;
|
||||
|
||||
@override
|
||||
int get hashCode => path.hashCode;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'path': path,
|
||||
};
|
||||
}
|
||||
|
||||
///
|
||||
/// Quick access to the file [name]
|
||||
///
|
||||
String get name {
|
||||
try {
|
||||
return path.split('/').last;
|
||||
} catch (e) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Quick access to the file [extension]
|
||||
///
|
||||
String get extension {
|
||||
try {
|
||||
return name.split('.').last;
|
||||
} catch (e) {
|
||||
throw NearbyServiceException('Can\'t get extension from $name');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NearbyFileInfo{path: $path}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import 'package:nearby_service/nearby_service.dart';
|
||||
|
||||
///
|
||||
/// The message that will be sent from the current device.
|
||||
///
|
||||
final class OutgoingNearbyMessage<Content extends NearbyMessageContentBase>
|
||||
extends NearbyMessageBase<Content> implements NearbyOutgoingInterface {
|
||||
///
|
||||
/// To send a message, in addition to [content], you need to pass [receiver]
|
||||
/// to know to whom the message is addressed.
|
||||
///
|
||||
const OutgoingNearbyMessage({
|
||||
required super.content,
|
||||
required this.receiver,
|
||||
});
|
||||
|
||||
///
|
||||
/// Data of the user to whom the message is addressed.
|
||||
///
|
||||
@override
|
||||
final NearbyDeviceInfo receiver;
|
||||
|
||||
///
|
||||
/// Get [Map] from [OutgoingNearbyMessage].
|
||||
///
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'content': content.toJson(),
|
||||
'receiver': receiver.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
super == other &&
|
||||
other is OutgoingNearbyMessage &&
|
||||
runtimeType == other.runtimeType &&
|
||||
receiver == other.receiver;
|
||||
|
||||
@override
|
||||
int get hashCode => super.hashCode ^ receiver.hashCode;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OutgoingNearbyMessage{receiver: $receiver content:$content}';
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Message received by the current device.
|
||||
///
|
||||
final class ReceivedNearbyMessage<Content extends NearbyMessageContentBase>
|
||||
extends NearbyMessageBase<Content> implements NearbyReceivedInterface {
|
||||
///
|
||||
/// The received message contains a [sender] in addition to [content],
|
||||
/// to know from whom the message came.
|
||||
///
|
||||
const ReceivedNearbyMessage({
|
||||
required super.content,
|
||||
required this.sender,
|
||||
});
|
||||
|
||||
///
|
||||
/// Get [ReceivedNearbyMessage] from [Map].
|
||||
///
|
||||
factory ReceivedNearbyMessage.fromJson(Map<String, dynamic>? json) {
|
||||
return ReceivedNearbyMessage(
|
||||
content: NearbyMessageContentBase.fromJson(json?['content']),
|
||||
sender: NearbyDeviceInfo.fromJson(json?['sender']),
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Data of the user from whom the message came.
|
||||
///
|
||||
@override
|
||||
final NearbyDeviceInfo sender;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
super == other &&
|
||||
other is ReceivedNearbyMessage &&
|
||||
runtimeType == other.runtimeType &&
|
||||
sender == other.sender;
|
||||
|
||||
@override
|
||||
int get hashCode => super.hashCode ^ sender.hashCode;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ReceivedNearbyMessage{sender: $sender content: $content}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
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 NearbyMessageContentBase {
|
||||
const NearbyMessageTextContent({required this.value});
|
||||
|
||||
///
|
||||
/// Gets [NearbyMessageTextContent] from [json]
|
||||
///
|
||||
factory NearbyMessageTextContent.fromJson(Map<String, dynamic>? json) {
|
||||
return NearbyMessageTextContent(
|
||||
value: json?['value'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// The message to be sent or received
|
||||
///
|
||||
final String value;
|
||||
|
||||
@override
|
||||
NearbyMessageContentType get type => NearbyMessageContentType.text;
|
||||
|
||||
@override
|
||||
bool get isValid => value.isNotEmpty;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is NearbyMessageTextContent &&
|
||||
runtimeType == other.runtimeType &&
|
||||
value == other.value;
|
||||
|
||||
@override
|
||||
int get hashCode => value.hashCode;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NearbyMessageTextContent{value: $value}';
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'value': value,
|
||||
...super.toJson(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Sealed class for files content in NearbyMessage.
|
||||
///
|
||||
sealed class NearbyMessageFilesContent extends NearbyMessageContentBase {
|
||||
///
|
||||
/// Here [type] = [NearbyMessageContentType.filesResponse] or
|
||||
/// [type] = [NearbyMessageContentType.filesRequest]
|
||||
///
|
||||
/// Also [NearbyMessageFilesContent] contains [id] of the files pack and
|
||||
/// list of [NearbyFileInfo] to determine the files.
|
||||
///
|
||||
const NearbyMessageFilesContent({
|
||||
required this.id,
|
||||
required this.files,
|
||||
});
|
||||
|
||||
///
|
||||
/// Info about the files to be sent or received.
|
||||
///
|
||||
final List<NearbyFileInfo> files;
|
||||
|
||||
///
|
||||
/// ID of this files pack
|
||||
///
|
||||
final String id;
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'files': [
|
||||
...files.map((e) => e.toJson()),
|
||||
],
|
||||
...super.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isValid =>
|
||||
files.isNotEmpty &&
|
||||
files.every(
|
||||
(element) => element.path.isNotEmpty,
|
||||
);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is NearbyMessageFilesContent &&
|
||||
runtimeType == other.runtimeType &&
|
||||
files == other.files &&
|
||||
id == other.id;
|
||||
|
||||
@override
|
||||
int get hashCode => files.hashCode ^ id.hashCode;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NearbyMessageFilesContent{files: $files, id: $id}';
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Nearby message File Request. Used for file sending requests.
|
||||
/// Does not contain files' bytes!
|
||||
///
|
||||
final class NearbyMessageFilesRequest extends NearbyMessageFilesContent {
|
||||
const NearbyMessageFilesRequest._({
|
||||
required super.id,
|
||||
required super.files,
|
||||
});
|
||||
|
||||
///
|
||||
/// Basic constructor with [files] to be sent or received.
|
||||
///
|
||||
NearbyMessageFilesRequest({required super.files})
|
||||
: super(
|
||||
id: RandomUtils.instance.nextInt(1000000, 9999999).toString(),
|
||||
);
|
||||
|
||||
///
|
||||
/// Gets [NearbyMessageFilesRequest] from [json].
|
||||
///
|
||||
factory NearbyMessageFilesRequest.fromJson(Map<String, dynamic>? json) {
|
||||
return NearbyMessageFilesRequest._(
|
||||
id: json?['id'] ?? '',
|
||||
files: [
|
||||
...?(json?['files'] as List?)?.map(
|
||||
(e) => NearbyFileInfo.fromJson(e),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
NearbyMessageContentType get type => NearbyMessageContentType.filesRequest;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NearbyMessageFileRequest{id: $id, files: $files}';
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Nearby message File Response. Used for file sending responses.
|
||||
/// Does not contain files' bytes!
|
||||
///
|
||||
final class NearbyMessageFilesResponse extends NearbyMessageFilesContent {
|
||||
///
|
||||
/// Used to send a response to a previously received request.
|
||||
/// Provide [id] and [files] from [NearbyMessageFilesRequest] or
|
||||
/// Use the [NearbyMessageFilesResponse.fromRequest] factory to generate a
|
||||
/// response.
|
||||
///
|
||||
NearbyMessageFilesResponse({
|
||||
required super.id,
|
||||
required super.files,
|
||||
required this.response,
|
||||
});
|
||||
|
||||
///
|
||||
/// Factory to quickly create a response to [NearbyMessageFilesRequest].
|
||||
///
|
||||
factory NearbyMessageFilesResponse.fromRequest(
|
||||
NearbyMessageFilesRequest request, {
|
||||
required bool response,
|
||||
}) {
|
||||
return NearbyMessageFilesResponse(
|
||||
id: request.id,
|
||||
files: request.files,
|
||||
response: response,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Gets [NearbyMessageFilesResponse] from [Map]
|
||||
///
|
||||
factory NearbyMessageFilesResponse.fromJson(Map<String, dynamic>? json) {
|
||||
return NearbyMessageFilesResponse(
|
||||
id: json?['id'] ?? '',
|
||||
files: [
|
||||
...?(json?['files'] as List?)?.map(
|
||||
(e) => NearbyFileInfo.fromJson(e),
|
||||
),
|
||||
],
|
||||
response: json?['response'] ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// The main response to the received [NearbyMessageFilesRequest].
|
||||
///
|
||||
final bool response;
|
||||
|
||||
@override
|
||||
NearbyMessageContentType get type => NearbyMessageContentType.filesResponse;
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'response': response,
|
||||
...super.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NearbyMessageFileResponse{response: $response, id: $id, files: $files}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
///
|
||||
/// Type of the message.
|
||||
///
|
||||
/// If [text], 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,
|
||||
filesRequest,
|
||||
filesResponse;
|
||||
|
||||
///
|
||||
/// Checks if this is [NearbyMessageContentType.text]
|
||||
///
|
||||
bool get isText {
|
||||
return this == NearbyMessageContentType.text;
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks if this is [NearbyMessageContentType.filesRequest]
|
||||
///
|
||||
bool get isFilesRequest {
|
||||
return this == NearbyMessageContentType.filesRequest;
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks if this is [NearbyMessageContentType.filesResponse]
|
||||
///
|
||||
bool get isFilesResponse {
|
||||
return this == NearbyMessageContentType.filesResponse;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user