Fix foreground notification navigation to activity sessions for course pings (#4369)
* Initial plan * Fix foreground notification navigation to activity sessions Co-authored-by: ggurdin <46800240+ggurdin@users.noreply.github.com> * Add clarifying comments to notification handling code Co-authored-by: ggurdin <46800240+ggurdin@users.noreply.github.com> * Refactor to reduce duplicate code between _onOpenNotification and goToRoom Co-authored-by: ggurdin <46800240+ggurdin@users.noreply.github.com> * chore: fix foreground notif small icon --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ggurdin <46800240+ggurdin@users.noreply.github.com> Co-authored-by: ggurdin <ggurdin@gmail.com>
This commit is contained in:
parent
f59f72c53d
commit
5609632641
4 changed files with 118 additions and 43 deletions
|
|
@ -5314,5 +5314,6 @@
|
|||
"unsubscribedResponseError": "This feature requires a subscription",
|
||||
"leaveDesc": "Leave this space and all chats within it",
|
||||
"selectAll": "Select all",
|
||||
"deselectAll": "Deselect all"
|
||||
"deselectAll": "Deselect all",
|
||||
"newMessageInPangeaChat": "💬 New message in Pangea Chat"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,18 +76,24 @@ class BackgroundPush {
|
|||
void _init() async {
|
||||
try {
|
||||
// #Pangea
|
||||
// Handle notifications when app is opened from terminated/background state
|
||||
FirebaseMessaging.instance.getInitialMessage().then(_onOpenNotification);
|
||||
FirebaseMessaging.onMessageOpenedApp.listen(_onOpenNotification);
|
||||
// Pangea#
|
||||
await _flutterLocalNotificationsPlugin.initialize(
|
||||
const InitializationSettings(
|
||||
android: AndroidInitializationSettings('notifications_icon'),
|
||||
// #Pangea
|
||||
// android: AndroidInitializationSettings('notifications_icon'),
|
||||
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
|
||||
// Pangea#
|
||||
iOS: DarwinInitializationSettings(),
|
||||
),
|
||||
onDidReceiveNotificationResponse: goToRoom,
|
||||
);
|
||||
|
||||
// #Pangea
|
||||
// Handle notifications when app is in foreground
|
||||
// Pass additionalData to preserve activity session info for local notifications
|
||||
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||
pushHelper(
|
||||
PushNotification.fromJson(message.data),
|
||||
|
|
@ -95,6 +101,7 @@ class BackgroundPush {
|
|||
l10n: l10n,
|
||||
activeRoomId: matrix?.activeRoomId,
|
||||
flutterLocalNotificationsPlugin: _flutterLocalNotificationsPlugin,
|
||||
additionalData: message.data,
|
||||
);
|
||||
});
|
||||
// Pangea#
|
||||
|
|
@ -137,36 +144,32 @@ class BackgroundPush {
|
|||
}
|
||||
|
||||
// #Pangea
|
||||
Future<void> _onOpenNotification(RemoteMessage? message) async {
|
||||
const sessionIdKey = "content_pangea.activity.session_room_id";
|
||||
const activityIdKey = "content_pangea.activity.id";
|
||||
// Helper to ensure a room is loaded or synced.
|
||||
Future<Room?> _ensureRoomLoaded(String id) async {
|
||||
await client.roomsLoading;
|
||||
await client.accountDataLoading;
|
||||
|
||||
// Early return if no room_id.
|
||||
final roomId = message?.data['room_id'];
|
||||
if (roomId is! String || roomId.isEmpty) return;
|
||||
|
||||
// Helper to ensure a room is loaded or synced.
|
||||
Future<Room?> ensureRoomLoaded(String id) async {
|
||||
await client.roomsLoading;
|
||||
await client.accountDataLoading;
|
||||
|
||||
var room = client.getRoomById(id);
|
||||
if (room == null) {
|
||||
await client.waitForRoomInSync(id).timeout(const Duration(seconds: 30));
|
||||
room = client.getRoomById(id);
|
||||
}
|
||||
return room;
|
||||
var room = client.getRoomById(id);
|
||||
if (room == null) {
|
||||
await client.waitForRoomInSync(id).timeout(const Duration(seconds: 30));
|
||||
room = client.getRoomById(id);
|
||||
}
|
||||
return room;
|
||||
}
|
||||
|
||||
// Navigate to activity session or fallback to room
|
||||
Future<void> _navigateToActivityOrRoom({
|
||||
required String roomId,
|
||||
String? sessionRoomId,
|
||||
String? activityId,
|
||||
}) async {
|
||||
// Handle session room if provided.
|
||||
final sessionRoomId = message?.data[sessionIdKey];
|
||||
final activityId = message?.data[activityIdKey];
|
||||
if (sessionRoomId is String &&
|
||||
if (sessionRoomId != null &&
|
||||
sessionRoomId.isNotEmpty &&
|
||||
activityId is String &&
|
||||
activityId != null &&
|
||||
activityId.isNotEmpty) {
|
||||
try {
|
||||
final course = await ensureRoomLoaded(roomId);
|
||||
final course = await _ensureRoomLoaded(roomId);
|
||||
if (course == null) return;
|
||||
|
||||
final session = client.getRoomById(sessionRoomId);
|
||||
|
|
@ -186,7 +189,7 @@ class BackgroundPush {
|
|||
|
||||
// Fallback: just open the original room.
|
||||
try {
|
||||
final room = await ensureRoomLoaded(roomId);
|
||||
final room = await _ensureRoomLoaded(roomId);
|
||||
FluffyChatApp.router.go(
|
||||
room?.membership == Membership.invite ? '/rooms' : '/rooms/$roomId',
|
||||
);
|
||||
|
|
@ -194,6 +197,24 @@ class BackgroundPush {
|
|||
ErrorHandler.logError(e: err, s: s, data: {"roomId": roomId});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onOpenNotification(RemoteMessage? message) async {
|
||||
const sessionIdKey = "content_pangea.activity.session_room_id";
|
||||
const activityIdKey = "content_pangea.activity.id";
|
||||
|
||||
// Early return if no room_id.
|
||||
final roomId = message?.data['room_id'];
|
||||
if (roomId is! String || roomId.isEmpty) return;
|
||||
|
||||
final sessionRoomId = message?.data[sessionIdKey] as String?;
|
||||
final activityId = message?.data[activityIdKey] as String?;
|
||||
|
||||
await _navigateToActivityOrRoom(
|
||||
roomId: roomId,
|
||||
sessionRoomId: sessionRoomId,
|
||||
activityId: activityId,
|
||||
);
|
||||
}
|
||||
// Pangea#
|
||||
|
||||
factory BackgroundPush.clientOnly(Client client) {
|
||||
|
|
@ -461,23 +482,38 @@ class BackgroundPush {
|
|||
|
||||
Future<void> goToRoom(NotificationResponse? response) async {
|
||||
try {
|
||||
final roomId = response?.payload;
|
||||
Logs().v('[Push] Attempting to go to room $roomId...');
|
||||
if (roomId == null) {
|
||||
final payload = response?.payload;
|
||||
Logs().v('[Push] Attempting to go to room with payload: $payload');
|
||||
if (payload == null) {
|
||||
return;
|
||||
}
|
||||
await client.roomsLoading;
|
||||
await client.accountDataLoading;
|
||||
if (client.getRoomById(roomId) == null) {
|
||||
await client
|
||||
.waitForRoomInSync(roomId)
|
||||
.timeout(const Duration(seconds: 30));
|
||||
|
||||
// #Pangea - Handle activity session data if present
|
||||
String? roomId;
|
||||
String? sessionRoomId;
|
||||
String? activityId;
|
||||
|
||||
try {
|
||||
final payloadData = jsonDecode(payload) as Map<String, dynamic>;
|
||||
roomId = payloadData['room_id'] as String?;
|
||||
sessionRoomId =
|
||||
payloadData['content_pangea.activity.session_room_id'] as String?;
|
||||
activityId = payloadData['content_pangea.activity.id'] as String?;
|
||||
} catch (_) {
|
||||
// If payload is not JSON, treat it as a simple room ID
|
||||
roomId = payload;
|
||||
}
|
||||
FluffyChatApp.router.go(
|
||||
client.getRoomById(roomId)?.membership == Membership.invite
|
||||
? '/rooms'
|
||||
: '/rooms/$roomId',
|
||||
|
||||
if (roomId == null || roomId.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
await _navigateToActivityOrRoom(
|
||||
roomId: roomId,
|
||||
sessionRoomId: sessionRoomId,
|
||||
activityId: activityId,
|
||||
);
|
||||
// Pangea#
|
||||
} catch (e, s) {
|
||||
Logs().e('[Push] Failed to open room', e, s);
|
||||
// #Pangea
|
||||
|
|
|
|||
|
|
@ -216,7 +216,10 @@ abstract class ClientManager {
|
|||
|
||||
await flutterLocalNotificationsPlugin.initialize(
|
||||
const InitializationSettings(
|
||||
android: AndroidInitializationSettings('notifications_icon'),
|
||||
// #Pangea
|
||||
// android: AndroidInitializationSettings('notifications_icon'),
|
||||
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
|
||||
// Pangea#
|
||||
iOS: DarwinInitializationSettings(),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ Future<void> pushHelper(
|
|||
L10n? l10n,
|
||||
String? activeRoomId,
|
||||
required FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin,
|
||||
// #Pangea
|
||||
Map<String, dynamic>? additionalData,
|
||||
// Pangea#
|
||||
}) async {
|
||||
try {
|
||||
await _tryPushHelper(
|
||||
|
|
@ -34,6 +37,9 @@ Future<void> pushHelper(
|
|||
l10n: l10n,
|
||||
activeRoomId: activeRoomId,
|
||||
flutterLocalNotificationsPlugin: flutterLocalNotificationsPlugin,
|
||||
// #Pangea
|
||||
additionalData: additionalData,
|
||||
// Pangea#
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logs().v('Push Helper has crashed!', e, s);
|
||||
|
|
@ -41,7 +47,10 @@ Future<void> pushHelper(
|
|||
l10n ??= await lookupL10n(const Locale('en'));
|
||||
flutterLocalNotificationsPlugin.show(
|
||||
notification.roomId?.hashCode ?? 0,
|
||||
l10n.newMessageInFluffyChat,
|
||||
// #Pangea
|
||||
// l10n.newMessageInFluffyChat,
|
||||
l10n.newMessageInPangeaChat,
|
||||
// Pangea#
|
||||
l10n.openAppToReadMessages,
|
||||
NotificationDetails(
|
||||
iOS: const DarwinNotificationDetails(),
|
||||
|
|
@ -69,6 +78,9 @@ Future<void> _tryPushHelper(
|
|||
L10n? l10n,
|
||||
String? activeRoomId,
|
||||
required FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin,
|
||||
// #Pangea
|
||||
Map<String, dynamic>? additionalData,
|
||||
// Pangea#
|
||||
}) async {
|
||||
final isBackgroundMessage = client == null;
|
||||
Logs().v(
|
||||
|
|
@ -144,7 +156,10 @@ Future<void> _tryPushHelper(
|
|||
|
||||
// Calculate the body
|
||||
final body = event.type == EventTypes.Encrypted
|
||||
? l10n.newMessageInFluffyChat
|
||||
// #Pangea
|
||||
// ? l10n.newMessageInFluffyChat
|
||||
? l10n.newMessageInPangeaChat
|
||||
// Pangea#
|
||||
: await event.calcLocalizedBody(
|
||||
matrixLocals,
|
||||
plaintextBody: true,
|
||||
|
|
@ -297,12 +312,32 @@ Future<void> _tryPushHelper(
|
|||
await _setShortcut(event, l10n, title, roomAvatarFile);
|
||||
}
|
||||
|
||||
// #Pangea - Include activity session data in payload
|
||||
String payload = event.roomId!;
|
||||
if (additionalData != null) {
|
||||
const sessionIdKey = "content_pangea.activity.session_room_id";
|
||||
const activityIdKey = "content_pangea.activity.id";
|
||||
final sessionRoomId = additionalData[sessionIdKey];
|
||||
final activityId = additionalData[activityIdKey];
|
||||
if (sessionRoomId is String && activityId is String) {
|
||||
payload = jsonEncode({
|
||||
'room_id': event.roomId,
|
||||
sessionIdKey: sessionRoomId,
|
||||
activityIdKey: activityId,
|
||||
});
|
||||
}
|
||||
}
|
||||
// Pangea#
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
id,
|
||||
title,
|
||||
body,
|
||||
platformChannelSpecifics,
|
||||
payload: event.roomId,
|
||||
// #Pangea
|
||||
// payload: event.roomId,
|
||||
payload: payload,
|
||||
// Pangea#
|
||||
);
|
||||
Logs().v('Push helper has been completed!');
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue