Merge branch 'main' of gitlab.com:famedly/company/frontend/famedlysdk into td/fix-lastevent-preview

This commit is contained in:
Jayesh Nirve 2021-08-26 02:42:36 +05:30
commit 42614bdfbd
No known key found for this signature in database
GPG Key ID: E9F26B1FCEB549BD
11 changed files with 82 additions and 56 deletions

View File

@ -1,3 +1,8 @@
## [0.3.2] - 20nd Aug 2021
- feat: cache archived rooms to access them with `getRoomById`
- fix: requestHistory() for archived rooms
- refactor: Change name of archive getter to function
## [0.3.1] - 20nd Aug 2021 ## [0.3.1] - 20nd Aug 2021
- hotfix: Opt-out null safety for crypto files because of an error in web - hotfix: Opt-out null safety for crypto files because of an error in web

View File

@ -275,10 +275,14 @@ class Client extends MatrixApi {
return null; return null;
} }
/// Searches in the local cache for the given room and returns null if not
/// found. If you have loaded the [loadArchive()] before, it can also return
/// archived rooms.
Room getRoomById(String id) { Room getRoomById(String id) {
for (final room in rooms) { for (final room in <Room>[...rooms, ..._archivedRooms]) {
if (room.id == id) return room; if (room.id == id) return room;
} }
return null; return null;
} }
@ -645,8 +649,13 @@ class Client extends MatrixApi {
avatarUrl: profile.avatarUrl); avatarUrl: profile.avatarUrl);
} }
Future<List<Room>> get archive async { final List<Room> _archivedRooms = [];
final archiveList = <Room>[];
@Deprecated('Use [loadArchive()] instead.')
Future<List<Room>> get archive => loadArchive();
Future<List<Room>> loadArchive() async {
_archivedRooms.clear();
final syncResp = await sync( final syncResp = await sync(
filter: '{"room":{"include_leave":true,"timeline":{"limit":10}}}', filter: '{"room":{"include_leave":true,"timeline":{"limit":10}}}',
timeout: 0, timeout: 0,
@ -681,16 +690,16 @@ class Client extends MatrixApi {
)); ));
} }
} }
archiveList.add(leftRoom); _archivedRooms.add(leftRoom);
} }
} }
return archiveList; return _archivedRooms;
} }
/// Uploads a file and automatically caches it in the database, if it is small enough /// Uploads a file and automatically caches it in the database, if it is small enough
/// and returns the mxc url as a string. /// and returns the mxc url.
@override @override
Future<String> uploadContent(Uint8List file, Future<Uri> uploadContent(Uint8List file,
{String filename, String contentType}) async { {String filename, String contentType}) async {
final mxc = await super final mxc = await super
.uploadContent(file, filename: filename, contentType: contentType); .uploadContent(file, filename: filename, contentType: contentType);
@ -721,7 +730,7 @@ class Client extends MatrixApi {
/// Uploads a new user avatar for this user. /// Uploads a new user avatar for this user.
Future<void> setAvatar(MatrixFile file) async { Future<void> setAvatar(MatrixFile file) async {
final uploadResp = await uploadContent(file.bytes, filename: file.name); final uploadResp = await uploadContent(file.bytes, filename: file.name);
await setAvatarUrl(userID, Uri.parse(uploadResp)); await setAvatarUrl(userID, uploadResp);
return; return;
} }
@ -1296,7 +1305,8 @@ class Client extends MatrixApi {
await _handleRoomEvents( await _handleRoomEvents(
id, id,
room.timeline.events.map((i) => i.toJson()).toList(), room.timeline.events.map((i) => i.toJson()).toList(),
EventUpdateType.timeline); EventUpdateType.timeline,
sortAtTheEnd: sortAtTheEnd);
handledEvents = true; handledEvents = true;
} }
if (room.accountData?.isNotEmpty ?? false) { if (room.accountData?.isNotEmpty ?? false) {

View File

@ -81,9 +81,9 @@ abstract class DatabaseApi {
Future<List<Event>> getEventList(int clientId, Room room); Future<List<Event>> getEventList(int clientId, Room room);
Future<Uint8List> getFile(String mxcUri); Future<Uint8List> getFile(Uri mxcUri);
Future storeFile(String mxcUri, Uint8List bytes, int time); Future storeFile(Uri mxcUri, Uint8List bytes, int time);
Future storeSyncFilterId(String syncFilterId, int clientId); Future storeSyncFilterId(String syncFilterId, int clientId);

View File

@ -329,7 +329,7 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
} }
@override @override
Future<Uint8List> getFile(String mxcUri) async { Future<Uint8List> getFile(Uri mxcUri) async {
return null; return null;
} }
@ -886,7 +886,7 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
} }
@override @override
Future<void> storeFile(String mxcUri, Uint8List bytes, int time) async { Future<void> storeFile(Uri mxcUri, Uint8List bytes, int time) async {
return; return;
} }

View File

@ -401,16 +401,16 @@ class Event extends MatrixEvent {
: ''); : '');
/// Gets the underyling mxc url of an attachment of a file event, or null if not present /// Gets the underyling mxc url of an attachment of a file event, or null if not present
String get attachmentMxcUrl => Uri get attachmentMxcUrl => Uri.parse(
isAttachmentEncrypted ? content['file']['url'] : content['url']; isAttachmentEncrypted ? content['file']['url'] : content['url']);
/// Gets the underyling mxc url of a thumbnail of a file event, or null if not present /// Gets the underyling mxc url of a thumbnail of a file event, or null if not present
String get thumbnailMxcUrl => isThumbnailEncrypted Uri get thumbnailMxcUrl => Uri.parse(isThumbnailEncrypted
? infoMap['thumbnail_file']['url'] ? infoMap['thumbnail_file']['url']
: infoMap['thumbnail_url']; : infoMap['thumbnail_url']);
/// Gets the mxc url of an attachemnt/thumbnail of a file event, taking sizes into account, or null if not present /// Gets the mxc url of an attachemnt/thumbnail of a file event, taking sizes into account, or null if not present
String attachmentOrThumbnailMxcUrl({bool getThumbnail = false}) { Uri attachmentOrThumbnailMxcUrl({bool getThumbnail = false}) {
if (getThumbnail && if (getThumbnail &&
infoMap['size'] is int && infoMap['size'] is int &&
thumbnailInfoMap['size'] is int && thumbnailInfoMap['size'] is int &&
@ -479,8 +479,8 @@ class Event extends MatrixEvent {
throw ("This event has the type '$type' and so it can't contain an attachment."); throw ("This event has the type '$type' and so it can't contain an attachment.");
} }
final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail); final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail);
if (!(mxcUrl is String)) { if (mxcUrl == null) {
throw ("This event hasn't any attachment or thumbnail."); throw "This event hasn't any attachment or thumbnail.";
} }
getThumbnail = mxcUrl != attachmentMxcUrl; getThumbnail = mxcUrl != attachmentMxcUrl;
// Is this file storeable? // Is this file storeable?
@ -507,8 +507,8 @@ class Event extends MatrixEvent {
throw ("This event has the type '$type' and so it can't contain an attachment."); throw ("This event has the type '$type' and so it can't contain an attachment.");
} }
final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail); final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail);
if (!(mxcUrl is String)) { if (mxcUrl == null) {
throw ("This event hasn't any attachment or thumbnail."); throw "This event hasn't any attachment or thumbnail.";
} }
getThumbnail = mxcUrl != attachmentMxcUrl; getThumbnail = mxcUrl != attachmentMxcUrl;
final isEncrypted = final isEncrypted =
@ -517,7 +517,6 @@ class Event extends MatrixEvent {
if (isEncrypted && !room.client.encryptionEnabled) { if (isEncrypted && !room.client.encryptionEnabled) {
throw ('Encryption is not enabled in your Client.'); throw ('Encryption is not enabled in your Client.');
} }
final mxContent = Uri.parse(mxcUrl);
Uint8List uint8list; Uint8List uint8list;
@ -528,7 +527,7 @@ class Event extends MatrixEvent {
thisInfoMap['size'] <= room.client.database.maxFileSize; thisInfoMap['size'] <= room.client.database.maxFileSize;
if (storeable) { if (storeable) {
uint8list = await room.client.database.getFile(mxContent.toString()); uint8list = await room.client.database.getFile(mxcUrl);
} }
// Download the file // Download the file
@ -536,13 +535,12 @@ class Event extends MatrixEvent {
downloadCallback ??= (Uri url) async { downloadCallback ??= (Uri url) async {
return (await http.get(url)).bodyBytes; return (await http.get(url)).bodyBytes;
}; };
uint8list = uint8list = await downloadCallback(mxcUrl.getDownloadLink(room.client));
await downloadCallback(mxContent.getDownloadLink(room.client));
storeable = storeable && storeable = storeable &&
uint8list.lengthInBytes < room.client.database.maxFileSize; uint8list.lengthInBytes < room.client.database.maxFileSize;
if (storeable) { if (storeable) {
await room.client.database.storeFile(mxContent.toString(), uint8list, await room.client.database.storeFile(
DateTime.now().millisecondsSinceEpoch); mxcUrl, uint8list, DateTime.now().millisecondsSinceEpoch);
} }
} }

View File

@ -630,7 +630,7 @@ class Room {
/// the message event has received the server. Otherwise the future will only /// the message event has received the server. Otherwise the future will only
/// wait until the file has been uploaded. /// wait until the file has been uploaded.
/// Optionally specify [extraContent] to tack on to the event. /// Optionally specify [extraContent] to tack on to the event.
Future<String> sendFileEvent( Future<Uri> sendFileEvent(
MatrixFile file, { MatrixFile file, {
String txid, String txid,
Event inReplyTo, Event inReplyTo,
@ -670,10 +670,10 @@ class Room {
'msgtype': file.msgType, 'msgtype': file.msgType,
'body': file.name, 'body': file.name,
'filename': file.name, 'filename': file.name,
if (encryptedFile == null) 'url': uploadResp, if (encryptedFile == null) 'url': uploadResp.toString(),
if (encryptedFile != null) if (encryptedFile != null)
'file': { 'file': {
'url': uploadResp, 'url': uploadResp.toString(),
'mimetype': file.mimeType, 'mimetype': file.mimeType,
'v': 'v2', 'v': 'v2',
'key': { 'key': {
@ -692,7 +692,7 @@ class Room {
'thumbnail_url': thumbnailUploadResp, 'thumbnail_url': thumbnailUploadResp,
if (thumbnail != null && encryptedThumbnail != null) if (thumbnail != null && encryptedThumbnail != null)
'thumbnail_file': { 'thumbnail_file': {
'url': thumbnailUploadResp, 'url': thumbnailUploadResp.toString(),
'mimetype': thumbnail.mimeType, 'mimetype': thumbnail.mimeType,
'v': 'v2', 'v': 'v2',
'key': { 'key': {
@ -959,12 +959,22 @@ class Room {
await client.handleSync( await client.handleSync(
SyncUpdate(nextBatch: '') SyncUpdate(nextBatch: '')
..rooms = (RoomsUpdate() ..rooms = (RoomsUpdate()
..join = ({}..[id] = (JoinedRoomUpdate() ..join = membership == Membership.join
? ({}..[id] = ((JoinedRoomUpdate()
..state = resp.state ..state = resp.state
..timeline = (TimelineUpdate() ..timeline = (TimelineUpdate()
..limited = false ..limited = false
..events = resp.chunk ..events = resp.chunk
..prevBatch = resp.end)))), ..prevBatch = resp.end))))
: null
..leave = membership != Membership.join
? ({}..[id] = ((LeftRoomUpdate()
..state = resp.state
..timeline = (TimelineUpdate()
..limited = false
..events = resp.chunk
..prevBatch = resp.end))))
: null),
sortAtTheEnd: true); sortAtTheEnd: true);
}; };
@ -1322,7 +1332,7 @@ class Room {
id, id,
EventTypes.RoomAvatar, EventTypes.RoomAvatar,
'', '',
{'url': uploadResp}, {'url': uploadResp.toString()},
); );
} }

View File

@ -1,6 +1,6 @@
name: matrix name: matrix
description: Matrix Dart SDK description: Matrix Dart SDK
version: 0.3.1 version: 0.3.2
homepage: https://famedly.com homepage: https://famedly.com
environment: environment:
@ -16,7 +16,7 @@ dependencies:
crypto: ^3.0.0 crypto: ^3.0.0
base58check: ^2.0.0 base58check: ^2.0.0
olm: ^2.0.0 olm: ^2.0.0
matrix_api_lite: ^0.4.1 matrix_api_lite: ^0.4.2
hive: ^2.0.4 hive: ^2.0.4
ffi: ^1.0.0 ffi: ^1.0.0
js: ^0.6.3 js: ^0.6.3

View File

@ -351,7 +351,7 @@ void main() {
}); });
test('get archive', () async { test('get archive', () async {
final archive = await matrix.archive; final archive = await matrix.loadArchive();
await Future.delayed(Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 50));
expect(archive.length, 2); expect(archive.length, 2);
@ -645,7 +645,7 @@ void main() {
final client = await getClient(); final client = await getClient();
final response = final response =
await client.uploadContent(Uint8List(0), filename: 'file.jpeg'); await client.uploadContent(Uint8List(0), filename: 'file.jpeg');
expect(response, 'mxc://example.com/AQwafuaFswefuhsfAFAgsw'); expect(response.toString(), 'mxc://example.com/AQwafuaFswefuhsfAFAgsw');
expect(await client.database.getFile(response) != null, expect(await client.database.getFile(response) != null,
client.database.supportsFileStoring); client.database.supportsFileStoring);
await client.dispose(closeDatabase: true); await client.dispose(closeDatabase: true);

View File

@ -67,16 +67,17 @@ void testDatabase(Future<DatabaseApi> futureDatabase, int clientId) {
expect(toDeviceQueue.isEmpty, true); expect(toDeviceQueue.isEmpty, true);
}); });
test('storeFile', () async { test('storeFile', () async {
await database.storeFile('mxc://test', Uint8List.fromList([0]), 0); await database.storeFile(
final file = await database.getFile('mxc://test'); Uri.parse('mxc://test'), Uint8List.fromList([0]), 0);
final file = await database.getFile(Uri.parse('mxc://test'));
expect(file != null, database.supportsFileStoring); expect(file != null, database.supportsFileStoring);
}); });
test('getFile', () async { test('getFile', () async {
await database.getFile('mxc://test'); await database.getFile(Uri.parse('mxc://test'));
}); });
test('deleteOldFiles', () async { test('deleteOldFiles', () async {
await database.deleteOldFiles(1); await database.deleteOldFiles(1);
final file = await database.getFile('mxc://test'); final file = await database.getFile(Uri.parse('mxc://test'));
expect(file == null, true); expect(file == null, true);
}); });
test('storeRoomUpdate', () async { test('storeRoomUpdate', () async {

View File

@ -1090,8 +1090,9 @@ void main() {
var buffer = await event.downloadAndDecryptAttachment( var buffer = await event.downloadAndDecryptAttachment(
downloadCallback: downloadCallback); downloadCallback: downloadCallback);
expect(buffer.bytes, FILE_BUFF); expect(buffer.bytes, FILE_BUFF);
expect(event.attachmentOrThumbnailMxcUrl(), 'mxc://example.org/file'); expect(event.attachmentOrThumbnailMxcUrl().toString(),
expect(event.attachmentOrThumbnailMxcUrl(getThumbnail: true), 'mxc://example.org/file');
expect(event.attachmentOrThumbnailMxcUrl(getThumbnail: true).toString(),
'mxc://example.org/file'); 'mxc://example.org/file');
event = Event.fromJson({ event = Event.fromJson({
@ -1118,10 +1119,11 @@ void main() {
expect(event.isThumbnailEncrypted, false); expect(event.isThumbnailEncrypted, false);
expect(event.attachmentMimetype, 'application/octet-stream'); expect(event.attachmentMimetype, 'application/octet-stream');
expect(event.thumbnailMimetype, 'thumbnail/mimetype'); expect(event.thumbnailMimetype, 'thumbnail/mimetype');
expect(event.attachmentMxcUrl, 'mxc://example.org/file'); expect(event.attachmentMxcUrl.toString(), 'mxc://example.org/file');
expect(event.thumbnailMxcUrl, 'mxc://example.org/thumb'); expect(event.thumbnailMxcUrl.toString(), 'mxc://example.org/thumb');
expect(event.attachmentOrThumbnailMxcUrl(), 'mxc://example.org/file'); expect(event.attachmentOrThumbnailMxcUrl().toString(),
expect(event.attachmentOrThumbnailMxcUrl(getThumbnail: true), 'mxc://example.org/file');
expect(event.attachmentOrThumbnailMxcUrl(getThumbnail: true).toString(),
'mxc://example.org/thumb'); 'mxc://example.org/thumb');
expect(event.getAttachmentUrl().toString(), expect(event.getAttachmentUrl().toString(),
'https://fakeserver.notexisting/_matrix/media/r0/download/example.org/file'); 'https://fakeserver.notexisting/_matrix/media/r0/download/example.org/file');
@ -1238,8 +1240,8 @@ void main() {
expect(event.isThumbnailEncrypted, true); expect(event.isThumbnailEncrypted, true);
expect(event.attachmentMimetype, 'text/plain'); expect(event.attachmentMimetype, 'text/plain');
expect(event.thumbnailMimetype, 'text/plain'); expect(event.thumbnailMimetype, 'text/plain');
expect(event.attachmentMxcUrl, 'mxc://example.com/file'); expect(event.attachmentMxcUrl.toString(), 'mxc://example.com/file');
expect(event.thumbnailMxcUrl, 'mxc://example.com/thumb'); expect(event.thumbnailMxcUrl.toString(), 'mxc://example.com/thumb');
buffer = await event.downloadAndDecryptAttachment( buffer = await event.downloadAndDecryptAttachment(
downloadCallback: downloadCallback); downloadCallback: downloadCallback);
expect(buffer.bytes, FILE_BUFF_DEC); expect(buffer.bytes, FILE_BUFF_DEC);

View File

@ -587,7 +587,7 @@ void main() {
test('sendFileEvent', () async { test('sendFileEvent', () async {
final testFile = MatrixFile(bytes: Uint8List(0), name: 'file.jpeg'); final testFile = MatrixFile(bytes: Uint8List(0), name: 'file.jpeg');
final dynamic resp = await room.sendFileEvent(testFile, txid: 'testtxid'); final dynamic resp = await room.sendFileEvent(testFile, txid: 'testtxid');
expect(resp, 'mxc://example.com/AQwafuaFswefuhsfAFAgsw'); expect(resp.toString(), 'mxc://example.com/AQwafuaFswefuhsfAFAgsw');
}); });
test('pushRuleState', () async { test('pushRuleState', () async {