fluffychat/lib/utils/push_helper.dart

151 lines
4.8 KiB
Dart
Raw Normal View History

2022-04-14 07:34:55 +02:00
import 'dart:convert';
import 'dart:ui';
2022-04-14 19:26:20 +02:00
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
2022-04-14 07:34:55 +02:00
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:matrix/matrix.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions.dart/matrix_locals.dart';
Future<void> pushHelper(
PushNotification notification, {
Client? client,
L10n? l10n,
String? activeRoomId,
Future<dynamic> Function(String?)? onSelectNotification,
}) async {
final isBackgroundMessage = client == null;
Logs().v(
'Push helper has been started (background=$isBackgroundMessage).',
notification.toJson(),
);
if (!isBackgroundMessage &&
activeRoomId == notification.roomId &&
activeRoomId != null &&
client?.syncPresence == null) {
Logs().v('Room is in foreground. Stop push helper here.');
return;
}
// Initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
final _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await _flutterLocalNotificationsPlugin.initialize(
2022-04-14 19:26:20 +02:00
const InitializationSettings(
android: AndroidInitializationSettings('notifications_icon'),
iOS: IOSInitializationSettings(),
2022-04-14 07:34:55 +02:00
),
onSelectNotification: onSelectNotification,
);
client ??= (await ClientManager.getClients(initialize: false)).first;
final event = await client.getEventByPushNotification(
notification,
storeInDatabase: isBackgroundMessage,
);
if (event == null) {
Logs().v('Notification is a clearing indicator.');
await _flutterLocalNotificationsPlugin.cancelAll();
final store = await SharedPreferences.getInstance();
await store.setString(SettingKeys.notificationCurrentIds, json.encode({}));
return;
}
Logs().v('Push helper got notification event.');
l10n ??= await L10n.delegate.load(window.locale);
final matrixLocals = MatrixLocals(l10n);
// Calculate the body
final body = await event.calcLocalizedBody(
2022-04-14 07:34:55 +02:00
matrixLocals,
plaintextBody: true,
2022-04-15 08:02:23 +02:00
withSenderNamePrefix: !event.room.isDirectChat,
2022-04-14 07:34:55 +02:00
hideReply: true,
hideEdit: true,
removeMarkdown: true,
);
// The person object for the android message style notification
2022-04-15 08:02:23 +02:00
final avatar = event.room.avatar
?.getThumbnail(
client,
width: 126,
height: 126,
)
.toString();
2022-04-14 19:26:20 +02:00
final avatarFile =
avatar == null ? null : await DefaultCacheManager().getSingleFile(avatar);
2022-04-14 07:34:55 +02:00
// Show notification
final androidPlatformChannelSpecifics = AndroidNotificationDetails(
AppConfig.pushNotificationsChannelId,
AppConfig.pushNotificationsChannelName,
2022-04-14 19:26:20 +02:00
channelDescription: AppConfig.pushNotificationsChannelDescription,
2022-04-14 07:34:55 +02:00
styleInformation: MessagingStyleInformation(
2022-04-15 08:02:23 +02:00
Person(name: event.room.client.userID),
conversationTitle: event.room.displayname,
2022-04-14 07:34:55 +02:00
groupConversation: !event.room.isDirectChat,
messages: [
Message(
body,
event.originServerTs,
2022-04-15 08:02:23 +02:00
Person(
name: event.room.displayname,
icon: avatarFile == null
? null
: BitmapFilePathAndroidIcon(avatarFile.path),
),
2022-04-14 07:34:55 +02:00
)
],
),
2022-04-15 08:02:23 +02:00
ticker: l10n.unreadChats(notification.counts?.unread ?? 1),
2022-04-14 07:34:55 +02:00
importance: Importance.max,
priority: Priority.high,
2022-04-15 08:02:23 +02:00
groupKey: event.room.id,
2022-04-14 07:34:55 +02:00
);
const iOSPlatformChannelSpecifics = IOSNotificationDetails();
final platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
);
await _flutterLocalNotificationsPlugin.show(
await mapRoomIdToInt(event.room.id),
event.room.displayname,
body,
platformChannelSpecifics,
payload: event.roomId,
);
Logs().v('Push helper has been completed!');
}
/// Workaround for the problem that local notification IDs must be int but we
/// sort by [roomId] which is a String. To make sure that we don't have duplicated
/// IDs we map the [roomId] to a number and store this number.
Future<int> mapRoomIdToInt(String roomId) async {
final store = await SharedPreferences.getInstance();
2022-04-15 08:02:23 +02:00
final idMap = Map<String, int>.from(
jsonDecode(store.getString(SettingKeys.notificationCurrentIds) ?? '{}'));
2022-04-14 07:34:55 +02:00
int? currentInt;
try {
currentInt = idMap[roomId];
} catch (_) {
currentInt = null;
}
if (currentInt != null) {
return currentInt;
}
var nCurrentInt = 0;
2022-04-15 08:02:23 +02:00
while (idMap.values.contains(nCurrentInt)) {
2022-04-14 07:34:55 +02:00
nCurrentInt++;
}
idMap[roomId] = nCurrentInt;
await store.setString(SettingKeys.notificationCurrentIds, json.encode(idMap));
return nCurrentInt;
}