diff --git a/lib/src/client.dart b/lib/src/client.dart index c7405121..c4988093 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -2283,16 +2283,18 @@ class Client extends MatrixApi { // The timeout we send to the server for the sync loop. It says to the // server that we want to receive an empty sync response after this // amount of time if nothing happens. - timeout ??= const Duration(seconds: 30); + if (prevBatch != null) timeout ??= const Duration(seconds: 30); - await ensureNotSoftLoggedOut(timeout * 2); + await ensureNotSoftLoggedOut( + timeout == null ? const Duration(minutes: 1) : (timeout * 2), + ); await _checkSyncFilter(); final syncRequest = sync( filter: syncFilterId, since: prevBatch, - timeout: timeout.inMilliseconds, + timeout: timeout?.inMilliseconds, setPresence: syncPresence, ).then((v) => Future.value(v)).catchError((e) { if (e is MatrixException) { @@ -2308,11 +2310,13 @@ class Client extends MatrixApi { // The timeout for the response from the server. If we do not set a sync // timeout (for initial sync) we give the server a longer time to // responde. - final responseTimeout = timeout == Duration.zero - ? const Duration(minutes: 2) - : timeout + const Duration(seconds: 10); + final responseTimeout = + timeout == null ? null : timeout + const Duration(seconds: 10); + + final syncResp = responseTimeout == null + ? await syncRequest + : await syncRequest.timeout(responseTimeout); - final syncResp = await syncRequest.timeout(responseTimeout); onSyncStatus.add(SyncStatusUpdate(SyncStatus.processing)); if (syncResp == null) throw syncError ?? 'Unknown sync error'; if (_currentSyncId != syncRequest.hashCode) { diff --git a/lib/src/room.dart b/lib/src/room.dart index 5285017f..2b4272e5 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -1264,19 +1264,27 @@ class Room { reason: reason, ); - /// Request more previous events from the server. [historyCount] defines how much events should + /// Request more previous events from the server. [historyCount] defines how many events should /// be received maximum. When the request is answered, [onHistoryReceived] will be triggered **before** - /// the historical events will be published in the onEvent stream. + /// the historical events will be published in the onEvent stream. [filter] allows you to specify a + /// [StateFilter] object to filter the events, which can include various criteria such as event types + /// (e.g., [EventTypes.Message]) and other state-related filters. The [StateFilter] object will have + /// [lazyLoadMembers] set to true by default, but this can be overridden. /// Returns the actual count of received timeline events. Future requestHistory({ int historyCount = defaultHistoryCount, void Function()? onHistoryReceived, direction = Direction.b, + StateFilter? filter, }) async { final prev_batch = this.prev_batch; final storeInDatabase = !isArchived; + // Ensure stateFilter is not null and set lazyLoadMembers to true if not already set + filter ??= StateFilter(lazyLoadMembers: true); + filter.lazyLoadMembers ??= true; + if (prev_batch == null) { throw 'Tried to request history without a prev_batch token'; } @@ -1285,7 +1293,7 @@ class Room { direction, from: prev_batch, limit: historyCount, - filter: jsonEncode(StateFilter(lazyLoadMembers: true).toJson()), + filter: jsonEncode(filter.toJson()), ); if (onHistoryReceived != null) onHistoryReceived(); @@ -2093,16 +2101,22 @@ class Room { /// Returns the [PushRuleState] for this room, based on the m.push_rules stored in /// the account_data. PushRuleState get pushRuleState { - final globalPushRules = - client.accountData['m.push_rules']?.content['global']; - if (globalPushRules is! Map) { + final globalPushRules = client.globalPushRules; + if (globalPushRules == null) { + // We have no push rules specified at all so we fallback to just notify: return PushRuleState.notify; } - if (globalPushRules['override'] is List) { - for (final pushRule in globalPushRules['override']) { - if (pushRule['rule_id'] == id) { - if (pushRule['actions'].indexOf('dont_notify') != -1) { + final overridePushRules = globalPushRules.override; + if (overridePushRules != null) { + for (final pushRule in overridePushRules) { + if (pushRule.ruleId == id) { + // "dont_notify" and "coalesce" should be ignored in actions since + // https://spec.matrix.org/v1.7/client-server-api/#actions + pushRule.actions + ..remove('dont_notify') + ..remove('coalesce'); + if (pushRule.actions.isEmpty) { return PushRuleState.dontNotify; } break; @@ -2110,10 +2124,16 @@ class Room { } } - if (globalPushRules['room'] is List) { - for (final pushRule in globalPushRules['room']) { - if (pushRule['rule_id'] == id) { - if (pushRule['actions'].indexOf('dont_notify') != -1) { + final roomPushRules = globalPushRules.room; + if (roomPushRules != null) { + for (final pushRule in roomPushRules) { + if (pushRule.ruleId == id) { + // "dont_notify" and "coalesce" should be ignored in actions since + // https://spec.matrix.org/v1.7/client-server-api/#actions + pushRule.actions + ..remove('dont_notify') + ..remove('coalesce'); + if (pushRule.actions.isEmpty) { return PushRuleState.mentionsOnly; } break; @@ -2145,13 +2165,13 @@ class Room { await client.setPushRule( PushRuleKind.room, id, - [PushRuleAction.dontNotify], + [], ); } else if (pushRuleState == PushRuleState.notify) { await client.setPushRule( PushRuleKind.room, id, - [PushRuleAction.dontNotify], + [], ); } break; @@ -2163,7 +2183,7 @@ class Room { await client.setPushRule( PushRuleKind.override, id, - [PushRuleAction.dontNotify], + [], conditions: [ PushCondition(kind: 'event_match', key: 'room_id', pattern: id), ], diff --git a/lib/src/timeline.dart b/lib/src/timeline.dart index 36977bff..801b743d 100644 --- a/lib/src/timeline.dart +++ b/lib/src/timeline.dart @@ -84,22 +84,40 @@ class Timeline { (room.prev_batch != null && events.last.type != EventTypes.RoomCreate); } + /// Request more previous events from the server. [historyCount] defines how many events should + /// be received maximum. [filter] allows you to specify a [StateFilter] object to filter the + /// events, which can include various criteria such as event types (e.g., [EventTypes.Message]) + /// and other state-related filters. The [StateFilter] object will have [lazyLoadMembers] set to + /// true by default, but this can be overridden. + /// This method does not return a value. Future requestHistory({ int historyCount = Room.defaultHistoryCount, + StateFilter? filter, }) async { if (isRequestingHistory) { return; } isRequestingHistory = true; - await _requestEvents(direction: Direction.b, historyCount: historyCount); + await _requestEvents( + direction: Direction.b, + historyCount: historyCount, + filter: filter, + ); isRequestingHistory = false; } bool get canRequestFuture => !allowNewEvent; + /// Request more future events from the server. [historyCount] defines how many events should + /// be received maximum. [filter] allows you to specify a [StateFilter] object to filter the + /// events, which can include various criteria such as event types (e.g., [EventTypes.Message]) + /// and other state-related filters. The [StateFilter] object will have [lazyLoadMembers] set to + /// true by default, but this can be overridden. + /// This method does not return a value. Future requestFuture({ int historyCount = Room.defaultHistoryCount, + StateFilter? filter, }) async { if (allowNewEvent) { return; // we shouldn't force to add new events if they will autatically be added @@ -107,13 +125,18 @@ class Timeline { if (isRequestingFuture) return; isRequestingFuture = true; - await _requestEvents(direction: Direction.f, historyCount: historyCount); + await _requestEvents( + direction: Direction.f, + historyCount: historyCount, + filter: filter, + ); isRequestingFuture = false; } Future _requestEvents({ int historyCount = Room.defaultHistoryCount, required Direction direction, + StateFilter? filter, }) async { onUpdate?.call(); @@ -161,6 +184,7 @@ class Timeline { await getRoomEvents( historyCount: historyCount, direction: direction, + filter: filter, ); } else { if (room.prev_batch == null) { @@ -172,6 +196,7 @@ class Timeline { onHistoryReceived: () { _collectHistoryUpdates = true; }, + filter: filter, ); } } @@ -185,18 +210,26 @@ class Timeline { /// Request more previous events from the server. [historyCount] defines how much events should /// be received maximum. When the request is answered, [onHistoryReceived] will be triggered **before** - /// the historical events will be published in the onEvent stream. + /// the historical events will be published in the onEvent stream. [filter] allows you to specify a + /// [StateFilter] object to filter the events, which can include various criteria such as + /// event types (e.g., [EventTypes.Message]) and other state-related filters. + /// The [StateFilter] object will have [lazyLoadMembers] set to true by default, but this can be overridden. /// Returns the actual count of received timeline events. Future getRoomEvents({ int historyCount = Room.defaultHistoryCount, direction = Direction.b, + StateFilter? filter, }) async { + // Ensure stateFilter is not null and set lazyLoadMembers to true if not already set + filter ??= StateFilter(lazyLoadMembers: true); + filter.lazyLoadMembers ??= true; + final resp = await room.client.getRoomEvents( room.id, direction, from: direction == Direction.b ? chunk.prevBatch : chunk.nextBatch, limit: historyCount, - filter: jsonEncode(StateFilter(lazyLoadMembers: true).toJson()), + filter: jsonEncode(filter.toJson()), ); if (resp.end == null) {