feat: Implement member change type

For easier handling and
comparing of m.room.member
state events to better
know what these event
actually changes.
This commit is contained in:
Krille 2023-09-19 10:42:14 +02:00
parent 02d7569c90
commit 8ac86a883d
No known key found for this signature in database
6 changed files with 169 additions and 72 deletions

View File

@ -49,6 +49,7 @@ export 'src/utils/matrix_file.dart';
export 'src/utils/matrix_id_string_extension.dart';
export 'src/utils/matrix_localizations.dart';
export 'src/utils/native_implementations.dart';
export 'src/utils/room_member_change_type.dart';
export 'src/utils/push_notification.dart';
export 'src/utils/pushrule_evaluator.dart';
export 'src/models/receipts.dart';

View File

@ -114,89 +114,59 @@ abstract class EventLocalizations {
final userIsTarget = event.stateKey == event.room.client.userID;
final userIsSender = event.senderId == event.room.client.userID;
// Fallback message if just nothing has changed:
var text = i18n.joinedTheChat(targetName);
// Has the membership changed?
final newMembership = event.content['membership'] ?? '';
final oldMembership = event.prevContent?['membership'] ?? '';
if (newMembership != oldMembership) {
if (oldMembership == 'invite' && newMembership == 'join') {
text = userIsTarget
? i18n.youAcceptedTheInvitation
: i18n.acceptedTheInvitation(targetName);
} else if (oldMembership == 'invite' && newMembership == 'leave') {
if (event.stateKey == event.senderId) {
text = userIsTarget
? i18n.youRejectedTheInvitation
: i18n.rejectedTheInvitation(targetName);
} else {
text = userIsSender
? i18n.youHaveWithdrawnTheInvitationFor(targetName)
: i18n.hasWithdrawnTheInvitationFor(senderName, targetName);
}
} else if (oldMembership == 'leave' && newMembership == 'join') {
text = userIsTarget
switch (event.roomMemberChangeType) {
case RoomMemberChangeType.avatar:
return i18n.changedTheProfileAvatar(targetName);
case RoomMemberChangeType.displayname:
final newDisplayname =
event.content.tryGet<String>('displayname') ?? '';
final oldDisplayname =
event.prevContent?.tryGet<String>('displayname') ?? '';
return i18n.changedTheDisplaynameTo(oldDisplayname, newDisplayname);
case RoomMemberChangeType.join:
return userIsTarget
? i18n.youJoinedTheChat
: i18n.joinedTheChat(targetName);
} else if (oldMembership == 'join' && newMembership == 'ban') {
text = userIsSender
? i18n.youKickedAndBanned(targetName)
: i18n.kickedAndBanned(senderName, targetName);
} else if (oldMembership == 'join' &&
newMembership == 'leave' &&
event.stateKey != event.senderId) {
text = userIsSender
case RoomMemberChangeType.acceptInvite:
return userIsTarget
? i18n.youAcceptedTheInvitation
: i18n.acceptedTheInvitation(targetName);
case RoomMemberChangeType.rejectInvite:
return userIsTarget
? i18n.youRejectedTheInvitation
: i18n.rejectedTheInvitation(targetName);
case RoomMemberChangeType.withdrawInvitation:
return userIsSender
? i18n.youHaveWithdrawnTheInvitationFor(targetName)
: i18n.hasWithdrawnTheInvitationFor(senderName, targetName);
case RoomMemberChangeType.leave:
return i18n.userLeftTheChat(targetName);
case RoomMemberChangeType.kick:
return userIsSender
? i18n.youKicked(targetName)
: i18n.kicked(senderName, targetName);
} else if (oldMembership == 'join' &&
newMembership == 'leave' &&
event.stateKey == event.senderId) {
text = i18n.userLeftTheChat(targetName);
} else if (oldMembership == 'invite' && newMembership == 'ban') {
text = userIsSender
? i18n.youBannedUser(targetName)
: i18n.bannedUser(senderName, targetName);
} else if (oldMembership == 'leave' && newMembership == 'ban') {
text = userIsSender
? i18n.youBannedUser(targetName)
: i18n.bannedUser(senderName, targetName);
} else if (oldMembership == 'ban' && newMembership == 'leave') {
text = userIsSender
? i18n.youUnbannedUser(targetName)
: i18n.unbannedUser(senderName, targetName);
} else if (newMembership == 'invite') {
text = userIsSender
case RoomMemberChangeType.invite:
return userIsSender
? i18n.youInvitedUser(targetName)
: userIsTarget
? i18n.youInvitedBy(senderName)
: i18n.invitedUser(senderName, targetName);
} else if (newMembership == 'join') {
text = userIsTarget
case RoomMemberChangeType.ban:
return userIsSender
? i18n.youBannedUser(targetName)
: i18n.bannedUser(senderName, targetName);
case RoomMemberChangeType.unban:
return userIsSender
? i18n.youUnbannedUser(targetName)
: i18n.unbannedUser(senderName, targetName);
case RoomMemberChangeType.knock:
return i18n.hasKnocked(targetName);
case RoomMemberChangeType.other:
default:
return userIsTarget
? i18n.youJoinedTheChat
: 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(

View File

@ -274,4 +274,7 @@ class MatrixDefaultLocalizations extends MatrixLocalizations {
@override
String get unknownUser => 'Unknown user';
@override
String hasKnocked(String targetName) => '$targetName has knocked';
}

View File

@ -161,6 +161,8 @@ abstract class MatrixLocalizations {
String sentCallInformations(String senderName);
String wasDirectChatDisplayName(String oldDisplayName);
String hasKnocked(String targetName);
}
extension HistoryVisibilityDisplayString on HistoryVisibility {

View File

@ -0,0 +1,112 @@
import 'package:matrix/matrix.dart';
/// The kind of what has changed with this m.room.member event to have a
/// comparable type.
enum RoomMemberChangeType {
/// The user has changed the avatar.
avatar,
/// The user has changed the displayname.
displayname,
/// The user has joined the chat from being not a user before. The user
/// also was not invited before.
join,
/// The user was invited before and has joined.
acceptInvite,
/// The user was invited before and has left.
rejectInvite,
/// The user was invited before and the invitation got withdrawn by someone.
withdrawInvitation,
/// The user was joined before and has now left the room by themself.
leave,
/// The user was joined before and has now been kicked out of the room by
/// someone.
kick,
/// The user has been invited by someone.
invite,
/// The user has been banned by someone.
ban,
/// The user was banned before and has been unbanned by someone.
unban,
/// The user was not a member of the room and now knocks.
knock,
/// Something else which is not handled yet.
other,
}
extension RoomMemberChangeTypeExtension on Event {
/// Returns the comparable type of this m.room.member event to handle this
/// differently in the UI. If the event is not of the type m.room.member,
/// this throws an exception!
RoomMemberChangeType get roomMemberChangeType {
if (type != EventTypes.RoomMember) {
throw Exception(
'Tried to call `roomMemberChangeType` but the Event has a type of `$type`',
);
}
// Has the membership changed?
final newMembership = content.tryGet<String>('membership') ?? '';
final oldMembership = prevContent?.tryGet<String>('membership') ?? '';
if (newMembership != oldMembership) {
if (oldMembership == 'invite' && newMembership == 'join') {
return RoomMemberChangeType.acceptInvite;
} else if (oldMembership == 'invite' && newMembership == 'leave') {
if (stateKey == senderId) {
return RoomMemberChangeType.rejectInvite;
} else {
return RoomMemberChangeType.withdrawInvitation;
}
} else if ((oldMembership == 'leave' || oldMembership == '') &&
newMembership == 'join') {
return RoomMemberChangeType.join;
} else if (oldMembership == 'join' && newMembership == 'ban') {
return RoomMemberChangeType.ban;
} else if (oldMembership == 'join' &&
newMembership == 'leave' &&
stateKey != senderId) {
return RoomMemberChangeType.kick;
} else if (oldMembership == 'join' &&
newMembership == 'leave' &&
stateKey == senderId) {
return RoomMemberChangeType.leave;
} else if (oldMembership != newMembership && newMembership == 'ban') {
return RoomMemberChangeType.ban;
} else if (oldMembership == 'ban' && newMembership == 'leave') {
return RoomMemberChangeType.unban;
} else if (newMembership == 'invite') {
return RoomMemberChangeType.invite;
} else if (newMembership == 'knock') {
return RoomMemberChangeType.knock;
}
} else if (newMembership == 'join') {
final newAvatar = content.tryGet<String>('avatar_url') ?? '';
final oldAvatar = prevContent?.tryGet<String>('avatar_url') ?? '';
final newDisplayname = content.tryGet<String>('displayname') ?? '';
final oldDisplayname = prevContent?.tryGet<String>('displayname') ?? '';
// Has the user avatar changed?
if (newAvatar != oldAvatar) {
return RoomMemberChangeType.avatar;
}
// Has the user displayname changed?
else if (newDisplayname != oldDisplayname && stateKey != null) {
return RoomMemberChangeType.displayname;
}
}
return RoomMemberChangeType.other;
}
}

View File

@ -569,6 +569,7 @@ void main() {
'type': 'm.room.member',
'unsigned': {'age': 1234}
}, room);
expect(event.roomMemberChangeType, RoomMemberChangeType.join);
expect(await event.calcLocalizedBody(MatrixDefaultLocalizations()),
'Alice joined the chat');
expect(event.isEventTypeKnown, true);
@ -582,6 +583,7 @@ void main() {
'state_key': '@alice:example.org',
'type': 'm.room.member'
}, room);
expect(event.roomMemberChangeType, RoomMemberChangeType.invite);
expect(await event.calcLocalizedBody(MatrixDefaultLocalizations()),
'Example has invited Alice');
expect(event.isEventTypeKnown, true);
@ -598,6 +600,7 @@ void main() {
'prev_content': {'membership': 'join'},
}
}, room);
expect(event.roomMemberChangeType, RoomMemberChangeType.kick);
expect(await event.calcLocalizedBody(MatrixDefaultLocalizations()),
'Example kicked Alice');
expect(event.isEventTypeKnown, true);
@ -614,6 +617,7 @@ void main() {
'prev_content': {'membership': 'join'},
}
}, room);
expect(event.roomMemberChangeType, RoomMemberChangeType.ban);
expect(await event.calcLocalizedBody(MatrixDefaultLocalizations()),
'Example banned Alice');
expect(event.isEventTypeKnown, true);
@ -630,6 +634,7 @@ void main() {
'prev_content': {'membership': 'invite'},
}
}, room);
expect(event.roomMemberChangeType, RoomMemberChangeType.acceptInvite);
expect(await event.calcLocalizedBody(MatrixDefaultLocalizations()),
'Alice accepted the invitation');
expect(event.isEventTypeKnown, true);
@ -646,6 +651,7 @@ void main() {
'prev_content': {'membership': 'join'},
}
}, room);
expect(event.roomMemberChangeType, RoomMemberChangeType.invite);
expect(await event.calcLocalizedBody(MatrixDefaultLocalizations()),
'Example has invited Alice');
expect(event.isEventTypeKnown, true);
@ -662,6 +668,8 @@ void main() {
'prev_content': {'membership': 'invite'},
}
}, room);
expect(
event.roomMemberChangeType, RoomMemberChangeType.withdrawInvitation);
expect(await event.calcLocalizedBody(MatrixDefaultLocalizations()),
'Example has withdrawn the invitation for Alice');
expect(event.isEventTypeKnown, true);
@ -678,6 +686,7 @@ void main() {
'prev_content': {'membership': 'invite'},
}
}, room);
expect(event.roomMemberChangeType, RoomMemberChangeType.rejectInvite);
expect(await event.calcLocalizedBody(MatrixDefaultLocalizations()),
'Alice rejected the invitation');
expect(event.isEventTypeKnown, true);