service: Allow sending multiple files
This commit is contained in:
		
							parent
							
								
									0acd812a60
								
							
						
					
					
						commit
						660c56e27a
					
				| @ -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: | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user