refactor: room displayname calculation

This deprecates the displayname
getter in favor of the new
getLocalizedDisplayname which
gets the default localization
by default so it can be
called without defining localizations. It adds a method
to calculate if a room is an
abandoned DM room where
it is made sure that the room
is actually empty.
This commit is contained in:
Krille 2023-01-17 08:51:07 +01:00
parent 1e605c6728
commit d6c4b530c5
4 changed files with 60 additions and 86 deletions

View File

@ -233,29 +233,45 @@ class Room {
/// of just 'Alice' to make it different to a direct chat.
/// Empty chats will become the localized version of 'Empty Chat'.
/// This method requires a localization class which implements [MatrixLocalizations]
String getLocalizedDisplayname(MatrixLocalizations i18n) {
if (name.isEmpty &&
canonicalAlias.isEmpty &&
!isDirectChat &&
(summary.mHeroes != null && summary.mHeroes?.isNotEmpty == true)) {
return i18n.groupWith(displayname);
String getLocalizedDisplayname([
MatrixLocalizations i18n = const MatrixDefaultLocalizations(),
]) {
if (name.isNotEmpty) return name;
final canonicalAlias = this.canonicalAlias.localpart;
if (canonicalAlias != null && canonicalAlias.isNotEmpty) {
return canonicalAlias;
}
if (displayname.isNotEmpty) {
if (directChatMatrixID != null) {
final displayName =
unsafeGetUserFromMemoryOrFallback(directChatMatrixID!)
.calcDisplayname();
final dmPartnerMembership =
getState(EventTypes.RoomMember, directChatMatrixID!)
?.asUser
.membership;
if (dmPartnerMembership == null ||
dmPartnerMembership == Membership.leave) {
return i18n.wasDirectChatDisplayName(displayName);
}
return displayName;
final directChatMatrixID = this.directChatMatrixID;
final heroes = summary.mHeroes ??
(directChatMatrixID == null ? [] : [directChatMatrixID]);
if (heroes.isNotEmpty) {
final result = heroes
.where((hero) => hero.isNotEmpty)
.map((hero) =>
unsafeGetUserFromMemoryOrFallback(hero).calcDisplayname())
.join(', ');
if (isAbandonedDMRoom) {
return i18n.wasDirectChatDisplayName(result);
}
return isDirectChat ? result : i18n.groupWith(result);
}
if (membership == Membership.invite) {
final sender = getState(EventTypes.RoomMember, client.userID!)
?.senderFromMemoryOrFallback
.calcDisplayname();
if (sender != null) return sender;
}
if (membership == Membership.leave) {
final invitation = getState(EventTypes.RoomMember, client.userID!);
if (invitation != null && invitation.unsigned?['prev_sender'] != null) {
final name = unsafeGetUserFromMemoryOrFallback(
invitation.unsigned?['prev_sender'])
.calcDisplayname();
return i18n.wasDirectChatDisplayName(name);
}
return displayname;
}
return i18n.emptyChat;
}
@ -416,67 +432,24 @@ class Room {
/// history of this room.
static const int defaultHistoryCount = 30;
/// Checks if this is an abandoned DM room where the other participant has
/// left the room. This is false when there are still other users in the room
/// or the room is not marked as a DM room.
bool get isAbandonedDMRoom {
final directChatMatrixID = this.directChatMatrixID;
if (directChatMatrixID == null) return false;
final dmPartnerMembership =
unsafeGetUserFromMemoryOrFallback(directChatMatrixID).membership;
return dmPartnerMembership == Membership.leave &&
summary.mJoinedMemberCount == 1 &&
summary.mInvitedMemberCount == 0;
}
/// Calculates the displayname. First checks if there is a name, then checks for a canonical alias and
/// then generates a name from the heroes.
String get displayname {
if (name.isNotEmpty) return name;
final canonicalAlias = this.canonicalAlias.localpart;
if (canonicalAlias != null && canonicalAlias.isNotEmpty) {
return canonicalAlias;
}
final heroes = summary.mHeroes;
if (heroes != null && heroes.isNotEmpty) {
final result = heroes
.where((hero) => hero.isNotEmpty)
.map((hero) =>
unsafeGetUserFromMemoryOrFallback(hero).calcDisplayname())
.join(', ');
if (directChatMatrixID != null) {
final dmPartnerMembership = getState(
EventTypes.RoomMember,
directChatMatrixID!,
)?.asUser.membership;
if (dmPartnerMembership == null ||
dmPartnerMembership == Membership.leave) {
return leavedDirectChatName(result);
}
return result;
} else {
return result;
}
}
if (isDirectChat) {
final user = directChatMatrixID;
if (user != null) {
final displayName =
unsafeGetUserFromMemoryOrFallback(user).calcDisplayname();
return membership == Membership.leave
? leavedDirectChatName(displayName)
: displayName;
}
}
if (membership == Membership.invite) {
final sender = getState(EventTypes.RoomMember, client.userID!)
?.senderFromMemoryOrFallback
.calcDisplayname();
if (sender != null) return sender;
}
if (membership == Membership.leave) {
final invitation = getState(EventTypes.RoomMember, client.userID!);
if (invitation != null && invitation.unsigned?['prev_sender'] != null) {
final name = unsafeGetUserFromMemoryOrFallback(
invitation.unsigned?['prev_sender'])
.calcDisplayname();
return leavedDirectChatName(name);
}
}
return emptyRoomName;
}
String leavedDirectChatName(String prevName) {
return '$emptyRoomName (was $prevName)';
}
@Deprecated('Use `getLocalizedDisplayname()` instead')
String get displayname => getLocalizedDisplayname();
/// When the last message received.
DateTime get timeCreated => lastEvent?.originServerTs ?? DateTime.now();
@ -1581,7 +1554,7 @@ class Room {
Map<String, dynamic>? resp;
try {
Logs().v(
'Request missing user $mxID in room $displayname from the server...');
'Request missing user $mxID in room ${getLocalizedDisplayname()} from the server...');
resp = await client.getRoomStateWithKey(
id,
EventTypes.RoomMember,

View File

@ -47,7 +47,7 @@ extension ImagePackRoomExtension on Room {
finalSlug,
() => ImagePackContent.fromJson({})
..pack.displayName = imagePack.pack.displayName ??
room?.displayname ??
room?.getLocalizedDisplayname() ??
finalSlug
..pack.avatarUrl = imagePack.pack.avatarUrl ?? room?.avatar
..pack.attribution = imagePack.pack.attribution)
@ -68,7 +68,7 @@ extension ImagePackRoomExtension on Room {
for (final stateKeyEntry in roomEntry.value.entries) {
final stateKey = stateKeyEntry.key;
final fallbackSlug =
'${room.displayname}-${stateKey.isNotEmpty ? '$stateKey-' : ''}${room.id}';
'${room.getLocalizedDisplayname()}-${stateKey.isNotEmpty ? '$stateKey-' : ''}${room.id}';
addImagePack(room.getState('im.ponies.room_emotes', stateKey),
room: room, slug: fallbackSlug);
}

View File

@ -305,6 +305,7 @@ class CallSession {
String? get groupCallId => opts.groupCallId;
String get callId => opts.callId;
String get localPartyId => opts.localPartyId;
@Deprecated('Use room.getLocalizedDisplayname() instead')
String? get displayName => room.displayname;
CallDirection get direction => opts.dir;
CallState state = CallState.kFledgling;

View File

@ -90,7 +90,7 @@ void main() {
expect(room.summary.mJoinedMemberCount, notificationCount);
expect(room.summary.mInvitedMemberCount, notificationCount);
expect(room.summary.mHeroes, heroes);
expect(room.displayname, 'Alice, Bob, Charley');
expect(room.getLocalizedDisplayname(), 'Group with Alice, Bob, Charley');
expect(
room.getState('m.room.join_rules')?.content['join_rule'], 'public');
expect(room.roomAccountData['com.test.foo']?.content['foo'], 'bar');
@ -106,7 +106,7 @@ void main() {
originServerTs: DateTime.now(),
stateKey: ''),
);
expect(room.displayname, 'testalias');
expect(room.getLocalizedDisplayname(), 'testalias');
expect(room.canonicalAlias, '#testalias:example.com');
room.setState(
@ -119,7 +119,7 @@ void main() {
originServerTs: DateTime.now(),
stateKey: ''),
);
expect(room.displayname, 'testname');
expect(room.getLocalizedDisplayname(), 'testname');
expect(room.topic, '');
room.setState(