service: Allow sending multiple files
This commit is contained in:
parent
0acd812a60
commit
660c56e27a
@ -220,13 +220,13 @@ files:
|
|||||||
quotedMessage:
|
quotedMessage:
|
||||||
type: Message?
|
type: Message?
|
||||||
deserialise: true
|
deserialise: true
|
||||||
- name: SendFileCommand
|
- name: SendFilesCommand
|
||||||
extends: BackgroundCommand
|
extends: BackgroundCommand
|
||||||
implements:
|
implements:
|
||||||
- JsonImplementation
|
- JsonImplementation
|
||||||
attributes:
|
attributes:
|
||||||
jid: String
|
jid: String
|
||||||
path: String
|
paths: List<String>
|
||||||
- name: BlockJidCommand
|
- name: BlockJidCommand
|
||||||
extends: BackgroundCommand
|
extends: BackgroundCommand
|
||||||
implements:
|
implements:
|
||||||
|
@ -49,7 +49,7 @@ void setupBackgroundEventHandler() {
|
|||||||
EventTypeMatcher<SendChatStateCommand>(performSendChatState),
|
EventTypeMatcher<SendChatStateCommand>(performSendChatState),
|
||||||
EventTypeMatcher<GetFeaturesCommand>(performGetFeatures),
|
EventTypeMatcher<GetFeaturesCommand>(performGetFeatures),
|
||||||
EventTypeMatcher<SignOutCommand>(performSignOut),
|
EventTypeMatcher<SignOutCommand>(performSignOut),
|
||||||
EventTypeMatcher<SendFileCommand>(performSendFile),
|
EventTypeMatcher<SendFilesCommand>(performSendFiles),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
GetIt.I.registerSingleton<EventHandler>(handler);
|
GetIt.I.registerSingleton<EventHandler>(handler);
|
||||||
@ -409,6 +409,6 @@ Future<void> performSignOut(SignOutCommand command, { dynamic extra }) async {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> performSendFile(SendFileCommand command, { dynamic extra }) async {
|
Future<void> performSendFiles(SendFilesCommand command, { dynamic extra }) async {
|
||||||
await GetIt.I.get<XmppService>().sendFile(command.path, command.jid);
|
await GetIt.I.get<XmppService>().sendFiles(command.paths, command.jid);
|
||||||
}
|
}
|
||||||
|
@ -321,81 +321,105 @@ class XmppService {
|
|||||||
return GetIt.I.get<XmppConnection>().connectAwaitable(lastResource: lastResource);
|
return GetIt.I.get<XmppConnection>().connectAwaitable(lastResource: lastResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> sendFile(String path, String recipient) async {
|
Future<void> sendFiles(List<String> paths, String recipient) async {
|
||||||
// Create a new message
|
// Create a new message
|
||||||
final ms = GetIt.I.get<MessageService>();
|
final ms = GetIt.I.get<MessageService>();
|
||||||
final cs = GetIt.I.get<ConversationService>();
|
final cs = GetIt.I.get<ConversationService>();
|
||||||
final us = GetIt.I.get<UploadService>();
|
final us = GetIt.I.get<UploadService>();
|
||||||
final conn = GetIt.I.get<XmppConnection>();
|
final conn = GetIt.I.get<XmppConnection>();
|
||||||
final httpManager = conn.getManagerById<HttpFileUploadManager>(httpFileUploadManager)!;
|
final httpManager = conn.getManagerById<HttpFileUploadManager>(httpFileUploadManager)!;
|
||||||
final sid = conn.generateId();
|
|
||||||
final originId = conn.generateId();
|
|
||||||
|
|
||||||
_log.finest('Requesting upload slot');
|
// Path -> Message
|
||||||
final stat = File(path).statSync();
|
final messages = <String, Message>{};
|
||||||
final result = await httpManager.requestUploadSlot(pathlib.basename(path), stat.size);
|
|
||||||
if (result.isError()) {
|
// Create the messages
|
||||||
_log.severe('Failed to request slot');
|
for (final path in paths) {
|
||||||
// TODO(PapaTutuWawa): Do not let it end here
|
final msg = await ms.addMessageFromData(
|
||||||
return;
|
'',
|
||||||
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
|
conn.getConnectionSettings().jid.toString(),
|
||||||
|
recipient,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
conn.generateId(),
|
||||||
|
// TODO(Unknown): Maybe don't have the UI depend on srcUrl if we sent it.
|
||||||
|
srcUrl: 'https://server.example',
|
||||||
|
mediaUrl: path,
|
||||||
|
mediaType: lookupMimeType(path),
|
||||||
|
originId: conn.generateId(),
|
||||||
|
);
|
||||||
|
messages[path] = msg;
|
||||||
|
sendEvent(MessageAddedEvent(message: msg.copyWith(isUploading: true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
final slot = result.getValue();
|
// Requesting Upload slots and uploading
|
||||||
final fileMime = lookupMimeType(path);
|
|
||||||
var msg = await ms.addMessageFromData(
|
|
||||||
'',
|
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
|
||||||
conn.getConnectionSettings().jid.toString(),
|
|
||||||
recipient,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
sid,
|
|
||||||
srcUrl: slot.getUrl,
|
|
||||||
mediaUrl: path,
|
|
||||||
mediaType: fileMime,
|
|
||||||
originId: originId,
|
|
||||||
);
|
|
||||||
// Notify the UI
|
|
||||||
msg = msg.copyWith(isUploading: true);
|
|
||||||
sendEvent(MessageAddedEvent(message: msg));
|
|
||||||
|
|
||||||
final uploadResult = await us.uploadFile(path, slot.putUrl, slot.headers, msg.id);
|
final conversationId = (await cs.getConversationByJid(recipient))!.id;
|
||||||
msg = msg.copyWith(isUploading: false);
|
for (final path in paths) {
|
||||||
sendEvent(MessageUpdatedEvent(message: msg));
|
_log.finest('Requesting upload slot for $path');
|
||||||
|
final stat = File(path).statSync();
|
||||||
|
final result = await httpManager.requestUploadSlot(pathlib.basename(path), stat.size);
|
||||||
|
if (result.isError()) {
|
||||||
|
_log.severe('Failed to request slot for $path!');
|
||||||
|
// TODO(PapaTutuWawa): Do not let it end here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!uploadResult) {
|
final slot = result.getValue();
|
||||||
_log.severe('Upload failed');
|
final fileMime = lookupMimeType(path);
|
||||||
// TODO(PapaTutuWawa): Do not abort here
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final id = (await cs.getConversationByJid(recipient))!.id;
|
final uploadResult = await us.uploadFile(
|
||||||
final updatedConversation = await cs.updateConversation(
|
path,
|
||||||
id,
|
slot.putUrl,
|
||||||
lastMessageBody: mimeTypeToConversationBody(fileMime),
|
slot.headers,
|
||||||
lastChangeTimestamp: DateTime.now().millisecondsSinceEpoch,
|
messages[path]!.id,
|
||||||
);
|
);
|
||||||
sendEvent(ConversationUpdatedEvent(conversation: updatedConversation));
|
|
||||||
|
if (!uploadResult) {
|
||||||
conn.getManagerById<MessageManager>(messageManager)!.sendMessage(
|
_log.severe('Upload failed for $path!');
|
||||||
MessageDetails(
|
// TODO(PapaTutuWawa): Do not abort here
|
||||||
to: recipient,
|
return;
|
||||||
body: slot.getUrl,
|
}
|
||||||
requestDeliveryReceipt: true,
|
|
||||||
id: sid,
|
// Notify UI of upload completion
|
||||||
originId: originId,
|
sendEvent(
|
||||||
sfs: StatelessFileSharingData(
|
MessageUpdatedEvent(
|
||||||
url: slot.getUrl,
|
message: messages[path]!.copyWith(isUploading: false),
|
||||||
metadata: FileMetadataData(
|
),
|
||||||
mediaType: fileMime,
|
);
|
||||||
size: stat.size,
|
|
||||||
name: pathlib.basename(path),
|
// Update conversation
|
||||||
thumbnails: [],
|
final updatedConversation = await cs.updateConversation(
|
||||||
|
conversationId,
|
||||||
|
lastMessageBody: mimeTypeToConversationBody(fileMime),
|
||||||
|
lastChangeTimestamp: DateTime.now().millisecondsSinceEpoch,
|
||||||
|
);
|
||||||
|
sendEvent(ConversationUpdatedEvent(conversation: updatedConversation));
|
||||||
|
|
||||||
|
// Send the url to the recipient
|
||||||
|
final message = messages[path]!;
|
||||||
|
conn.getManagerById<MessageManager>(messageManager)!.sendMessage(
|
||||||
|
MessageDetails(
|
||||||
|
to: recipient,
|
||||||
|
body: slot.getUrl,
|
||||||
|
requestDeliveryReceipt: true,
|
||||||
|
id: message.sid,
|
||||||
|
originId: message.originId,
|
||||||
|
sfs: StatelessFileSharingData(
|
||||||
|
url: slot.getUrl,
|
||||||
|
metadata: FileMetadataData(
|
||||||
|
mediaType: fileMime,
|
||||||
|
size: stat.size,
|
||||||
|
name: pathlib.basename(path),
|
||||||
|
thumbnails: [],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
_log.finest('Sent message with file upload for $path');
|
||||||
_log.finest('Sent message with file upload');
|
}
|
||||||
|
|
||||||
|
_log.finest('File upload done');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onConnectionStateChanged(ConnectionStateChangedEvent event, { dynamic extra }) async {
|
Future<void> _onConnectionStateChanged(ConnectionStateChangedEvent event, { dynamic extra }) async {
|
||||||
|
@ -290,12 +290,12 @@ class ConversationBloc extends Bloc<ConversationEvent, ConversationState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFileUploadRequested(FileUploadRequestedEvent event, Emitter<ConversationState> emit) async {
|
Future<void> _onFileUploadRequested(FileUploadRequestedEvent event, Emitter<ConversationState> emit) async {
|
||||||
final result = await FilePicker.platform.pickFiles(type: FileType.image);
|
final result = await FilePicker.platform.pickFiles(type: FileType.image, allowMultiple: true);
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
await MoxplatformPlugin.handler.getDataSender().sendData(
|
await MoxplatformPlugin.handler.getDataSender().sendData(
|
||||||
SendFileCommand(
|
SendFilesCommand(
|
||||||
path: result.files.single.path!,
|
paths: result.files.map((PlatformFile file) => file.path!).toList(),
|
||||||
jid: state.conversation!.jid,
|
jid: state.conversation!.jid,
|
||||||
),
|
),
|
||||||
awaitable: false,
|
awaitable: false,
|
||||||
|
Loading…
Reference in New Issue
Block a user