diff --git a/android/app/build.gradle b/android/app/build.gradle index 3d9326d5..dd7a10ab 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -95,6 +95,7 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.google.firebase:firebase-messaging:20.1.6' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b27e14dc..7b16048e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ (context, I18n); } diff --git a/lib/utils/firebase_controller.dart b/lib/utils/firebase_controller.dart index 8c1b4c24..cab1f1e1 100644 --- a/lib/utils/firebase_controller.dart +++ b/lib/utils/firebase_controller.dart @@ -14,6 +14,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:famedlysdk/famedlysdk.dart'; import '../utils/event_extension.dart'; import '../utils/room_extension.dart'; +import 'famedlysdk_store.dart'; abstract class FirebaseController { static FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); @@ -40,7 +41,7 @@ abstract class FirebaseController { await client.setPushers( token, "http", - "chat.fluffy.fluffychat", + "chat.fluffy.fluffychat.data", clientName, client.deviceName, "en", @@ -83,115 +84,181 @@ abstract class FirebaseController { onSelectNotification: goToRoom); _firebaseMessaging.configure( - onMessage: (Map message) async { - try { - print(message); - final data = message['data'] ?? message; - final String roomId = data["room_id"]; - final String eventId = data["event_id"]; - final int unread = json.decode(data["counts"])["unread"]; - if ((roomId?.isEmpty ?? true) || - (eventId?.isEmpty ?? true) || - unread == 0) { - await _flutterLocalNotificationsPlugin.cancelAll(); - return null; - } - if (Matrix.of(context).activeRoomId == roomId) return null; - - // Get the room - Room room = client.getRoomById(roomId); - if (room == null) { - await client.onRoomUpdate.stream - .where((u) => u.id == roomId) - .first - .timeout(Duration(seconds: 10)); - room = client.getRoomById(roomId); - if (room == null) return null; - } - - // Get the event - Event event = await client.store.getEventById(eventId, room); - if (event == null) { - final EventUpdate eventUpdate = await client.onEvent.stream - .where((u) => u.content["event_id"] == eventId) - .first - .timeout(Duration(seconds: 10)); - event = Event.fromJson(eventUpdate.content, room); - if (room == null) return null; - } - - // Count all unread events - int unreadEvents = 0; - client.rooms - .forEach((Room room) => unreadEvents += room.notificationCount); - - // Calculate title - final String title = unread > 1 - ? I18n.of(context).unreadMessagesInChats( - unreadEvents.toString(), unread.toString()) - : I18n.of(context).unreadMessages(unreadEvents.toString()); - - // Calculate the body - final String body = event.getLocalizedBody(context, - withSenderNamePrefix: true, hideReply: true); - - // The person object for the android message style notification - final person = Person( - name: room.getLocalizedDisplayname(context), - icon: room.avatar == null - ? null - : await downloadAndSaveAvatar( - room.avatar, - client, - width: 126, - height: 126, - ), - iconSource: IconSource.FilePath, - ); - - // Show notification - var androidPlatformChannelSpecifics = AndroidNotificationDetails( - 'fluffychat_push', - 'FluffyChat push channel', - 'Push notifications for FluffyChat', - style: AndroidNotificationStyle.Messaging, - styleInformation: MessagingStyleInformation( - person, - conversationTitle: title, - messages: [ - Message( - body, - event.time, - person, - ) - ], - ), - importance: Importance.Max, - priority: Priority.High, - ticker: I18n.of(context).newMessageInFluffyChat); - var iOSPlatformChannelSpecifics = IOSNotificationDetails(); - var platformChannelSpecifics = NotificationDetails( - androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics); - await _flutterLocalNotificationsPlugin.show( - 0, - room.getLocalizedDisplayname(context), - body, - platformChannelSpecifics, - payload: roomId); - } catch (exception) { - debugPrint("[Push] Error while processing notification: " + - exception.toString()); - } - return null; - }, + onMessage: _onMessage, + onBackgroundMessage: _onMessage, onResume: goToRoom, - // Currently fires unexpectetly... https://github.com/FirebaseExtended/flutterfire/issues/1060 - //onLaunch: goToRoom, + onLaunch: goToRoom, ); debugPrint("[Push] Firebase initialized"); return; } + static Future _onMessage(Map message) async { + try { + final data = message['data'] ?? message; + final String roomId = data["room_id"]; + final String eventId = data["event_id"]; + final int unread = json.decode(data["counts"])["unread"]; + if ((roomId?.isEmpty ?? true) || + (eventId?.isEmpty ?? true) || + unread == 0) { + await _flutterLocalNotificationsPlugin.cancelAll(); + return null; + } + if (context != null && Matrix.of(context).activeRoomId == roomId) { + return null; + } + + // Get the client + print("Get client"); + Client client; + if (context != null) { + client = Matrix.of(context).client; + } else { + final platform = kIsWeb ? "Web" : Platform.operatingSystem; + final clientName = "FluffyChat $platform"; + print("Clientname: $clientName"); + client = Client(clientName, debug: false); + client.storeAPI = ExtendedStore(client); + await client.onLoginStateChanged.stream + .firstWhere((l) => l == LoginState.logged) + .timeout( + Duration(seconds: 2), + ); + } + + // Get the room + print("Get room"); + Room room = client.getRoomById(roomId); + if (room == null) { + await client.onRoomUpdate.stream + .where((u) => u.id == roomId) + .first + .timeout(Duration(seconds: 10)); + room = client.getRoomById(roomId); + if (room == null) return null; + } + + // Get the event + print("Get event"); + Event event = await client.store.getEventById(eventId, room); + if (event == null) { + final EventUpdate eventUpdate = await client.onEvent.stream + .where((u) => u.content["event_id"] == eventId) + .first + .timeout(Duration(seconds: 10)); + event = Event.fromJson(eventUpdate.content, room); + if (room == null) return null; + } + + // Count all unread events + int unreadEvents = 0; + client.rooms + .forEach((Room room) => unreadEvents += room.notificationCount); + + // Calculate title + final String title = unread > 1 + ? I18n.of(context) + .unreadMessagesInChats(unreadEvents.toString(), unread.toString()) + : I18n.of(context).unreadMessages(unreadEvents.toString()); + + // Calculate the body + final String body = event.getLocalizedBody(context, + withSenderNamePrefix: true, hideReply: true); + + // The person object for the android message style notification + final person = Person( + name: room.getLocalizedDisplayname(context), + icon: room.avatar == null + ? null + : await downloadAndSaveAvatar( + room.avatar, + client, + width: 126, + height: 126, + ), + iconSource: IconSource.FilePath, + ); + + // Show notification + var androidPlatformChannelSpecifics = AndroidNotificationDetails( + 'fluffychat_push', + 'FluffyChat push channel', + 'Push notifications for FluffyChat', + style: AndroidNotificationStyle.Messaging, + styleInformation: MessagingStyleInformation( + person, + conversationTitle: title, + messages: [ + Message( + body, + event.time, + person, + ) + ], + ), + importance: Importance.Max, + priority: Priority.High, + ticker: I18n.of(context).newMessageInFluffyChat); + var iOSPlatformChannelSpecifics = IOSNotificationDetails(); + var platformChannelSpecifics = NotificationDetails( + androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics); + await _flutterLocalNotificationsPlugin.show(0, + room.getLocalizedDisplayname(context), body, platformChannelSpecifics, + payload: roomId); + } catch (exception) { + debugPrint("[Push] Error while processing notification: " + + exception.toString()); + } + return null; + } + + static Future _handleOnBackgroundMessage( + Map message) async { + try { + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + // Init notifications framework + var initializationSettingsAndroid = + AndroidInitializationSettings('notifications_icon'); + var initializationSettingsIOS = IOSInitializationSettings(); + var initializationSettings = InitializationSettings( + initializationSettingsAndroid, initializationSettingsIOS); + await flutterLocalNotificationsPlugin.initialize(initializationSettings); + + // Notification data and matrix data + Map data = message['data'] ?? message; + String eventID = data["event_id"]; + String roomID = data["room_id"]; + final int unread = data.containsKey("counts") + ? json.decode(data["counts"])["unread"] + : 1; + await flutterLocalNotificationsPlugin.cancelAll(); + if (unread == 0 || roomID == null || eventID == null) { + return; + } + + // Display notification + var androidPlatformChannelSpecifics = AndroidNotificationDetails( + 'fluffychat_push', + 'FluffyChat push channel', + 'Push notifications for FluffyChat', + importance: Importance.Max, + priority: Priority.High); + var iOSPlatformChannelSpecifics = IOSNotificationDetails(); + var platformChannelSpecifics = NotificationDetails( + androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics); + final String title = "$unread ungelesene Unterhaltungen"; + await flutterLocalNotificationsPlugin.show(1, title, + 'App öffnen, um Nachricht zu entschlüsseln', platformChannelSpecifics, + payload: roomID); + } catch (exception) { + debugPrint("[Push] Error while processing background notification: " + + exception.toString()); + } + return Future.value(); + } + static Future downloadAndSaveAvatar(Uri content, Client client, {int width, int height}) async { final bool thumbnail = width == null && height == null ? false : true; diff --git a/pubspec.lock b/pubspec.lock index d941fe7c..c0a4a4e0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -142,7 +142,7 @@ packages: name: firebase_messaging url: "https://pub.dartlang.org" source: hosted - version: "6.0.9" + version: "6.0.13" flutter: dependency: "direct main" description: flutter @@ -168,7 +168,7 @@ packages: name: flutter_local_notifications url: "https://pub.dartlang.org" source: hosted - version: "0.9.1+2" + version: "0.8.4+3" flutter_localizations: dependency: "direct main" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index da855972..5e819cca 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,8 +38,8 @@ dependencies: url_launcher_web: ^0.1.0 sqflite: ^1.2.0 flutter_advanced_networkimage: any - firebase_messaging: ^6.0.9 - flutter_local_notifications: ^0.9.1+2 + firebase_messaging: ^6.0.13 + flutter_local_notifications: ^0.8.4 link_text: ^0.1.1 path_provider: ^1.5.1 webview_flutter: ^0.3.19+9