mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 23:38:41 +00:00
fix: self-dos because of Skill Issues
This commit is contained in:
parent
385cf11654
commit
1f51d3174f
7 changed files with 330 additions and 305 deletions
|
|
@ -12,6 +12,7 @@ enum UploadState {
|
|||
|
||||
pending,
|
||||
readyToUpload,
|
||||
uploadTaskStarted,
|
||||
receiverNotified,
|
||||
// after all users notified all media files that are not storable by the other person will be deleted
|
||||
}
|
||||
|
|
|
|||
|
|
@ -357,13 +357,14 @@ Future finalizeUpload(int mediaUploadId, List<int> contactIds,
|
|||
|
||||
final lockingHandleNextMediaUploadStep = Mutex();
|
||||
Future handleNextMediaUploadSteps(int mediaUploadId) async {
|
||||
bool rerun = await lockingHandleNextMediaUploadStep.protect<bool>(() async {
|
||||
await lockingHandleNextMediaUploadStep.protect(() async {
|
||||
var mediaUpload = await twonlyDB.mediaUploadsDao
|
||||
.getMediaUploadById(mediaUploadId)
|
||||
.getSingleOrNull();
|
||||
|
||||
if (mediaUpload == null) return false;
|
||||
if (mediaUpload.state == UploadState.receiverNotified) {
|
||||
if (mediaUpload.state == UploadState.receiverNotified ||
|
||||
mediaUpload.state == UploadState.uploadTaskStarted) {
|
||||
/// Upload done and all users are notified :)
|
||||
Log.info("$mediaUploadId is already done");
|
||||
return false;
|
||||
|
|
@ -380,16 +381,13 @@ Future handleNextMediaUploadSteps(int mediaUploadId) async {
|
|||
return false;
|
||||
}
|
||||
|
||||
return await handleMediaUpload(mediaUpload);
|
||||
await handleMediaUpload(mediaUpload);
|
||||
} catch (e) {
|
||||
Log.error("Non recoverable error while sending media file: $e");
|
||||
await handleUploadError(mediaUpload);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (rerun) {
|
||||
handleNextMediaUploadSteps(mediaUploadId);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
|
|
@ -402,6 +400,8 @@ Future handleUploadStatusUpdate(TaskStatusUpdate update) async {
|
|||
bool failed = false;
|
||||
int mediaUploadId = int.parse(update.task.taskId.replaceAll("upload_", ""));
|
||||
|
||||
Log.info("Upload $mediaUploadId done.");
|
||||
|
||||
MediaUpload? media = await twonlyDB.mediaUploadsDao
|
||||
.getMediaUploadById(mediaUploadId)
|
||||
.getSingleOrNull();
|
||||
|
|
@ -478,11 +478,11 @@ Future handleUploadError(MediaUpload mediaUpload) async {
|
|||
await twonlyDB.mediaUploadsDao.deleteMediaUpload(mediaUpload.mediaUploadId);
|
||||
}
|
||||
|
||||
Future<bool> handleMediaUpload(MediaUpload media) async {
|
||||
Future handleMediaUpload(MediaUpload media) async {
|
||||
Uint8List bytesToUpload =
|
||||
await readSendMediaFile(media.mediaUploadId, "encrypted");
|
||||
|
||||
if (media.messageIds == null) return false;
|
||||
if (media.messageIds == null) return;
|
||||
|
||||
List<Uint8List> downloadTokens =
|
||||
createDownloadTokens(media.messageIds!.length);
|
||||
|
|
@ -571,7 +571,7 @@ Future<bool> handleMediaUpload(MediaUpload media) async {
|
|||
await FlutterSecureStorage().read(key: SecureStorageKeys.apiAuthToken);
|
||||
if (apiAuthToken == null) {
|
||||
Log.error("api auth token not defined.");
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
File uploadRequestFile = await writeSendMediaFile(
|
||||
|
|
@ -600,11 +600,17 @@ Future<bool> handleMediaUpload(MediaUpload media) async {
|
|||
|
||||
final result = await FileDownloader().enqueue(task);
|
||||
|
||||
return result;
|
||||
if (result) {
|
||||
await twonlyDB.mediaUploadsDao.updateMediaUpload(
|
||||
media.mediaUploadId,
|
||||
MediaUploadsCompanion(
|
||||
state: Value(UploadState.uploadTaskStarted),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
Log.error("Exception during upload: $e");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> compressVideoIfExists(int mediaUploadId) async {
|
||||
|
|
|
|||
|
|
@ -206,8 +206,9 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
avatarSvg: Value(content.avatarSvg),
|
||||
displayName: Value(content.displayName),
|
||||
);
|
||||
twonlyDB.contactsDao.updateContact(fromUserId, update);
|
||||
await twonlyDB.contactsDao.updateContact(fromUserId, update);
|
||||
}
|
||||
createPushAvatars();
|
||||
break;
|
||||
|
||||
case MessageKind.requestPushKey:
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ import 'package:firebase_messaging/firebase_messaging.dart';
|
|||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/constants/secure_storage_keys.dart';
|
||||
import 'package:twonly/src/database/twonly_database.dart';
|
||||
import 'package:twonly/src/services/notification.service.dart';
|
||||
import 'package:twonly/src/services/notification.background.service.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'dart:io' show Platform;
|
||||
import '../../firebase_options.dart';
|
||||
|
|
@ -79,9 +78,7 @@ Future initFCMService() async {
|
|||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
initLogger();
|
||||
Log.info('Handling a background message: ${message.messageId}');
|
||||
twonlyDB = TwonlyDatabase();
|
||||
await handleRemoteMessage(message);
|
||||
|
||||
// make sure every thing run...
|
||||
await Future.delayed(Duration(milliseconds: 2000));
|
||||
}
|
||||
|
|
|
|||
282
lib/src/services/notification.background.service.dart
Normal file
282
lib/src/services/notification.background.service.dart
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'package:cryptography_plus/cryptography_plus.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:twonly/src/services/notification.service.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
|
||||
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
Future customLocalPushNotification(String title, String msg) async {
|
||||
const AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails(
|
||||
'1',
|
||||
'System',
|
||||
channelDescription: 'System messages.',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
);
|
||||
|
||||
const DarwinNotificationDetails darwinNotificationDetails =
|
||||
DarwinNotificationDetails();
|
||||
const NotificationDetails notificationDetails = NotificationDetails(
|
||||
android: androidNotificationDetails, iOS: darwinNotificationDetails);
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
999999 + Random.secure().nextInt(9999),
|
||||
title,
|
||||
msg,
|
||||
notificationDetails,
|
||||
);
|
||||
}
|
||||
|
||||
Future handlePushData(String pushDataJson) async {
|
||||
try {
|
||||
String jsonString = utf8.decode(base64.decode(pushDataJson));
|
||||
final pushData = PushNotification.fromJson(jsonDecode(jsonString));
|
||||
|
||||
PushKind? pushKind;
|
||||
PushUser? pushUser;
|
||||
int? fromUserId;
|
||||
|
||||
if (pushData.keyId == 0) {
|
||||
List<int> key = "InsecureOnlyUsedForAddingContact".codeUnits;
|
||||
pushKind = await tryDecryptMessage(key, pushData);
|
||||
} else {
|
||||
var pushKeys = await getPushKeys("receivingPushKeys");
|
||||
for (final userId in pushKeys.keys) {
|
||||
for (final key in pushKeys[userId]!.keys) {
|
||||
if (key.id == pushData.keyId) {
|
||||
pushKind = await tryDecryptMessage(key.key, pushData);
|
||||
if (pushKind != null) {
|
||||
pushUser = pushKeys[userId]!;
|
||||
fromUserId = userId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// found correct key and user
|
||||
if (pushUser != null) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pushKind != null) {
|
||||
if (pushKind == PushKind.testNotification) {
|
||||
await customLocalPushNotification(
|
||||
"Test notification", "This is a test notification.");
|
||||
} else if (pushUser != null && fromUserId != null) {
|
||||
await showLocalPushNotification(pushUser, fromUserId, pushKind);
|
||||
} else {
|
||||
await showLocalPushNotificationWithoutUserId(pushKind);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Log.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<PushKind?> tryDecryptMessage(
|
||||
List<int> key, PushNotification noti) async {
|
||||
try {
|
||||
final chacha20 = Chacha20.poly1305Aead();
|
||||
SecretKeyData secretKeyData = SecretKeyData(key);
|
||||
|
||||
SecretBox secretBox = SecretBox(
|
||||
noti.cipherText,
|
||||
nonce: noti.nonce,
|
||||
mac: Mac(noti.mac),
|
||||
);
|
||||
|
||||
final plaintext =
|
||||
await chacha20.decrypt(secretBox, secretKey: secretKeyData);
|
||||
final plaintextString = utf8.decode(plaintext);
|
||||
return PushKindExtension.fromString(plaintextString);
|
||||
} catch (e) {
|
||||
// this error is allowed to happen...
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future showLocalPushNotification(
|
||||
PushUser pushUser,
|
||||
int fromUserId,
|
||||
PushKind pushKind,
|
||||
) async {
|
||||
String? title;
|
||||
String? body;
|
||||
|
||||
// do not show notification for blocked users...
|
||||
if (pushUser.blocked) {
|
||||
Log.info("Blocked a message from a blocked user!");
|
||||
return;
|
||||
}
|
||||
|
||||
title = pushUser.displayName;
|
||||
body = getPushNotificationText(pushKind);
|
||||
if (body == "") {
|
||||
Log.error("No push notification type defined!");
|
||||
}
|
||||
|
||||
FilePathAndroidBitmap? styleInformation;
|
||||
String? avatarPath = await getAvatarIcon(fromUserId);
|
||||
if (avatarPath != null) {
|
||||
styleInformation = FilePathAndroidBitmap(avatarPath);
|
||||
}
|
||||
|
||||
AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails('0', 'Messages',
|
||||
channelDescription: 'Messages from other users.',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
ticker: 'You got a new message.',
|
||||
largeIcon: styleInformation);
|
||||
|
||||
const DarwinNotificationDetails darwinNotificationDetails =
|
||||
DarwinNotificationDetails();
|
||||
NotificationDetails notificationDetails = NotificationDetails(
|
||||
android: androidNotificationDetails, iOS: darwinNotificationDetails);
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
fromUserId,
|
||||
title,
|
||||
body,
|
||||
notificationDetails,
|
||||
payload: pushKind.name,
|
||||
);
|
||||
}
|
||||
|
||||
Future showLocalPushNotificationWithoutUserId(
|
||||
PushKind pushKind,
|
||||
) async {
|
||||
String? title;
|
||||
String? body;
|
||||
|
||||
body = getPushNotificationTextWithoutUserId(pushKind);
|
||||
if (body == "") {
|
||||
Log.error("No push notification type defined!");
|
||||
}
|
||||
|
||||
AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails('0', 'Messages',
|
||||
channelDescription: 'Messages from other users.',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
ticker: 'You got a new message.');
|
||||
|
||||
const DarwinNotificationDetails darwinNotificationDetails =
|
||||
DarwinNotificationDetails();
|
||||
NotificationDetails notificationDetails = NotificationDetails(
|
||||
android: androidNotificationDetails, iOS: darwinNotificationDetails);
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
2,
|
||||
title,
|
||||
body,
|
||||
notificationDetails,
|
||||
payload: pushKind.name,
|
||||
);
|
||||
}
|
||||
|
||||
Future<String?> getAvatarIcon(int contactId) async {
|
||||
final directory = await getApplicationCacheDirectory();
|
||||
final avatarsDirectory = Directory('${directory.path}/avatars');
|
||||
final filePath = '${avatarsDirectory.path}/$contactId.png';
|
||||
final file = File(filePath);
|
||||
if (file.existsSync()) {
|
||||
return filePath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String getPushNotificationTextWithoutUserId(PushKind pushKind) {
|
||||
Map<String, String> pushNotificationText;
|
||||
|
||||
String systemLanguage = Platform.localeName;
|
||||
|
||||
if (systemLanguage.contains("de")) {
|
||||
pushNotificationText = {
|
||||
PushKind.text.name: "Du hast eine neue Nachricht erhalten.",
|
||||
PushKind.twonly.name: "Du hast ein neues twonly erhalten.",
|
||||
PushKind.video.name: "Du hast ein neues Video erhalten.",
|
||||
PushKind.image.name: "Du hast ein neues Bild erhalten.",
|
||||
PushKind.contactRequest.name:
|
||||
"Du hast eine neue Kontaktanfrage erhalten.",
|
||||
PushKind.acceptRequest.name: "Deine Kontaktanfrage wurde angenommen.",
|
||||
PushKind.storedMediaFile.name: "Dein Bild wurde gespeichert.",
|
||||
PushKind.reaction.name: "Du hast eine Reaktion auf dein Bild erhalten.",
|
||||
PushKind.reopenedMedia.name: "Dein Bild wurde erneut geöffnet.",
|
||||
PushKind.reactionToVideo.name:
|
||||
"Du hast eine Reaktion auf dein Video erhalten.",
|
||||
PushKind.reactionToText.name:
|
||||
"Du hast eine Reaktion auf deinen Text erhalten.",
|
||||
PushKind.reactionToImage.name:
|
||||
"Du hast eine Reaktion auf dein Bild erhalten.",
|
||||
PushKind.response.name: "Du hast eine Antwort erhalten.",
|
||||
};
|
||||
} else {
|
||||
pushNotificationText = {
|
||||
PushKind.text.name: "You have received a new message.",
|
||||
PushKind.twonly.name: "You have received a new twonly.",
|
||||
PushKind.video.name: "You have received a new video.",
|
||||
PushKind.image.name: "You have received a new image.",
|
||||
PushKind.contactRequest.name: "You have received a new contact request.",
|
||||
PushKind.acceptRequest.name: "Your contact request has been accepted.",
|
||||
PushKind.storedMediaFile.name: "Your image has been saved.",
|
||||
PushKind.reaction.name: "You have received a reaction to your image.",
|
||||
PushKind.reopenedMedia.name: "Your image has been reopened.",
|
||||
PushKind.reactionToVideo.name:
|
||||
"You have received a reaction to your video.",
|
||||
PushKind.reactionToText.name:
|
||||
"You have received a reaction to your text.",
|
||||
PushKind.reactionToImage.name:
|
||||
"You have received a reaction to your image.",
|
||||
PushKind.response.name: "You have received a response.",
|
||||
};
|
||||
}
|
||||
return pushNotificationText[pushKind.name] ?? "";
|
||||
}
|
||||
|
||||
String getPushNotificationText(PushKind pushKind) {
|
||||
String systemLanguage = Platform.localeName;
|
||||
|
||||
Map<String, String> pushNotificationText;
|
||||
|
||||
if (systemLanguage.contains("de")) {
|
||||
pushNotificationText = {
|
||||
PushKind.text.name: "hat dir eine Nachricht gesendet.",
|
||||
PushKind.twonly.name: "hat dir ein twonly gesendet.",
|
||||
PushKind.video.name: "hat dir ein Video gesendet.",
|
||||
PushKind.image.name: "hat dir ein Bild gesendet.",
|
||||
PushKind.contactRequest.name: "möchte sich mit dir vernetzen.",
|
||||
PushKind.acceptRequest.name: "ist jetzt mit dir vernetzt.",
|
||||
PushKind.storedMediaFile.name: "hat dein Bild gespeichert.",
|
||||
PushKind.reaction.name: "hat auf dein Bild reagiert.",
|
||||
PushKind.reopenedMedia.name: "hat dein Bild erneut geöffnet.",
|
||||
PushKind.reactionToVideo.name: "hat auf dein Video reagiert.",
|
||||
PushKind.reactionToText.name: "hat auf deinen Text reagiert.",
|
||||
PushKind.reactionToImage.name: "hat auf dein Bild reagiert.",
|
||||
PushKind.response.name: "hat dir geantwortet.",
|
||||
};
|
||||
} else {
|
||||
pushNotificationText = {
|
||||
PushKind.text.name: "has sent you a message.",
|
||||
PushKind.twonly.name: "has sent you a twonly.",
|
||||
PushKind.video.name: "has sent you a video.",
|
||||
PushKind.image.name: "has sent you an image.",
|
||||
PushKind.contactRequest.name: "wants to connect with you.",
|
||||
PushKind.acceptRequest.name: "is now connected with you.",
|
||||
PushKind.storedMediaFile.name: "has stored your image.",
|
||||
PushKind.reaction.name: "has reacted to your image.",
|
||||
PushKind.reopenedMedia.name: "has reopened your image.",
|
||||
PushKind.reactionToVideo.name: "has reacted to your video.",
|
||||
PushKind.reactionToText.name: "has reacted to your text.",
|
||||
PushKind.reactionToImage.name: "has reacted to your image.",
|
||||
PushKind.response.name: "has responded.",
|
||||
};
|
||||
}
|
||||
return pushNotificationText[pushKind.name] ?? "";
|
||||
}
|
||||
|
|
@ -290,72 +290,6 @@ Future<Uint8List?> getPushData(int toUserId, PushKind kind) async {
|
|||
return Utf8Encoder().convert(jsonEncode(res.toJson()));
|
||||
}
|
||||
|
||||
Future<PushKind?> tryDecryptMessage(
|
||||
List<int> key, PushNotification noti) async {
|
||||
try {
|
||||
final chacha20 = Chacha20.poly1305Aead();
|
||||
SecretKeyData secretKeyData = SecretKeyData(key);
|
||||
|
||||
SecretBox secretBox = SecretBox(
|
||||
noti.cipherText,
|
||||
nonce: noti.nonce,
|
||||
mac: Mac(noti.mac),
|
||||
);
|
||||
|
||||
final plaintext =
|
||||
await chacha20.decrypt(secretBox, secretKey: secretKeyData);
|
||||
final plaintextString = utf8.decode(plaintext);
|
||||
return PushKindExtension.fromString(plaintextString);
|
||||
} catch (e) {
|
||||
// this error is allowed to happen...
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future handlePushData(String pushDataJson) async {
|
||||
try {
|
||||
String jsonString = utf8.decode(base64.decode(pushDataJson));
|
||||
final pushData = PushNotification.fromJson(jsonDecode(jsonString));
|
||||
|
||||
PushKind? pushKind;
|
||||
int? fromUserId;
|
||||
|
||||
if (pushData.keyId == 0) {
|
||||
List<int> key = "InsecureOnlyUsedForAddingContact".codeUnits;
|
||||
pushKind = await tryDecryptMessage(key, pushData);
|
||||
} else {
|
||||
var pushKeys = await getPushKeys("receivingPushKeys");
|
||||
for (final userId in pushKeys.keys) {
|
||||
for (final key in pushKeys[userId]!.keys) {
|
||||
if (key.id == pushData.keyId) {
|
||||
pushKind = await tryDecryptMessage(key.key, pushData);
|
||||
if (pushKind != null) {
|
||||
fromUserId = userId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// found correct key and user
|
||||
if (fromUserId != null) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pushKind != null) {
|
||||
if (pushKind == PushKind.testNotification) {
|
||||
await customLocalPushNotification(
|
||||
"Test notification", "This is a test notification.");
|
||||
} else if (fromUserId != null) {
|
||||
await showLocalPushNotification(fromUserId, pushKind);
|
||||
} else {
|
||||
await showLocalPushNotificationWithoutUserId(pushKind);
|
||||
await setupNotificationWithUsers();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Log.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<int, PushUser>> getPushKeys(String storageKey) async {
|
||||
var storage = FlutterSecureStorage();
|
||||
String? pushKeysJson = await storage.read(
|
||||
|
|
@ -455,229 +389,34 @@ Future<void> setupPushNotification() async {
|
|||
);
|
||||
}
|
||||
|
||||
Future showLocalPushNotification(
|
||||
int fromUserId,
|
||||
PushKind pushKind,
|
||||
) async {
|
||||
String? title;
|
||||
String? body;
|
||||
|
||||
Contact? user = await twonlyDB.contactsDao
|
||||
.getContactByUserId(fromUserId)
|
||||
.getSingleOrNull();
|
||||
|
||||
if (user == null) return;
|
||||
|
||||
// do not show notification for blocked users...
|
||||
if (user.blocked) {
|
||||
Log.info("Blocked a message from a blocked user!");
|
||||
return;
|
||||
Future createPushAvatars() async {
|
||||
if (!Platform.isAndroid) {
|
||||
return; // avatars currently only shown in Android...
|
||||
}
|
||||
final contacts = await twonlyDB.contactsDao.getAllNotBlockedContacts();
|
||||
|
||||
title = getContactDisplayName(user);
|
||||
body = getPushNotificationText(pushKind);
|
||||
if (body == "") {
|
||||
Log.error("No push notification type defined!");
|
||||
for (final contact in contacts) {
|
||||
if (contact.avatarSvg == null) return null;
|
||||
|
||||
final PictureInfo pictureInfo =
|
||||
await vg.loadPicture(SvgStringLoader(contact.avatarSvg!), null);
|
||||
|
||||
final ui.Image image = await pictureInfo.picture.toImage(300, 300);
|
||||
|
||||
final ByteData? byteData =
|
||||
await image.toByteData(format: ui.ImageByteFormat.png);
|
||||
final Uint8List pngBytes = byteData!.buffer.asUint8List();
|
||||
|
||||
// Get the directory to save the image
|
||||
final directory = await getApplicationCacheDirectory();
|
||||
final avatarsDirectory = Directory('${directory.path}/avatars');
|
||||
|
||||
// Create the avatars directory if it does not exist
|
||||
if (!await avatarsDirectory.exists()) {
|
||||
await avatarsDirectory.create(recursive: true);
|
||||
}
|
||||
final filePath = '${avatarsDirectory.path}/${contact.userId}.png';
|
||||
await File(filePath).writeAsBytes(pngBytes);
|
||||
pictureInfo.picture.dispose();
|
||||
}
|
||||
|
||||
FilePathAndroidBitmap? styleInformation;
|
||||
String? avatarPath = await getAvatarIcon(user);
|
||||
if (avatarPath != null) {
|
||||
styleInformation = FilePathAndroidBitmap(avatarPath);
|
||||
}
|
||||
|
||||
AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails('0', 'Messages',
|
||||
channelDescription: 'Messages from other users.',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
ticker: 'You got a new message.',
|
||||
largeIcon: styleInformation);
|
||||
|
||||
const DarwinNotificationDetails darwinNotificationDetails =
|
||||
DarwinNotificationDetails();
|
||||
NotificationDetails notificationDetails = NotificationDetails(
|
||||
android: androidNotificationDetails, iOS: darwinNotificationDetails);
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
fromUserId,
|
||||
title,
|
||||
body,
|
||||
notificationDetails,
|
||||
payload: pushKind.name,
|
||||
);
|
||||
}
|
||||
|
||||
Future showLocalPushNotificationWithoutUserId(
|
||||
PushKind pushKind,
|
||||
) async {
|
||||
String? title;
|
||||
String? body;
|
||||
|
||||
body = getPushNotificationTextWithoutUserId(pushKind);
|
||||
if (body == "") {
|
||||
Log.error("No push notification type defined!");
|
||||
}
|
||||
|
||||
AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails('0', 'Messages',
|
||||
channelDescription: 'Messages from other users.',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
ticker: 'You got a new message.');
|
||||
|
||||
const DarwinNotificationDetails darwinNotificationDetails =
|
||||
DarwinNotificationDetails();
|
||||
NotificationDetails notificationDetails = NotificationDetails(
|
||||
android: androidNotificationDetails, iOS: darwinNotificationDetails);
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
2,
|
||||
title,
|
||||
body,
|
||||
notificationDetails,
|
||||
payload: pushKind.name,
|
||||
);
|
||||
}
|
||||
|
||||
Future customLocalPushNotification(String title, String msg) async {
|
||||
const AndroidNotificationDetails androidNotificationDetails =
|
||||
AndroidNotificationDetails(
|
||||
'1',
|
||||
'System',
|
||||
channelDescription: 'System messages.',
|
||||
importance: Importance.max,
|
||||
priority: Priority.max,
|
||||
);
|
||||
|
||||
const DarwinNotificationDetails darwinNotificationDetails =
|
||||
DarwinNotificationDetails();
|
||||
const NotificationDetails notificationDetails = NotificationDetails(
|
||||
android: androidNotificationDetails, iOS: darwinNotificationDetails);
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
999999 + Random.secure().nextInt(9999),
|
||||
title,
|
||||
msg,
|
||||
notificationDetails,
|
||||
);
|
||||
}
|
||||
|
||||
String getPushNotificationTextWithoutUserId(PushKind pushKind) {
|
||||
Map<String, String> pushNotificationText;
|
||||
|
||||
String systemLanguage = Platform.localeName;
|
||||
|
||||
if (systemLanguage.contains("de")) {
|
||||
pushNotificationText = {
|
||||
PushKind.text.name: "Du hast eine neue Nachricht erhalten.",
|
||||
PushKind.twonly.name: "Du hast ein neues twonly erhalten.",
|
||||
PushKind.video.name: "Du hast ein neues Video erhalten.",
|
||||
PushKind.image.name: "Du hast ein neues Bild erhalten.",
|
||||
PushKind.contactRequest.name:
|
||||
"Du hast eine neue Kontaktanfrage erhalten.",
|
||||
PushKind.acceptRequest.name: "Deine Kontaktanfrage wurde angenommen.",
|
||||
PushKind.storedMediaFile.name: "Dein Bild wurde gespeichert.",
|
||||
PushKind.reaction.name: "Du hast eine Reaktion auf dein Bild erhalten.",
|
||||
PushKind.reopenedMedia.name: "Dein Bild wurde erneut geöffnet.",
|
||||
PushKind.reactionToVideo.name:
|
||||
"Du hast eine Reaktion auf dein Video erhalten.",
|
||||
PushKind.reactionToText.name:
|
||||
"Du hast eine Reaktion auf deinen Text erhalten.",
|
||||
PushKind.reactionToImage.name:
|
||||
"Du hast eine Reaktion auf dein Bild erhalten.",
|
||||
PushKind.response.name: "Du hast eine Antwort erhalten.",
|
||||
};
|
||||
} else {
|
||||
pushNotificationText = {
|
||||
PushKind.text.name: "You have received a new message.",
|
||||
PushKind.twonly.name: "You have received a new twonly.",
|
||||
PushKind.video.name: "You have received a new video.",
|
||||
PushKind.image.name: "You have received a new image.",
|
||||
PushKind.contactRequest.name: "You have received a new contact request.",
|
||||
PushKind.acceptRequest.name: "Your contact request has been accepted.",
|
||||
PushKind.storedMediaFile.name: "Your image has been saved.",
|
||||
PushKind.reaction.name: "You have received a reaction to your image.",
|
||||
PushKind.reopenedMedia.name: "Your image has been reopened.",
|
||||
PushKind.reactionToVideo.name:
|
||||
"You have received a reaction to your video.",
|
||||
PushKind.reactionToText.name:
|
||||
"You have received a reaction to your text.",
|
||||
PushKind.reactionToImage.name:
|
||||
"You have received a reaction to your image.",
|
||||
PushKind.response.name: "You have received a response.",
|
||||
};
|
||||
}
|
||||
return pushNotificationText[pushKind.name] ?? "";
|
||||
}
|
||||
|
||||
String getPushNotificationText(PushKind pushKind) {
|
||||
String systemLanguage = Platform.localeName;
|
||||
|
||||
Map<String, String> pushNotificationText;
|
||||
|
||||
if (systemLanguage.contains("de")) {
|
||||
pushNotificationText = {
|
||||
PushKind.text.name: "hat dir eine Nachricht gesendet.",
|
||||
PushKind.twonly.name: "hat dir ein twonly gesendet.",
|
||||
PushKind.video.name: "hat dir ein Video gesendet.",
|
||||
PushKind.image.name: "hat dir ein Bild gesendet.",
|
||||
PushKind.contactRequest.name: "möchte sich mit dir vernetzen.",
|
||||
PushKind.acceptRequest.name: "ist jetzt mit dir vernetzt.",
|
||||
PushKind.storedMediaFile.name: "hat dein Bild gespeichert.",
|
||||
PushKind.reaction.name: "hat auf dein Bild reagiert.",
|
||||
PushKind.reopenedMedia.name: "hat dein Bild erneut geöffnet.",
|
||||
PushKind.reactionToVideo.name: "hat auf dein Video reagiert.",
|
||||
PushKind.reactionToText.name: "hat auf deinen Text reagiert.",
|
||||
PushKind.reactionToImage.name: "hat auf dein Bild reagiert.",
|
||||
PushKind.response.name: "hat dir geantwortet.",
|
||||
};
|
||||
} else {
|
||||
pushNotificationText = {
|
||||
PushKind.text.name: "has sent you a message.",
|
||||
PushKind.twonly.name: "has sent you a twonly.",
|
||||
PushKind.video.name: "has sent you a video.",
|
||||
PushKind.image.name: "has sent you an image.",
|
||||
PushKind.contactRequest.name: "wants to connect with you.",
|
||||
PushKind.acceptRequest.name: "is now connected with you.",
|
||||
PushKind.storedMediaFile.name: "has stored your image.",
|
||||
PushKind.reaction.name: "has reacted to your image.",
|
||||
PushKind.reopenedMedia.name: "has reopened your image.",
|
||||
PushKind.reactionToVideo.name: "has reacted to your video.",
|
||||
PushKind.reactionToText.name: "has reacted to your text.",
|
||||
PushKind.reactionToImage.name: "has reacted to your image.",
|
||||
PushKind.response.name: "has responded.",
|
||||
};
|
||||
}
|
||||
return pushNotificationText[pushKind.name] ?? "";
|
||||
}
|
||||
|
||||
Future<String?> getAvatarIcon(Contact user) async {
|
||||
if (user.avatarSvg == null) return null;
|
||||
|
||||
final PictureInfo pictureInfo =
|
||||
await vg.loadPicture(SvgStringLoader(user.avatarSvg!), null);
|
||||
|
||||
final ui.Image image = await pictureInfo.picture.toImage(300, 300);
|
||||
|
||||
final ByteData? byteData =
|
||||
await image.toByteData(format: ui.ImageByteFormat.png);
|
||||
final Uint8List pngBytes = byteData!.buffer.asUint8List();
|
||||
|
||||
// Get the directory to save the image
|
||||
final directory = await getApplicationCacheDirectory();
|
||||
final avatarsDirectory = Directory('${directory.path}/avatars');
|
||||
|
||||
// Create the avatars directory if it does not exist
|
||||
if (!await avatarsDirectory.exists()) {
|
||||
await avatarsDirectory.create(recursive: true);
|
||||
}
|
||||
|
||||
final filePath = '${avatarsDirectory.path}/${user.userId}.png';
|
||||
final file = File(filePath);
|
||||
await file.writeAsBytes(pngBytes);
|
||||
|
||||
pictureInfo.picture.dispose();
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ Future performTwonlySafeBackup({bool force = false}) async {
|
|||
final user = await getUser();
|
||||
|
||||
if (user == null || user.twonlySafeBackup == null || user.isDemoUser) {
|
||||
Log.warn("perform twonly safe backup was called while it is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue