diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b7aeaa85..d6e742c4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,7 @@
-stages:
- - coverage
- - builddocs
- - deploy
- - publish
+include:
+ - project: "famedly/company/frontend/ci-templates"
+ ref: main
+ file: "/all.yml"
workflow:
rules:
@@ -16,7 +15,7 @@ variables:
coverage:
tags:
- linux
- stage: coverage
+ stage: test
image: registry.gitlab.com/famedly/company/frontend/flutter-dockerimages/flutter-linux/stable:${FLUTTER_IMAGE_TAG}
dependencies: []
script:
@@ -31,7 +30,7 @@ coverage:
coverage_without_olm:
tags:
- linux
- stage: coverage
+ stage: test
image: dart
dependencies: []
script:
@@ -41,7 +40,7 @@ coverage_without_olm:
e2ee_test:
tags:
- linux
- stage: coverage
+ stage: test
image: registry.gitlab.com/famedly/company/frontend/flutter-dockerimages/flutter-linux/stable:${FLUTTER_IMAGE_TAG}
dependencies: []
script:
@@ -51,35 +50,8 @@ e2ee_test:
timeout: 16m
resource_group: e2ee_test
-code_analyze:
- tags:
- - docker
- stage: coverage
- image: dart
- dependencies: []
- script:
- - dart pub get
- - dart format lib/ test/ test_driver/ --set-exit-if-changed
- - dart analyze
-
-code_quality:
- tags:
- - docker
- stage: coverage
- image: dart
- before_script:
- - dart pub global activate dart_code_metrics
- script:
- - dart pub global run dart_code_metrics:metrics analyze lib -r gitlab > code-quality-report.json
- artifacts:
- reports:
- codequality: code-quality-report.json
- # also create an actual artifact for inspection purposes
- paths:
- - code-quality-report.json
-
dry-run:
- stage: publish
+ stage: deploy
image: dart
script:
- rm -rf ./docs
@@ -88,7 +60,7 @@ dry-run:
pub-dev:
- stage: publish
+ stage: deploy
image: dart
dependencies: [
dry-run
diff --git a/lib/encryption/cross_signing.dart b/lib/encryption/cross_signing.dart
index 60d9a64c..ac4afed7 100644
--- a/lib/encryption/cross_signing.dart
+++ b/lib/encryption/cross_signing.dart
@@ -18,9 +18,9 @@
import 'dart:typed_data';
-import 'package:matrix/encryption/utils/base64_unpadded.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:matrix/encryption/utils/base64_unpadded.dart';
import '../matrix.dart';
import 'encryption.dart';
import 'ssss.dart';
diff --git a/lib/encryption/encryption.dart b/lib/encryption/encryption.dart
index 73e30406..19c8f508 100644
--- a/lib/encryption/encryption.dart
+++ b/lib/encryption/encryption.dart
@@ -16,8 +16,8 @@
* along with this program. If not, see .
*/
-import 'dart:convert';
import 'dart:async';
+import 'dart:convert';
import 'package:olm/olm.dart' as olm;
diff --git a/lib/encryption/key_manager.dart b/lib/encryption/key_manager.dart
index 2182ae6f..5fc4c3fb 100644
--- a/lib/encryption/key_manager.dart
+++ b/lib/encryption/key_manager.dart
@@ -19,16 +19,16 @@
import 'dart:async';
import 'dart:convert';
+import 'package:collection/collection.dart';
+import 'package:olm/olm.dart' as olm;
+
import 'package:matrix/encryption/utils/base64_unpadded.dart';
import 'package:matrix/encryption/utils/stored_inbound_group_session.dart';
-import 'package:olm/olm.dart' as olm;
-import 'package:collection/collection.dart';
-
+import '../matrix.dart';
+import '../src/utils/run_in_root.dart';
import './encryption.dart';
import './utils/outbound_group_session.dart';
import './utils/session_key.dart';
-import '../matrix.dart';
-import '../src/utils/run_in_root.dart';
const megolmKey = EventTypes.MegolmBackup;
diff --git a/lib/encryption/olm_manager.dart b/lib/encryption/olm_manager.dart
index 24529a4e..0a040733 100644
--- a/lib/encryption/olm_manager.dart
+++ b/lib/encryption/olm_manager.dart
@@ -21,9 +21,9 @@ import 'dart:convert';
import 'package:async/async.dart';
import 'package:canonical_json/canonical_json.dart';
import 'package:collection/collection.dart';
-import 'package:matrix/matrix.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:matrix/matrix.dart';
import '../encryption/utils/json_signature_check_extension.dart';
import '../src/utils/run_in_root.dart';
import 'encryption.dart';
diff --git a/lib/encryption/ssss.dart b/lib/encryption/ssss.dart
index 60e4dabf..9941b873 100644
--- a/lib/encryption/ssss.dart
+++ b/lib/encryption/ssss.dart
@@ -22,10 +22,10 @@ import 'dart:core';
import 'dart:typed_data';
import 'package:base58check/base58.dart';
-import 'package:crypto/crypto.dart';
import 'package:collection/collection.dart';
-import 'package:matrix/encryption/utils/base64_unpadded.dart';
+import 'package:crypto/crypto.dart';
+import 'package:matrix/encryption/utils/base64_unpadded.dart';
import '../matrix.dart';
import '../src/utils/crypto/crypto.dart' as uc;
import '../src/utils/run_in_root.dart';
diff --git a/lib/encryption/utils/bootstrap.dart b/lib/encryption/utils/bootstrap.dart
index 515d0744..62482dcc 100644
--- a/lib/encryption/utils/bootstrap.dart
+++ b/lib/encryption/utils/bootstrap.dart
@@ -22,10 +22,10 @@ import 'dart:typed_data';
import 'package:canonical_json/canonical_json.dart';
import 'package:olm/olm.dart' as olm;
-import '../encryption.dart';
-import '../ssss.dart';
-import '../key_manager.dart';
import '../../matrix.dart';
+import '../encryption.dart';
+import '../key_manager.dart';
+import '../ssss.dart';
import 'base64_unpadded.dart';
enum BootstrapState {
diff --git a/lib/encryption/utils/session_key.dart b/lib/encryption/utils/session_key.dart
index 310b1397..e219f658 100644
--- a/lib/encryption/utils/session_key.dart
+++ b/lib/encryption/utils/session_key.dart
@@ -16,10 +16,10 @@
* along with this program. If not, see .
*/
-import 'package:matrix/encryption/utils/stored_inbound_group_session.dart';
import 'package:matrix_api_lite/src/utils/filter_map_extension.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:matrix/encryption/utils/stored_inbound_group_session.dart';
import '../../matrix.dart';
class SessionKey {
diff --git a/lib/msc_extensions/msc_2835_uia_login/msc_2835_uia_login.dart b/lib/msc_extensions/msc_2835_uia_login/msc_2835_uia_login.dart
index e90a858a..d5b435de 100644
--- a/lib/msc_extensions/msc_2835_uia_login/msc_2835_uia_login.dart
+++ b/lib/msc_extensions/msc_2835_uia_login/msc_2835_uia_login.dart
@@ -3,6 +3,7 @@ library msc_2835_uia_login;
import 'dart:convert';
import 'package:http/http.dart' hide Client;
+
import 'package:matrix/matrix.dart';
extension UiaLogin on Client {
diff --git a/lib/src/client.dart b/lib/src/client.dart
index 56cb6d9b..e3312a7b 100644
--- a/lib/src/client.dart
+++ b/lib/src/client.dart
@@ -23,15 +23,16 @@ import 'dart:typed_data';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:http/http.dart' as http;
-import 'package:matrix/src/utils/cached_stream_controller.dart';
-import 'package:matrix/src/utils/run_in_root.dart';
-import 'package:matrix/src/utils/sync_update_item_count.dart';
import 'package:mime/mime.dart';
import 'package:olm/olm.dart' as olm;
import 'package:random_string/random_string.dart';
+import 'package:matrix/src/utils/cached_stream_controller.dart';
+import 'package:matrix/src/utils/run_in_root.dart';
+import 'package:matrix/src/utils/sync_update_item_count.dart';
import '../encryption.dart';
import '../matrix.dart';
+import 'models/timeline_chunk.dart';
import 'utils/multilock.dart';
import 'utils/run_benchmarked.dart';
@@ -287,7 +288,7 @@ class Client extends MatrixApi {
/// found. If you have loaded the [loadArchive()] before, it can also return
/// archived rooms.
Room? getRoomById(String id) {
- for (final room in [...rooms, ..._archivedRooms]) {
+ for (final room in [...rooms, ..._archivedRooms.map((e) => e.room)]) {
if (room.id == id) return room;
}
@@ -781,9 +782,35 @@ class Client extends MatrixApi {
avatarUrl: profile.avatarUrl);
}
- final List _archivedRooms = [];
+ final List _archivedRooms = [];
+ /// Return an archive room containing the room and the timeline for a specific archived room.
+ ArchivedRoom? getArchiveRoomFromCache(String roomId) {
+ for (var i = 0; i < _archivedRooms.length; i++) {
+ final archive = _archivedRooms[i];
+ if (archive.room.id == roomId) return archive;
+ }
+ return null;
+ }
+
+ /// Remove all the archives stored in cache.
+ void clearArchivesFromCache() {
+ _archivedRooms.clear();
+ }
+
+ @Deprecated('Use [loadArchive()] instead.')
+ Future> get archive => loadArchive();
+
+ /// Fetch all the archived rooms from the server and return the list of the
+ /// room. If you want to have the Timelines bundled with it, use
+ /// loadArchiveWithTimeline instead.
Future> loadArchive() async {
+ return (await loadArchiveWithTimeline()).map((e) => e.room).toList();
+ }
+
+ /// Fetch the archived rooms from the server and return them as a list of
+ /// [ArchivedRoom] objects containing the [Room] and the associated [Timeline].
+ Future> loadArchiveWithTimeline() async {
_archivedRooms.clear();
final syncResp = await sync(
filter: '{"room":{"include_leave":true,"timeline":{"limit":10}}}',
@@ -804,12 +831,32 @@ class Client extends MatrixApi {
{},
);
+ final timeline = Timeline(
+ room: leftRoom,
+ chunk: TimelineChunk(
+ events: room.timeline?.events?.reversed
+ .toList() // we display the event in the other sence
+ .map((e) => Event.fromMatrixEvent(e, leftRoom))
+ .toList() ??
+ []));
+
+ for (var i = 0; i < timeline.events.length; i++) {
+ // Try to decrypt encrypted events but don't update the database.
+ if (leftRoom.encrypted && leftRoom.client.encryptionEnabled) {
+ if (timeline.events[i].type == EventTypes.Encrypted) {
+ timeline.events[i] = await leftRoom.client.encryption!
+ .decryptRoomEvent(leftRoom.id, timeline.events[i]);
+ }
+ }
+ }
+
room.timeline?.events?.forEach((event) {
leftRoom.setState(Event.fromMatrixEvent(
event,
leftRoom,
));
});
+
leftRoom.prev_batch = room.timeline?.prevBatch;
room.state?.forEach((event) {
leftRoom.setState(Event.fromMatrixEvent(
@@ -817,7 +864,8 @@ class Client extends MatrixApi {
leftRoom,
));
});
- _archivedRooms.add(leftRoom);
+
+ _archivedRooms.add(ArchivedRoom(room: leftRoom, timeline: timeline));
}
}
return _archivedRooms;
@@ -1658,6 +1706,12 @@ class Client extends MatrixApi {
await database?.storeRoomUpdate(id, syncRoomUpdate, this);
final room = _updateRoomsByRoomUpdate(id, syncRoomUpdate);
+ final timelineUpdateType = direction != null
+ ? (direction == Direction.b
+ ? EventUpdateType.history
+ : EventUpdateType.timeline)
+ : EventUpdateType.timeline;
+
/// Handle now all room events and save them in the database
if (syncRoomUpdate is JoinedRoomUpdate) {
final state = syncRoomUpdate.state;
@@ -1673,14 +1727,7 @@ class Client extends MatrixApi {
final timelineEvents = syncRoomUpdate.timeline?.events;
if (timelineEvents != null && timelineEvents.isNotEmpty) {
- await _handleRoomEvents(
- room,
- timelineEvents,
- direction != null
- ? (direction == Direction.b
- ? EventUpdateType.history
- : EventUpdateType.timeline)
- : EventUpdateType.timeline);
+ await _handleRoomEvents(room, timelineEvents, timelineUpdateType);
}
final ephemeral = syncRoomUpdate.ephemeral;
@@ -1705,23 +1752,19 @@ class Client extends MatrixApi {
if (syncRoomUpdate is LeftRoomUpdate) {
final timelineEvents = syncRoomUpdate.timeline?.events;
if (timelineEvents != null && timelineEvents.isNotEmpty) {
- await _handleRoomEvents(
- room,
- timelineEvents,
- EventUpdateType.timeline,
- );
+ await _handleRoomEvents(room, timelineEvents, timelineUpdateType,
+ store: false);
}
final accountData = syncRoomUpdate.accountData;
if (accountData != null && accountData.isNotEmpty) {
await _handleRoomEvents(
- room,
- accountData,
- EventUpdateType.accountData,
- );
+ room, accountData, EventUpdateType.accountData,
+ store: false);
}
final state = syncRoomUpdate.state;
if (state != null && state.isNotEmpty) {
- await _handleRoomEvents(room, state, EventUpdateType.state);
+ await _handleRoomEvents(room, state, EventUpdateType.state,
+ store: false);
}
}
@@ -1795,10 +1838,8 @@ class Client extends MatrixApi {
}
Future _handleRoomEvents(
- Room room,
- List events,
- EventUpdateType type,
- ) async {
+ Room room, List events, EventUpdateType type,
+ {bool store = true}) async {
// Calling events can be omitted if they are outdated from the same sync. So
// we collect them first before we handle them.
final callEvents = {};
@@ -1833,7 +1874,7 @@ class Client extends MatrixApi {
}
}
_updateRoomsByEventUpdate(room, update);
- if (type != EventUpdateType.ephemeral) {
+ if (type != EventUpdateType.ephemeral && store) {
await database?.storeEventUpdate(update, this);
}
if (encryptionEnabled) {
@@ -1941,6 +1982,10 @@ class Client extends MatrixApi {
// Does the chat already exist in the list rooms?
if (!found && membership != Membership.leave) {
+ // Check if the room is not in the rooms in the invited list
+ if (_archivedRooms.isNotEmpty) {
+ _archivedRooms.removeWhere((archive) => archive.room.id == roomId);
+ }
final position = membership == Membership.invite ? 0 : rooms.length;
// Add the new chat to the list
rooms.insert(position, room);
@@ -2857,3 +2902,9 @@ class HomeserverSummary {
required this.loginFlows,
});
}
+
+class ArchivedRoom {
+ final Room room;
+ final Timeline timeline;
+ ArchivedRoom({required this.room, required this.timeline});
+}
diff --git a/lib/src/database/database_api.dart b/lib/src/database/database_api.dart
index c8a65477..1d32f777 100644
--- a/lib/src/database/database_api.dart
+++ b/lib/src/database/database_api.dart
@@ -23,7 +23,6 @@ import 'package:matrix/encryption/utils/outbound_group_session.dart';
import 'package:matrix/encryption/utils/ssss_cache.dart';
import 'package:matrix/encryption/utils/stored_inbound_group_session.dart';
import 'package:matrix/src/utils/queued_to_device_event.dart';
-
import '../../matrix.dart';
abstract class DatabaseApi {
diff --git a/lib/src/database/fluffybox_database.dart b/lib/src/database/fluffybox_database.dart
index 804dcdda..c94c3069 100644
--- a/lib/src/database/fluffybox_database.dart
+++ b/lib/src/database/fluffybox_database.dart
@@ -23,6 +23,7 @@ import 'dart:typed_data';
import 'package:fluffybox/fluffybox.dart';
import 'package:fluffybox/hive.dart' show HiveCipher;
+
import 'package:matrix/encryption/utils/olm_session.dart';
import 'package:matrix/encryption/utils/outbound_group_session.dart';
import 'package:matrix/encryption/utils/ssss_cache.dart';
diff --git a/lib/src/database/hive_collections_database.dart b/lib/src/database/hive_collections_database.dart
index b9d10d26..2a5663b3 100644
--- a/lib/src/database/hive_collections_database.dart
+++ b/lib/src/database/hive_collections_database.dart
@@ -22,6 +22,7 @@ import 'dart:math';
import 'dart:typed_data';
import 'package:hive/hive.dart';
+
import 'package:matrix/encryption/utils/olm_session.dart';
import 'package:matrix/encryption/utils/outbound_group_session.dart';
import 'package:matrix/encryption/utils/ssss_cache.dart';
diff --git a/lib/src/database/hive_database.dart b/lib/src/database/hive_database.dart
index d8b285c0..cb5f6386 100644
--- a/lib/src/database/hive_database.dart
+++ b/lib/src/database/hive_database.dart
@@ -22,6 +22,7 @@ import 'dart:math';
import 'dart:typed_data';
import 'package:hive/hive.dart';
+
import 'package:matrix/encryption/utils/olm_session.dart';
import 'package:matrix/encryption/utils/outbound_group_session.dart';
import 'package:matrix/encryption/utils/ssss_cache.dart';
diff --git a/lib/src/event.dart b/lib/src/event.dart
index 6218cd97..385564b9 100644
--- a/lib/src/event.dart
+++ b/lib/src/event.dart
@@ -22,8 +22,8 @@ import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:html/parser.dart';
import 'package:http/http.dart' as http;
-import 'package:matrix/src/utils/file_send_request_credentials.dart';
+import 'package:matrix/src/utils/file_send_request_credentials.dart';
import '../matrix.dart';
import 'utils/event_localizations.dart';
import 'utils/html_to_text.dart';
diff --git a/lib/src/room.dart b/lib/src/room.dart
index c8c80437..207c6be5 100644
--- a/lib/src/room.dart
+++ b/lib/src/room.dart
@@ -22,12 +22,12 @@ import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:html_unescape/html_unescape.dart';
+
import 'package:matrix/src/models/timeline_chunk.dart';
+import 'package:matrix/src/utils/cached_stream_controller.dart';
import 'package:matrix/src/utils/crypto/crypto.dart';
import 'package:matrix/src/utils/file_send_request_credentials.dart';
-import 'package:matrix/src/utils/cached_stream_controller.dart';
import 'package:matrix/src/utils/space_child.dart';
-
import '../matrix.dart';
import 'utils/markdown.dart';
import 'utils/marked_unread.dart';
@@ -1136,6 +1136,9 @@ class Room {
void Function()? onHistoryReceived,
direction = Direction.b}) async {
final prev_batch = this.prev_batch;
+
+ final storeInDatabase = !isArchived;
+
if (prev_batch == null) {
throw 'Tried to request history without a prev_batch token';
}
@@ -1179,7 +1182,9 @@ class Room {
state: resp.state,
timeline: TimelineUpdate(
limited: false,
- events: resp.chunk,
+ events: direction == Direction.b
+ ? resp.chunk
+ : resp.chunk.reversed.toList(),
prevBatch: direction == Direction.b
? resp.end
: resp.start,
@@ -1193,7 +1198,9 @@ class Room {
if (client.database != null) {
await client.database?.transaction(() async {
- await client.database?.setRoomPrevBatch(resp.end!, id, client);
+ if (storeInDatabase) {
+ await client.database?.setRoomPrevBatch(resp.end!, id, client);
+ }
await loadFn();
});
} else {
@@ -1304,6 +1311,9 @@ class Room {
return;
}
+ /// Is the room archived
+ bool get isArchived => membership == Membership.leave;
+
/// Creates a timeline from the store. Returns a [Timeline] object. If you
/// just want to update the whole timeline on every change, use the [onUpdate]
/// callback. For updating only the parts that have changed, use the
@@ -1319,35 +1329,41 @@ class Room {
String? eventContextId}) async {
await postLoad();
- final _events = await client.database?.getEventList(
- this,
- limit: defaultHistoryCount,
- );
+ var events;
- var chunk = TimelineChunk(events: _events ?? []);
+ if (!isArchived) {
+ events = await client.database?.getEventList(
+ this,
+ limit: defaultHistoryCount,
+ ) ??
+ [];
+ } else {
+ final archive = client.getArchiveRoomFromCache(id);
+ events = archive?.timeline.events.toList() ?? [];
+ }
- if (_events != null) {
- if (eventContextId != null) {
- if (_events
- .firstWhereOrNull((event) => event.eventId == eventContextId) !=
- null) {
- chunk = TimelineChunk(events: _events);
- } else {
- chunk = await getEventContext(eventContextId) ??
- TimelineChunk(events: []);
- }
- }
-
- // Fetch all users from database we have got here.
- if (eventContextId == null) {
- for (final event in _events) {
- if (getState(EventTypes.RoomMember, event.senderId) != null) continue;
- final dbUser = await client.database?.getUser(event.senderId, this);
- if (dbUser != null) setState(dbUser);
- }
+ var chunk = TimelineChunk(events: events);
+ // Load the timeline arround eventContextId if set
+ if (eventContextId != null) {
+ if (events.firstWhereOrNull((event) => event.eventId == eventContextId) !=
+ null) {
+ chunk = TimelineChunk(events: events);
+ } else {
+ chunk =
+ await getEventContext(eventContextId) ?? TimelineChunk(events: []);
}
}
+ // Fetch all users from database we have got here.
+ if (eventContextId == null) {
+ for (final event in events) {
+ if (getState(EventTypes.RoomMember, event.senderId) != null) continue;
+ final dbUser = await client.database?.getUser(event.senderId, this);
+ if (dbUser != null) setState(dbUser);
+ }
+ }
+
+ // Try again to decrypt encrypted events and update the database.
if (encrypted && client.encryptionEnabled) {
// decrypt messages
for (var i = 0; i < chunk.events.length; i++) {
@@ -1364,8 +1380,9 @@ class Room {
await client.database?.transaction(() async {
for (var i = 0; i < chunk.events.length; i++) {
if (chunk.events[i].content['can_request_session'] == true) {
- chunk.events[i] = await client.encryption!
- .decryptRoomEvent(id, chunk.events[i], store: true);
+ chunk.events[i] = await client.encryption!.decryptRoomEvent(
+ id, chunk.events[i],
+ store: !isArchived);
}
}
});
diff --git a/lib/src/timeline.dart b/lib/src/timeline.dart
index c85d206e..581bfdde 100644
--- a/lib/src/timeline.dart
+++ b/lib/src/timeline.dart
@@ -224,9 +224,7 @@ class Timeline {
}
// Try to decrypt encrypted events but don't update the database.
- if (room.encrypted &&
- room.client.database != null &&
- room.client.encryptionEnabled) {
+ if (room.encrypted && room.client.encryptionEnabled) {
for (var i = 0; i < newEvents.length; i++) {
if (newEvents[i].type == EventTypes.Encrypted) {
newEvents[i] = await room.client.encryption!
diff --git a/lib/src/utils/crypto/crypto.dart b/lib/src/utils/crypto/crypto.dart
index 7bbddf80..a97417ee 100644
--- a/lib/src/utils/crypto/crypto.dart
+++ b/lib/src/utils/crypto/crypto.dart
@@ -18,8 +18,8 @@
export 'native.dart' if (dart.library.js) 'js.dart';
-import 'dart:typed_data';
import 'dart:math';
+import 'dart:typed_data';
Uint8List secureRandomBytes(int len) {
final rng = Random.secure();
diff --git a/lib/src/utils/crypto/encrypted_file.dart b/lib/src/utils/crypto/encrypted_file.dart
index d3dd874b..5d5dcbc1 100644
--- a/lib/src/utils/crypto/encrypted_file.dart
+++ b/lib/src/utils/crypto/encrypted_file.dart
@@ -15,11 +15,11 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import 'dart:typed_data';
+
import 'dart:convert';
+import 'dart:typed_data';
import 'package:matrix/encryption/utils/base64_unpadded.dart';
-
import 'crypto.dart';
class EncryptedFile {
diff --git a/lib/src/utils/crypto/ffi.dart b/lib/src/utils/crypto/ffi.dart
index f4415c14..ed32e2c9 100644
--- a/lib/src/utils/crypto/ffi.dart
+++ b/lib/src/utils/crypto/ffi.dart
@@ -15,6 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+
import 'dart:ffi';
import 'dart:io';
diff --git a/lib/src/utils/crypto/js.dart b/lib/src/utils/crypto/js.dart
index b889720a..7b6ad5f2 100644
--- a/lib/src/utils/crypto/js.dart
+++ b/lib/src/utils/crypto/js.dart
@@ -3,8 +3,8 @@
import 'dart:typed_data';
-import 'subtle.dart';
import 'subtle.dart' as subtle;
+import 'subtle.dart';
abstract class Hash {
Hash._(this.name);
diff --git a/lib/src/utils/crypto/native.dart b/lib/src/utils/crypto/native.dart
index ce317859..e66c0b7a 100644
--- a/lib/src/utils/crypto/native.dart
+++ b/lib/src/utils/crypto/native.dart
@@ -1,6 +1,7 @@
import 'dart:async';
-import 'dart:typed_data';
import 'dart:ffi';
+import 'dart:typed_data';
+
import 'package:ffi/ffi.dart';
import 'ffi.dart';
diff --git a/lib/src/utils/crypto/subtle.dart b/lib/src/utils/crypto/subtle.dart
index a96ea31c..34997373 100644
--- a/lib/src/utils/crypto/subtle.dart
+++ b/lib/src/utils/crypto/subtle.dart
@@ -4,11 +4,12 @@
@JS()
library subtle;
-import 'package:js/js.dart';
import 'dart:async';
import 'dart:js_util';
import 'dart:typed_data';
+import 'package:js/js.dart';
+
@JS()
@anonymous
class Pbkdf2Params {
diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart
index baaa298e..7265dec4 100644
--- a/lib/src/utils/device_keys_list.dart
+++ b/lib/src/utils/device_keys_list.dart
@@ -20,9 +20,9 @@ import 'dart:convert';
import 'package:canonical_json/canonical_json.dart';
import 'package:collection/collection.dart' show IterableExtension;
-import 'package:matrix/matrix.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:matrix/matrix.dart';
import '../../encryption.dart';
enum UserVerifiedStatus { verified, unknown, unknownDevice }
diff --git a/lib/src/utils/html_to_text.dart b/lib/src/utils/html_to_text.dart
index aa4d0bf2..ba216ccc 100644
--- a/lib/src/utils/html_to_text.dart
+++ b/lib/src/utils/html_to_text.dart
@@ -17,9 +17,8 @@
*/
import 'package:collection/collection.dart';
-
-import 'package:html/parser.dart';
import 'package:html/dom.dart';
+import 'package:html/parser.dart';
import 'package:html_unescape/html_unescape.dart';
class HtmlToText {
diff --git a/lib/src/utils/image_pack_extension.dart b/lib/src/utils/image_pack_extension.dart
index 92b3b924..d5b9e3ff 100644
--- a/lib/src/utils/image_pack_extension.dart
+++ b/lib/src/utils/image_pack_extension.dart
@@ -16,8 +16,8 @@
* along with this program. If not, see .
*/
-import 'package:slugify/slugify.dart';
import 'package:matrix_api_lite/matrix_api_lite.dart';
+import 'package:slugify/slugify.dart';
import '../room.dart';
diff --git a/lib/src/utils/markdown.dart b/lib/src/utils/markdown.dart
index 0924e9dc..56507908 100644
--- a/lib/src/utils/markdown.dart
+++ b/lib/src/utils/markdown.dart
@@ -16,9 +16,10 @@
* along with this program. If not, see .
*/
-import 'package:markdown/markdown.dart';
import 'dart:convert';
+import 'package:markdown/markdown.dart';
+
const htmlAttrEscape = HtmlEscape(HtmlEscapeMode.attribute);
class LinebreakSyntax extends InlineSyntax {
diff --git a/lib/src/utils/matrix_default_localizations.dart b/lib/src/utils/matrix_default_localizations.dart
index 4ad60ab2..28736a41 100644
--- a/lib/src/utils/matrix_default_localizations.dart
+++ b/lib/src/utils/matrix_default_localizations.dart
@@ -15,6 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+
import 'package:matrix/matrix.dart';
class MatrixDefaultLocalizations extends MatrixLocalizations {
diff --git a/lib/src/utils/multilock.dart b/lib/src/utils/multilock.dart
index 035232ef..852527e2 100644
--- a/lib/src/utils/multilock.dart
+++ b/lib/src/utils/multilock.dart
@@ -15,6 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+
import 'dart:async';
/// Lock management class. It allows to lock and unlock multiple keys at once. The keys have
diff --git a/lib/src/utils/queued_to_device_event.dart b/lib/src/utils/queued_to_device_event.dart
index 3296510f..71657aec 100644
--- a/lib/src/utils/queued_to_device_event.dart
+++ b/lib/src/utils/queued_to_device_event.dart
@@ -15,6 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+
import 'dart:convert';
class QueuedToDeviceEvent {
diff --git a/lib/src/voip/call.dart b/lib/src/voip/call.dart
index feeafc28..4943897f 100644
--- a/lib/src/voip/call.dart
+++ b/lib/src/voip/call.dart
@@ -19,9 +19,9 @@
import 'dart:async';
import 'dart:core';
-import 'package:matrix/src/utils/cached_stream_controller.dart';
import 'package:webrtc_interface/webrtc_interface.dart';
+import 'package:matrix/src/utils/cached_stream_controller.dart';
import '../../matrix.dart';
/// https://github.com/matrix-org/matrix-doc/pull/2746
@@ -84,9 +84,9 @@ class WrappedMediaStream {
renderer.srcObject = null;
if (isLocal() && !isGroupCall && stream != null) {
if (isWeb) {
- stream!.getTracks().forEach((element) {
- element.stop();
- });
+ for (final element in stream!.getTracks()) {
+ await element.stop();
+ }
}
await stream?.dispose();
stream = null;
@@ -395,7 +395,7 @@ class CallSession {
setCallState(CallState.kCreateOffer);
final stream = await _getUserMedia(type);
if (stream != null) {
- addLocalStream(stream, SDPStreamMetadataPurpose.Usermedia);
+ await addLocalStream(stream, SDPStreamMetadataPurpose.Usermedia);
}
}
@@ -407,7 +407,7 @@ class CallSession {
if (!isGroupCall) {
final stream = await _getUserMedia(type);
if (stream != null) {
- addLocalStream(stream, SDPStreamMetadataPurpose.Usermedia);
+ await addLocalStream(stream, SDPStreamMetadataPurpose.Usermedia);
}
}
@@ -473,12 +473,12 @@ class CallSession {
waitForLocalAVStream = false;
- callFeeds.forEach((element) async {
- addLocalStream(
+ for (final element in callFeeds) {
+ await addLocalStream(
await voip.delegate.cloneStream(element.stream!), element.purpose);
- });
+ }
- answer();
+ await answer();
}
Future placeCallWithStreams(List callFeeds,
@@ -490,27 +490,27 @@ class CallSession {
// create the peer connection now so it can be gathering candidates while we get user
// media (assuming a candidate pool size is configured)
await _preparePeerConnection();
- gotCallFeedsForInvite(callFeeds, requestScreenshareFeed);
+ await gotCallFeedsForInvite(callFeeds, requestScreenshareFeed);
}
- void gotCallFeedsForInvite(List callFeeds,
- [bool requestScreenshareFeed = false]) {
+ Future gotCallFeedsForInvite(List callFeeds,
+ [bool requestScreenshareFeed = false]) async {
if (successor != null) {
- successor!.gotCallFeedsForAnswer(callFeeds);
+ await successor!.gotCallFeedsForAnswer(callFeeds);
return;
}
if (state == CallState.kEnded) {
- cleanUp();
+ await cleanUp();
return;
}
- callFeeds.forEach((element) async {
- addLocalStream(
+ for (final element in callFeeds) {
+ await addLocalStream(
await voip.delegate.cloneStream(element.stream!), element.purpose);
- });
+ }
if (requestScreenshareFeed) {
- pc!.addTransceiver(
+ await pc!.addTransceiver(
kind: RTCRtpMediaType.RTCRtpMediaTypeVideo,
init:
RTCRtpTransceiverInit(direction: TransceiverDirection.RecvOnly));
@@ -526,7 +526,7 @@ class CallSession {
setCallState(CallState.kEnded);
}
- void onAnswerReceived(
+ Future onAnswerReceived(
RTCSessionDescription answer, SDPStreamMetadata? metadata) async {
if (metadata != null) {
_updateRemoteSDPStreamMetadata(metadata);
@@ -535,7 +535,9 @@ class CallSession {
if (direction == CallDirection.kOutgoing) {
setCallState(CallState.kConnecting);
await pc!.setRemoteDescription(answer);
- remoteCandidates.forEach((candidate) => pc!.addCandidate(candidate));
+ for (final candidate in remoteCandidates) {
+ await pc!.addCandidate(candidate);
+ }
}
/// Send select_answer event.
@@ -543,7 +545,7 @@ class CallSession {
opts.room, callId, lifetimeMs, localPartyId, remotePartyId!);
}
- void onNegotiateReceived(
+ Future onNegotiateReceived(
SDPStreamMetadata? metadata, RTCSessionDescription description) async {
final polite = direction == CallDirection.kIncoming;
@@ -611,13 +613,13 @@ class CallSession {
});
}
- void onSDPStreamMetadataReceived(SDPStreamMetadata metadata) async {
+ Future onSDPStreamMetadataReceived(SDPStreamMetadata metadata) async {
_updateRemoteSDPStreamMetadata(metadata);
fireCallEvent(CallEvent.kFeedsChanged);
}
- void onCandidatesReceived(List candidates) {
- candidates.forEach((json) async {
+ Future onCandidatesReceived(List candidates) async {
+ for (final json in candidates) {
final candidate = RTCIceCandidate(
json['candidate'],
json['sdpMid'] ?? '',
@@ -633,16 +635,16 @@ class CallSession {
} else {
remoteCandidates.add(candidate);
}
- });
+ }
if (pc != null &&
pc!.iceConnectionState ==
RTCIceConnectionState.RTCIceConnectionStateDisconnected) {
- restartIce();
+ await restartIce();
}
}
- void onAssertedIdentityReceived(AssertedIdentity identity) async {
+ void onAssertedIdentityReceived(AssertedIdentity identity) {
remoteAssertedIdentity = identity;
fireCallEvent(CallEvent.kAssertedIdentityChanged);
}
@@ -674,7 +676,7 @@ class CallSession {
setScreensharingEnabled(false);
};
});
- addLocalStream(stream, SDPStreamMetadataPurpose.Screenshare);
+ await addLocalStream(stream, SDPStreamMetadataPurpose.Screenshare);
return true;
} catch (err) {
fireCallEvent(CallEvent.kError);
@@ -696,7 +698,7 @@ class CallSession {
}
}
- void addLocalStream(MediaStream stream, String purpose,
+ Future addLocalStream(MediaStream stream, String purpose,
{bool addToPeerConnection = true}) async {
final existingStream =
getLocalStreams.where((element) => element.purpose == purpose);
@@ -722,14 +724,14 @@ class CallSession {
if (addToPeerConnection) {
if (purpose == SDPStreamMetadataPurpose.Screenshare) {
screensharingSenders.clear();
- stream.getTracks().forEach((track) async {
+ for (final track in stream.getTracks()) {
screensharingSenders.add(await pc!.addTrack(track, stream));
- });
+ }
} else if (purpose == SDPStreamMetadataPurpose.Usermedia) {
usermediaSenders.clear();
- stream.getTracks().forEach((track) async {
+ for (final track in stream.getTracks()) {
usermediaSenders.add(await pc!.addTrack(track, stream));
- });
+ }
}
}
@@ -744,7 +746,7 @@ class CallSession {
fireCallEvent(CallEvent.kFeedsChanged);
}
- void _addRemoteStream(MediaStream stream) async {
+ Future _addRemoteStream(MediaStream stream) async {
//final userId = remoteUser.id;
final metadata = remoteSDPStreamMetadata!.sdpStreamMetadatas[stream.id];
if (metadata == null) {
@@ -783,17 +785,17 @@ class CallSession {
Logs().i('Pushed remote stream (id="${stream.id}", purpose=$purpose)');
}
- void deleteAllStreams() {
- streams.forEach((stream) async {
+ Future deleteAllStreams() async {
+ for (final stream in streams) {
if (stream.isLocal() || groupCallId == null) {
await stream.dispose();
}
- });
+ }
streams.clear();
fireCallEvent(CallEvent.kFeedsChanged);
}
- void deleteFeedByStream(MediaStream stream) {
+ Future deleteFeedByStream(MediaStream stream) async {
final index =
streams.indexWhere((element) => element.stream!.id == stream.id);
if (index == -1) {
@@ -802,23 +804,23 @@ class CallSession {
}
final wstream = streams.elementAt(index);
onStreamRemoved.add(wstream);
- deleteStream(wstream);
+ await deleteStream(wstream);
}
- void deleteStream(WrappedMediaStream stream) {
- stream.dispose();
+ Future deleteStream(WrappedMediaStream stream) async {
+ await stream.dispose();
streams.removeAt(streams.indexOf(stream));
fireCallEvent(CallEvent.kFeedsChanged);
}
- void removeLocalStream(WrappedMediaStream callFeed) {
+ Future removeLocalStream(WrappedMediaStream callFeed) async {
final senderArray = callFeed.purpose == SDPStreamMetadataPurpose.Usermedia
? usermediaSenders
: screensharingSenders;
- senderArray.forEach((element) async {
+ for (final element in senderArray) {
await pc!.removeTrack(element);
- });
+ }
if (callFeed.purpose == SDPStreamMetadataPurpose.Screenshare) {
stopMediaStream(callFeed.stream);
@@ -827,7 +829,7 @@ class CallSession {
// Empty the array
senderArray.removeRange(0, senderArray.length);
onStreamRemoved.add(callFeed);
- deleteStream(callFeed);
+ await deleteStream(callFeed);
}
void setCallState(CallState newState) {
@@ -850,7 +852,7 @@ class CallSession {
bool get isMicrophoneMuted => localUserMediaStream?.isAudioMuted() ?? false;
- void setRemoteOnHold(bool onHold) async {
+ Future setRemoteOnHold(bool onHold) async {
if (isRemoteOnHold == onHold) return;
remoteOnHold = onHold;
final transceivers = await pc!.getTransceivers();
@@ -859,7 +861,7 @@ class CallSession {
? TransceiverDirection.SendOnly
: TransceiverDirection.SendRecv);
}
- _updateMuteStatus();
+ await _updateMuteStatus();
fireCallEvent(CallEvent.kRemoteHoldUnhold);
}
@@ -884,7 +886,7 @@ class CallSession {
return callOnHold;
}
- void answer() async {
+ Future answer() async {
if (inviteOrAnswerSent) {
return;
}
@@ -895,7 +897,9 @@ class CallSession {
setCallState(CallState.kCreateAnswer);
final answer = await pc!.createAnswer({});
- remoteCandidates.forEach((candidate) => pc!.addCandidate(candidate));
+ for (final candidate in remoteCandidates) {
+ await pc!.addCandidate(candidate);
+ }
final callCapabilities = CallCapabilities()
..dtmf = false
@@ -924,7 +928,7 @@ class CallSession {
/// This used to be done by calling hangup, but is a separate method and protocol
/// event as of MSC2746.
///
- void reject() {
+ Future reject() async {
// stop play ringtone
voip.delegate.stopRingtone();
@@ -933,15 +937,15 @@ class CallSession {
return;
}
Logs().d('[VOIP] Rejecting call: $callId');
- terminate(CallParty.kLocal, CallErrorCode.UserHangup, true);
- sendCallReject(room, callId, lifetimeMs, localPartyId);
+ await terminate(CallParty.kLocal, CallErrorCode.UserHangup, true);
+ await sendCallReject(room, callId, lifetimeMs, localPartyId);
}
- void hangup([String? reason, bool suppressEvent = true]) async {
+ Future hangup([String? reason, bool suppressEvent = true]) async {
// stop play ringtone
voip.delegate.stopRingtone();
- terminate(
+ await terminate(
CallParty.kLocal, reason ?? CallErrorCode.UserHangup, !suppressEvent);
try {
@@ -953,7 +957,7 @@ class CallSession {
}
}
- void sendDTMF(String tones) async {
+ Future sendDTMF(String tones) async {
final senders = await pc!.getSenders();
for (final sender in senders) {
if (sender.track != null && sender.track!.kind == 'audio') {
@@ -964,7 +968,8 @@ class CallSession {
Logs().e('Unable to find a track to send DTMF on');
}
- void terminate(CallParty party, String reason, bool shouldEmit) async {
+ Future terminate(
+ CallParty party, String reason, bool shouldEmit) async {
if (state == CallState.kEnded) {
return;
}
@@ -981,7 +986,7 @@ class CallSession {
setCallState(CallState.kEnded);
voip.currentCID = null;
voip.calls.remove(callId);
- cleanUp();
+ await cleanUp();
onCallHangup.add(this);
@@ -991,7 +996,7 @@ class CallSession {
}
}
- void onRejectReceived(String? reason) {
+ Future onRejectReceived(String? reason) async {
Logs().v('[VOIP] Reject received for call ID ' + callId);
// No need to check party_id for reject because if we'd received either
// an answer or reject, we wouldn't be in state InviteSent
@@ -1001,7 +1006,8 @@ class CallSession {
CallState.kRinging == state;
if (shouldTerminate) {
- terminate(CallParty.kRemote, reason ?? CallErrorCode.UserHangup, true);
+ await terminate(
+ CallParty.kRemote, reason ?? CallErrorCode.UserHangup, true);
} else {
Logs().e('Call is in state: ${state.toString()}: ignoring reject');
}
@@ -1018,7 +1024,8 @@ class CallSession {
await pc!.setLocalDescription(offer);
} catch (err) {
Logs().d('Error setting local description! ${err.toString()}');
- terminate(CallParty.kLocal, CallErrorCode.SetLocalDescription, true);
+ await terminate(
+ CallParty.kLocal, CallErrorCode.SetLocalDescription, true);
return;
}
@@ -1051,7 +1058,7 @@ class CallSession {
}
}
- void onNegotiationNeeded() async {
+ Future onNegotiationNeeded() async {
Logs().i('Negotiation is needed!');
makingOffer = true;
try {
@@ -1112,10 +1119,10 @@ class CallSession {
terminate(CallParty.kRemote, CallErrorCode.AnsweredElsewhere, true);
}
- void cleanUp() async {
- streams.forEach((stream) {
- stream.dispose();
- });
+ Future cleanUp() async {
+ for (final stream in streams) {
+ await stream.dispose();
+ }
streams.clear();
if (pc != null) {
await pc!.close();
@@ -1123,7 +1130,7 @@ class CallSession {
}
}
- void _updateMuteStatus() async {
+ Future _updateMuteStatus() async {
final micShouldBeMuted = (localUserMediaStream != null &&
localUserMediaStream!.isAudioMuted()) ||
remoteOnHold;
@@ -1141,9 +1148,9 @@ class CallSession {
}
void _setTracksEnabled(List tracks, bool enabled) {
- tracks.forEach((track) async {
+ for (final track in tracks) {
track.enabled = enabled;
- });
+ }
}
SDPStreamMetadata _getLocalSDPStreamMetadata() {
@@ -1159,7 +1166,7 @@ class CallSession {
return metadata;
}
- void restartIce() async {
+ Future restartIce() async {
Logs().v('[VOIP] iceRestart.');
// Needs restart ice on session.pc and renegotiation.
iceGatheringFinished = false;
@@ -1229,7 +1236,7 @@ class CallSession {
pc?.createDataChannel(label, dataChannelDict);
}
- void tryRemoveStopedStreams() {
+ Future tryRemoveStopedStreams() async {
final removedStreams = {};
streams.forEach((stream) {
if (stream.stopped) {
@@ -1238,9 +1245,9 @@ class CallSession {
});
streams
.removeWhere((stream) => removedStreams.containsKey(stream.stream!.id));
- removedStreams.forEach((id, element) {
- _removeStream(element.stream!);
- });
+ for (final element in removedStreams.entries) {
+ await _removeStream(element.value.stream!);
+ }
}
Future _removeStream(MediaStream stream) async {
diff --git a/lib/src/voip/group_call.dart b/lib/src/voip/group_call.dart
index 3646509c..eb60c7e7 100644
--- a/lib/src/voip/group_call.dart
+++ b/lib/src/voip/group_call.dart
@@ -19,9 +19,10 @@
import 'dart:async';
import 'dart:core';
+import 'package:webrtc_interface/webrtc_interface.dart';
+
import 'package:matrix/matrix.dart';
import 'package:matrix/src/utils/cached_stream_controller.dart';
-import 'package:webrtc_interface/webrtc_interface.dart';
/// TODO(@duan): Need to add voice activity detection mechanism
/// const int SPEAKING_THRESHOLD = -60; // dB
diff --git a/lib/src/voip/voip.dart b/lib/src/voip/voip.dart
index fc836e23..4d7ee3de 100644
--- a/lib/src/voip/voip.dart
+++ b/lib/src/voip/voip.dart
@@ -1,9 +1,9 @@
import 'dart:core';
-import 'package:matrix/src/utils/cached_stream_controller.dart';
-import 'package:webrtc_interface/webrtc_interface.dart';
import 'package:sdp_transform/sdp_transform.dart' as sdp_transform;
+import 'package:webrtc_interface/webrtc_interface.dart';
+import 'package:matrix/src/utils/cached_stream_controller.dart';
import '../../matrix.dart';
/// Delegate WebRTC basic functionality.
@@ -219,7 +219,7 @@ class VoIP {
delegate.playRingtone();
}
- void onCallAnswer(
+ Future onCallAnswer(
String roomId, String senderId, Map content) async {
Logs().v('[VOIP] onCallAnswer => ${content.toString()}');
final String callId = content['call_id'];
@@ -252,13 +252,13 @@ class VoIP {
if (content[sdpStreamMetadataKey] != null) {
metadata = SDPStreamMetadata.fromJson(content[sdpStreamMetadataKey]);
}
- call.onAnswerReceived(answer, metadata);
+ await call.onAnswerReceived(answer, metadata);
} else {
Logs().v('[VOIP] onCallAnswer: Session [$callId] not found!');
}
}
- void onCallCandidates(
+ Future onCallCandidates(
String roomId, String senderId, Map content) async {
if (senderId == client.userID) {
// Ignore messages to yourself.
@@ -273,13 +273,13 @@ class VoIP {
'Ignoring call candidates for room $roomId claiming to be for call in room ${call.room.id}');
return;
}
- call.onCandidatesReceived(content['candidates']);
+ await call.onCandidatesReceived(content['candidates']);
} else {
Logs().v('[VOIP] onCallCandidates: Session [$callId] not found!');
}
}
- void onCallHangup(String roomId, String _ /*senderId unused*/,
+ Future onCallHangup(String roomId, String _ /*senderId unused*/,
Map content) async {
// stop play ringtone, if this is an incoming call
if (!delegate.isBackgroud) {
@@ -295,7 +295,7 @@ class VoIP {
return;
}
// hangup in any case, either if the other party hung up or we did on another device
- call.terminate(CallParty.kRemote,
+ await call.terminate(CallParty.kRemote,
content['reason'] ?? CallErrorCode.UserHangup, true);
} else {
Logs().v('[VOIP] onCallHangup: Session [$callId] not found!');
@@ -303,7 +303,7 @@ class VoIP {
currentCID = null;
}
- void onCallReject(
+ Future onCallReject(
String roomId, String senderId, Map content) async {
if (senderId == client.userID) {
// Ignore messages to yourself.
@@ -319,13 +319,13 @@ class VoIP {
'Ignoring call reject for room $roomId claiming to be for call in room ${call.room.id}');
return;
}
- call.onRejectReceived(content['reason']);
+ await call.onRejectReceived(content['reason']);
} else {
Logs().v('[VOIP] onCallHangup: Session [$callId] not found!');
}
}
- void onCallReplaces(
+ Future onCallReplaces(
String roomId, String senderId, Map content) async {
if (senderId == client.userID) {
// Ignore messages to yourself.
@@ -344,7 +344,7 @@ class VoIP {
}
}
- void onCallSelectAnswer(
+ Future onCallSelectAnswer(
String roomId, String senderId, Map content) async {
if (senderId == client.userID) {
// Ignore messages to yourself.
@@ -365,7 +365,7 @@ class VoIP {
}
}
- void onSDPStreamMetadataChangedReceived(
+ Future onSDPStreamMetadataChangedReceived(
String roomId, String senderId, Map content) async {
if (senderId == client.userID) {
// Ignore messages to yourself.
@@ -385,12 +385,12 @@ class VoIP {
Logs().d('SDP Stream metadata is null');
return;
}
- call.onSDPStreamMetadataReceived(
+ await call.onSDPStreamMetadataReceived(
SDPStreamMetadata.fromJson(content[sdpStreamMetadataKey]));
}
}
- void onAssertedIdentityReceived(
+ Future onAssertedIdentityReceived(
String roomId, String senderId, Map content) async {
if (senderId == client.userID) {
// Ignore messages to yourself.
@@ -415,7 +415,7 @@ class VoIP {
}
}
- void onCallNegotiate(
+ Future onCallNegotiate(
String roomId, String senderId, Map content) async {
if (senderId == client.userID) {
// Ignore messages to yourself.
@@ -437,7 +437,7 @@ class VoIP {
if (content[sdpStreamMetadataKey] != null) {
metadata = SDPStreamMetadata.fromJson(content[sdpStreamMetadataKey]);
}
- call.onNegotiateReceived(metadata,
+ await call.onNegotiateReceived(metadata,
RTCSessionDescription(description['sdp'], description['type']));
} catch (err) {
Logs().e('Failed to complete negotiation ${err.toString()}');
@@ -564,7 +564,7 @@ class VoIP {
return groupCalls[groupCallId];
}
- void startGroupCalls() async {
+ Future startGroupCalls() async {
final rooms = client.rooms;
rooms.forEach((element) {
createGroupCallForRoom(element);
diff --git a/pubspec.yaml b/pubspec.yaml
index 07f0346e..2f2b4737 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -32,6 +32,7 @@ dependencies:
fluffybox: ^0.4.3
dev_dependencies:
+ import_sorter: ^4.6.0
dart_code_metrics: ^4.10.1
pedantic: ^1.11.0
test: ^1.15.7
diff --git a/test/canonical_json_test.dart b/test/canonical_json_test.dart
index 8787dce0..9cdddd36 100644
--- a/test/canonical_json_test.dart
+++ b/test/canonical_json_test.dart
@@ -17,9 +17,10 @@
*/
import 'package:canonical_json/canonical_json.dart';
-import 'package:matrix/matrix.dart';
import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
+
void main() {
/// All Tests related to the ChatTime
group('Canonical Json', () {
diff --git a/test/client_test.dart b/test/client_test.dart
index 045b15d0..fd39c64d 100644
--- a/test/client_test.dart
+++ b/test/client_test.dart
@@ -20,12 +20,11 @@ import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
-import 'package:matrix/matrix.dart';
-
+import 'package:canonical_json/canonical_json.dart';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
-import 'package:canonical_json/canonical_json.dart';
+import 'package:matrix/matrix.dart';
import 'fake_client.dart';
import 'fake_database.dart';
import 'fake_matrix_api.dart';
@@ -339,21 +338,6 @@ void main() {
);
});
- test('get archive', () async {
- final archive = await matrix.loadArchive();
-
- await Future.delayed(Duration(milliseconds: 50));
- expect(archive.length, 2);
- expect(archive[0].id, '!5345234234:example.com');
- expect(archive[0].membership, Membership.leave);
- expect(archive[0].name, 'The room name');
- expect(archive[0].lastEvent?.body, 'This is an example text message');
- expect(archive[0].roomAccountData.length, 1);
- expect(archive[1].id, '!5345234235:example.com');
- expect(archive[1].membership, Membership.leave);
- expect(archive[1].name, 'The room name 2');
- });
-
test('sync state event in-memory handling', () async {
final roomId = '!726s6s6q:example.com';
final room = matrix.getRoomById(roomId)!;
diff --git a/test/commands_test.dart b/test/commands_test.dart
index 10d7f103..053afc5d 100644
--- a/test/commands_test.dart
+++ b/test/commands_test.dart
@@ -18,8 +18,9 @@
import 'dart:convert';
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+
import 'package:matrix/matrix.dart';
import 'fake_client.dart';
import 'fake_matrix_api.dart';
diff --git a/test/database_api_test.dart b/test/database_api_test.dart
index 6a7fa540..43efdd84 100644
--- a/test/database_api_test.dart
+++ b/test/database_api_test.dart
@@ -15,14 +15,15 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+
+import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
-import 'dart:async';
+
+import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
import 'package:matrix/matrix.dart';
-import 'package:test/test.dart';
-import 'package:olm/olm.dart' as olm;
-
import 'fake_database.dart';
void main() {
diff --git a/test/device_keys_list_test.dart b/test/device_keys_list_test.dart
index a1bdc991..36b2ad8e 100644
--- a/test/device_keys_list_test.dart
+++ b/test/device_keys_list_test.dart
@@ -18,11 +18,10 @@
import 'dart:convert';
-import 'package:matrix/matrix.dart';
-
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import './fake_client.dart';
import './fake_matrix_api.dart';
diff --git a/test/encryption/bootstrap_test.dart b/test/encryption/bootstrap_test.dart
index 69a643fe..428c795d 100644
--- a/test/encryption/bootstrap_test.dart
+++ b/test/encryption/bootstrap_test.dart
@@ -19,12 +19,11 @@
import 'dart:async';
import 'dart:convert';
-import 'package:matrix/matrix.dart';
-import 'package:matrix/encryption.dart';
-
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/encryption.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
void main() {
diff --git a/test/encryption/cross_signing_test.dart b/test/encryption/cross_signing_test.dart
index 0ceb1e73..15bb22ca 100644
--- a/test/encryption/cross_signing_test.dart
+++ b/test/encryption/cross_signing_test.dart
@@ -18,11 +18,10 @@
import 'dart:convert';
-import 'package:matrix/matrix.dart';
-
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
import '../fake_matrix_api.dart';
diff --git a/test/encryption/encrypt_decrypt_room_message_test.dart b/test/encryption/encrypt_decrypt_room_message_test.dart
index bc2e007e..d150e3fc 100644
--- a/test/encryption/encrypt_decrypt_room_message_test.dart
+++ b/test/encryption/encrypt_decrypt_room_message_test.dart
@@ -16,11 +16,10 @@
* along with this program. If not, see .
*/
-import 'package:matrix/matrix.dart';
-
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
void main() {
diff --git a/test/encryption/encrypt_decrypt_to_device_test.dart b/test/encryption/encrypt_decrypt_to_device_test.dart
index 42fb4b2e..10904eae 100644
--- a/test/encryption/encrypt_decrypt_to_device_test.dart
+++ b/test/encryption/encrypt_decrypt_to_device_test.dart
@@ -16,11 +16,10 @@
* along with this program. If not, see .
*/
-import 'package:matrix/matrix.dart';
-
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
import '../fake_database.dart';
import '../fake_matrix_api.dart';
diff --git a/test/encryption/key_manager_test.dart b/test/encryption/key_manager_test.dart
index f22cf5de..d9f0e77f 100644
--- a/test/encryption/key_manager_test.dart
+++ b/test/encryption/key_manager_test.dart
@@ -18,11 +18,10 @@
import 'dart:convert';
-import 'package:matrix/matrix.dart';
-
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
import '../fake_matrix_api.dart';
diff --git a/test/encryption/key_request_test.dart b/test/encryption/key_request_test.dart
index 5bb53769..4470e1b0 100644
--- a/test/encryption/key_request_test.dart
+++ b/test/encryption/key_request_test.dart
@@ -17,11 +17,11 @@
*/
import 'dart:convert';
-import 'package:matrix/matrix.dart';
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
import '../fake_matrix_api.dart';
diff --git a/test/encryption/key_verification_test.dart b/test/encryption/key_verification_test.dart
index 82eaf0bc..d6dc9aa0 100644
--- a/test/encryption/key_verification_test.dart
+++ b/test/encryption/key_verification_test.dart
@@ -19,12 +19,11 @@
import 'dart:async';
import 'dart:convert';
-import 'package:matrix/matrix.dart';
-import 'package:matrix/encryption.dart';
-
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/encryption.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
import '../fake_database.dart';
import '../fake_matrix_api.dart';
diff --git a/test/encryption/olm_manager_test.dart b/test/encryption/olm_manager_test.dart
index 514aa38b..5792b761 100644
--- a/test/encryption/olm_manager_test.dart
+++ b/test/encryption/olm_manager_test.dart
@@ -17,12 +17,12 @@
*/
import 'dart:convert';
-import 'package:matrix/matrix.dart';
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
-import 'package:matrix/encryption/utils/json_signature_check_extension.dart';
+import 'package:test/test.dart';
+import 'package:matrix/encryption/utils/json_signature_check_extension.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
import '../fake_matrix_api.dart';
diff --git a/test/encryption/online_key_backup_test.dart b/test/encryption/online_key_backup_test.dart
index a966545e..aa46ecfd 100644
--- a/test/encryption/online_key_backup_test.dart
+++ b/test/encryption/online_key_backup_test.dart
@@ -18,11 +18,10 @@
import 'dart:convert';
-import 'package:matrix/matrix.dart';
-
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
import '../fake_matrix_api.dart';
diff --git a/test/encryption/ssss_test.dart b/test/encryption/ssss_test.dart
index 301ddf0b..d7a9e7f4 100644
--- a/test/encryption/ssss_test.dart
+++ b/test/encryption/ssss_test.dart
@@ -16,16 +16,15 @@
* along with this program. If not, see .
*/
-import 'dart:typed_data';
import 'dart:convert';
import 'dart:math';
+import 'dart:typed_data';
-import 'package:matrix/matrix.dart';
-import 'package:matrix/encryption.dart';
-
-import 'package:test/test.dart';
import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+import 'package:matrix/encryption.dart';
+import 'package:matrix/matrix.dart';
import '../fake_client.dart';
import '../fake_matrix_api.dart';
diff --git a/test/encryption/utils_test.dart b/test/encryption/utils_test.dart
index b21d0990..59e79a58 100644
--- a/test/encryption/utils_test.dart
+++ b/test/encryption/utils_test.dart
@@ -18,9 +18,10 @@
import 'dart:convert';
+import 'package:test/test.dart';
+
import 'package:matrix/encryption/utils/base64_unpadded.dart';
import 'package:matrix/matrix.dart';
-import 'package:test/test.dart';
void main() {
group('Utils', () {
diff --git a/test/event_test.dart b/test/event_test.dart
index e03cf41f..8cc4edd2 100644
--- a/test/event_test.dart
+++ b/test/event_test.dart
@@ -19,12 +19,12 @@
import 'dart:convert';
import 'dart:typed_data';
-import 'package:matrix/encryption.dart';
-import 'package:matrix/matrix.dart';
-import 'package:matrix/src/models/timeline_chunk.dart';
import 'package:olm/olm.dart' as olm;
import 'package:test/test.dart';
+import 'package:matrix/encryption.dart';
+import 'package:matrix/matrix.dart';
+import 'package:matrix/src/models/timeline_chunk.dart';
import 'fake_client.dart';
import 'fake_matrix_api.dart';
diff --git a/test/fake_client.dart b/test/fake_client.dart
index f7afd062..acfb5e04 100644
--- a/test/fake_client.dart
+++ b/test/fake_client.dart
@@ -17,9 +17,8 @@
*/
import 'package:matrix/matrix.dart';
-
-import 'fake_matrix_api.dart';
import 'fake_database.dart';
+import 'fake_matrix_api.dart';
const ssssPassphrase = 'nae7ahDiequ7ohniufah3ieS2je1thohX4xeeka7aixohsho9O';
const ssssKey = 'EsT9 RzbW VhPW yqNp cC7j ViiW 5TZB LuY4 ryyv 9guN Ysmr WDPH';
diff --git a/test/fake_database.dart b/test/fake_database.dart
index 6c076fcb..5e78e25c 100644
--- a/test/fake_database.dart
+++ b/test/fake_database.dart
@@ -19,10 +19,11 @@
import 'dart:io';
import 'dart:math';
-import 'package:matrix/matrix.dart';
import 'package:file/memory.dart';
import 'package:hive/hive.dart';
+import 'package:matrix/matrix.dart';
+
Future getDatabase(Client? _) => getHiveCollectionsDatabase(_);
bool hiveInitialized = false;
diff --git a/test/fake_matrix_api.dart b/test/fake_matrix_api.dart
index eec6d180..5eea00d8 100644
--- a/test/fake_matrix_api.dart
+++ b/test/fake_matrix_api.dart
@@ -22,6 +22,7 @@ import 'dart:core';
import 'dart:math';
import 'package:http/http.dart';
+
import 'package:matrix/matrix.dart' as sdk;
import 'package:matrix/matrix.dart';
@@ -360,6 +361,65 @@ class FakeMatrixApi extends BaseClient {
'state': [],
};
+ static Map archivesMessageResponse = {
+ 'start': 't47429-4392820_219380_26003_2265',
+ 'end': 't47409-4357353_219380_26003_2265',
+ 'chunk': [
+ {
+ 'content': {
+ 'body': 'This is an example text message',
+ 'msgtype': 'm.text',
+ 'format': 'org.matrix.custom.html',
+ 'formatted_body': 'This is an example text message'
+ },
+ 'type': 'm.room.message',
+ 'event_id': '3143273582443PhrSn:example.org',
+ 'room_id': '!5345234234:example.com',
+ 'sender': '@example:example.org',
+ 'origin_server_ts': 1432735824653,
+ 'unsigned': {'age': 1234}
+ },
+ {
+ 'content': {'name': 'The room name'},
+ 'type': 'm.room.name',
+ 'event_id': '2143273582443PhrSn:example.org',
+ 'room_id': '!5345234234:example.com',
+ 'sender': '@example:example.org',
+ 'origin_server_ts': 1432735824653,
+ 'unsigned': {'age': 1234},
+ 'state_key': ''
+ },
+ {
+ 'content': {
+ 'body': 'Gangnam Style',
+ 'url': 'mxc://example.org/a526eYUSFFxlgbQYZmo442',
+ 'info': {
+ 'thumbnail_url': 'mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe',
+ 'thumbnail_info': {
+ 'mimetype': 'image/jpeg',
+ 'size': 46144,
+ 'w': 300,
+ 'h': 300
+ },
+ 'w': 480,
+ 'h': 320,
+ 'duration': 2140786,
+ 'size': 1563685,
+ 'mimetype': 'video/mp4'
+ },
+ 'msgtype': 'm.video'
+ },
+ 'type': 'm.room.message',
+ 'event_id': '1143273582466PhrSn:example.org',
+ 'room_id': '!5345234234:example.com',
+ 'sender': '@example:example.org',
+ 'origin_server_ts': 1432735824654,
+ 'unsigned': {'age': 1234}
+ }
+ ],
+ 'state': [],
+ };
+
static Map syncResponse = {
'next_batch': Random().nextDouble().toString(),
'rooms': {
@@ -887,19 +947,36 @@ class FakeMatrixApi extends BaseClient {
'events': [
{
'content': {
- 'body': 'This is an example text message',
+ 'body': 'This is a second text example message',
'msgtype': 'm.text',
'format': 'org.matrix.custom.html',
- 'formatted_body': 'This is an example text message'
+ 'formatted_body':
+ 'This is a second text example message'
},
'type': 'm.room.message',
- 'event_id': '143273582443PhrSn:example.org',
+ 'event_id': '143274597446PhrSn:example.org',
+ 'room_id': '!5345234234:example.com',
+ 'sender': '@example:example.org',
+ 'origin_server_ts': 1432735824654,
+ 'unsigned': {'age': 1234}
+ },
+ {
+ 'content': {
+ 'body': 'This is a first text example message',
+ 'msgtype': 'm.text',
+ 'format': 'org.matrix.custom.html',
+ 'formatted_body':
+ 'This is a first text example message'
+ },
+ 'type': 'm.room.message',
+ 'event_id': '143274597443PhrSn:example.org',
'room_id': '!5345234234:example.com',
'sender': '@example:example.org',
'origin_server_ts': 1432735824653,
'unsigned': {'age': 1234}
- },
- ]
+ }
+ ],
+ 'prev_batch': 't_1234a'
},
'state': {
'events': [
@@ -939,7 +1016,8 @@ class FakeMatrixApi extends BaseClient {
'state_key': ''
},
]
- }
+ },
+ 'prev_batch': 't_1234b'
},
},
}
@@ -1517,6 +1595,8 @@ class FakeMatrixApi extends BaseClient {
(var req) => messagesResponseFutureEnd,
'/client/v3/rooms/!1234%3Aexample.com/messages?from=t789&dir=f&limit=30&filter=%7B%22lazy_load_members%22%3Atrue%7D':
(var req) => messagesResponseFutureEnd,
+ '/client/v3/rooms/!5345234234%3Aexample.com/messages?from=t_1234a&dir=b&limit=30&filter=%7B%22lazy_load_members%22%3Atrue%7D':
+ (var req) => archivesMessageResponse,
'/client/versions': (var req) => {
'versions': [
'v1.1',
diff --git a/test/html_to_text_test.dart b/test/html_to_text_test.dart
index 9dde56e7..27ba947a 100644
--- a/test/html_to_text_test.dart
+++ b/test/html_to_text_test.dart
@@ -16,9 +16,10 @@
* along with this program. If not, see .
*/
-import 'package:matrix/src/utils/html_to_text.dart';
import 'package:test/test.dart';
+import 'package:matrix/src/utils/html_to_text.dart';
+
void main() {
group('htmlToText', () {
final testMap = {
diff --git a/test/image_pack_test.dart b/test/image_pack_test.dart
index 513dd7c5..c801d2c3 100644
--- a/test/image_pack_test.dart
+++ b/test/image_pack_test.dart
@@ -17,6 +17,7 @@
*/
import 'package:test/test.dart';
+
import 'package:matrix/matrix.dart';
import 'fake_client.dart';
diff --git a/test/markdown_test.dart b/test/markdown_test.dart
index 2c3dab85..dac27912 100644
--- a/test/markdown_test.dart
+++ b/test/markdown_test.dart
@@ -16,9 +16,10 @@
* along with this program. If not, see .
*/
-import 'package:matrix/src/utils/markdown.dart';
import 'package:test/test.dart';
+import 'package:matrix/src/utils/markdown.dart';
+
void main() {
group('markdown', () {
final emotePacks = {
diff --git a/test/matrix_api/map_copy_extension_test.dart b/test/matrix_api/map_copy_extension_test.dart
index e7027952..56a21936 100644
--- a/test/matrix_api/map_copy_extension_test.dart
+++ b/test/matrix_api/map_copy_extension_test.dart
@@ -16,9 +16,10 @@
* along with this program. If not, see .
*/
-import 'package:matrix/src/utils/map_copy_extension.dart';
import 'package:test/test.dart';
+import 'package:matrix/src/utils/map_copy_extension.dart';
+
void main() {
group('Map-copy-extension', () {
test('it should work', () {
diff --git a/test/matrix_database_test.dart b/test/matrix_database_test.dart
index 0c88c612..6c333e9b 100644
--- a/test/matrix_database_test.dart
+++ b/test/matrix_database_test.dart
@@ -17,9 +17,9 @@
*
*/
-import 'package:matrix/matrix.dart';
-
import 'package:test/test.dart';
+
+import 'package:matrix/matrix.dart';
import 'fake_database.dart';
void main() {
diff --git a/test/matrix_exception_test.dart b/test/matrix_exception_test.dart
index 5378f325..f9769edd 100644
--- a/test/matrix_exception_test.dart
+++ b/test/matrix_exception_test.dart
@@ -15,11 +15,12 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import 'package:matrix/matrix.dart';
-import 'package:http/http.dart';
+import 'package:http/http.dart';
import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
+
void main() {
/// All Tests related to device keys
group('Matrix Exception', () {
diff --git a/test/matrix_file_test.dart b/test/matrix_file_test.dart
index 7f6aef06..cd36b1ae 100644
--- a/test/matrix_file_test.dart
+++ b/test/matrix_file_test.dart
@@ -18,11 +18,11 @@
import 'dart:typed_data';
-import 'package:matrix/matrix.dart';
-
-import 'package:test/test.dart';
-import 'package:olm/olm.dart' as olm;
import 'package:http/http.dart' as http;
+import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+
+import 'package:matrix/matrix.dart';
void main() {
/// All Tests related to device keys
diff --git a/test/matrix_id_string_extension_test.dart b/test/matrix_id_string_extension_test.dart
index e5fd2842..5b9c0072 100644
--- a/test/matrix_id_string_extension_test.dart
+++ b/test/matrix_id_string_extension_test.dart
@@ -17,6 +17,7 @@
*/
import 'package:test/test.dart';
+
import 'package:matrix/src/utils/matrix_id_string_extension.dart';
void main() {
diff --git a/test/matrix_localizations_test.dart b/test/matrix_localizations_test.dart
index 53e9a6b7..4c72451b 100644
--- a/test/matrix_localizations_test.dart
+++ b/test/matrix_localizations_test.dart
@@ -15,9 +15,11 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import 'package:matrix/matrix.dart';
+
import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
+
void main() {
/// All Tests related to device keys
group('Matrix Localizations', () {
diff --git a/test/multilock_test.dart b/test/multilock_test.dart
index 292b1e4e..d973e87f 100644
--- a/test/multilock_test.dart
+++ b/test/multilock_test.dart
@@ -16,9 +16,10 @@
* along with this program. If not, see .
*/
-import 'package:matrix/src/utils/multilock.dart';
import 'package:test/test.dart';
+import 'package:matrix/src/utils/multilock.dart';
+
void main() {
group('lock', () {
final lock = MultiLock();
diff --git a/test/mxc_uri_extension_test.dart b/test/mxc_uri_extension_test.dart
index b2248a35..290265b2 100644
--- a/test/mxc_uri_extension_test.dart
+++ b/test/mxc_uri_extension_test.dart
@@ -16,10 +16,9 @@
* along with this program. If not, see .
*/
-import 'package:matrix/matrix.dart';
-
import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import 'fake_matrix_api.dart';
void main() {
diff --git a/test/push_notification.dart b/test/push_notification.dart
index 330a4c29..f35220da 100644
--- a/test/push_notification.dart
+++ b/test/push_notification.dart
@@ -1,8 +1,9 @@
import 'dart:convert';
-import 'package:matrix/matrix.dart';
import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
+
void main() {
group('Push Notification', () {
Logs().level = Level.error;
diff --git a/test/room_archived_test.dart b/test/room_archived_test.dart
new file mode 100644
index 00000000..c99af5ab
--- /dev/null
+++ b/test/room_archived_test.dart
@@ -0,0 +1,138 @@
+/*
+ * Famedly Matrix SDK
+ * Copyright (C) 2022 Famedly GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import 'dart:async';
+
+import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+
+import 'package:matrix/matrix.dart';
+import 'fake_client.dart';
+
+void main() {
+ group('Timeline', () {
+ Logs().level = Level.error;
+ var olmEnabled = true;
+
+ final insertList = [];
+
+ late Client client;
+
+ setUp(() async {
+ try {
+ await olm.init();
+ olm.get_library_version();
+ } catch (e) {
+ olmEnabled = false;
+ Logs().w('[LibOlm] Failed to load LibOlm', e);
+ }
+ Logs().i('[LibOlm] Enabled: $olmEnabled');
+
+ client = await getClient();
+ client.sendMessageTimeoutSeconds = 5;
+
+ await client.abortSync();
+ insertList.clear();
+ });
+
+ tearDown(() => client.dispose().onError((e, s) {}));
+
+ test('archive room not loaded', () async {
+ final archiveRoom =
+ client.getArchiveRoomFromCache('!5345234234:example.com');
+ expect(archiveRoom, null);
+ });
+
+ test('get archive', () async {
+ final archive = await client.loadArchiveWithTimeline();
+
+ expect(archive.length, 2);
+ expect(client.rooms.length, 2);
+ expect(archive[0].room.id, '!5345234234:example.com');
+ expect(archive[0].room.membership, Membership.leave);
+ expect(archive[0].room.name, 'The room name');
+ expect(archive[0].room.lastEvent?.body,
+ 'This is a second text example message');
+ expect(archive[0].room.roomAccountData.length, 1);
+ expect(archive[1].room.id, '!5345234235:example.com');
+ expect(archive[1].room.membership, Membership.leave);
+ expect(archive[1].room.name, 'The room name 2');
+
+ final archiveRoom =
+ client.getArchiveRoomFromCache('!5345234234:example.com');
+ expect(archiveRoom != null, true);
+ expect(archiveRoom!.timeline.events.length, 2);
+ });
+
+ test('request history', () async {
+ await client.loadArchiveWithTimeline();
+ final archiveRoom = client.getRoomById('!5345234234:example.com');
+ expect(archiveRoom != null, true);
+
+ final timeline = await archiveRoom!.getTimeline(onInsert: insertList.add);
+
+ expect(timeline.events.length, 2);
+ expect(timeline.events[0].eventId, '143274597443PhrSn:example.org');
+ expect(timeline.events[1].eventId, '143274597446PhrSn:example.org');
+
+ await timeline.requestHistory();
+
+ expect(timeline.events.length, 5);
+ expect(timeline.events[0].eventId, '143274597443PhrSn:example.org');
+ expect(timeline.events[1].eventId, '143274597446PhrSn:example.org');
+ expect(timeline.events[2].eventId, '3143273582443PhrSn:example.org');
+ expect(timeline.events[3].eventId, '2143273582443PhrSn:example.org');
+ expect(timeline.events[4].eventId, '1143273582466PhrSn:example.org');
+ expect(insertList.length, 3);
+ });
+
+ test('expect database to be empty', () async {
+ await client.loadArchiveWithTimeline();
+ final archiveRoom = client.getRoomById('!5345234234:example.com');
+ expect(archiveRoom != null, true);
+
+ final eventsFromStore = await client.database?.getEventList(
+ archiveRoom!,
+ start: 0,
+ limit: Room.defaultHistoryCount,
+ );
+ expect(eventsFromStore?.isEmpty, true);
+ });
+
+ test('discard room from archives when membership change', () async {
+ await client.loadArchiveWithTimeline();
+ expect(client.getArchiveRoomFromCache('!5345234235:example.com') != null,
+ true);
+ await client.handleSync(SyncUpdate(
+ nextBatch: 't_456',
+ rooms: RoomsUpdate(
+ invite: {'!5345234235:example.com': InvitedRoomUpdate()})));
+ expect(client.getArchiveRoomFromCache('!5345234235:example.com'), null);
+ });
+
+ test('clear archive', () async {
+ await client.loadArchiveWithTimeline();
+ client.clearArchivesFromCache();
+ expect(client.getArchiveRoomFromCache('!5345234234:example.com'), null);
+ });
+
+ test('logout', () async {
+ await client.logout();
+ });
+ });
+}
diff --git a/test/room_test.dart b/test/room_test.dart
index a757b4a9..a466ad22 100644
--- a/test/room_test.dart
+++ b/test/room_test.dart
@@ -19,10 +19,9 @@
import 'dart:convert';
import 'dart:typed_data';
-import 'package:matrix/matrix.dart';
-
import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import 'fake_client.dart';
import 'fake_matrix_api.dart';
diff --git a/test/sync_filter_test.dart b/test/sync_filter_test.dart
index bb0b2630..60d1ed56 100644
--- a/test/sync_filter_test.dart
+++ b/test/sync_filter_test.dart
@@ -16,10 +16,10 @@
* along with this program. If not, see .
*/
-import 'package:matrix/matrix.dart';
-
import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
+
const updates = {
'empty': {
'next_batch': 'blah',
diff --git a/test/timeline_context_test.dart b/test/timeline_context_test.dart
index 20d6d3e3..466330a0 100644
--- a/test/timeline_context_test.dart
+++ b/test/timeline_context_test.dart
@@ -18,11 +18,11 @@
import 'dart:async';
+import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+
import 'package:matrix/matrix.dart';
import 'package:matrix/src/models/timeline_chunk.dart';
-
-import 'package:test/test.dart';
-import 'package:olm/olm.dart' as olm;
import 'fake_client.dart';
import 'fake_matrix_api.dart';
diff --git a/test/timeline_test.dart b/test/timeline_test.dart
index e43182b0..38b69d26 100644
--- a/test/timeline_test.dart
+++ b/test/timeline_test.dart
@@ -19,11 +19,11 @@
import 'dart:async';
import 'dart:math';
+import 'package:olm/olm.dart' as olm;
+import 'package:test/test.dart';
+
import 'package:matrix/matrix.dart';
import 'package:matrix/src/models/timeline_chunk.dart';
-
-import 'package:test/test.dart';
-import 'package:olm/olm.dart' as olm;
import 'fake_client.dart';
void main() {
diff --git a/test/uia_test.dart b/test/uia_test.dart
index f8300936..fd733419 100644
--- a/test/uia_test.dart
+++ b/test/uia_test.dart
@@ -18,10 +18,10 @@
import 'dart:async';
-import 'package:matrix/matrix.dart';
-
import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
+
void main() {
group('UIA', () {
Logs().level = Level.error;
diff --git a/test/user_test.dart b/test/user_test.dart
index bead02cd..c88b75c1 100644
--- a/test/user_test.dart
+++ b/test/user_test.dart
@@ -16,10 +16,9 @@
* along with this program. If not, see .
*/
-import 'package:matrix/matrix.dart';
-
import 'package:test/test.dart';
+import 'package:matrix/matrix.dart';
import 'fake_matrix_api.dart';
void main() {
diff --git a/test_driver/matrixsdk_test.dart b/test_driver/matrixsdk_test.dart
index 72844e51..e0354c7c 100644
--- a/test_driver/matrixsdk_test.dart
+++ b/test_driver/matrixsdk_test.dart
@@ -15,11 +15,13 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
+
import 'package:hive/hive.dart';
+import 'package:olm/olm.dart' as olm;
+
import 'package:matrix/matrix.dart';
import '../test/fake_database.dart';
import 'test_config.dart';
-import 'package:olm/olm.dart' as olm;
void main() => test();
const String testMessage = 'Hello world';