2020-01-19 15:07:42 +01:00
|
|
|
import 'package:famedlysdk/famedlysdk.dart';
|
2020-01-20 13:46:39 +01:00
|
|
|
import 'package:fluffychat/i18n/i18n.dart';
|
2020-01-19 15:07:42 +01:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'room_state_enums_extensions.dart';
|
|
|
|
|
|
|
|
extension LocalizedBody on Event {
|
|
|
|
static Set<MessageTypes> textOnlyMessageTypes = {
|
|
|
|
MessageTypes.Text,
|
|
|
|
MessageTypes.Reply,
|
|
|
|
MessageTypes.Notice,
|
|
|
|
MessageTypes.Emote,
|
|
|
|
MessageTypes.None,
|
|
|
|
};
|
|
|
|
|
2020-02-09 16:26:24 +01:00
|
|
|
String getLocalizedBody(BuildContext context,
|
2020-02-20 20:45:38 +01:00
|
|
|
{bool withSenderNamePrefix = false, bool hideReply = false}) {
|
2020-01-19 15:07:42 +01:00
|
|
|
if (this.redacted) {
|
2020-01-20 13:46:39 +01:00
|
|
|
return I18n.of(context)
|
|
|
|
.removedBy(redactedBecause.sender.calcDisplayname());
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|
|
|
|
String localizedBody = body;
|
|
|
|
final String senderName = this.sender.calcDisplayname();
|
|
|
|
switch (this.type) {
|
|
|
|
case EventTypes.Sticker:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).sentASticker(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.Redaction:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).redactedAnEvent(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.RoomAliases:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).changedTheRoomAliases(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.RoomCanonicalAlias:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody =
|
|
|
|
I18n.of(context).changedTheRoomInvitationLink(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.RoomCreate:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).createdTheChat(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.RoomJoinRules:
|
|
|
|
JoinRules joinRules = JoinRules.values.firstWhere(
|
|
|
|
(r) =>
|
|
|
|
r.toString().replaceAll("JoinRules.", "") ==
|
|
|
|
content["join_rule"],
|
|
|
|
orElse: () => null);
|
|
|
|
if (joinRules == null) {
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).changedTheJoinRules(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
} else {
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).changedTheJoinRulesTo(
|
|
|
|
senderName, joinRules.getLocalizedString(context));
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EventTypes.RoomMember:
|
|
|
|
String text = "Failed to parse member event";
|
|
|
|
final String targetName = this.stateKeyUser.calcDisplayname();
|
|
|
|
// Has the membership changed?
|
|
|
|
final String newMembership = this.content["membership"] ?? "";
|
|
|
|
final String oldMembership =
|
|
|
|
this.unsigned["prev_content"] is Map<String, dynamic>
|
|
|
|
? this.unsigned["prev_content"]["membership"] ?? ""
|
|
|
|
: "";
|
|
|
|
if (newMembership != oldMembership) {
|
|
|
|
if (oldMembership == "invite" && newMembership == "join") {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).acceptedTheInvitation(targetName);
|
2020-01-19 17:12:03 +01:00
|
|
|
} else if (oldMembership == "invite" && newMembership == "leave") {
|
|
|
|
if (this.stateKey == this.senderId) {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).rejectedTheInvitation(targetName);
|
2020-01-19 17:12:03 +01:00
|
|
|
} else {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context)
|
|
|
|
.hasWithdrawnTheInvitationFor(senderName, targetName);
|
2020-01-19 17:12:03 +01:00
|
|
|
}
|
2020-01-19 15:07:42 +01:00
|
|
|
} else if (oldMembership == "leave" && newMembership == "join") {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).joinedTheChat(targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
} else if (oldMembership == "join" && newMembership == "ban") {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).kickedAndBanned(senderName, targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
} else if (oldMembership == "join" &&
|
|
|
|
newMembership == "leave" &&
|
|
|
|
this.stateKey != this.senderId) {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).kicked(senderName, targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
} else if (oldMembership == "join" &&
|
|
|
|
newMembership == "leave" &&
|
|
|
|
this.stateKey == this.senderId) {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).userLeftTheChat(targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
} else if (oldMembership == "invite" && newMembership == "ban") {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).bannedUser(senderName, targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
} else if (oldMembership == "leave" && newMembership == "ban") {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).bannedUser(senderName, targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
} else if (oldMembership == "ban" && newMembership == "leave") {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).unbannedUser(senderName, targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
} else if (newMembership == "invite") {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).invitedUser(senderName, targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
} else if (newMembership == "join") {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).joinedTheChat(targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|
|
|
|
} else if (newMembership == "join") {
|
|
|
|
final String newAvatar = this.content["avatar_url"] ?? "";
|
|
|
|
final String oldAvatar =
|
|
|
|
this.unsigned["prev_content"] is Map<String, dynamic>
|
|
|
|
? this.unsigned["prev_content"]["avatar_url"] ?? ""
|
|
|
|
: "";
|
|
|
|
|
|
|
|
final String newDisplayname = this.content["displayname"] ?? "";
|
|
|
|
final String oldDisplayname =
|
|
|
|
this.unsigned["prev_content"] is Map<String, dynamic>
|
|
|
|
? this.unsigned["prev_content"]["displayname"] ?? ""
|
|
|
|
: "";
|
|
|
|
|
|
|
|
// Has the user avatar changed?
|
|
|
|
if (newAvatar != oldAvatar) {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context).changedTheProfileAvatar(targetName);
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|
|
|
|
// Has the user avatar changed?
|
|
|
|
else if (newDisplayname != oldDisplayname) {
|
2020-01-20 13:46:39 +01:00
|
|
|
text = I18n.of(context)
|
|
|
|
.changedTheDisplaynameTo(targetName, newDisplayname);
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
localizedBody = text;
|
|
|
|
break;
|
|
|
|
case EventTypes.RoomPowerLevels:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).changedTheChatPermissions(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.RoomName:
|
|
|
|
localizedBody =
|
2020-01-20 13:46:39 +01:00
|
|
|
I18n.of(context).changedTheChatNameTo(senderName, content["name"]);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.RoomTopic:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context)
|
|
|
|
.changedTheChatDescriptionTo(senderName, content["topic"]);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.RoomAvatar:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).changedTheChatAvatar(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.GuestAccess:
|
|
|
|
GuestAccess guestAccess = GuestAccess.values.firstWhere(
|
|
|
|
(r) =>
|
|
|
|
r.toString().replaceAll("GuestAccess.", "") ==
|
|
|
|
content["guest_access"],
|
|
|
|
orElse: () => null);
|
|
|
|
if (guestAccess == null) {
|
|
|
|
localizedBody =
|
2020-01-20 13:46:39 +01:00
|
|
|
I18n.of(context).changedTheGuestAccessRules(senderName);
|
|
|
|
} else {
|
|
|
|
localizedBody = I18n.of(context).changedTheGuestAccessRulesTo(
|
|
|
|
senderName, guestAccess.getLocalizedString(context));
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EventTypes.HistoryVisibility:
|
|
|
|
HistoryVisibility historyVisibility = HistoryVisibility.values
|
|
|
|
.firstWhere(
|
|
|
|
(r) =>
|
|
|
|
r.toString().replaceAll("HistoryVisibility.", "") ==
|
|
|
|
content["history_visibility"],
|
|
|
|
orElse: () => null);
|
|
|
|
if (historyVisibility == null) {
|
|
|
|
localizedBody =
|
2020-01-20 13:46:39 +01:00
|
|
|
I18n.of(context).changedTheHistoryVisibility(senderName);
|
|
|
|
} else {
|
|
|
|
localizedBody = I18n.of(context).changedTheHistoryVisibilityTo(
|
|
|
|
senderName, historyVisibility.getLocalizedString(context));
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EventTypes.Encryption:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody =
|
2020-02-15 09:20:08 +01:00
|
|
|
I18n.of(context).activatedEndToEndEncryption(senderName);
|
|
|
|
if (!room.client.encryptionEnabled) {
|
|
|
|
localizedBody += ". " + I18n.of(context).needPantalaimonWarning;
|
|
|
|
}
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case EventTypes.Encrypted:
|
|
|
|
case EventTypes.Message:
|
|
|
|
switch (this.messageType) {
|
|
|
|
case MessageTypes.Image:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).sentAPicture(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case MessageTypes.File:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).sentAFile(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case MessageTypes.Audio:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).sentAnAudio(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case MessageTypes.Video:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).sentAVideo(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case MessageTypes.Location:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).sharedTheLocation(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case MessageTypes.Sticker:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).sentASticker(senderName);
|
2020-01-19 15:07:42 +01:00
|
|
|
break;
|
|
|
|
case MessageTypes.Emote:
|
|
|
|
localizedBody = "* $body";
|
|
|
|
break;
|
2020-02-18 08:13:20 +01:00
|
|
|
case MessageTypes.BadEncrypted:
|
2020-02-22 08:27:08 +01:00
|
|
|
String errorText;
|
|
|
|
switch (body) {
|
|
|
|
case DecryptError.CHANNEL_CORRUPTED:
|
|
|
|
errorText = I18n.of(context).channelCorruptedDecryptError + ".";
|
|
|
|
break;
|
|
|
|
case DecryptError.NOT_ENABLED:
|
|
|
|
errorText = I18n.of(context).encryptionNotEnabled + ".";
|
|
|
|
break;
|
|
|
|
case DecryptError.UNKNOWN_ALGORITHM:
|
|
|
|
errorText = I18n.of(context).unknownEncryptionAlgorithm + ".";
|
|
|
|
break;
|
|
|
|
case DecryptError.UNKNOWN_SESSION:
|
|
|
|
errorText = I18n.of(context).noPermission + ".";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
errorText = body;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
localizedBody = "🔒 " +
|
|
|
|
I18n.of(context).couldNotDecryptMessage +
|
|
|
|
": " +
|
|
|
|
errorText;
|
2020-02-18 08:13:20 +01:00
|
|
|
break;
|
2020-01-19 15:07:42 +01:00
|
|
|
case MessageTypes.Text:
|
|
|
|
case MessageTypes.Notice:
|
|
|
|
case MessageTypes.None:
|
|
|
|
case MessageTypes.Reply:
|
|
|
|
localizedBody = body;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2020-01-20 13:46:39 +01:00
|
|
|
localizedBody = I18n.of(context).unknownEvent(this.typeKey);
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|
|
|
|
|
2020-02-20 20:45:38 +01:00
|
|
|
// Hide reply fallback
|
|
|
|
if (hideReply) {
|
2020-02-21 09:45:37 +01:00
|
|
|
localizedBody = localizedBody.replaceFirst(
|
2020-02-23 08:49:58 +01:00
|
|
|
RegExp(r'^>( \*)? <[^>]+>[^\n\r]+\r?\n(> [^\n]*\r?\n)*\r?\n'), "");
|
2020-02-09 16:26:24 +01:00
|
|
|
}
|
|
|
|
|
2020-01-19 15:07:42 +01:00
|
|
|
// Add the sender name prefix
|
|
|
|
if (withSenderNamePrefix &&
|
|
|
|
this.type == EventTypes.Message &&
|
|
|
|
textOnlyMessageTypes.contains(this.messageType)) {
|
2020-02-07 19:44:16 +01:00
|
|
|
final String senderNameOrYou = this.senderId == room.client.userID
|
|
|
|
? I18n.of(context).you
|
|
|
|
: senderName;
|
|
|
|
localizedBody = "$senderNameOrYou: $localizedBody";
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return localizedBody;
|
|
|
|
}
|
2020-03-13 20:09:32 +01:00
|
|
|
|
|
|
|
IconData get statusIcon {
|
|
|
|
switch (this.status) {
|
|
|
|
case -1:
|
|
|
|
return Icons.error_outline;
|
|
|
|
case 0:
|
|
|
|
return Icons.timer;
|
|
|
|
case 1:
|
|
|
|
return Icons.done;
|
|
|
|
case 2:
|
|
|
|
return Icons.done_all;
|
|
|
|
default:
|
|
|
|
return Icons.done;
|
|
|
|
}
|
|
|
|
}
|
2020-03-13 21:58:48 +01:00
|
|
|
|
|
|
|
String get sizeString {
|
|
|
|
if (content["info"] is Map<String, dynamic> &&
|
|
|
|
content["info"].containsKey("size")) {
|
|
|
|
num size = content["info"]["size"];
|
|
|
|
if (size < 1000000) {
|
|
|
|
size = size / 1000;
|
|
|
|
return "${size.toString()}kb";
|
|
|
|
} else if (size < 1000000000) {
|
|
|
|
size = size / 1000000;
|
|
|
|
return "${size.toString()}mb";
|
|
|
|
} else {
|
|
|
|
size = size / 1000000000;
|
|
|
|
return "${size.toString()}gb";
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
return null;
|
|
|
|
}
|
2020-01-19 15:07:42 +01:00
|
|
|
}
|