fluffychat/lib/pangea/join_codes/knock_notification_utils.dart
wcjord 6f32aab48b
fix: show "knock accepted" push notification body instead of "You have been invited" (#5823) (#5835)
* fix: show knock-accepted notification body when invite follows a knock (#5823)

When Synapse accepts a knock it sends an m.room.member invite event. The client
was displaying the generic 'You have been invited by X' push notification body
because the invite event alone doesn't carry prev_content on the push path.

Use KnockTracker (already used for auto-join) to detect knock-accepted invites
and show a dedicated 'Your join request was accepted!' notification body instead.

- Add knockAccepted string to intl_en.arb
- Extract condition into isKnockAcceptedInvite() pure util for testability
- Expose KnockTracker.getKnockedRoomIds() publicly (was _getKnockedRoomIds)
- Override notification body in push_helper.dart (background) and
  local_notifications_extension.dart (foreground/web)
- Unit tests for all isKnockAcceptedInvite() branches (9 tests)

* formatting

* fix up pangea comments

* fix: avoid race condition with knocked room account data updates and local push notification content

* translations

---------

Co-authored-by: ggurdin <ggurdin@gmail.com>
2026-02-27 12:29:50 -05:00

36 lines
1.1 KiB
Dart

import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/join_codes/knock_room_extension.dart';
/// Returns true when a push notification event is an accepted-knock invite —
/// i.e. an m.room.member invite targeting the current user in a room the user
/// previously knocked on.
///
/// Extracted as a pure function so it can be unit-tested without a Flutter
/// environment or a live Matrix client.
bool isKnockAcceptedInvite({
required String eventType,
required String? newMembership,
required String? stateKey,
required String? currentUserId,
required bool hasKnocked,
}) {
return eventType == EventTypes.RoomMember &&
newMembership == 'invite' &&
stateKey == currentUserId &&
hasKnocked;
}
/// Convenience wrapper that reads [KnockTracker] state from a live [Client].
bool isKnockAcceptedInviteForClient({
required Event event,
required Client client,
}) {
return isKnockAcceptedInvite(
eventType: event.type,
newMembership: event.content.tryGet<String>('membership'),
stateKey: event.stateKey,
currentUserId: client.userID,
hasKnocked: client.hasEverKnockedRoom(event.room.id),
);
}