Merge branch 'krille/refactor-room-displayname' into 'main'

refactor: room displayname calculation

Closes famedly/fluffychat#1114

See merge request famedly/company/frontend/famedlysdk!1211
This commit is contained in:
Malin Errenst 2023-01-17 15:31:48 +00:00
commit 3fb134dfb2
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. /// of just 'Alice' to make it different to a direct chat.
/// Empty chats will become the localized version of 'Empty Chat'. /// Empty chats will become the localized version of 'Empty Chat'.
/// This method requires a localization class which implements [MatrixLocalizations] /// This method requires a localization class which implements [MatrixLocalizations]
String getLocalizedDisplayname(MatrixLocalizations i18n) { String getLocalizedDisplayname([
if (name.isEmpty && MatrixLocalizations i18n = const MatrixDefaultLocalizations(),
canonicalAlias.isEmpty && ]) {
!isDirectChat && if (name.isNotEmpty) return name;
(summary.mHeroes != null && summary.mHeroes?.isNotEmpty == true)) {
return i18n.groupWith(displayname); final canonicalAlias = this.canonicalAlias.localpart;
if (canonicalAlias != null && canonicalAlias.isNotEmpty) {
return canonicalAlias;
} }
if (displayname.isNotEmpty) {
if (directChatMatrixID != null) { final directChatMatrixID = this.directChatMatrixID;
final displayName = final heroes = summary.mHeroes ??
unsafeGetUserFromMemoryOrFallback(directChatMatrixID!) (directChatMatrixID == null ? [] : [directChatMatrixID]);
.calcDisplayname(); if (heroes.isNotEmpty) {
final dmPartnerMembership = final result = heroes
getState(EventTypes.RoomMember, directChatMatrixID!) .where((hero) => hero.isNotEmpty)
?.asUser .map((hero) =>
.membership; unsafeGetUserFromMemoryOrFallback(hero).calcDisplayname())
if (dmPartnerMembership == null || .join(', ');
dmPartnerMembership == Membership.leave) { if (isAbandonedDMRoom) {
return i18n.wasDirectChatDisplayName(displayName); return i18n.wasDirectChatDisplayName(result);
} }
return displayName;
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; return i18n.emptyChat;
} }
@ -416,67 +432,24 @@ class Room {
/// history of this room. /// history of this room.
static const int defaultHistoryCount = 30; 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 /// Calculates the displayname. First checks if there is a name, then checks for a canonical alias and
/// then generates a name from the heroes. /// then generates a name from the heroes.
String get displayname { @Deprecated('Use `getLocalizedDisplayname()` instead')
if (name.isNotEmpty) return name; String get displayname => getLocalizedDisplayname();
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)';
}
/// When the last message received. /// When the last message received.
DateTime get timeCreated => lastEvent?.originServerTs ?? DateTime.now(); DateTime get timeCreated => lastEvent?.originServerTs ?? DateTime.now();
@ -1581,7 +1554,7 @@ class Room {
Map<String, dynamic>? resp; Map<String, dynamic>? resp;
try { try {
Logs().v( 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( resp = await client.getRoomStateWithKey(
id, id,
EventTypes.RoomMember, EventTypes.RoomMember,

View File

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

View File

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

View File

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