diff --git a/lib/src/room.dart b/lib/src/room.dart index 113009e5..eb3de7da 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -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? 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, diff --git a/lib/src/utils/image_pack_extension.dart b/lib/src/utils/image_pack_extension.dart index 222067c3..00b97430 100644 --- a/lib/src/utils/image_pack_extension.dart +++ b/lib/src/utils/image_pack_extension.dart @@ -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); } diff --git a/lib/src/voip/call.dart b/lib/src/voip/call.dart index 7d43e19c..018ff787 100644 --- a/lib/src/voip/call.dart +++ b/lib/src/voip/call.dart @@ -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; diff --git a/test/room_test.dart b/test/room_test.dart index a76d9166..a51a15e6 100644 --- a/test/room_test.dart +++ b/test/room_test.dart @@ -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(