fluffychat/lib/utils/push_helper.dart
ggurdin e8428783e6
Fluffychat merge 2 (#5590)
* build: Reenable shrink resources and minify in gradle

* build: (deps): bump image from 4.6.0 to 4.7.1

Bumps [image](https://github.com/brendan-duncan/image) from 4.6.0 to 4.7.1.
- [Changelog](https://github.com/brendan-duncan/image/blob/main/CHANGELOG.md)
- [Commits](https://github.com/brendan-duncan/image/commits)

---
updated-dependencies:
- dependency-name: image
  dependency-version: 4.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* build: (deps): bump file_picker from 10.3.7 to 10.3.8

Bumps [file_picker](https://github.com/miguelpruivo/flutter_file_picker) from 10.3.7 to 10.3.8.
- [Release notes](https://github.com/miguelpruivo/flutter_file_picker/releases)
- [Changelog](https://github.com/miguelpruivo/flutter_file_picker/blob/master/CHANGELOG.md)
- [Commits](https://github.com/miguelpruivo/flutter_file_picker/compare/v10.3.7...v10.3.8)

---
updated-dependencies:
- dependency-name: file_picker
  dependency-version: 10.3.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* feat: Improved search

* build: Use matrix sdk vom pub.dev again

* chore: Follow up better search

* build: (deps): bump image from 4.7.1 to 4.7.2

Bumps [image](https://github.com/brendan-duncan/image) from 4.7.1 to 4.7.2.
- [Changelog](https://github.com/brendan-duncan/image/blob/main/CHANGELOG.md)
- [Commits](https://github.com/brendan-duncan/image/commits)

---
updated-dependencies:
- dependency-name: image
  dependency-version: 4.7.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: Make cross signing self sign mandatory for bootstrap

* chore: Update user device keys before creating bootstrap

* fix: Better wait for secrets after verification bootstrap

* refactor: Remove native imaging and enable web worker

* refactor: Remove unused html onfocus streams

* build: (deps): bump flutter_foreground_task from 9.1.0 to 9.2.0

Bumps [flutter_foreground_task](https://github.com/Dev-hwang/flutter_foreground_task) from 9.1.0 to 9.2.0.
- [Changelog](https://github.com/Dev-hwang/flutter_foreground_task/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Dev-hwang/flutter_foreground_task/commits)

---
updated-dependencies:
- dependency-name: flutter_foreground_task
  dependency-version: 9.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(translations): Translated using Weblate (Uzbek)

Currently translated at 99.7% (823 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/uz/

* chore(translations): Translated using Weblate (Russian)

Currently translated at 99.8% (824 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ru/

* chore(translations): Translated using Weblate (Norwegian Bokmål)

Currently translated at 90.9% (750 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/nb_NO/

* chore(translations): Translated using Weblate (Galician)

Currently translated at 100.0% (825 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/gl/

* chore(translations): Translated using Weblate (Basque)

Currently translated at 99.7% (823 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/eu/

* chore(translations): Translated using Weblate (Ukrainian)

Currently translated at 100.0% (825 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/uk/

* chore(translations): Translated using Weblate (Estonian)

Currently translated at 100.0% (825 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/et/

* chore(translations): Translated using Weblate (Dutch)

Currently translated at 100.0% (825 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/nl/

* chore(translations): Translated using Weblate (Russian)

Currently translated at 100.0% (825 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ru/

* chore(translations): Translated using Weblate (Spanish)

Currently translated at 95.2% (788 of 827 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/es/

* chore(translations): Translated using Weblate (Spanish)

Currently translated at 96.3% (797 of 827 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/es/

* chore(translations): Translated using Weblate (Russian)

Currently translated at 100.0% (825 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ru/

* chore(translations): Translated using Weblate (Russian)

Currently translated at 100.0% (825 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/ru/

* fix: Broken ruzzian plurals

* chore(translations): Translated using Weblate (Norwegian Bokmål)

Currently translated at 91.2% (753 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/nb_NO/

* chore(translations): Translated using Weblate (Bengali)

Currently translated at 4.5% (38 of 827 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/bn/

* chore(translations): Translated using Weblate (French)

Currently translated at 82.3% (679 of 825 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/fr/

* build: (deps): bump translations_cleaner from 0.0.5 to 0.1.0

Bumps [translations_cleaner](https://github.com/Chinmay-KB/translations_cleaner) from 0.0.5 to 0.1.0.
- [Changelog](https://github.com/Chinmay-KB/translations_cleaner/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Chinmay-KB/translations_cleaner/commits)

---
updated-dependencies:
- dependency-name: translations_cleaner
  dependency-version: 0.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(translations): Translated using Weblate (German)

Currently translated at 99.2% (821 of 827 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/de/

* chore(translations): Translated using Weblate (Estonian)

Currently translated at 100.0% (827 of 827 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/et/

* build: Bump version to 2.4.0

* build: (deps): bump sqflite_common_ffi from 2.3.6 to 2.3.7+1

Bumps [sqflite_common_ffi](https://github.com/tekartik/sqflite) from 2.3.6 to 2.3.7+1.
- [Commits](https://github.com/tekartik/sqflite/compare/sqflite_common_ffi_v2.3.6...sqflite_common_ffi/v2.3.7)

---
updated-dependencies:
- dependency-name: sqflite_common_ffi
  dependency-version: 2.3.7+1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(translations): Translated using Weblate (Czech)

Currently translated at 66.1% (547 of 827 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/cs/

* chore(translations): Translated using Weblate (Czech)

Currently translated at 72.7% (602 of 827 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/cs/

* chore(translations): Translated using Weblate (German)

Currently translated at 99.8% (826 of 827 strings)

Translation: FluffyChat/Translations
Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations/de/

* chore: Add security.md file

* fix: Locale unlocalized strings

* build: (deps): bump matrix from 4.1.0 to 5.0.0

Bumps [matrix](https://github.com/famedly/matrix-dart-sdk) from 4.1.0 to 5.0.0.
- [Release notes](https://github.com/famedly/matrix-dart-sdk/releases)
- [Changelog](https://github.com/famedly/matrix-dart-sdk/blob/main/CHANGELOG.md)
- [Commits](https://github.com/famedly/matrix-dart-sdk/compare/v4.1.0...v5.0.0)

---
updated-dependencies:
- dependency-name: matrix
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: Notifications on web correctly managed when tab not focused

* chore: Add changelog for android

* chore: Remove duplicated localization

* fix: Sign in label

* chore: Versionize fcm shared isolate

* build: Remove unused packag

* build: (deps): bump package_info_plus from 8.3.1 to 9.0.0

Bumps [package_info_plus](https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus) from 8.3.1 to 9.0.0.
- [Release notes](https://github.com/fluttercommunity/plus_plugins/releases)
- [Commits](https://github.com/fluttercommunity/plus_plugins/commits/package_info_plus-v9.0.0/packages/package_info_plus)

---
updated-dependencies:
- dependency-name: package_info_plus
  dependency-version: 9.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* feat: Display particle animation on login page

* chore: Use fixed version of fcm shared isolate

* fix: apk crash on some platforms due new flutter version

* chore: Correct kotlin format

* fix iOS notifications

* fluffychat merge

* fluffychat merge

* fluffychat merge

* fluffychat merge

* fluffychat merge

* fluffychat merge

* add missing type annotations

* update matrix version

* fluffychat merge

* fluffychat merge

* fix notification on click actions

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Christian Kußowski <c.kussowski@famedly.com>
Co-authored-by: Krille-chan <christian-kussowski@posteo.de>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: BeMeritus <bemerituss@gmail.com>
Co-authored-by: Frank Paul Silye <frankps@gmail.com>
Co-authored-by: josé m. <correoxm@disroot.org>
Co-authored-by: xabirequejo <xabi.rn@gmail.com>
Co-authored-by: Ihor Hordiichuk <igor_ck@outlook.com>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Co-authored-by: Jelv <post@jelv.nl>
Co-authored-by: Дмитрий Михирев <bizdelnick@gmail.com>
Co-authored-by: Kimby <kimbyqs@gmail.com>
Co-authored-by: Christian <christian-pauly@posteo.de>
Co-authored-by: Kom nake <kominak310@svcache.com>
Co-authored-by: hugues de keyzer <komputilisto@hugues.info>
Co-authored-by: nautilusx <translate@disroot.org>
Co-authored-by: Šebestová <ka.sebestova.cz@gmail.com>
2026-02-10 08:01:12 -05:00

452 lines
14 KiB
Dart

import 'dart:convert';
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_shortcuts_new/flutter_shortcuts_new.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/setting_keys.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/utils/client_download_content_extension.dart';
import 'package:fluffychat/utils/client_manager.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/notification_background_handler.dart';
import 'package:fluffychat/utils/platform_infos.dart';
const notificationAvatarDimension = 128;
Future<void> pushHelper(
PushNotification notification, {
Client? client,
L10n? l10n,
String? activeRoomId,
required FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin,
// #Pangea
Map<String, dynamic>? additionalData,
// Pangea#
bool useNotificationActions = true,
}) async {
try {
await _tryPushHelper(
notification,
client: client,
l10n: l10n,
activeRoomId: activeRoomId,
flutterLocalNotificationsPlugin: flutterLocalNotificationsPlugin,
// #Pangea
additionalData: additionalData,
// Pangea#
useNotificationActions: useNotificationActions,
);
} catch (e, s) {
Logs().e('Push Helper has crashed! Writing into temporary file', e, s);
l10n ??= await lookupL10n(PlatformDispatcher.instance.locale);
flutterLocalNotificationsPlugin.show(
notification.roomId?.hashCode ?? 0,
// #Pangea
// l10n.newMessageInFluffyChat,
l10n.newMessageInPangeaChat,
// Pangea#
l10n.openAppToReadMessages,
NotificationDetails(
iOS: const DarwinNotificationDetails(),
android: AndroidNotificationDetails(
AppConfig.pushNotificationsChannelId,
l10n.incomingMessages,
number: notification.counts?.unread,
ticker: l10n.unreadChatsInApp(
AppSettings.applicationName.value,
(notification.counts?.unread ?? 0).toString(),
),
importance: Importance.high,
priority: Priority.max,
shortcutId: notification.roomId,
),
),
);
rethrow;
}
}
Future<void> _tryPushHelper(
PushNotification notification, {
Client? client,
L10n? l10n,
String? activeRoomId,
required FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin,
// #Pangea
Map<String, dynamic>? additionalData,
// Pangea#
bool useNotificationActions = true,
}) async {
final isBackgroundMessage = client == null;
Logs().v(
'Push helper has been started (background=$isBackgroundMessage).',
notification.toJson(),
);
if (notification.roomId != null &&
activeRoomId == notification.roomId &&
WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed) {
Logs().v('Room is in foreground. Stop push helper here.');
return;
}
client ??= (await ClientManager.getClients(
initialize: false,
store: await AppSettings.init(),
)).first;
final event = await client.getEventByPushNotification(
notification,
storeInDatabase: false,
);
if (event == null) {
Logs().v('Notification is a clearing indicator.');
if (notification.counts?.unread == null ||
notification.counts?.unread == 0) {
await flutterLocalNotificationsPlugin.cancelAll();
} else {
// Make sure client is fully loaded and synced before dismiss notifications:
await client.roomsLoading;
await client.oneShotSync();
final activeNotifications = await flutterLocalNotificationsPlugin
.getActiveNotifications();
for (final activeNotification in activeNotifications) {
final room = client.rooms.singleWhereOrNull(
(room) => room.id.hashCode == activeNotification.id,
);
if (room == null || !room.isUnreadOrInvited) {
flutterLocalNotificationsPlugin.cancel(activeNotification.id!);
}
}
}
return;
}
Logs().v('Push helper got notification event of type ${event.type}.');
if (event.type.startsWith('m.call')) {
// make sure bg sync is on (needed to update hold, unhold events)
// prevent over write from app life cycle change
client.backgroundSync = true;
}
if (event.type == EventTypes.CallHangup) {
client.backgroundSync = false;
}
if (event.type.startsWith('m.call') && event.type != EventTypes.CallInvite) {
Logs().v('Push message is a m.call but not invite. Do not display.');
return;
}
if ((event.type.startsWith('m.call') &&
event.type != EventTypes.CallInvite) ||
event.type == 'org.matrix.call.sdp_stream_metadata_changed') {
Logs().v('Push message was for a call, but not call invite.');
return;
}
l10n ??= await L10n.delegate.load(PlatformDispatcher.instance.locale);
final matrixLocals = MatrixLocals(l10n);
// Calculate the body
final body = event.type == EventTypes.Encrypted
// #Pangea
// ? l10n.newMessageInFluffyChat
? l10n.newMessageInPangeaChat
// Pangea#
: await event.calcLocalizedBody(
matrixLocals,
plaintextBody: true,
withSenderNamePrefix: false,
hideReply: true,
hideEdit: true,
removeMarkdown: true,
);
// The person object for the android message style notification
final avatar = event.room.avatar;
final senderAvatar = event.room.isDirectChat
? avatar
: event.senderFromMemoryOrFallback.avatarUrl;
Uint8List? roomAvatarFile, senderAvatarFile;
try {
roomAvatarFile = avatar == null
? null
: await client
.downloadMxcCached(
avatar,
thumbnailMethod: ThumbnailMethod.crop,
width: notificationAvatarDimension,
height: notificationAvatarDimension,
animated: false,
isThumbnail: true,
rounded: true,
)
.timeout(const Duration(seconds: 3));
} catch (e, s) {
Logs().e('Unable to get avatar picture', e, s);
// #Pangea
ErrorHandler.logError(e: e, s: s, data: {"avatarUri": avatar.toString()});
// Pangea#
}
try {
senderAvatarFile = event.room.isDirectChat
? roomAvatarFile
: senderAvatar == null
? null
: await client
.downloadMxcCached(
senderAvatar,
thumbnailMethod: ThumbnailMethod.crop,
width: notificationAvatarDimension,
height: notificationAvatarDimension,
animated: false,
isThumbnail: true,
rounded: true,
)
.timeout(const Duration(seconds: 3));
} catch (e, s) {
Logs().e('Unable to get avatar picture', e, s);
}
final id = notification.roomId.hashCode;
final senderName = event.senderFromMemoryOrFallback.calcDisplayname();
// Show notification
final newMessage = Message(
body,
event.originServerTs,
Person(
bot: event.messageType == MessageTypes.Notice,
key: event.senderId,
name: senderName,
icon: senderAvatarFile == null
? null
: ByteArrayAndroidIcon(senderAvatarFile),
),
);
final messagingStyleInformation = PlatformInfos.isAndroid
? await AndroidFlutterLocalNotificationsPlugin()
.getActiveNotificationMessagingStyle(id)
: null;
messagingStyleInformation?.messages?.add(newMessage);
final roomName = event.room.getLocalizedDisplayname(MatrixLocals(l10n));
final notificationGroupId = event.room.isDirectChat
? 'directChats'
: 'groupChats';
// #Pangea
// final groupName = event.room.isDirectChat ? l10n.directChats : l10n.groups;
final groupName = event.room.isDirectChat ? l10n.directChats : l10n.chats;
// Pangea#
final messageRooms = AndroidNotificationChannelGroup(
notificationGroupId,
groupName,
);
final roomsChannel = AndroidNotificationChannel(
event.room.id,
roomName,
groupId: notificationGroupId,
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>()
?.createNotificationChannelGroup(messageRooms);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>()
?.createNotificationChannel(roomsChannel);
final androidPlatformChannelSpecifics = AndroidNotificationDetails(
AppConfig.pushNotificationsChannelId,
l10n.incomingMessages,
number: notification.counts?.unread,
category: AndroidNotificationCategory.message,
shortcutId: event.room.id,
styleInformation:
messagingStyleInformation ??
MessagingStyleInformation(
Person(
name: senderName,
icon: roomAvatarFile == null
? null
: ByteArrayAndroidIcon(roomAvatarFile),
key: event.roomId,
important: event.room.isFavourite,
),
conversationTitle: event.room.isDirectChat ? null : roomName,
groupConversation: !event.room.isDirectChat,
messages: [newMessage],
),
ticker: event.calcLocalizedBodyFallback(
matrixLocals,
plaintextBody: true,
withSenderNamePrefix: !event.room.isDirectChat,
hideReply: true,
hideEdit: true,
removeMarkdown: true,
),
importance: Importance.high,
priority: Priority.max,
groupKey: event.room.spaceParents.firstOrNull?.roomId ?? 'rooms',
actions: event.type == EventTypes.RoomMember || !useNotificationActions
? null
: <AndroidNotificationAction>[
AndroidNotificationAction(
FluffyChatNotificationActions.reply.name,
l10n.reply,
inputs: [
AndroidNotificationActionInput(label: l10n.writeAMessage),
],
cancelNotification: false,
allowGeneratedReplies: true,
semanticAction: SemanticAction.reply,
),
AndroidNotificationAction(
FluffyChatNotificationActions.markAsRead.name,
l10n.markAsRead,
semanticAction: SemanticAction.markAsRead,
),
],
);
const iOSPlatformChannelSpecifics = DarwinNotificationDetails();
final platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
);
final title = event.room.getLocalizedDisplayname(MatrixLocals(l10n));
if (PlatformInfos.isAndroid && messagingStyleInformation == null) {
await _setShortcut(event, l10n, title, roomAvatarFile);
}
// #Pangea - Include activity session data in payload
final Map<String, String> additionalDataMap = {};
if (additionalData != null) {
additionalData.forEach((key, value) {
if (value is String) {
additionalDataMap[key] = value;
}
});
}
final payload = FluffyChatPushPayload(
client.clientName,
event.room.id,
event.eventId,
additionalData: additionalDataMap,
).toString();
// Pangea#
await flutterLocalNotificationsPlugin.show(
id,
title,
body,
platformChannelSpecifics,
// #Pangea
// payload: FluffyChatPushPayload(
// client.clientName,
// event.room.id,
// event.eventId,
// ).toString(),
payload: payload,
// Pangea#
);
Logs().v('Push helper has been completed!');
}
class FluffyChatPushPayload {
final String? clientName, roomId, eventId;
// #Pangea
final Map<String, String> additionalData;
// Pangea#
// #Pangea
// FluffyChatPushPayload(this.clientName, this.roomId, this.eventId);
FluffyChatPushPayload(
this.clientName,
this.roomId,
this.eventId, {
this.additionalData = const {},
});
// Pangea#
factory FluffyChatPushPayload.fromString(String payload) {
final parts = payload.split('|');
// #Pangea
// if (parts.length != 3) {
// return FluffyChatPushPayload(null, null, null);
// }
// return FluffyChatPushPayload(parts[0], parts[1], parts[2]);
if (parts.length < 3) {
return FluffyChatPushPayload(null, null, null);
}
Map<String, String> additionalData = {};
if (parts.length > 3) {
try {
additionalData = Map<String, String>.from(jsonDecode(parts[3]));
} catch (e, s) {
Logs().e('Unable to parse additional data from payload', e, s);
}
}
return FluffyChatPushPayload(
parts[0],
parts[1],
parts[2],
additionalData: additionalData,
);
// Pangea#
}
// #Pangea
// @override
// String toString() => '$clientName|$roomId|$eventId';
@override
String toString() =>
'$clientName|$roomId|$eventId|${jsonEncode(additionalData)}';
// Pangea#
}
/// Creates a shortcut for Android platform but does not block displaying the
/// notification. This is optional but provides a nicer view of the
/// notification popup.
Future<void> _setShortcut(
Event event,
L10n l10n,
String title,
Uint8List? avatarFile,
) async {
final flutterShortcuts = FlutterShortcuts();
await flutterShortcuts.initialize(debug: !kReleaseMode);
await flutterShortcuts.pushShortcutItem(
shortcut: ShortcutItem(
id: event.room.id,
action: AppConfig.inviteLinkPrefix + event.room.id,
shortLabel: title,
conversationShortcut: true,
icon: avatarFile == null ? null : base64Encode(avatarFile),
shortcutIconAsset: avatarFile == null
? ShortcutIconAsset.androidAsset
: ShortcutIconAsset.memoryAsset,
isImportant: event.room.isFavourite,
),
);
}