feat: Display dummy event in timeline for sending files
For thumbnail generation, encrypting and uploading it is not necessary to block the UI. The given file event should already be displayed in the timeline. This placed it in the UI and adds a additional fileSendingStatus property so the app can fetch the current status.
This commit is contained in:
parent
23e0d29a0d
commit
a915cdacc8
|
|
@ -19,6 +19,7 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
|
@ -796,4 +797,19 @@ class Event extends MatrixEvent {
|
||||||
return _countEmojiRegex.allMatches(plaintextBody).length;
|
return _countEmojiRegex.allMatches(plaintextBody).length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this event is in Status SENDING and it aims to send a file, then this
|
||||||
|
/// shows the status of the file sending.
|
||||||
|
FileSendingStatus? get fileSendingStatus {
|
||||||
|
final status = unsigned?.tryGet<String>(fileSendingStatusKey);
|
||||||
|
if (status == null) return null;
|
||||||
|
return FileSendingStatus.values.singleWhereOrNull(
|
||||||
|
(fileSendingStatus) => fileSendingStatus.name == status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FileSendingStatus {
|
||||||
|
generatingThumbnail,
|
||||||
|
encrypting,
|
||||||
|
uploading,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,9 @@ const Map<HistoryVisibility, String> _historyVisibilityMap = {
|
||||||
const String messageSendingStatusKey =
|
const String messageSendingStatusKey =
|
||||||
'com.famedly.famedlysdk.message_sending_status';
|
'com.famedly.famedlysdk.message_sending_status';
|
||||||
|
|
||||||
|
const String fileSendingStatusKey =
|
||||||
|
'com.famedly.famedlysdk.file_sending_status';
|
||||||
|
|
||||||
const String sortOrderKey = 'com.famedly.famedlysdk.sort_order';
|
const String sortOrderKey = 'com.famedly.famedlysdk.sort_order';
|
||||||
|
|
||||||
/// Represents a Matrix room.
|
/// Represents a Matrix room.
|
||||||
|
|
@ -687,25 +690,78 @@ class Room {
|
||||||
///
|
///
|
||||||
/// In case [file] is a [MatrixImageFile], [thumbnail] is automatically
|
/// In case [file] is a [MatrixImageFile], [thumbnail] is automatically
|
||||||
/// computed unless it is explicitly provided.
|
/// computed unless it is explicitly provided.
|
||||||
|
/// Set [shrinkImageMaxDimension] to for example `1600` if you want to shrink
|
||||||
|
/// your image before sending. This is ignored if the File is not a
|
||||||
|
/// [MatrixImageFile].
|
||||||
Future<Uri> sendFileEvent(
|
Future<Uri> sendFileEvent(
|
||||||
MatrixFile file, {
|
MatrixFile file, {
|
||||||
String? txid,
|
String? txid,
|
||||||
Event? inReplyTo,
|
Event? inReplyTo,
|
||||||
String? editEventId,
|
String? editEventId,
|
||||||
bool waitUntilSent = false,
|
bool waitUntilSent = false,
|
||||||
|
int? shrinkImageMaxDimension,
|
||||||
MatrixImageFile? thumbnail,
|
MatrixImageFile? thumbnail,
|
||||||
Map<String, dynamic>? extraContent,
|
Map<String, dynamic>? extraContent,
|
||||||
}) async {
|
}) async {
|
||||||
|
txid ??= client.generateUniqueTransactionId();
|
||||||
|
|
||||||
|
// Create a fake Event object as a placeholder for the uploading file:
|
||||||
|
final syncUpdate = SyncUpdate(
|
||||||
|
nextBatch: '',
|
||||||
|
rooms: RoomsUpdate(
|
||||||
|
join: {
|
||||||
|
id: JoinedRoomUpdate(
|
||||||
|
timeline: TimelineUpdate(
|
||||||
|
events: [
|
||||||
|
MatrixEvent(
|
||||||
|
content: {
|
||||||
|
'msgtype': file.msgType,
|
||||||
|
'body': file.name,
|
||||||
|
'filename': file.name,
|
||||||
|
},
|
||||||
|
type: EventTypes.Message,
|
||||||
|
eventId: txid,
|
||||||
|
senderId: client.userID!,
|
||||||
|
originServerTs: DateTime.now(),
|
||||||
|
unsigned: {
|
||||||
|
messageSendingStatusKey: EventStatus.sending.intValue,
|
||||||
|
'transaction_id': txid,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
MatrixFile uploadFile = file; // ignore: omit_local_variable_types
|
MatrixFile uploadFile = file; // ignore: omit_local_variable_types
|
||||||
// computing the thumbnail in case we can
|
// computing the thumbnail in case we can
|
||||||
thumbnail ??= (file is MatrixImageFile && encrypted
|
if (file is MatrixImageFile &&
|
||||||
? await file.generateThumbnail(compute: client.runInBackground)
|
(thumbnail == null || shrinkImageMaxDimension != null)) {
|
||||||
: null);
|
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
|
||||||
|
.unsigned![fileSendingStatusKey] =
|
||||||
|
FileSendingStatus.generatingThumbnail.name;
|
||||||
|
await _handleFakeSync(syncUpdate);
|
||||||
|
thumbnail ??=
|
||||||
|
await file.generateThumbnail(compute: client.runInBackground);
|
||||||
|
if (shrinkImageMaxDimension != null) {
|
||||||
|
file = await MatrixImageFile.shrink(
|
||||||
|
bytes: file.bytes,
|
||||||
|
name: file.name,
|
||||||
|
maxDimension: shrinkImageMaxDimension,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MatrixFile? uploadThumbnail =
|
MatrixFile? uploadThumbnail =
|
||||||
thumbnail; // ignore: omit_local_variable_types
|
thumbnail; // ignore: omit_local_variable_types
|
||||||
EncryptedFile? encryptedFile;
|
EncryptedFile? encryptedFile;
|
||||||
EncryptedFile? encryptedThumbnail;
|
EncryptedFile? encryptedThumbnail;
|
||||||
if (encrypted && client.fileEncryptionEnabled) {
|
if (encrypted && client.fileEncryptionEnabled) {
|
||||||
|
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
|
||||||
|
.unsigned![fileSendingStatusKey] = FileSendingStatus.encrypting.name;
|
||||||
|
await _handleFakeSync(syncUpdate);
|
||||||
encryptedFile = await file.encrypt();
|
encryptedFile = await file.encrypt();
|
||||||
uploadFile = encryptedFile.toMatrixFile();
|
uploadFile = encryptedFile.toMatrixFile();
|
||||||
|
|
||||||
|
|
@ -717,6 +773,9 @@ class Room {
|
||||||
Uri? uploadResp, thumbnailUploadResp;
|
Uri? uploadResp, thumbnailUploadResp;
|
||||||
|
|
||||||
final timeoutDate = DateTime.now().add(client.sendTimelineEventTimeout);
|
final timeoutDate = DateTime.now().add(client.sendTimelineEventTimeout);
|
||||||
|
|
||||||
|
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
|
||||||
|
.unsigned![fileSendingStatusKey] = FileSendingStatus.uploading.name;
|
||||||
while (uploadResp == null ||
|
while (uploadResp == null ||
|
||||||
(uploadThumbnail != null && thumbnailUploadResp == null)) {
|
(uploadThumbnail != null && thumbnailUploadResp == null)) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -733,9 +792,15 @@ class Room {
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
} on MatrixException catch (_) {
|
} on MatrixException catch (_) {
|
||||||
|
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
|
||||||
|
.unsigned![messageSendingStatusKey] = EventStatus.error.intValue;
|
||||||
|
await _handleFakeSync(syncUpdate);
|
||||||
rethrow;
|
rethrow;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
if (DateTime.now().isAfter(timeoutDate)) {
|
if (DateTime.now().isAfter(timeoutDate)) {
|
||||||
|
syncUpdate.rooms!.join!.values.first.timeline!.events!.first
|
||||||
|
.unsigned![messageSendingStatusKey] = EventStatus.error.intValue;
|
||||||
|
await _handleFakeSync(syncUpdate);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
Logs().v('Send File into room failed. Try again...');
|
Logs().v('Send File into room failed. Try again...');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue