mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 14:48:41 +00:00
fix #65
This commit is contained in:
parent
98b4c60e21
commit
586c4aa16a
14 changed files with 129 additions and 22 deletions
|
|
@ -32,7 +32,7 @@ class NotificationService: UNNotificationServiceExtension {
|
|||
bestAttemptContent.body = data!.body;
|
||||
bestAttemptContent.threadIdentifier = String(format: "%d", data!.notificationId)
|
||||
} else {
|
||||
bestAttemptContent.title = "\(bestAttemptContent.title) [failed to decrypt]"
|
||||
bestAttemptContent.title = "\(bestAttemptContent.title) [10]"
|
||||
}
|
||||
|
||||
contentHandler(bestAttemptContent)
|
||||
|
|
@ -60,6 +60,7 @@ enum PushKind: String, Codable {
|
|||
case storedMediaFile
|
||||
case reaction
|
||||
case testNotification
|
||||
case reopenedMedia
|
||||
}
|
||||
|
||||
import CryptoKit
|
||||
|
|
@ -106,8 +107,6 @@ func getPushNotificationData(pushDataJson: String) -> (title: String, body: Stri
|
|||
// Handle the push notification based on the pushKind
|
||||
if let pushKind = pushKind {
|
||||
|
||||
let bestAttemptContent = UNMutableNotificationContent()
|
||||
|
||||
if pushKind == .testNotification {
|
||||
return ("Test Notification", "This is a test notification.", 0)
|
||||
} else if displayName != nil && fromUserId != nil {
|
||||
|
|
@ -180,6 +179,8 @@ func determinePushKind(from message: String) -> PushKind? {
|
|||
return .reaction
|
||||
} else if message.contains("testNotification") {
|
||||
return .testNotification
|
||||
} else if message.contains("reopenedMedia") {
|
||||
return .reopenedMedia
|
||||
} else {
|
||||
return nil // Unknown PushKind
|
||||
}
|
||||
|
|
@ -319,7 +320,8 @@ func getPushNotificationText(pushKind: PushKind) -> String {
|
|||
.contactRequest: "möchte sich mit dir vernetzen.",
|
||||
.acceptRequest: "ist jetzt mit dir vernetzt.",
|
||||
.storedMediaFile: "hat dein Bild gespeichert.",
|
||||
.reaction: "hat auf dein Bild reagiert."
|
||||
.reaction: "hat auf dein Bild reagiert.",
|
||||
.reopenedMedia: "Dein Bild wurde erneut geöffnet."
|
||||
]
|
||||
} else { // Default to English
|
||||
pushNotificationText = [
|
||||
|
|
@ -330,7 +332,8 @@ func getPushNotificationText(pushKind: PushKind) -> String {
|
|||
.contactRequest: "wants to connect with you.",
|
||||
.acceptRequest: "is now connected with you.",
|
||||
.storedMediaFile: "has stored your image.",
|
||||
.reaction: "has reacted to your image."
|
||||
.reaction: "has reacted to your image.",
|
||||
.reopenedMedia: "Your image was reopened."
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -353,7 +356,8 @@ func getPushNotificationTextWithoutUserId(pushKind: PushKind) -> String {
|
|||
.contactRequest: "Du hast eine Kontaktanfrage erhalten.",
|
||||
.acceptRequest: "Deine Kontaktanfrage wurde angenommen.",
|
||||
.storedMediaFile: "Dein Bild wurde gespeichert.",
|
||||
.reaction: "Du hast eine Reaktion auf dein Bild erhalten."
|
||||
.reaction: "Du hast eine Reaktion auf dein Bild erhalten.",
|
||||
.reopenedMedia: "hat dein Bild erneut geöffnet."
|
||||
]
|
||||
} else { // Default to English
|
||||
pushNotificationText = [
|
||||
|
|
@ -364,7 +368,8 @@ func getPushNotificationTextWithoutUserId(pushKind: PushKind) -> String {
|
|||
.contactRequest: "You got a contact request.",
|
||||
.acceptRequest: "Your contact request has been accepted.",
|
||||
.storedMediaFile: "Your image has been saved.",
|
||||
.reaction: "You got a reaction to your image."
|
||||
.reaction: "You got a reaction to your image.",
|
||||
.reopenedMedia: "has reopened your image."
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import 'package:twonly/src/database/tables/contacts_table.dart';
|
|||
enum MessageKind {
|
||||
textMessage,
|
||||
storedMediaFile,
|
||||
reopenedMedia,
|
||||
media,
|
||||
contactRequest,
|
||||
profileChange,
|
||||
|
|
|
|||
|
|
@ -80,7 +80,9 @@
|
|||
"messageSendState_Sending": "Wird gesendet",
|
||||
"messageSendState_TapToLoad": "Tippe zum Laden",
|
||||
"messageSendState_Loading": "Herunterladen",
|
||||
"messageStoredInGalery": "In Gallerie gespeichert",
|
||||
"messageStoredInGalery": "Gespeichert",
|
||||
"messageReopened": "Erneut geöffnet",
|
||||
"@messageReopened": {},
|
||||
"imageEditorDrawOk": "Zeichnung machen",
|
||||
"settingsTitle": "Einstellungen",
|
||||
"settingsChats": "Chats",
|
||||
|
|
|
|||
|
|
@ -136,6 +136,8 @@
|
|||
"@messageSendState_Loading": {},
|
||||
"messageStoredInGalery": "Stored in gallery",
|
||||
"@messageStoredInGalery": {},
|
||||
"messageReopened": "Re-opened",
|
||||
"@messageReopened": {},
|
||||
"imageEditorDrawOk": "Take drawing",
|
||||
"@imageEditorDrawOk": {},
|
||||
"settingsTitle": "Settings",
|
||||
|
|
|
|||
|
|
@ -491,6 +491,12 @@ abstract class AppLocalizations {
|
|||
/// **'Stored in gallery'**
|
||||
String get messageStoredInGalery;
|
||||
|
||||
/// No description provided for @messageReopened.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Re-opened'**
|
||||
String get messageReopened;
|
||||
|
||||
/// No description provided for @imageEditorDrawOk.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
|
|||
|
|
@ -206,7 +206,10 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
String get messageSendState_Loading => 'Herunterladen';
|
||||
|
||||
@override
|
||||
String get messageStoredInGalery => 'In Gallerie gespeichert';
|
||||
String get messageStoredInGalery => 'Gespeichert';
|
||||
|
||||
@override
|
||||
String get messageReopened => 'Erneut geöffnet';
|
||||
|
||||
@override
|
||||
String get imageEditorDrawOk => 'Zeichnung machen';
|
||||
|
|
|
|||
|
|
@ -208,6 +208,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
@override
|
||||
String get messageStoredInGalery => 'Stored in gallery';
|
||||
|
||||
@override
|
||||
String get messageReopened => 'Re-opened';
|
||||
|
||||
@override
|
||||
String get imageEditorDrawOk => 'Take drawing';
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Color getMessageColorFromType(MessageContent content, BuildContext context) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
return Colors.black;
|
||||
return (isDarkMode(context)) ? Colors.white : Colors.black;
|
||||
}
|
||||
}
|
||||
return color;
|
||||
|
|
@ -85,6 +85,8 @@ class MessageContent {
|
|||
return StoredMediaFileContent.fromJson(json);
|
||||
case MessageKind.pushKey:
|
||||
return PushKeyContent.fromJson(json);
|
||||
case MessageKind.reopenedMedia:
|
||||
return ReopenedMediaFileContent.fromJson(json);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
@ -188,6 +190,20 @@ class StoredMediaFileContent extends MessageContent {
|
|||
}
|
||||
}
|
||||
|
||||
class ReopenedMediaFileContent extends MessageContent {
|
||||
int messageId;
|
||||
ReopenedMediaFileContent({required this.messageId});
|
||||
|
||||
static ReopenedMediaFileContent fromJson(Map json) {
|
||||
return ReopenedMediaFileContent(messageId: json['messageId']);
|
||||
}
|
||||
|
||||
@override
|
||||
Map toJson() {
|
||||
return {'messageId': messageId};
|
||||
}
|
||||
}
|
||||
|
||||
class ProfileContent extends MessageContent {
|
||||
String avatarSvg;
|
||||
String displayName;
|
||||
|
|
|
|||
|
|
@ -274,6 +274,12 @@ Future<Uint8List?> readMediaFile(int mediaId, String type) async {
|
|||
return await file.readAsBytes();
|
||||
}
|
||||
|
||||
Future<bool> existsMediaFile(int mediaId, String type) async {
|
||||
String basePath = await getMediaFilePath(mediaId, "received");
|
||||
File file = File("$basePath.$type");
|
||||
return await file.exists();
|
||||
}
|
||||
|
||||
Future<void> writeMediaFile(int mediaId, String type, Uint8List data) async {
|
||||
String basePath = await getMediaFilePath(mediaId, "received");
|
||||
File file = File("$basePath.$type");
|
||||
|
|
|
|||
|
|
@ -130,7 +130,8 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
default:
|
||||
if (message.kind != MessageKind.textMessage &&
|
||||
message.kind != MessageKind.media &&
|
||||
message.kind != MessageKind.storedMediaFile) {
|
||||
message.kind != MessageKind.storedMediaFile &&
|
||||
message.kind != MessageKind.reopenedMedia) {
|
||||
Logger("handleServerMessages")
|
||||
.shout("Got unknown MessageKind $message");
|
||||
} else if (message.content == null || message.messageId == null) {
|
||||
|
|
@ -147,7 +148,8 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
bool acknowledgeByUser = false;
|
||||
DateTime? openedAt;
|
||||
|
||||
if (message.kind == MessageKind.storedMediaFile) {
|
||||
if (message.kind == MessageKind.storedMediaFile ||
|
||||
message.kind == MessageKind.reopenedMedia) {
|
||||
acknowledgeByUser = true;
|
||||
openedAt = DateTime.now();
|
||||
}
|
||||
|
|
@ -159,6 +161,9 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
if (content is TextMessageContent) {
|
||||
responseToMessageId = content.responseToMessageId;
|
||||
}
|
||||
if (content is ReopenedMediaFileContent) {
|
||||
responseToMessageId = content.messageId;
|
||||
}
|
||||
if (content is StoredMediaFileContent) {
|
||||
responseToMessageId = content.messageId;
|
||||
await twonlyDatabase.messagesDao.updateMessageByOtherUser(
|
||||
|
|
|
|||
|
|
@ -163,7 +163,8 @@ enum PushKind {
|
|||
contactRequest,
|
||||
acceptRequest,
|
||||
storedMediaFile,
|
||||
testNotification
|
||||
testNotification,
|
||||
reopenedMedia
|
||||
}
|
||||
|
||||
extension PushKindExtension on PushKind {
|
||||
|
|
@ -532,7 +533,8 @@ String getPushNotificationTextWithoutUserId(PushKind pushKind) {
|
|||
PushKind.contactRequest.name: "Du hast eine 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.reaction.name: "Du hast eine Reaktion auf dein Bild erhalten.",
|
||||
PushKind.reopenedMedia.name: "Dein Bild wurde erneut geöffnet."
|
||||
};
|
||||
} else {
|
||||
pushNotificationText = {
|
||||
|
|
@ -543,7 +545,8 @@ String getPushNotificationTextWithoutUserId(PushKind pushKind) {
|
|||
PushKind.contactRequest.name: "You got a contact request.",
|
||||
PushKind.acceptRequest.name: "Your contact request has been accepted.",
|
||||
PushKind.storedMediaFile.name: "Your image has been saved.",
|
||||
PushKind.reaction.name: "You got a reaction to your image."
|
||||
PushKind.reaction.name: "You got a reaction to your image.",
|
||||
PushKind.reopenedMedia.name: "Your image was reopened."
|
||||
};
|
||||
}
|
||||
return pushNotificationText[pushKind.name] ?? "";
|
||||
|
|
@ -563,7 +566,8 @@ String getPushNotificationText(PushKind pushKind) {
|
|||
PushKind.contactRequest.name: "möchte sich mir 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.reaction.name: "hat auf dein Bild reagiert.",
|
||||
PushKind.reopenedMedia.name: "hat dein Bild erneut geöffnet."
|
||||
};
|
||||
} else {
|
||||
pushNotificationText = {
|
||||
|
|
@ -574,7 +578,8 @@ String getPushNotificationText(PushKind pushKind) {
|
|||
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.reaction.name: "has reacted to your image.",
|
||||
PushKind.reopenedMedia.name: "has reopened your image."
|
||||
};
|
||||
}
|
||||
return pushNotificationText[pushKind.name] ?? "";
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:drift/drift.dart' show Value;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
|
|
@ -118,11 +119,35 @@ class ChatListEntry extends StatelessWidget {
|
|||
Widget getReactionRow() {
|
||||
List<Widget> children = [];
|
||||
bool hasOneTextReaction = false;
|
||||
bool hasOneStored = false;
|
||||
bool hasOneReopened = false;
|
||||
for (final reaction in reactions) {
|
||||
MessageContent? content = MessageContent.fromJson(
|
||||
reaction.kind, jsonDecode(reaction.contentJson!));
|
||||
|
||||
if (content is StoredMediaFileContent || message.mediaStored) {
|
||||
// if (content is StoredMediaFileContent || message.mediaStored) {
|
||||
// if (hasOneStored) continue;
|
||||
// hasOneStored = true;
|
||||
// children.add(
|
||||
// Expanded(
|
||||
// child: Align(
|
||||
// alignment: Alignment.bottomRight,
|
||||
// child: Padding(
|
||||
// padding: EdgeInsets.only(right: 3),
|
||||
// child: FaIcon(
|
||||
// FontAwesomeIcons.floppyDisk,
|
||||
// size: 12,
|
||||
// color: Colors.blue,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
if (content is ReopenedMediaFileContent) {
|
||||
if (hasOneReopened) continue;
|
||||
hasOneReopened = true;
|
||||
children.add(
|
||||
Expanded(
|
||||
child: Align(
|
||||
|
|
@ -130,16 +155,15 @@ class ChatListEntry extends StatelessWidget {
|
|||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 3),
|
||||
child: FaIcon(
|
||||
FontAwesomeIcons.floppyDisk,
|
||||
FontAwesomeIcons.repeat,
|
||||
size: 12,
|
||||
color: Colors.blue,
|
||||
color: Colors.yellow,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// only show one reaction
|
||||
if (hasOneTextReaction) continue;
|
||||
|
||||
|
|
@ -282,6 +306,30 @@ class ChatListEntry extends StatelessWidget {
|
|||
);
|
||||
|
||||
child = GestureDetector(
|
||||
onDoubleTap: () async {
|
||||
if (message.openedAt == null && message.messageOtherId != null) {
|
||||
return;
|
||||
}
|
||||
if (await existsMediaFile(message.messageId, "png")) {
|
||||
encryptAndSendMessage(
|
||||
null,
|
||||
contact.userId,
|
||||
MessageJson(
|
||||
kind: MessageKind.reopenedMedia,
|
||||
messageId: message.messageId,
|
||||
content: ReopenedMediaFileContent(
|
||||
messageId: message.messageOtherId!,
|
||||
),
|
||||
timestamp: DateTime.now(),
|
||||
),
|
||||
pushKind: PushKind.reopenedMedia,
|
||||
);
|
||||
await twonlyDatabase.messagesDao.updateMessageByMessageId(
|
||||
message.messageId,
|
||||
MessagesCompanion(openedAt: Value(null)),
|
||||
);
|
||||
}
|
||||
},
|
||||
onTap: () {
|
||||
if (message.kind == MessageKind.media) {
|
||||
if (message.downloadState == DownloadState.downloaded &&
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
progressTimer?.cancel();
|
||||
if (allMediaFiles.isNotEmpty) {
|
||||
try {
|
||||
if (!imageSaved) {
|
||||
if (!imageSaved && maxShowTime != gMediaShowInfinite) {
|
||||
await deleteMediaFile(allMediaFiles.first.messageId, "mp4");
|
||||
await deleteMediaFile(allMediaFiles.first.messageId, "png");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,6 +144,11 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
|||
text = context.lang.messageStoredInGalery;
|
||||
}
|
||||
|
||||
if (message.kind == MessageKind.reopenedMedia) {
|
||||
icon = FaIcon(FontAwesomeIcons.repeat, size: 12, color: color);
|
||||
text = context.lang.messageReopened;
|
||||
}
|
||||
|
||||
if (message.errorWhileSending) {
|
||||
icon =
|
||||
FaIcon(FontAwesomeIcons.circleExclamation, size: 12, color: color);
|
||||
|
|
|
|||
Loading…
Reference in a new issue