225 lines
10 KiB
Dart
225 lines
10 KiB
Dart
/*
|
|
* Famedly Matrix SDK
|
|
* Copyright (C) 2019, 2020, 2021 Famedly GmbH
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import 'package:collection/collection.dart';
|
|
|
|
import '../../encryption.dart';
|
|
import '../../matrix.dart';
|
|
|
|
abstract class EventLocalizations {
|
|
// As we need to create the localized body off of a different set of parameters, we
|
|
// might create it with `event.plaintextBody`, maybe with `event.body`, maybe with the
|
|
// reply fallback stripped, and maybe with the new body in `event.content['m.new_content']`.
|
|
// Thus, it seems easier to offload that logic into `Event.getLocalizedBody()` and pass the
|
|
// `body` variable around here.
|
|
static String _localizedBodyNormalMessage(
|
|
Event event, MatrixLocalizations i18n, String body) {
|
|
switch (event.messageType) {
|
|
case MessageTypes.Image:
|
|
return i18n.sentAPicture(event.sender.calcDisplayname());
|
|
case MessageTypes.File:
|
|
return i18n.sentAFile(event.sender.calcDisplayname());
|
|
case MessageTypes.Audio:
|
|
return i18n.sentAnAudio(event.sender.calcDisplayname());
|
|
case MessageTypes.Video:
|
|
return i18n.sentAVideo(event.sender.calcDisplayname());
|
|
case MessageTypes.Location:
|
|
return i18n.sharedTheLocation(event.sender.calcDisplayname());
|
|
case MessageTypes.Sticker:
|
|
return i18n.sentASticker(event.sender.calcDisplayname());
|
|
case MessageTypes.Emote:
|
|
return '* $body';
|
|
case MessageTypes.BadEncrypted:
|
|
String errorText;
|
|
switch (event.body) {
|
|
case DecryptException.channelCorrupted:
|
|
errorText = i18n.channelCorruptedDecryptError + '.';
|
|
break;
|
|
case DecryptException.notEnabled:
|
|
errorText = i18n.encryptionNotEnabled + '.';
|
|
break;
|
|
case DecryptException.unknownAlgorithm:
|
|
errorText = i18n.unknownEncryptionAlgorithm + '.';
|
|
break;
|
|
case DecryptException.unknownSession:
|
|
errorText = i18n.noPermission + '.';
|
|
break;
|
|
default:
|
|
errorText = body;
|
|
break;
|
|
}
|
|
return i18n.couldNotDecryptMessage(errorText);
|
|
case MessageTypes.Text:
|
|
case MessageTypes.Notice:
|
|
case MessageTypes.None:
|
|
default:
|
|
return body;
|
|
}
|
|
}
|
|
|
|
// This map holds how to localize event types, and thus which event types exist.
|
|
// If an event exists but it does not have a localized body, set its callback to null
|
|
static final Map<String,
|
|
String Function(Event event, MatrixLocalizations i18n, String body)?>
|
|
localizationsMap = {
|
|
EventTypes.Sticker: (event, i18n, body) =>
|
|
i18n.sentASticker(event.sender.calcDisplayname()),
|
|
EventTypes.Redaction: (event, i18n, body) =>
|
|
i18n.redactedAnEvent(event.sender.calcDisplayname()),
|
|
EventTypes.RoomAliases: (event, i18n, body) =>
|
|
i18n.changedTheRoomAliases(event.sender.calcDisplayname()),
|
|
EventTypes.RoomCanonicalAlias: (event, i18n, body) =>
|
|
i18n.changedTheRoomInvitationLink(event.sender.calcDisplayname()),
|
|
EventTypes.RoomCreate: (event, i18n, body) =>
|
|
i18n.createdTheChat(event.sender.calcDisplayname()),
|
|
EventTypes.RoomTombstone: (event, i18n, body) => i18n.roomHasBeenUpgraded,
|
|
EventTypes.RoomJoinRules: (event, i18n, body) {
|
|
final joinRules = JoinRules.values.firstWhereOrNull((r) =>
|
|
r.toString().replaceAll('JoinRules.', '') ==
|
|
event.content['join_rule']);
|
|
if (joinRules == null) {
|
|
return i18n.changedTheJoinRules(event.sender.calcDisplayname());
|
|
} else {
|
|
return i18n.changedTheJoinRulesTo(
|
|
event.sender.calcDisplayname(), joinRules.getLocalizedString(i18n));
|
|
}
|
|
},
|
|
EventTypes.RoomMember: (event, i18n, body) {
|
|
var text = 'Failed to parse member event';
|
|
final targetName = event.stateKeyUser?.calcDisplayname() ?? '';
|
|
// Has the membership changed?
|
|
final newMembership = event.content['membership'] ?? '';
|
|
final oldMembership = event.prevContent?['membership'] ?? '';
|
|
|
|
if (newMembership != oldMembership) {
|
|
if (oldMembership == 'invite' && newMembership == 'join') {
|
|
text = i18n.acceptedTheInvitation(targetName);
|
|
} else if (oldMembership == 'invite' && newMembership == 'leave') {
|
|
if (event.stateKey == event.senderId) {
|
|
text = i18n.rejectedTheInvitation(targetName);
|
|
} else {
|
|
text = i18n.hasWithdrawnTheInvitationFor(
|
|
event.sender.calcDisplayname(), targetName);
|
|
}
|
|
} else if (oldMembership == 'leave' && newMembership == 'join') {
|
|
text = i18n.joinedTheChat(targetName);
|
|
} else if (oldMembership == 'join' && newMembership == 'ban') {
|
|
text =
|
|
i18n.kickedAndBanned(event.sender.calcDisplayname(), targetName);
|
|
} else if (oldMembership == 'join' &&
|
|
newMembership == 'leave' &&
|
|
event.stateKey != event.senderId) {
|
|
text = i18n.kicked(event.sender.calcDisplayname(), targetName);
|
|
} else if (oldMembership == 'join' &&
|
|
newMembership == 'leave' &&
|
|
event.stateKey == event.senderId) {
|
|
text = i18n.userLeftTheChat(targetName);
|
|
} else if (oldMembership == 'invite' && newMembership == 'ban') {
|
|
text = i18n.bannedUser(event.sender.calcDisplayname(), targetName);
|
|
} else if (oldMembership == 'leave' && newMembership == 'ban') {
|
|
text = i18n.bannedUser(event.sender.calcDisplayname(), targetName);
|
|
} else if (oldMembership == 'ban' && newMembership == 'leave') {
|
|
text = i18n.unbannedUser(event.sender.calcDisplayname(), targetName);
|
|
} else if (newMembership == 'invite') {
|
|
text = i18n.invitedUser(event.sender.calcDisplayname(), targetName);
|
|
} else if (newMembership == 'join') {
|
|
text = i18n.joinedTheChat(targetName);
|
|
}
|
|
} else if (newMembership == 'join') {
|
|
final newAvatar = event.content.tryGet<String>('avatar_url') ?? '';
|
|
final oldAvatar = event.prevContent?.tryGet<String>('avatar_url') ?? '';
|
|
|
|
final newDisplayname =
|
|
event.content.tryGet<String>('displayname') ?? '';
|
|
final oldDisplayname =
|
|
event.prevContent?.tryGet<String>('displayname') ?? '';
|
|
final stateKey = event.stateKey;
|
|
|
|
// Has the user avatar changed?
|
|
if (newAvatar != oldAvatar) {
|
|
text = i18n.changedTheProfileAvatar(targetName);
|
|
}
|
|
// Has the user displayname changed?
|
|
else if (newDisplayname != oldDisplayname && stateKey != null) {
|
|
text = i18n.changedTheDisplaynameTo(oldDisplayname, newDisplayname);
|
|
}
|
|
}
|
|
return text;
|
|
},
|
|
EventTypes.RoomPowerLevels: (event, i18n, body) =>
|
|
i18n.changedTheChatPermissions(event.sender.calcDisplayname()),
|
|
EventTypes.RoomName: (event, i18n, body) => i18n.changedTheChatNameTo(
|
|
event.sender.calcDisplayname(), event.content['name']),
|
|
EventTypes.RoomTopic: (event, i18n, body) =>
|
|
i18n.changedTheChatDescriptionTo(
|
|
event.sender.calcDisplayname(), event.content['topic']),
|
|
EventTypes.RoomAvatar: (event, i18n, body) =>
|
|
i18n.changedTheChatAvatar(event.sender.calcDisplayname()),
|
|
EventTypes.GuestAccess: (event, i18n, body) {
|
|
final guestAccess = GuestAccess.values.firstWhereOrNull((r) =>
|
|
r.toString().replaceAll('GuestAccess.', '') ==
|
|
event.content['guest_access']);
|
|
if (guestAccess == null) {
|
|
return i18n.changedTheGuestAccessRules(event.sender.calcDisplayname());
|
|
} else {
|
|
return i18n.changedTheGuestAccessRulesTo(event.sender.calcDisplayname(),
|
|
guestAccess.getLocalizedString(i18n));
|
|
}
|
|
},
|
|
EventTypes.HistoryVisibility: (event, i18n, body) {
|
|
final historyVisibility = HistoryVisibility.values.firstWhereOrNull((r) =>
|
|
r.toString().replaceAll('HistoryVisibility.', '') ==
|
|
event.content['history_visibility']);
|
|
if (historyVisibility == null) {
|
|
return i18n.changedTheHistoryVisibility(event.sender.calcDisplayname());
|
|
} else {
|
|
return i18n.changedTheHistoryVisibilityTo(
|
|
event.sender.calcDisplayname(),
|
|
historyVisibility.getLocalizedString(i18n));
|
|
}
|
|
},
|
|
EventTypes.Encryption: (event, i18n, body) {
|
|
var localizedBody =
|
|
i18n.activatedEndToEndEncryption(event.sender.calcDisplayname());
|
|
if (event.room.client.encryptionEnabled == false) {
|
|
localizedBody += '. ' + i18n.needPantalaimonWarning;
|
|
}
|
|
return localizedBody;
|
|
},
|
|
EventTypes.CallAnswer: (event, i18n, body) =>
|
|
i18n.answeredTheCall(event.sender.calcDisplayname()),
|
|
EventTypes.CallHangup: (event, i18n, body) =>
|
|
i18n.endedTheCall(event.sender.calcDisplayname()),
|
|
EventTypes.CallInvite: (event, i18n, body) =>
|
|
i18n.startedACall(event.sender.calcDisplayname()),
|
|
EventTypes.CallCandidates: (event, i18n, body) =>
|
|
i18n.sentCallInformations(event.sender.calcDisplayname()),
|
|
EventTypes.Encrypted: (event, i18n, body) =>
|
|
_localizedBodyNormalMessage(event, i18n, body),
|
|
EventTypes.Message: (event, i18n, body) =>
|
|
_localizedBodyNormalMessage(event, i18n, body),
|
|
EventTypes.Reaction: (event, i18n, body) => i18n.sentReaction(
|
|
event.sender.calcDisplayname(),
|
|
event.content
|
|
.tryGetMap<String, dynamic>('m.relates_to')
|
|
?.tryGet<String>('key') ??
|
|
body,
|
|
),
|
|
};
|
|
}
|