service: Allow sending multiple files

This commit is contained in:
PapaTutuWawa 2022-07-24 14:38:13 +02:00
parent 0acd812a60
commit 660c56e27a
4 changed files with 93 additions and 69 deletions

View File

@ -220,13 +220,13 @@ files:
quotedMessage:
type: Message?
deserialise: true
- name: SendFileCommand
- name: SendFilesCommand
extends: BackgroundCommand
implements:
- JsonImplementation
attributes:
jid: String
path: String
paths: List<String>
- name: BlockJidCommand
extends: BackgroundCommand
implements:

View File

@ -49,7 +49,7 @@ void setupBackgroundEventHandler() {
EventTypeMatcher<SendChatStateCommand>(performSendChatState),
EventTypeMatcher<GetFeaturesCommand>(performGetFeatures),
EventTypeMatcher<SignOutCommand>(performSignOut),
EventTypeMatcher<SendFileCommand>(performSendFile),
EventTypeMatcher<SendFilesCommand>(performSendFiles),
]);
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 {
await GetIt.I.get<XmppService>().sendFile(command.path, command.jid);
Future<void> performSendFiles(SendFilesCommand command, { dynamic extra }) async {
await GetIt.I.get<XmppService>().sendFiles(command.paths, command.jid);
}

View File

@ -321,81 +321,105 @@ class XmppService {
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
final ms = GetIt.I.get<MessageService>();
final cs = GetIt.I.get<ConversationService>();
final us = GetIt.I.get<UploadService>();
final conn = GetIt.I.get<XmppConnection>();
final httpManager = conn.getManagerById<HttpFileUploadManager>(httpFileUploadManager)!;
final sid = conn.generateId();
final originId = conn.generateId();
_log.finest('Requesting upload slot');
final stat = File(path).statSync();
final result = await httpManager.requestUploadSlot(pathlib.basename(path), stat.size);
if (result.isError()) {
_log.severe('Failed to request slot');
// TODO(PapaTutuWawa): Do not let it end here
return;
// Path -> Message
final messages = <String, Message>{};
// Create the messages
for (final path in paths) {
final msg = await ms.addMessageFromData(
'',
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();
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));
// Requesting Upload slots and uploading
final uploadResult = await us.uploadFile(path, slot.putUrl, slot.headers, msg.id);
msg = msg.copyWith(isUploading: false);
sendEvent(MessageUpdatedEvent(message: msg));
final conversationId = (await cs.getConversationByJid(recipient))!.id;
for (final path in paths) {
_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) {
_log.severe('Upload failed');
// TODO(PapaTutuWawa): Do not abort here
return;
}
final slot = result.getValue();
final fileMime = lookupMimeType(path);
final id = (await cs.getConversationByJid(recipient))!.id;
final updatedConversation = await cs.updateConversation(
id,
lastMessageBody: mimeTypeToConversationBody(fileMime),
lastChangeTimestamp: DateTime.now().millisecondsSinceEpoch,
);
sendEvent(ConversationUpdatedEvent(conversation: updatedConversation));
conn.getManagerById<MessageManager>(messageManager)!.sendMessage(
MessageDetails(
to: recipient,
body: slot.getUrl,
requestDeliveryReceipt: true,
id: sid,
originId: originId,
sfs: StatelessFileSharingData(
url: slot.getUrl,
metadata: FileMetadataData(
mediaType: fileMime,
size: stat.size,
name: pathlib.basename(path),
thumbnails: [],
final uploadResult = await us.uploadFile(
path,
slot.putUrl,
slot.headers,
messages[path]!.id,
);
if (!uploadResult) {
_log.severe('Upload failed for $path!');
// TODO(PapaTutuWawa): Do not abort here
return;
}
// Notify UI of upload completion
sendEvent(
MessageUpdatedEvent(
message: messages[path]!.copyWith(isUploading: false),
),
);
// Update conversation
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');
);
_log.finest('Sent message with file upload for $path');
}
_log.finest('File upload done');
}
Future<void> _onConnectionStateChanged(ConnectionStateChangedEvent event, { dynamic extra }) async {

View File

@ -290,12 +290,12 @@ class ConversationBloc extends Bloc<ConversationEvent, ConversationState> {
}
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) {
await MoxplatformPlugin.handler.getDataSender().sendData(
SendFileCommand(
path: result.files.single.path!,
SendFilesCommand(
paths: result.files.map((PlatformFile file) => file.path!).toList(),
jid: state.conversation!.jid,
),
awaitable: false,