From c537e94146fb4e4bd27204b878282f6e9e4cf143 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Wed, 23 Apr 2025 15:53:40 +0200 Subject: [PATCH] Split `MatrixRoom` into `BaseRoom` and `JoinedRoom` (#4561) `JoinedRoom` will now contain both a mandatory live timeline reference and all the functionality associated to it. `BaseRoom` on the other hand will contain only functionality that's shared for both joined and not joined rooms. `NotJoinedRoom` is a wrapper around `RoomPreviewInfo` data and a possible local `BaseRoom`, if it exists. The `RustRoomFactory` cache is now gone since the persistent event cache should have the same effect. --- .../x/di/DefaultRoomComponentFactory.kt | 9 +- .../io/element/android/x/di/RoomComponent.kt | 9 +- .../android/appnav/di/RoomComponentFactory.kt | 4 +- .../android/appnav/loggedin/SendQueues.kt | 3 + .../room/joined/JoinedRoomLoadedFlowNode.kt | 5 +- .../appnav/room/joined/LoadingRoomState.kt | 10 +- ...t.kt => JoinBaseRoomLoadedFlowNodeTest.kt} | 17 +- .../android/appnav/loggedin/SendQueuesTest.kt | 10 +- ...=> LoadingBaseRoomStateFlowFactoryTest.kt} | 9 +- .../call/impl/ui/CallScreenPresenter.kt | 2 +- .../impl/utils/DefaultCallWidgetProvider.kt | 2 +- .../call/ui/CallScreenPresenterTest.kt | 4 +- .../utils/DefaultActiveCallManagerTest.kt | 6 +- .../utils/DefaultCallWidgetProviderTest.kt | 10 +- ...t.kt => ConfigureBaseRoomPresenterTest.kt} | 2 +- ... => JoinBaseRoomByAddressPresenterTest.kt} | 2 +- ...st.kt => JoinBaseRoomByAddressViewTest.kt} | 2 +- ....kt => CreateBaseRoomRootPresenterTest.kt} | 2 +- ...wTest.kt => CreateBaseRoomRootViewTest.kt} | 2 +- .../response/AcceptDeclineInvitePresenter.kt | 2 +- .../AcceptDeclineInvitePresenterTest.kt | 33 +- .../joinroom/impl/JoinRoomPresenter.kt | 8 +- .../joinroom/impl/di/CancelKnockRoom.kt | 4 +- .../features/joinroom/impl/di/ForgetRoom.kt | 6 +- ...erTest.kt => JoinBaseRoomPresenterTest.kt} | 22 +- ...oomViewTest.kt => JoinBaseRoomViewTest.kt} | 2 +- .../impl/data/KnockRequestPermissions.kt | 4 +- .../impl/data/KnockRequestsModule.kt | 4 +- ...rTest.kt => LeaveBaseRoomPresenterTest.kt} | 20 +- .../impl/send/SendLocationPresenter.kt | 4 +- .../impl/send/SendLocationPresenterTest.kt | 20 +- .../messages/impl/MessagesFlowNode.kt | 4 +- .../features/messages/impl/MessagesNode.kt | 4 +- .../messages/impl/MessagesPresenter.kt | 16 +- .../impl/actionlist/ActionListPresenter.kt | 4 +- .../identity/IdentityChangeStatePresenter.kt | 4 +- .../VerifiedUserSendFailureFactory.kt | 4 +- ...ResolveVerifiedUserSendFailurePresenter.kt | 4 +- .../VerifiedUserSendFailureResolver.kt | 4 +- .../impl/draft/MatrixComposerDraftStore.kt | 4 +- .../MessageComposerPresenter.kt | 4 +- .../suggestions/SuggestionsProcessor.kt | 4 +- .../pinned/PinnedEventsTimelineProvider.kt | 5 +- .../banner/PinnedMessagesBannerPresenter.kt | 4 +- .../list/PinnedMessagesListPresenter.kt | 4 +- .../impl/report/ReportMessagePresenter.kt | 4 +- .../impl/timeline/TimelineController.kt | 4 +- .../impl/timeline/TimelinePresenter.kt | 4 +- .../ReactionSummaryPresenter.kt | 4 +- .../protection/TimelineProtectionPresenter.kt | 5 +- .../typing/TypingNotificationPresenter.kt | 4 +- .../messages/impl/MessagesPresenterTest.kt | 390 ++++++------ .../actionlist/ActionListPresenterTest.kt | 10 +- .../AttachmentsPreviewPresenterTest.kt | 26 +- .../IdentityChangeStatePresenterTest.kt | 29 +- ...lveVerifiedUserSendFailurePresenterTest.kt | 34 +- .../forward/ForwardMessagesPresenterTest.kt | 14 +- .../MessageComposerPresenterTest.kt | 74 +-- .../suggestions/SuggestionsProcessorTest.kt | 38 +- .../PinnedMessagesBannerPresenterTest.kt | 14 +- .../list/PinnedMessagesListPresenterTest.kt | 71 ++- .../impl/report/ReportMessagePresenterTest.kt | 20 +- .../impl/timeline/TimelineControllerTest.kt | 30 +- .../impl/timeline/TimelinePresenterTest.kt | 35 +- .../ReactionSummaryPresenterTest.kt | 8 +- .../TimelineProtectionPresenterTest.kt | 10 +- .../typing/TypingNotificationPresenterTest.kt | 58 +- .../VoiceMessageComposerPresenterTest.kt | 6 +- .../poll/impl/actions/DefaultEndPollAction.kt | 4 +- .../actions/DefaultSendPollResponseAction.kt | 4 +- .../features/poll/impl/data/PollRepository.kt | 4 +- .../poll/impl/history/PollHistoryPresenter.kt | 4 +- .../impl/create/CreatePollPresenterTest.kt | 15 +- .../impl/history/PollHistoryPresenterTest.kt | 7 +- .../roomcall/impl/RoomCallStatePresenter.kt | 4 +- .../impl/RoomCallStatePresenterTest.kt | 53 +- .../roomdetails/impl/RoomDetailsFlowNode.kt | 4 +- .../roomdetails/impl/RoomDetailsNode.kt | 4 +- .../roomdetails/impl/RoomDetailsPresenter.kt | 10 +- .../impl/analytics/AnalyticUtils.kt | 4 +- .../roomdetails/impl/di/RoomMemberModule.kt | 4 +- .../impl/edit/RoomDetailsEditPresenter.kt | 4 +- .../impl/invite/RoomInviteMembersNode.kt | 4 +- .../impl/members/RoomMemberListDataSource.kt | 4 +- .../impl/members/RoomMemberListPresenter.kt | 14 +- .../details/RoomMemberDetailsPresenter.kt | 4 +- .../RoomMembersModerationPresenter.kt | 4 +- .../RoomNotificationSettingsPresenter.kt | 4 +- .../RolesAndPermissionsNode.kt | 4 +- .../RolesAndPermissionsPresenter.kt | 8 +- .../changeroles/ChangeRolesPresenter.kt | 4 +- .../ChangeRoomPermissionsPresenter.kt | 10 +- .../permissions/ChangeRoomPermissionsState.kt | 4 +- .../ChangeRoomPermissionsStateProvider.kt | 8 +- .../permissions/ChangeRoomPermissionsView.kt | 6 +- .../SecurityAndPrivacyPresenter.kt | 8 +- .../EditRoomAddressPresenter.kt | 8 +- .../SecurityAndPrivacyPermissions.kt | 4 +- .../roomdetails/impl/MatrixRoomFixture.kt | 97 ++- .../impl/RoomDetailsPresenterTest.kt | 59 +- .../impl/edit/RoomDetailsEditPresenterTest.kt | 48 +- .../invite/RoomInviteMembersPresenterTest.kt | 34 +- ...PowerLevelBaseRoomMemberComparatorTest.kt} | 2 +- .../members/RoomMemberListPresenterTest.kt | 90 ++- .../details/RoomMemberDetailsPresenterTest.kt | 72 ++- .../RoomMembersModerationPresenterTest.kt | 56 +- .../RoomNotificationSettingsPresenterTest.kt | 10 +- .../RolesAndPermissionPresenterTest.kt | 10 +- .../changeroles/ChangeRolesPresenterTest.kt | 78 ++- ...ChangeBaseRoomPermissionsPresenterTest.kt} | 27 +- ...t => ChangeBaseRoomPermissionsViewTest.kt} | 2 +- .../SecurityAndPrivacyPresenterTest.kt | 40 +- ...kt => EditBaseRoomAddressPresenterTest.kt} | 22 +- ...Test.kt => EditBaseRoomAddressViewTest.kt} | 2 +- .../impl/root/RoomDirectoryPresenterTest.kt | 3 +- .../roomlist/impl/RoomListPresenter.kt | 2 - .../roomlist/impl/RoomListPresenterTest.kt | 14 +- ...Test.kt => RoomListBaseRoomSummaryTest.kt} | 2 +- .../features/share/impl/SharePresenter.kt | 4 +- .../features/share/impl/SharePresenterTest.kt | 10 +- .../impl/UserProfilePresenterTest.kt | 4 +- ...efaultBaseRoomLastMessageFormatterTest.kt} | 2 +- .../libraries/matrix/api/MatrixClient.kt | 15 +- .../matrix/api/analytics/ViewRoomExt.kt | 8 +- .../NotificationSettingsService.kt | 4 +- .../libraries/matrix/api/room/BaseRoom.kt | 231 +++++++ .../api/room/{MatrixRoom.kt => JoinedRoom.kt} | 288 +++------ .../MatrixRoomNotificationSettingsState.kt | 24 - .../room/{RoomPreview.kt => NotJoinedRoom.kt} | 15 +- .../room/{MatrixRoomInfo.kt => RoomInfo.kt} | 2 +- .../matrix/api/room/RoomIsDmCheck.kt | 8 +- ...oomMembersState.kt => RoomMembersState.kt} | 22 +- .../api/room/RoomNotificationSettingsState.kt | 24 + .../matrix/api/room/alias/MatrixRoomAlias.kt | 4 +- .../powerlevels/MatrixRoomMembersWithRole.kt | 4 +- .../room/powerlevels/MatrixRoomPowerLevels.kt | 70 -- .../api/room/powerlevels/RoomPowerLevels.kt | 70 ++ .../api/room/recent/RecentDirectRoom.kt | 4 +- .../matrix/api/roomlist/RoomSummary.kt | 4 +- .../libraries/matrix/impl/RustMatrixClient.kt | 49 +- .../matrix/impl/analytics/JoinedRoomExt.kt | 4 +- .../{RustMatrixRoom.kt => JoinedRustRoom.kt} | 598 ++++++------------ .../matrix/impl/room/NotJoinedRustRoom.kt | 35 + ...rixRoomInfoMapper.kt => RoomInfoMapper.kt} | 46 +- .../matrix/impl/room/RustBaseRoom.kt | 267 ++++++++ .../matrix/impl/room/RustRoomFactory.kt | 197 +++--- .../matrix/impl/room/RustRoomPreview.kt | 59 -- .../impl/room/member/RoomMemberListFetcher.kt | 22 +- .../room/powerlevels/RoomPowerLevelsMapper.kt | 6 +- .../impl/roomlist/RoomSummaryFactory.kt | 4 +- .../matrix/impl/timeline/RustTimeline.kt | 17 +- ...nedRoomExtKtTest.kt => JoinedExtKtTest.kt} | 18 +- ...nfoMapperTest.kt => RoomInfoMapperTest.kt} | 12 +- .../impl/room/join/DefaultJoinRoomTest.kt | 8 +- .../room/member/RoomMemberListFetcherTest.kt | 48 +- .../powerlevels/RoomPowerLevelsMapperTest.kt | 4 +- ...st.kt => RustBaseRoomDirectoryListTest.kt} | 2 +- ...kt => RustBaseRoomDirectoryServiceTest.kt} | 2 +- ...Test.kt => RustBaseRoomListServiceTest.kt} | 2 +- .../matrix/impl/timeline/RustTimelineTest.kt | 8 +- .../libraries/matrix/test/FakeMatrixClient.kt | 21 +- .../matrix/test/room/FakeBaseRoom.kt | 220 +++++++ .../{FakeMatrixRoom.kt => FakeJoinedRoom.kt} | 535 +++++----------- ...akeRoomPreview.kt => FakeNotJoinedRoom.kt} | 23 +- .../matrix/test/room/RoomInfoFixture.kt | 4 +- .../test/room/RoomPreviewInfoFixture.kt | 14 +- .../matrix/test/room/RoomSummaryFixture.kt | 6 +- .../test/timeline/LiveTimelineProvider.kt | 4 +- .../matrix/ui/model/RoomInfoExtension.kt | 4 +- .../matrix/ui/room/MatrixRoomMembers.kt | 12 +- .../matrix/ui/room/MatrixRoomState.kt | 32 +- .../ObserveRoomMemberIdentityStateChange.kt | 6 +- ...xRoomMembersTest.kt => RoomMembersTest.kt} | 60 +- .../libraries/mediaupload/api/MediaSender.kt | 6 +- .../mediaupload/api/MediaSenderTest.kt | 14 +- ...edTimelineMediaGalleryDataSourceFactory.kt | 4 +- .../impl/datasource/MediaGalleryDataSource.kt | 4 +- .../impl/datasource/MediaTimeline.kt | 6 +- .../impl/gallery/MediaGalleryPresenter.kt | 4 +- .../impl/viewer/MediaViewerPresenter.kt | 4 +- ...melineMediaGalleryDataSourceFactoryTest.kt | 4 +- .../datasource/FocusedMediaTimelineTest.kt | 10 +- .../impl/datasource/LiveMediaTimelineTest.kt | 8 +- .../TimelineMediaGalleryDataSourceTest.kt | 18 +- .../impl/gallery/MediaGalleryPresenterTest.kt | 39 +- .../impl/viewer/MediaViewerPresenterTest.kt | 35 +- .../NotificationBroadcastReceiverHandler.kt | 6 +- .../push/impl/push/SyncOnNotifiableEvent.kt | 9 +- ...DefaultBaseRoomGroupMessageCreatorTest.kt} | 2 +- ...otificationBroadcastReceiverHandlerTest.kt | 39 +- .../impl/push/SyncOnNotifiableEventTest.kt | 11 +- .../impl/file/DefaultVoiceFileManager.kt | 4 +- .../main/kotlin/extension/KoverExtension.kt | 2 +- 193 files changed, 2921 insertions(+), 2567 deletions(-) rename appnav/src/test/kotlin/io/element/android/appnav/{JoinRoomLoadedFlowNodeTest.kt => JoinBaseRoomLoadedFlowNodeTest.kt} (93%) rename appnav/src/test/kotlin/io/element/android/appnav/room/{LoadingRoomStateFlowFactoryTest.kt => LoadingBaseRoomStateFlowFactoryTest.kt} (87%) rename features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/{ConfigureRoomPresenterTest.kt => ConfigureBaseRoomPresenterTest.kt} (99%) rename features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/{JoinRoomByAddressPresenterTest.kt => JoinBaseRoomByAddressPresenterTest.kt} (99%) rename features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/{JoinRoomByAddressViewTest.kt => JoinBaseRoomByAddressViewTest.kt} (98%) rename features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/{CreateRoomRootPresenterTest.kt => CreateBaseRoomRootPresenterTest.kt} (99%) rename features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/{CreateRoomRootViewTest.kt => CreateBaseRoomRootViewTest.kt} (99%) rename features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/{JoinRoomPresenterTest.kt => JoinBaseRoomPresenterTest.kt} (98%) rename features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/{JoinRoomViewTest.kt => JoinBaseRoomViewTest.kt} (99%) rename features/leaveroom/impl/src/test/kotlin/io/element/android/features/leaveroom/impl/{LeaveRoomPresenterTest.kt => LeaveBaseRoomPresenterTest.kt} (94%) rename features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/{PowerLevelRoomMemberComparatorTest.kt => PowerLevelBaseRoomMemberComparatorTest.kt} (98%) rename features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/{ChangeRoomPermissionsPresenterTest.kt => ChangeBaseRoomPermissionsPresenterTest.kt} (94%) rename features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/{ChangeRoomPermissionsViewTest.kt => ChangeBaseRoomPermissionsViewTest.kt} (99%) rename features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/{EditRoomAddressPresenterTest.kt => EditBaseRoomAddressPresenterTest.kt} (96%) rename features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/{EditRoomAddressViewTest.kt => EditBaseRoomAddressViewTest.kt} (99%) rename features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/{RoomListRoomSummaryTest.kt => RoomListBaseRoomSummaryTest.kt} (99%) rename libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/{DefaultRoomLastMessageFormatterTest.kt => DefaultBaseRoomLastMessageFormatterTest.kt} (99%) create mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt rename libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/{MatrixRoom.kt => JoinedRoom.kt} (72%) delete mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomNotificationSettingsState.kt rename libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/{RoomPreview.kt => NotJoinedRoom.kt} (60%) rename libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/{MatrixRoomInfo.kt => RoomInfo.kt} (99%) rename libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/{MatrixRoomMembersState.kt => RoomMembersState.kt} (56%) create mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomNotificationSettingsState.kt delete mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt create mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/RoomPowerLevels.kt rename libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/{RustMatrixRoom.kt => JoinedRustRoom.kt} (68%) create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/NotJoinedRustRoom.kt rename libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/{MatrixRoomInfoMapper.kt => RoomInfoMapper.kt} (70%) create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt delete mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomPreview.kt rename libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/analytics/{JoinedRoomExtKtTest.kt => JoinedExtKtTest.kt} (81%) rename libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/{MatrixRoomInfoMapperTest.kt => RoomInfoMapperTest.kt} (97%) rename libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/{RustRoomDirectoryListTest.kt => RustBaseRoomDirectoryListTest.kt} (98%) rename libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/{RustRoomDirectoryServiceTest.kt => RustBaseRoomDirectoryServiceTest.kt} (94%) rename libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/{RustRoomListServiceTest.kt => RustBaseRoomListServiceTest.kt} (98%) create mode 100644 libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt rename libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/{FakeMatrixRoom.kt => FakeJoinedRoom.kt} (54%) rename libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/{FakeRoomPreview.kt => FakeNotJoinedRoom.kt} (54%) rename libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/{MatrixRoomMembersTest.kt => RoomMembersTest.kt} (75%) rename libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/{DefaultRoomGroupMessageCreatorTest.kt => DefaultBaseRoomGroupMessageCreatorTest.kt} (99%) diff --git a/app/src/main/kotlin/io/element/android/x/di/DefaultRoomComponentFactory.kt b/app/src/main/kotlin/io/element/android/x/di/DefaultRoomComponentFactory.kt index 5ed8e89e24..fb7a24ae8a 100644 --- a/app/src/main/kotlin/io/element/android/x/di/DefaultRoomComponentFactory.kt +++ b/app/src/main/kotlin/io/element/android/x/di/DefaultRoomComponentFactory.kt @@ -10,14 +10,17 @@ package io.element.android.x.di import com.squareup.anvil.annotations.ContributesBinding import io.element.android.appnav.di.RoomComponentFactory import io.element.android.libraries.di.SessionScope -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import javax.inject.Inject @ContributesBinding(SessionScope::class) class DefaultRoomComponentFactory @Inject constructor( private val roomComponentBuilder: RoomComponent.Builder ) : RoomComponentFactory { - override fun create(room: MatrixRoom): Any { - return roomComponentBuilder.room(room).build() + override fun create(room: JoinedRoom): Any { + return roomComponentBuilder + .joinedRoom(room) + .baseRoom(room) + .build() } } diff --git a/app/src/main/kotlin/io/element/android/x/di/RoomComponent.kt b/app/src/main/kotlin/io/element/android/x/di/RoomComponent.kt index e595818051..ac126ce0f0 100644 --- a/app/src/main/kotlin/io/element/android/x/di/RoomComponent.kt +++ b/app/src/main/kotlin/io/element/android/x/di/RoomComponent.kt @@ -14,7 +14,8 @@ import io.element.android.libraries.architecture.NodeFactoriesBindings import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SingleIn -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom @SingleIn(RoomScope::class) @MergeSubcomponent(RoomScope::class) @@ -22,7 +23,11 @@ interface RoomComponent : NodeFactoriesBindings { @MergeSubcomponent.Builder interface Builder { @BindsInstance - fun room(room: MatrixRoom): Builder + fun joinedRoom(room: JoinedRoom): Builder + + @BindsInstance + fun baseRoom(room: BaseRoom): Builder + fun build(): RoomComponent } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt b/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt index 16575f1a91..4911ab50b5 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/di/RoomComponentFactory.kt @@ -7,8 +7,8 @@ package io.element.android.appnav.di -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom interface RoomComponentFactory { - fun create(room: MatrixRoom): Any + fun create(room: JoinedRoom): Any } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/SendQueues.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/SendQueues.kt index 8e66baf836..cbb247569a 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/SendQueues.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/SendQueues.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import timber.log.Timber import javax.inject.Inject @VisibleForTesting @@ -42,7 +43,9 @@ class SendQueues @Inject constructor( ) { syncState, _ -> syncState } .debounce(SEND_QUEUES_RETRY_DELAY_MILLIS) .onEach { syncState -> + Timber.tag("SendQueues").d("Sync state changed: $syncState") if (syncState == SyncState.Running) { + Timber.tag("SendQueues").d("Enabling send queues again") matrixClient.setAllSendQueuesEnabled(enabled = true) } } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt index 543c2558e1..094009f3d3 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt @@ -35,7 +35,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.permalink.PermalinkData -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.services.appnavstate.api.AppNavigationStateService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -72,7 +72,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor( } data class Inputs( - val room: MatrixRoom, + val room: JoinedRoom, val initialElement: RoomNavigationTarget, ) : NodeInputs @@ -95,6 +95,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor( }, onDestroy = { Timber.v("OnDestroy") + inputs.room.destroy() appNavigationStateService.onLeavingRoom(id) } ) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/LoadingRoomState.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/LoadingRoomState.kt index adba822ff7..14ead1be9a 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/LoadingRoomState.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/LoadingRoomState.kt @@ -13,7 +13,7 @@ import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SingleIn import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted @@ -27,7 +27,7 @@ import javax.inject.Inject sealed interface LoadingRoomState { data object Loading : LoadingRoomState data object Error : LoadingRoomState - data class Loaded(val room: MatrixRoom) : LoadingRoomState + data class Loaded(val room: JoinedRoom) : LoadingRoomState } open class LoadingRoomStateProvider : PreviewParameterProvider { @@ -41,7 +41,7 @@ open class LoadingRoomStateProvider : PreviewParameterProvider @SingleIn(SessionScope::class) class LoadingRoomStateFlowFactory @Inject constructor(private val matrixClient: MatrixClient) { fun create(lifecycleScope: CoroutineScope, roomId: RoomId): StateFlow = - getRoomFlow(roomId) + getJoinedRoomFlow(roomId) .map { room -> if (room != null) { LoadingRoomState.Loaded(room) @@ -51,8 +51,8 @@ class LoadingRoomStateFlowFactory @Inject constructor(private val matrixClient: } .stateIn(lifecycleScope, SharingStarted.Eagerly, LoadingRoomState.Loading) - private fun getRoomFlow(roomId: RoomId): Flow = suspend { - matrixClient.getRoom(roomId = roomId) + private fun getJoinedRoomFlow(roomId: RoomId): Flow = suspend { + matrixClient.getJoinedRoom(roomId = roomId) } .asFlow() } diff --git a/appnav/src/test/kotlin/io/element/android/appnav/JoinRoomLoadedFlowNodeTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/JoinBaseRoomLoadedFlowNodeTest.kt similarity index 93% rename from appnav/src/test/kotlin/io/element/android/appnav/JoinRoomLoadedFlowNodeTest.kt rename to appnav/src/test/kotlin/io/element/android/appnav/JoinBaseRoomLoadedFlowNodeTest.kt index be317701bb..bb15ed6bb9 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/JoinRoomLoadedFlowNodeTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/JoinBaseRoomLoadedFlowNodeTest.kt @@ -23,16 +23,17 @@ import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode import io.element.android.features.messages.api.MessagesEntryPoint import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint import io.element.android.libraries.architecture.childNode -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.services.appnavstate.test.FakeAppNavigationStateService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -class JoinRoomLoadedFlowNodeTest { +class JoinBaseRoomLoadedFlowNodeTest { @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule() @@ -68,7 +69,7 @@ class JoinRoomLoadedFlowNodeTest { } private class FakeRoomComponentFactory : RoomComponentFactory { - override fun create(room: MatrixRoom): Any { + override fun create(room: JoinedRoom): Any { return Unit } } @@ -114,9 +115,7 @@ class JoinRoomLoadedFlowNodeTest { @Test fun `given a room flow node when initialized then it loads messages entry point`() = runTest { // GIVEN - val room = FakeMatrixRoom( - updateMembersResult = { } - ) + val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {})) val fakeMessagesEntryPoint = FakeMessagesEntryPoint() val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages()) val roomFlowNode = createJoinedRoomLoadedFlowNode( @@ -137,9 +136,7 @@ class JoinRoomLoadedFlowNodeTest { @Test fun `given a room flow node when callback on room details is triggered then it loads room details entry point`() = runTest { // GIVEN - val room = FakeMatrixRoom( - updateMembersResult = { } - ) + val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(updateMembersResult = {})) val fakeMessagesEntryPoint = FakeMessagesEntryPoint() val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint() val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages()) diff --git a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/SendQueuesTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/SendQueuesTest.kt index 597139c5e9..c117dfb8f7 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/SendQueuesTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/SendQueuesTest.kt @@ -10,7 +10,7 @@ package io.element.android.appnav.loggedin import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.sync.SyncState import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.lambdaRecorder @@ -35,8 +35,8 @@ class SendQueuesTest { matrixClient.sendQueueDisabledFlow = sendQueueDisabledFlow matrixClient.setAllSendQueuesEnabledLambda = setAllSendQueuesEnabledLambda val setRoomSendQueueEnabledLambda = lambdaRecorder { _: Boolean -> } - val room = FakeMatrixRoom( - setSendQueueEnabledLambda = setRoomSendQueueEnabledLambda + val room = FakeJoinedRoom( + setSendQueueEnabledResult = setRoomSendQueueEnabledLambda ) matrixClient.givenGetRoomResult(room.roomId, room) sut.launchIn(backgroundScope) @@ -61,8 +61,8 @@ class SendQueuesTest { matrixClient.setAllSendQueuesEnabledLambda = setAllSendQueuesEnabledLambda syncService.emitSyncState(SyncState.Offline) val setRoomSendQueueEnabledLambda = lambdaRecorder { _: Boolean -> } - val room = FakeMatrixRoom( - setSendQueueEnabledLambda = setRoomSendQueueEnabledLambda + val room = FakeJoinedRoom( + setSendQueueEnabledResult = setRoomSendQueueEnabledLambda ) matrixClient.givenGetRoomResult(room.roomId, room) diff --git a/appnav/src/test/kotlin/io/element/android/appnav/room/LoadingRoomStateFlowFactoryTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/room/LoadingBaseRoomStateFlowFactoryTest.kt similarity index 87% rename from appnav/src/test/kotlin/io/element/android/appnav/room/LoadingRoomStateFlowFactoryTest.kt rename to appnav/src/test/kotlin/io/element/android/appnav/room/LoadingBaseRoomStateFlowFactoryTest.kt index c94cbd229a..d27cf5b567 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/room/LoadingRoomStateFlowFactoryTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/room/LoadingBaseRoomStateFlowFactoryTest.kt @@ -15,15 +15,16 @@ import io.element.android.libraries.matrix.api.roomlist.RoomList import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import kotlinx.coroutines.test.runTest import org.junit.Test -class LoadingRoomStateFlowFactoryTest { +class LoadingBaseRoomStateFlowFactoryTest { @Test fun `flow should emit Loading and then Loaded when there is a room in cache`() = runTest { - val room = FakeMatrixRoom(sessionId = A_SESSION_ID, roomId = A_ROOM_ID) + val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(sessionId = A_SESSION_ID, roomId = A_ROOM_ID)) val matrixClient = FakeMatrixClient(A_SESSION_ID).apply { givenGetRoomResult(A_ROOM_ID, room) } @@ -38,7 +39,7 @@ class LoadingRoomStateFlowFactoryTest { @Test fun `flow should emit Loading and then Loaded when there is a room in cache after SS is loaded`() = runTest { - val room = FakeMatrixRoom(sessionId = A_SESSION_ID, roomId = A_ROOM_ID) + val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(sessionId = A_SESSION_ID, roomId = A_ROOM_ID)) val roomListService = FakeRoomListService() val matrixClient = FakeMatrixClient(A_SESSION_ID, roomListService = roomListService) val flowFactory = LoadingRoomStateFlowFactory(matrixClient) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt index 6baffd8143..68243193f4 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt @@ -241,7 +241,7 @@ class CallScreenPresenter @AssistedInject constructor( private suspend fun MatrixClient.notifyCallStartIfNeeded(roomId: RoomId) { if (!notifiedCallStart) { - getRoom(roomId)?.sendCallNotificationIfNeeded() + getJoinedRoom(roomId)?.sendCallNotificationIfNeeded() ?.onSuccess { notifiedCallStart = true } } } diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt index a4c05e8e5c..1b6538e196 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/DefaultCallWidgetProvider.kt @@ -33,7 +33,7 @@ class DefaultCallWidgetProvider @Inject constructor( theme: String?, ): Result = runCatching { val matrixClient = matrixClientsProvider.getOrRestore(sessionId).getOrThrow() - val room = matrixClient.getRoom(roomId) ?: error("Room not found") + val room = matrixClient.getJoinedRoom(roomId) ?: error("Room not found") val customBaseUrl = appPreferencesStore.getCustomElementCallBaseUrlFlow().firstOrNull() val baseUrl = customBaseUrl ?: EMBEDDED_CALL_WIDGET_BASE_URL diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt index 5ec48ce6a1..43a1e7ceba 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt @@ -26,7 +26,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver import io.element.android.libraries.network.useragent.UserAgentProvider @@ -84,7 +84,7 @@ import kotlin.time.Duration.Companion.seconds fun `present - with CallType RoomCall sets call as active, loads URL, runs WidgetDriver and notifies the other clients a call started`() = runTest { val sendCallNotificationIfNeededLambda = lambdaRecorder> { Result.success(Unit) } val syncService = FakeSyncService(SyncState.Running) - val fakeRoom = FakeMatrixRoom(sendCallNotificationIfNeededResult = sendCallNotificationIfNeededLambda) + val fakeRoom = FakeJoinedRoom(sendCallNotificationIfNeededResult = sendCallNotificationIfNeededLambda) val client = FakeMatrixClient(syncService = syncService).apply { givenGetRoomResult(A_ROOM_ID, fakeRoom) } diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt index d6e06882a2..5f7309344a 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt @@ -28,7 +28,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.push.api.notifications.ForegroundServiceType import io.element.android.libraries.push.api.notifications.NotificationIdProvider @@ -227,7 +227,7 @@ class DefaultActiveCallManagerTest { @OptIn(ExperimentalCoroutinesApi::class) @Test fun `observeRingingCalls - will cancel the active ringing call if the call is cancelled`() = runTest { - val room = FakeMatrixRoom().apply { + val room = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo()) } val client = FakeMatrixClient().apply { @@ -254,7 +254,7 @@ class DefaultActiveCallManagerTest { @OptIn(ExperimentalCoroutinesApi::class) @Test fun `observeRingingCalls - will do nothing if either the session or the room are not found`() = runTest { - val room = FakeMatrixRoom().apply { + val room = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo()) } val client = FakeMatrixClient().apply { diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProviderTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProviderTest.kt index 66a85d1c36..cd81533a47 100644 --- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProviderTest.kt +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultCallWidgetProviderTest.kt @@ -15,7 +15,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.widget.FakeCallWidgetSettingsProvider import io.element.android.libraries.matrix.test.widget.FakeMatrixWidgetDriver import io.element.android.libraries.preferences.api.store.AppPreferencesStore @@ -41,7 +41,7 @@ class DefaultCallWidgetProviderTest { @Test fun `getWidget - fails if it can't generate the URL for the widget`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( generateWidgetWebViewUrlResult = { _, _, _, _ -> Result.failure(Exception("Can't generate URL for widget")) } ) val client = FakeMatrixClient().apply { @@ -53,7 +53,7 @@ class DefaultCallWidgetProviderTest { @Test fun `getWidget - fails if it can't get the widget driver`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( generateWidgetWebViewUrlResult = { _, _, _, _ -> Result.success("url") }, getWidgetDriverResult = { Result.failure(Exception("Can't get a widget driver")) } ) @@ -66,7 +66,7 @@ class DefaultCallWidgetProviderTest { @Test fun `getWidget - returns a widget driver when all steps are successful`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( generateWidgetWebViewUrlResult = { _, _, _, _ -> Result.success("url") }, getWidgetDriverResult = { Result.success(FakeMatrixWidgetDriver()) }, ) @@ -79,7 +79,7 @@ class DefaultCallWidgetProviderTest { @Test fun `getWidget - will use a custom base url if it exists`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( generateWidgetWebViewUrlResult = { _, _, _, _ -> Result.success("url") }, getWidgetDriverResult = { Result.success(FakeMatrixWidgetDriver()) }, ) diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureBaseRoomPresenterTest.kt similarity index 99% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTest.kt rename to features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureBaseRoomPresenterTest.kt index 60698b8e98..d8a7085f0d 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureBaseRoomPresenterTest.kt @@ -66,7 +66,7 @@ private const val AN_URI_FROM_CAMERA_2 = "content://uri_from_camera_2" private const val AN_URI_FROM_GALLERY = "content://uri_from_gallery" @RunWith(RobolectricTestRunner::class) -class ConfigureRoomPresenterTest { +class ConfigureBaseRoomPresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressPresenterTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt similarity index 99% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressPresenterTest.kt rename to features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt index d1ee3e801c..10cca20fa3 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressPresenterTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt @@ -21,7 +21,7 @@ import io.element.android.tests.testutils.test import kotlinx.coroutines.test.runTest import org.junit.Test -class JoinRoomByAddressPresenterTest { +class JoinBaseRoomByAddressPresenterTest { @Test fun `present - initial state`() = runTest { val presenter = createJoinRoomByAddressPresenter() diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressViewTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt similarity index 98% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressViewTest.kt rename to features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt index bb3ee3e493..93db738d35 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressViewTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt @@ -23,7 +23,7 @@ import org.junit.rules.TestRule import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class JoinRoomByAddressViewTest { +class JoinBaseRoomByAddressViewTest { @get:Rule val rule = createAndroidComposeRule() diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootPresenterTest.kt similarity index 99% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTest.kt rename to features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootPresenterTest.kt index 2d81580319..54cd1d201c 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootPresenterTest.kt @@ -36,7 +36,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -class CreateRoomRootPresenterTest { +class CreateBaseRoomRootPresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootViewTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootViewTest.kt similarity index 99% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootViewTest.kt rename to features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootViewTest.kt index 239248a57c..9104b2dfb2 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootViewTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootViewTest.kt @@ -33,7 +33,7 @@ import org.junit.runner.RunWith import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) -class CreateRoomRootViewTest { +class CreateBaseRoomRootViewTest { @get:Rule val rule = createAndroidComposeRule() diff --git a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt index e02642c32e..1e5b20d034 100644 --- a/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt +++ b/features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt @@ -121,7 +121,7 @@ class AcceptDeclineInvitePresenter @Inject constructor( declinedAction: MutableState>, ) = launch { suspend { - client.getPendingRoom(inviteData.roomId)?.use { + client.getRoom(inviteData.roomId)?.use { it.leave().getOrThrow() } if (blockUser) { diff --git a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt index 7feaff091e..bb8dc09b79 100644 --- a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt +++ b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt @@ -28,7 +28,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeRoomPreview +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom import io.element.android.libraries.push.api.notifications.NotificationCleaner import io.element.android.libraries.push.test.notifications.FakeNotificationCleaner @@ -88,11 +88,9 @@ class AcceptDeclineInvitePresenterTest { val declineInviteFailure = lambdaRecorder { -> Result.failure(RuntimeException("Failed to leave room")) } - val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> - Result.success(FakeRoomPreview(declineInviteResult = declineInviteFailure)) - } - ) + val client = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, FakeBaseRoom(leaveRoomLambda = declineInviteFailure)) + } val seenInvitesStore = InMemorySeenInvitesStore(setOf(A_ROOM_ID, A_ROOM_ID_2, A_ROOM_ID_3)) val presenter = createAcceptDeclineInvitePresenter( client = client, @@ -138,11 +136,9 @@ class AcceptDeclineInvitePresenterTest { val declineInviteSuccess = lambdaRecorder { -> Result.success(Unit) } - val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> - Result.success(FakeRoomPreview(declineInviteResult = declineInviteSuccess)) - } - ) + val client = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, FakeBaseRoom(leaveRoomLambda = declineInviteSuccess)) + } val seenInvitesStore = InMemorySeenInvitesStore(setOf(A_ROOM_ID, A_ROOM_ID_2, A_ROOM_ID_3)) val presenter = createAcceptDeclineInvitePresenter( client = client, @@ -186,11 +182,10 @@ class AcceptDeclineInvitePresenterTest { val declineInviteSuccess = lambdaRecorder { -> Result.success(Unit) } val ignoreUserSuccess = lambdaRecorder { _: UserId -> Result.success(Unit) } val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> - Result.success(FakeRoomPreview(declineInviteResult = declineInviteSuccess)) - }, ignoreUserResult = ignoreUserSuccess - ) + ).apply { + givenGetRoomResult(A_ROOM_ID, FakeBaseRoom(leaveRoomLambda = declineInviteSuccess)) + } val seenInvitesStore = InMemorySeenInvitesStore(setOf(A_ROOM_ID, A_ROOM_ID_2, A_ROOM_ID_3)) val presenter = createAcceptDeclineInvitePresenter( client = client, @@ -229,11 +224,9 @@ class AcceptDeclineInvitePresenterTest { val declineInviteFailure = lambdaRecorder { -> Result.failure(RuntimeException("Failed to leave room")) } - val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> - Result.success(FakeRoomPreview(declineInviteResult = declineInviteFailure)) - } - ) + val client = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, FakeBaseRoom(leaveRoomLambda = declineInviteFailure)) + } val seenInvitesStore = InMemorySeenInvitesStore(setOf(A_ROOM_ID, A_ROOM_ID_2, A_ROOM_ID_3)) val presenter = createAcceptDeclineInvitePresenter( client = client, diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt index 53f33be16a..a7c0f27fdd 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt @@ -44,7 +44,7 @@ import io.element.android.libraries.matrix.api.exception.ClientException import io.element.android.libraries.matrix.api.exception.ErrorKind import io.element.android.libraries.matrix.api.getRoomInfoFlow import io.element.android.libraries.matrix.api.room.CurrentUserMembership -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomType import io.element.android.libraries.matrix.api.room.isDm @@ -131,7 +131,7 @@ class JoinRoomPresenter @AssistedInject constructor( val result = matrixClient.getRoomPreview(roomIdOrAlias, serverNames) value = result.fold( onSuccess = { preview -> - val membershipInfo = when (preview.info.membership) { + val membershipInfo = when (preview.previewInfo.membership) { CurrentUserMembership.INVITED, CurrentUserMembership.BANNED, CurrentUserMembership.KNOCKED -> { @@ -139,7 +139,7 @@ class JoinRoomPresenter @AssistedInject constructor( } else -> null } - preview.info.toContentState( + preview.previewInfo.toContentState( senderMember = membershipInfo?.senderMember, reason = membershipInfo?.currentUserMember?.membershipChangeReason, ) @@ -296,7 +296,7 @@ internal fun RoomDescription.toContentState(): ContentState { } @VisibleForTesting -internal fun MatrixRoomInfo.toContentState(membershipSender: RoomMember?, reason: String?): ContentState { +internal fun RoomInfo.toContentState(membershipSender: RoomMember?, reason: String?): ContentState { return ContentState.Loaded( roomId = id, name = name, diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/CancelKnockRoom.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/CancelKnockRoom.kt index 2d885229bd..7826a819c6 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/CancelKnockRoom.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/CancelKnockRoom.kt @@ -21,8 +21,8 @@ interface CancelKnockRoom { class DefaultCancelKnockRoom @Inject constructor(private val client: MatrixClient) : CancelKnockRoom { override suspend fun invoke(roomId: RoomId): Result { return client - .getPendingRoom(roomId) - ?.leave() + .getRoom(roomId) + ?.use { it.leave() } ?: Result.failure(IllegalStateException("No pending room found")) } } diff --git a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/ForgetRoom.kt b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/ForgetRoom.kt index 496a911b1b..ac17e2c3e2 100644 --- a/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/ForgetRoom.kt +++ b/features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/ForgetRoom.kt @@ -20,9 +20,7 @@ interface ForgetRoom { @ContributesBinding(SessionScope::class) class DefaultForgetRoom @Inject constructor(private val client: MatrixClient) : ForgetRoom { override suspend fun invoke(roomId: RoomId): Result { - return client - .getPendingRoom(roomId) - ?.forget() - ?: Result.failure(IllegalStateException("No pending room found")) + return client.getRoom(roomId)?.use { it.forget() } + ?: Result.failure(IllegalStateException("Room not found")) } } diff --git a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinBaseRoomPresenterTest.kt similarity index 98% rename from features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt rename to features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinBaseRoomPresenterTest.kt index 7d151e5530..267b0c83c7 100644 --- a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt +++ b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinBaseRoomPresenterTest.kt @@ -64,7 +64,7 @@ import org.junit.Test import java.util.Optional @Suppress("LargeClass") -class JoinRoomPresenterTest { +class JoinBaseRoomPresenterTest { @get:Rule val warmUpRule = WarmUpRule() @@ -273,7 +273,7 @@ class JoinRoomPresenterTest { fun `present - when room is banned, then join authorization is equal to IsBanned`() = runTest { val roomSummary = aRoomSummary(currentUserMembership = CurrentUserMembership.BANNED, joinRule = JoinRule.Public) val matrixClient = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.success( aRoomPreview( info = aRoomPreviewInfo( @@ -546,7 +546,7 @@ class JoinRoomPresenterTest { @Test fun `present - when room is not known RoomPreview is loaded`() = runTest { val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.success( aRoomPreview( info = aRoomPreviewInfo( @@ -591,7 +591,7 @@ class JoinRoomPresenterTest { @Test fun `present - when room is not known RoomPreview is loaded as Private`() = runTest { val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.success( aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.Private)) ) @@ -611,7 +611,7 @@ class JoinRoomPresenterTest { @Test fun `present - when room is not known RoomPreview is loaded as Custom`() = runTest { val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.success( aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.Custom("custom"))) ) @@ -631,7 +631,7 @@ class JoinRoomPresenterTest { @Test fun `present - when room is not known RoomPreview is loaded as Invite`() = runTest { val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.success( aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.Invite)) ) @@ -651,7 +651,7 @@ class JoinRoomPresenterTest { @Test fun `present - when room is not known RoomPreview is loaded as KnockRestricted`() = runTest { val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.success( aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.KnockRestricted(emptyList()))) ) @@ -671,7 +671,7 @@ class JoinRoomPresenterTest { @Test fun `present - when room is not known RoomPreview is loaded as Restricted`() = runTest { val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.success( aRoomPreview(info = aRoomPreviewInfo(joinRule = JoinRule.Restricted(emptyList()))) ) @@ -691,7 +691,7 @@ class JoinRoomPresenterTest { @Test fun `present - when room is not known RoomPreview is loaded as Space`() = runTest { val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.success( aRoomPreview(info = aRoomPreviewInfo(isSpace = true)) ) @@ -711,7 +711,7 @@ class JoinRoomPresenterTest { @Test fun `present - when room is not known RoomPreview is loaded with error`() = runTest { val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.failure(AN_EXCEPTION) } ) @@ -741,7 +741,7 @@ class JoinRoomPresenterTest { @Test fun `present - when room is not known RoomPreview is loaded with error Forbidden`() = runTest { val client = FakeMatrixClient( - getRoomPreviewResult = { _, _ -> + getNotJoinedRoomResult = { _, _ -> Result.failure(ClientException.MatrixApi(ErrorKind.Forbidden, "403", "Forbidden", null)) } ) diff --git a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinBaseRoomViewTest.kt similarity index 99% rename from features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt rename to features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinBaseRoomViewTest.kt index e9ac23d76e..6d5a78999a 100644 --- a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomViewTest.kt +++ b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinBaseRoomViewTest.kt @@ -25,7 +25,7 @@ import org.junit.rules.TestRule import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class JoinRoomViewTest { +class JoinBaseRoomViewTest { @get:Rule val rule = createAndroidComposeRule() @Test diff --git a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/data/KnockRequestPermissions.kt b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/data/KnockRequestPermissions.kt index 901d496836..4de596a623 100644 --- a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/data/KnockRequestPermissions.kt +++ b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/data/KnockRequestPermissions.kt @@ -7,7 +7,7 @@ package io.element.android.features.knockrequests.impl.data -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.powerlevels.canBan import io.element.android.libraries.matrix.api.room.powerlevels.canInvite import io.element.android.libraries.matrix.api.room.powerlevels.canKick @@ -22,7 +22,7 @@ data class KnockRequestPermissions( val canHandle = canAccept || canDecline || canBan } -fun MatrixRoom.knockRequestPermissionsFlow(): Flow { +fun JoinedRoom.knockRequestPermissionsFlow(): Flow { return syncUpdateFlow.map { val canAccept = canInvite().getOrDefault(false) val canDecline = canKick().getOrDefault(false) diff --git a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/data/KnockRequestsModule.kt b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/data/KnockRequestsModule.kt index dc3e177d7c..671208e97b 100644 --- a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/data/KnockRequestsModule.kt +++ b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/data/KnockRequestsModule.kt @@ -14,14 +14,14 @@ import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SingleIn import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom @Module @ContributesTo(RoomScope::class) object KnockRequestsModule { @Provides @SingleIn(RoomScope::class) - fun knockRequestsService(room: MatrixRoom, featureFlagService: FeatureFlagService): KnockRequestsService { + fun knockRequestsService(room: JoinedRoom, featureFlagService: FeatureFlagService): KnockRequestsService { return KnockRequestsService( knockRequestsFlow = room.knockRequestsFlow, permissionsFlow = room.knockRequestPermissionsFlow(), diff --git a/features/leaveroom/impl/src/test/kotlin/io/element/android/features/leaveroom/impl/LeaveRoomPresenterTest.kt b/features/leaveroom/impl/src/test/kotlin/io/element/android/features/leaveroom/impl/LeaveBaseRoomPresenterTest.kt similarity index 94% rename from features/leaveroom/impl/src/test/kotlin/io/element/android/features/leaveroom/impl/LeaveRoomPresenterTest.kt rename to features/leaveroom/impl/src/test/kotlin/io/element/android/features/leaveroom/impl/LeaveBaseRoomPresenterTest.kt index 22407c93d4..108c2ddb53 100644 --- a/features/leaveroom/impl/src/test/kotlin/io/element/android/features/leaveroom/impl/LeaveRoomPresenterTest.kt +++ b/features/leaveroom/impl/src/test/kotlin/io/element/android/features/leaveroom/impl/LeaveBaseRoomPresenterTest.kt @@ -16,7 +16,7 @@ import io.element.android.features.leaveroom.api.LeaveRoomState import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.assert @@ -30,7 +30,7 @@ import org.junit.Rule import org.junit.Test @OptIn(ExperimentalCoroutinesApi::class) -class LeaveRoomPresenterTest { +class LeaveBaseRoomPresenterTest { @get:Rule val warmUpRule = WarmUpRule() @@ -53,7 +53,7 @@ class LeaveRoomPresenterTest { client = FakeMatrixClient().apply { givenGetRoomResult( roomId = A_ROOM_ID, - result = FakeMatrixRoom().apply { + result = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo(isDirect = false, isPublic = true, joinedMembersCount = 10)) } ) @@ -75,7 +75,7 @@ class LeaveRoomPresenterTest { client = FakeMatrixClient().apply { givenGetRoomResult( roomId = A_ROOM_ID, - result = FakeMatrixRoom().apply { + result = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo(isPublic = false)) }, ) @@ -97,7 +97,7 @@ class LeaveRoomPresenterTest { client = FakeMatrixClient().apply { givenGetRoomResult( roomId = A_ROOM_ID, - result = FakeMatrixRoom().apply { + result = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo(joinedMembersCount = 1)) }, ) @@ -119,7 +119,7 @@ class LeaveRoomPresenterTest { client = FakeMatrixClient().apply { givenGetRoomResult( roomId = A_ROOM_ID, - result = FakeMatrixRoom().apply { + result = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo(isDirect = true, activeMembersCount = 2)) }, ) @@ -142,7 +142,7 @@ class LeaveRoomPresenterTest { client = FakeMatrixClient().apply { givenGetRoomResult( roomId = A_ROOM_ID, - result = FakeMatrixRoom( + result = FakeBaseRoom( leaveRoomLambda = leaveRoomLambda ), ) @@ -167,7 +167,7 @@ class LeaveRoomPresenterTest { client = FakeMatrixClient().apply { givenGetRoomResult( roomId = A_ROOM_ID, - result = FakeMatrixRoom( + result = FakeBaseRoom( leaveRoomLambda = { Result.failure(RuntimeException("Blimey!")) } ), ) @@ -191,7 +191,7 @@ class LeaveRoomPresenterTest { client = FakeMatrixClient().apply { givenGetRoomResult( roomId = A_ROOM_ID, - result = FakeMatrixRoom( + result = FakeBaseRoom( leaveRoomLambda = { Result.success(Unit) } ), ) @@ -215,7 +215,7 @@ class LeaveRoomPresenterTest { client = FakeMatrixClient().apply { givenGetRoomResult( roomId = A_ROOM_ID, - result = FakeMatrixRoom( + result = FakeBaseRoom( leaveRoomLambda = { Result.failure(RuntimeException("Blimey!")) } ), ) diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationPresenter.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationPresenter.kt index f5f6190855..ce2b06a8b2 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationPresenter.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/send/SendLocationPresenter.kt @@ -24,7 +24,7 @@ import io.element.android.features.location.impl.common.permissions.PermissionsS import io.element.android.features.messages.api.MessageComposerContext import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.meta.BuildMeta -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.location.AssetType import io.element.android.services.analytics.api.AnalyticsService import kotlinx.coroutines.launch @@ -32,7 +32,7 @@ import javax.inject.Inject class SendLocationPresenter @Inject constructor( permissionsPresenterFactory: PermissionsPresenter.Factory, - private val room: MatrixRoom, + private val room: JoinedRoom, private val analyticsService: AnalyticsService, private val messageComposerContext: MessageComposerContext, private val locationActions: LocationActions, diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/SendLocationPresenterTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/SendLocationPresenterTest.kt index 69a8d2d032..0c4bb5e067 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/SendLocationPresenterTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/send/SendLocationPresenterTest.kt @@ -20,12 +20,12 @@ import io.element.android.features.location.impl.common.permissions.PermissionsE import io.element.android.features.location.impl.common.permissions.PermissionsPresenter import io.element.android.features.location.impl.common.permissions.PermissionsState import io.element.android.features.messages.test.FakeMessageComposerContext -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.location.AssetType import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.core.aBuildMeta -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.textcomposer.model.MessageComposerMode import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.WarmUpRule @@ -47,12 +47,12 @@ class SendLocationPresenterTest { private val fakeBuildMeta = aBuildMeta(applicationName = "app name") private fun createSendLocationPresenter( - matrixRoom: MatrixRoom = FakeMatrixRoom(), + joinedRoom: JoinedRoom = FakeJoinedRoom(), ): SendLocationPresenter = SendLocationPresenter( permissionsPresenterFactory = object : PermissionsPresenter.Factory { override fun create(permissions: List): PermissionsPresenter = fakePermissionsPresenter }, - room = matrixRoom, + room = joinedRoom, analyticsService = fakeAnalyticsService, messageComposerContext = fakeMessageComposerContext, locationActions = fakeLocationActions, @@ -265,10 +265,10 @@ class SendLocationPresenterTest { val sendLocationResult = lambdaRecorder> { _, _, _, _, _ -> Result.success(Unit) } - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( sendLocationResult = sendLocationResult, ) - val sendLocationPresenter = createSendLocationPresenter(matrixRoom) + val sendLocationPresenter = createSendLocationPresenter(joinedRoom) fakePermissionsPresenter.givenState( aPermissionsState( permissions = PermissionsState.Permissions.AllGranted, @@ -326,10 +326,10 @@ class SendLocationPresenterTest { val sendLocationResult = lambdaRecorder> { _, _, _, _, _ -> Result.success(Unit) } - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( sendLocationResult = sendLocationResult, ) - val sendLocationPresenter = createSendLocationPresenter(matrixRoom) + val sendLocationPresenter = createSendLocationPresenter(joinedRoom) fakePermissionsPresenter.givenState( aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, @@ -387,10 +387,10 @@ class SendLocationPresenterTest { val sendLocationResult = lambdaRecorder> { _, _, _, _, _ -> Result.success(Unit) } - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( sendLocationResult = sendLocationResult, ) - val sendLocationPresenter = createSendLocationPresenter(matrixRoom) + val sendLocationPresenter = createSendLocationPresenter(joinedRoom) fakePermissionsPresenter.givenState( aPermissionsState( permissions = PermissionsState.Permissions.NoneGranted, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index 6feaa23b62..8f97b6bc19 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -69,7 +69,7 @@ import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.permalink.PermalinkData -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.alias.matches import io.element.android.libraries.matrix.api.room.joinedRoomMembers import io.element.android.libraries.matrix.api.timeline.Timeline @@ -101,7 +101,7 @@ class MessagesFlowNode @AssistedInject constructor( private val mediaViewerEntryPoint: MediaViewerEntryPoint, private val analyticsService: AnalyticsService, private val locationService: LocationService, - private val room: MatrixRoom, + private val room: BaseRoom, private val roomMemberProfilesCache: RoomMemberProfilesCache, private val roomNamesCache: RoomNamesCache, private val mentionSpanUpdater: MentionSpanUpdater, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt index 4ea6a1c9d3..d2d4b1c705 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt @@ -53,7 +53,7 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.permalink.PermalinkData import io.element.android.libraries.matrix.api.permalink.PermalinkParser -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.alias.matches import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.mediaplayer.api.MediaPlayer @@ -67,7 +67,7 @@ class MessagesNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val coroutineScope: CoroutineScope, - private val room: MatrixRoom, + private val room: BaseRoom, private val analyticsService: AnalyticsService, messageComposerPresenterFactory: MessageComposerPresenter.Factory, timelinePresenterFactory: TimelinePresenter.Factory, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index b5a1842212..8bf5d330d7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -65,10 +65,10 @@ import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.permalink.PermalinkParser -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.MessageEventType +import io.element.android.libraries.matrix.api.room.RoomInfo +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.room.powerlevels.canPinUnpin import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther @@ -90,7 +90,7 @@ import timber.log.Timber class MessagesPresenter @AssistedInject constructor( @Assisted private val navigator: MessagesNavigator, - private val room: MatrixRoom, + private val room: JoinedRoom, @Assisted private val composerPresenter: Presenter, private val voiceMessageComposerPresenter: Presenter, @Assisted private val timelinePresenter: Presenter, @@ -279,7 +279,7 @@ class MessagesPresenter @AssistedInject constructor( } } - private fun MatrixRoomInfo.avatarData(): AvatarData { + private fun RoomInfo.avatarData(): AvatarData { return AvatarData( id = id.value, name = name, @@ -288,7 +288,7 @@ class MessagesPresenter @AssistedInject constructor( ) } - private fun MatrixRoomInfo.heroes(): List { + private fun RoomInfo.heroes(): List { return heroes.map { user -> user.getAvatarData(size = AvatarSize.TimelineRoom) } @@ -382,8 +382,8 @@ class MessagesPresenter @AssistedInject constructor( inviteProgress.value = AsyncData.Loading() runCatching { val memberList = when (val memberState = room.membersStateFlow.value) { - is MatrixRoomMembersState.Ready -> memberState.roomMembers - is MatrixRoomMembersState.Error -> memberState.prevRoomMembers.orEmpty() + is RoomMembersState.Ready -> memberState.roomMembers + is RoomMembersState.Error -> memberState.prevRoomMembers.orEmpty() else -> emptyList() } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index 2ca03e09ea..ee4f278366 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -43,7 +43,7 @@ import io.element.android.libraries.di.RoomScope import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.preferences.api.store.AppPreferencesStore import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -63,7 +63,7 @@ class DefaultActionListPresenter @AssistedInject constructor( private val postProcessor: TimelineItemActionPostProcessor, private val appPreferencesStore: AppPreferencesStore, private val isPinnedMessagesFeatureEnabled: IsPinnedMessagesFeatureEnabled, - private val room: MatrixRoom, + private val room: BaseRoom, private val userSendFailureFactory: VerifiedUserSendFailureFactory, private val featureFlagService: FeatureFlagService, private val dateFormatter: DateFormatter, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenter.kt index 4e37f34559..7b5f07649b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenter.kt @@ -14,7 +14,7 @@ import androidx.compose.runtime.rememberCoroutineScope import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.EncryptionService -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.ui.room.observeRoomMemberIdentityStateChange import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CoroutineScope @@ -23,7 +23,7 @@ import timber.log.Timber import javax.inject.Inject class IdentityChangeStatePresenter @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val encryptionService: EncryptionService, ) : Presenter { @Composable diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/VerifiedUserSendFailureFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/VerifiedUserSendFailureFactory.kt index c1fe6fffb5..1052332403 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/VerifiedUserSendFailureFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/VerifiedUserSendFailureFactory.kt @@ -7,12 +7,12 @@ package io.element.android.features.messages.impl.crypto.sendfailure -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import javax.inject.Inject class VerifiedUserSendFailureFactory @Inject constructor( - private val room: MatrixRoom, + private val room: BaseRoom, ) { suspend fun create( sendState: LocalEventSendState?, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenter.kt index e947af8346..0373002f7e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenter.kt @@ -19,13 +19,13 @@ import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUser import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runUpdatingState -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import kotlinx.coroutines.launch import javax.inject.Inject class ResolveVerifiedUserSendFailurePresenter @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val verifiedUserSendFailureFactory: VerifiedUserSendFailureFactory, ) : Presenter { @Composable diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/VerifiedUserSendFailureResolver.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/VerifiedUserSendFailureResolver.kt index 29d6d7a186..166ce212dd 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/VerifiedUserSendFailureResolver.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/VerifiedUserSendFailureResolver.kt @@ -10,7 +10,7 @@ package io.element.android.features.messages.impl.crypto.sendfailure.resolve import androidx.compose.runtime.mutableStateOf import io.element.android.libraries.matrix.api.core.SendHandle import io.element.android.libraries.matrix.api.core.TransactionId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import timber.log.Timber @@ -21,7 +21,7 @@ import timber.log.Timber * This way, the user can resolve and resend the message for each user concerned, one by one. */ class VerifiedUserSendFailureResolver( - private val room: MatrixRoom, + private val room: JoinedRoom, private val transactionId: TransactionId, private val sendHandle: SendHandle, private val iterator: VerifiedUserSendFailureIterator, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/draft/MatrixComposerDraftStore.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/draft/MatrixComposerDraftStore.kt index cd9d55b281..b850e7b559 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/draft/MatrixComposerDraftStore.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/draft/MatrixComposerDraftStore.kt @@ -21,7 +21,7 @@ class MatrixComposerDraftStore @Inject constructor( private val client: MatrixClient, ) : ComposerDraftStore { override suspend fun loadDraft(roomId: RoomId): ComposerDraft? { - return client.getRoom(roomId)?.let { room -> + return client.getRoom(roomId)?.use { room -> room.loadComposerDraft() .onFailure { Timber.e(it, "Failed to load composer draft for room $roomId") @@ -35,7 +35,7 @@ class MatrixComposerDraftStore @Inject constructor( } override suspend fun updateDraft(roomId: RoomId, draft: ComposerDraft?) { - client.getRoom(roomId)?.let { room -> + client.getRoom(roomId)?.use { room -> val updateDraftResult = if (draft == null) { room.clearComposerDraft() } else { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt index 32142734e1..11bb0868e7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt @@ -49,7 +49,7 @@ import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.room.IntentionalMention -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.draft.ComposerDraft import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType import io.element.android.libraries.matrix.api.room.isDm @@ -98,7 +98,7 @@ import io.element.android.libraries.core.mimetype.MimeTypes.Any as AnyMimeTypes class MessageComposerPresenter @AssistedInject constructor( @Assisted private val navigator: MessagesNavigator, private val appCoroutineScope: CoroutineScope, - private val room: MatrixRoom, + private val room: JoinedRoom, private val mediaPickerProvider: PickerProvider, private val featureFlagService: FeatureFlagService, private val sessionPreferencesStore: SessionPreferencesStore, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessor.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessor.kt index 3b0e9a236a..5055d09a3b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessor.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessor.kt @@ -9,8 +9,8 @@ package io.element.android.features.messages.impl.messagecomposer.suggestions import io.element.android.libraries.core.data.filterUpTo import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion @@ -33,7 +33,7 @@ class SuggestionsProcessor @Inject constructor() { */ suspend fun process( suggestion: Suggestion?, - roomMembersState: MatrixRoomMembersState, + roomMembersState: RoomMembersState, roomAliasSuggestions: List, currentUserId: UserId, canSendRoomMention: suspend () -> Boolean, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/PinnedEventsTimelineProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/PinnedEventsTimelineProvider.kt index 1135dcb2d6..5210631409 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/PinnedEventsTimelineProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/PinnedEventsTimelineProvider.kt @@ -15,7 +15,7 @@ import io.element.android.libraries.di.SingleIn import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.room.CreateTimelineParams -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.TimelineProvider @@ -33,7 +33,7 @@ import javax.inject.Inject @SingleIn(RoomScope::class) class PinnedEventsTimelineProvider @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val syncService: SyncService, private val featureFlagService: FeatureFlagService, private val dispatchers: CoroutineDispatchers, @@ -62,6 +62,7 @@ class PinnedEventsTimelineProvider @Inject constructor( } } .launchIn(scope) + .invokeOnCompletion { timelineStateFlow.value.dataOrNull()?.close() } } private suspend fun onActive() = coroutineScope { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt index 2a446df0e8..21a137b363 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenter.kt @@ -20,7 +20,7 @@ import androidx.compose.runtime.setValue import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -32,7 +32,7 @@ import kotlinx.coroutines.flow.onEach import javax.inject.Inject class PinnedMessagesBannerPresenter @Inject constructor( - private val room: MatrixRoom, + private val room: BaseRoom, private val itemFactory: PinnedMessagesBannerItemFactory, private val pinnedEventsTimelineProvider: PinnedEventsTimelineProvider, ) : Presenter { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt index bb88c32f5f..82f98724f1 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt @@ -38,7 +38,7 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.powerlevels.canPinUnpin import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn @@ -60,7 +60,7 @@ import timber.log.Timber class PinnedMessagesListPresenter @AssistedInject constructor( @Assisted private val navigator: PinnedMessagesListNavigator, - private val room: MatrixRoom, + private val room: JoinedRoom, timelineItemsFactoryCreator: TimelineItemsFactory.Creator, private val timelineProvider: PinnedEventsTimelineProvider, private val timelineProtectionPresenter: Presenter, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/report/ReportMessagePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/report/ReportMessagePresenter.kt index 471641e6a5..538d9ce25a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/report/ReportMessagePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/report/ReportMessagePresenter.kt @@ -25,13 +25,13 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatch import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch class ReportMessagePresenter @AssistedInject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, @Assisted private val inputs: Inputs, private val snackbarDispatcher: SnackbarDispatcher, ) : Presenter { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineController.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineController.kt index 985d4f6076..4800d64c9b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineController.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineController.kt @@ -12,7 +12,7 @@ import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SingleIn import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.room.CreateTimelineParams -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.TimelineProvider @@ -42,7 +42,7 @@ import javax.inject.Inject @SingleIn(RoomScope::class) @ContributesBinding(RoomScope::class, boundType = TimelineProvider::class) class TimelineController @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, ) : Closeable, TimelineProvider { private val coroutineScope = CoroutineScope(SupervisorJob()) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt index 6ac01c990b..cc6c9c5860 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt @@ -38,7 +38,7 @@ import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.MessageEventType import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.room.roomMembers @@ -62,7 +62,7 @@ const val FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS = 200L class TimelinePresenter @AssistedInject constructor( timelineItemsFactoryCreator: TimelineItemsFactory.Creator, - private val room: MatrixRoom, + private val room: JoinedRoom, private val dispatchers: CoroutineDispatchers, private val appScope: CoroutineScope, @Assisted private val navigator: MessagesNavigator, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenter.kt index 648f3254e5..a5c7eb89be 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenter.kt @@ -15,7 +15,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.api.user.MatrixUser @@ -24,7 +24,7 @@ import kotlinx.collections.immutable.toImmutableList import javax.inject.Inject class ReactionSummaryPresenter @Inject constructor( - private val room: MatrixRoom, + private val room: BaseRoom, ) : Presenter { @Composable override fun present(): ReactionSummaryState { diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineProtectionPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineProtectionPresenter.kt index b04ee1f176..00cde0f880 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineProtectionPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineProtectionPresenter.kt @@ -13,19 +13,18 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MediaPreviewValue import io.element.android.libraries.matrix.api.media.isPreviewEnabled -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.preferences.api.store.AppPreferencesStore import kotlinx.collections.immutable.toImmutableSet import javax.inject.Inject class TimelineProtectionPresenter @Inject constructor( private val appPreferencesStore: AppPreferencesStore, - private val room: MatrixRoom, + private val room: BaseRoom, ) : Presenter { private val allowedEvents = mutableStateOf>(setOf()) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenter.kt index 4dfc02a2a1..7d293055a2 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenter.kt @@ -18,7 +18,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.preferences.api.store.SessionPreferencesStore @@ -32,7 +32,7 @@ import kotlinx.coroutines.flow.onEach import javax.inject.Inject class TypingNotificationPresenter @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val sessionPreferencesStore: SessionPreferencesStore, ) : Presenter { @Composable diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index ea6dfa0607..2a3c34feee 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -51,9 +51,8 @@ import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.permalink.PermalinkParser -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MessageEventType +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId @@ -70,7 +69,8 @@ import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.sync.FakeSyncService @@ -128,19 +128,21 @@ class MessagesPresenterTest { @OptIn(ExperimentalCoroutinesApi::class) @Test fun `present - check that the room's unread flag is removed`() = runTest { - val room = FakeMatrixRoom( - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, ) - assertThat(room.markAsReadCalls).isEmpty() - val presenter = createMessagesPresenter(matrixRoom = room) + assertThat(room.baseRoom.markAsReadCalls).isEmpty() + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { runCurrent() - assertThat(room.setUnreadFlagCalls).isEqualTo(listOf(false)) + assertThat(room.baseRoom.setUnreadFlagCalls).isEqualTo(listOf(false)) cancelAndIgnoreRemainingEvents() } } @@ -155,16 +157,18 @@ class MessagesPresenterTest { val timeline = FakeTimeline().apply { this.toggleReactionLambda = toggleReactionSuccess } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ), liveTimeline = timeline, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, ) - val presenter = createMessagesPresenter(matrixRoom = room, coroutineDispatchers = coroutineDispatchers) + val presenter = createMessagesPresenter(joinedRoom = room, coroutineDispatchers = coroutineDispatchers) presenter.testWithLifecycleOwner { skipItems(1) val initialState = awaitItem() @@ -189,16 +193,18 @@ class MessagesPresenterTest { val timeline = FakeTimeline().apply { this.toggleReactionLambda = toggleReactionSuccess } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ), liveTimeline = timeline, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, ) - val presenter = createMessagesPresenter(matrixRoom = room, coroutineDispatchers = coroutineDispatchers) + val presenter = createMessagesPresenter(joinedRoom = room, coroutineDispatchers = coroutineDispatchers) presenter.testWithLifecycleOwner { val initialState = awaitItem() initialState.eventSink(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID.toEventOrTransactionId())) @@ -245,18 +251,20 @@ class MessagesPresenterTest { fun `present - handle action copy link`() = runTest { val clipboardHelper = FakeClipboardHelper() val event = aMessageEvent() - val matrixRoom = FakeMatrixRoom( - eventPermalinkResult = { Result.success("a link") }, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + eventPermalinkResult = { Result.success("a link") }, + ), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, ) val presenter = createMessagesPresenter( clipboardHelper = clipboardHelper, - matrixRoom = matrixRoom, + joinedRoom = room, ) presenter.testWithLifecycleOwner { val initialState = awaitItem() @@ -466,20 +474,22 @@ class MessagesPresenterTest { val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) val liveTimeline = FakeTimeline() - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ), liveTimeline = liveTimeline, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, ) val redactEventLambda = lambdaRecorder { _: EventOrTransactionId, _: String? -> Result.success(Unit) } liveTimeline.redactEventLambda = redactEventLambda val presenter = createMessagesPresenter( - matrixRoom = matrixRoom, + joinedRoom = joinedRoom, coroutineDispatchers = coroutineDispatchers, ) presenter.testWithLifecycleOwner { @@ -535,18 +545,19 @@ class MessagesPresenterTest { @Test fun `present - shows prompt to reinvite users in DM`() = runTest { - val room = FakeMatrixRoom( - sessionId = A_SESSION_ID, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ).apply { + givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 1, activeMembersCount = 1)) + }, typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, - ).apply { - givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 1, activeMembersCount = 1)) - } - val presenter = createMessagesPresenter(matrixRoom = room) + ) + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { val initialState = awaitItem() // Initially the composer doesn't have focus, so we don't show the alert @@ -567,18 +578,19 @@ class MessagesPresenterTest { @Test fun `present - doesn't show reinvite prompt in non-direct room`() = runTest { - val room = FakeMatrixRoom( - sessionId = A_SESSION_ID, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ).apply { + givenRoomInfo(aRoomInfo(isDirect = false, joinedMembersCount = 1, activeMembersCount = 1)) + }, typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, - ).apply { - givenRoomInfo(aRoomInfo(isDirect = false, joinedMembersCount = 1, activeMembersCount = 1)) - } - val presenter = createMessagesPresenter(matrixRoom = room) + ) + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { val initialState = awaitItem() assertThat(initialState.showReinvitePrompt).isFalse() @@ -592,18 +604,19 @@ class MessagesPresenterTest { @Test fun `present - doesn't show reinvite prompt if other party is present`() = runTest { - val room = FakeMatrixRoom( - sessionId = A_SESSION_ID, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ).apply { + givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 2, activeMembersCount = 2)) + }, typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, - ).apply { - givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 2, activeMembersCount = 2)) - } - val presenter = createMessagesPresenter(matrixRoom = room) + ) + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { val initialState = awaitItem() assertThat(initialState.showReinvitePrompt).isFalse() @@ -618,25 +631,26 @@ class MessagesPresenterTest { @Test fun `present - handle reinviting other user when memberlist is ready`() = runTest { val inviteUserResult = lambdaRecorder { _: UserId -> Result.success(Unit) } - val room = FakeMatrixRoom( - sessionId = A_SESSION_ID, - inviteUserResult = inviteUserResult, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, + inviteUserResult = inviteUserResult, ) room.givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( persistentListOf( aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN), aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE), ) ) ) - val presenter = createMessagesPresenter(matrixRoom = room) + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { val initialState = consumeItemsUntilTimeout().last() initialState.eventSink(MessagesEvents.InviteDialogDismissed(InviteDialogAction.Invite)) @@ -652,18 +666,19 @@ class MessagesPresenterTest { @Test fun `present - handle reinviting other user when memberlist is error`() = runTest { val inviteUserResult = lambdaRecorder { _: UserId -> Result.success(Unit) } - val room = FakeMatrixRoom( - sessionId = A_SESSION_ID, - inviteUserResult = inviteUserResult, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, + inviteUserResult = inviteUserResult, ) room.givenRoomMembersState( - MatrixRoomMembersState.Error( + RoomMembersState.Error( failure = Throwable(), prevRoomMembers = persistentListOf( aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN), @@ -671,7 +686,7 @@ class MessagesPresenterTest { ) ) ) - val presenter = createMessagesPresenter(matrixRoom = room) + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { val initialState = consumeItemsUntilTimeout().last() initialState.eventSink(MessagesEvents.InviteDialogDismissed(InviteDialogAction.Invite)) @@ -688,17 +703,18 @@ class MessagesPresenterTest { @Test fun `present - handle reinviting other user when memberlist is not ready`() = runTest { - val room = FakeMatrixRoom( - sessionId = A_SESSION_ID, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, ) - room.givenRoomMembersState(MatrixRoomMembersState.Unknown) - val presenter = createMessagesPresenter(matrixRoom = room) + room.givenRoomMembersState(RoomMembersState.Unknown) + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { val initialState = consumeItemsUntilTimeout().last() initialState.eventSink(MessagesEvents.InviteDialogDismissed(InviteDialogAction.Invite)) @@ -712,25 +728,26 @@ class MessagesPresenterTest { @Test fun `present - handle reinviting other user when inviting fails`() = runTest { - val room = FakeMatrixRoom( - sessionId = A_SESSION_ID, - inviteUserResult = { Result.failure(Throwable("Oops!")) }, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, + inviteUserResult = { Result.failure(Throwable("Oops!")) }, ) room.givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( persistentListOf( aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN), aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE), ) ) ) - val presenter = createMessagesPresenter(matrixRoom = room) + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { val initialState = consumeItemsUntilTimeout().last() initialState.eventSink(MessagesEvents.InviteDialogDismissed(InviteDialogAction.Invite)) @@ -749,21 +766,23 @@ class MessagesPresenterTest { @Test fun `present - permission to post`() = runTest { - val matrixRoom = FakeMatrixRoom( - canUserSendMessageResult = { _, messageEventType -> - when (messageEventType) { - MessageEventType.ROOM_MESSAGE -> Result.success(true) - MessageEventType.REACTION -> Result.success(true) - else -> lambdaError() - } - }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + canUserSendMessageResult = { _, messageEventType -> + when (messageEventType) { + MessageEventType.ROOM_MESSAGE -> Result.success(true) + MessageEventType.REACTION -> Result.success(true) + else -> lambdaError() + } + }, + ), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, ) - val presenter = createMessagesPresenter(matrixRoom = matrixRoom) + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { skipItems(1) val state = awaitItem() @@ -773,21 +792,23 @@ class MessagesPresenterTest { @Test fun `present - no permission to post`() = runTest { - val matrixRoom = FakeMatrixRoom( - canUserSendMessageResult = { _, messageEventType -> - when (messageEventType) { - MessageEventType.ROOM_MESSAGE -> Result.success(false) - MessageEventType.REACTION -> Result.success(false) - else -> lambdaError() - } - }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + canUserSendMessageResult = { _, messageEventType -> + when (messageEventType) { + MessageEventType.ROOM_MESSAGE -> Result.success(false) + MessageEventType.REACTION -> Result.success(false) + else -> lambdaError() + } + }, + ), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, ) - val presenter = createMessagesPresenter(matrixRoom = matrixRoom) + val presenter = createMessagesPresenter(joinedRoom = room) presenter.testWithLifecycleOwner { // Default value assertThat(awaitItem().userEventPermissions.canSendMessage).isTrue() @@ -797,15 +818,17 @@ class MessagesPresenterTest { @Test fun `present - permission to redact own`() = runTest { - val matrixRoom = FakeMatrixRoom( - canRedactOwnResult = { Result.success(true) }, - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOtherResult = { Result.success(false) }, - canUserJoinCallResult = { Result.success(true) }, + val joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canRedactOwnResult = { Result.success(true) }, + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOtherResult = { Result.success(false) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, ) - val presenter = createMessagesPresenter(matrixRoom = matrixRoom) + val presenter = createMessagesPresenter(joinedRoom = joinedRoom) presenter.testWithLifecycleOwner { val initialState = consumeItemsUntilPredicate { it.userEventPermissions.canRedactOwn }.last() assertThat(initialState.userEventPermissions.canRedactOwn).isTrue() @@ -816,15 +839,17 @@ class MessagesPresenterTest { @Test fun `present - permission to redact other`() = runTest { - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOtherResult = { Result.success(true) }, canUserSendMessageResult = { _, _ -> Result.success(true) }, canRedactOwnResult = { Result.success(false) }, canUserJoinCallResult = { Result.success(true) }, - typingNoticeResult = { Result.success(Unit) }, canUserPinUnpinResult = { Result.success(true) }, + ), + typingNoticeResult = { Result.success(Unit) }, ) - val presenter = createMessagesPresenter(matrixRoom = matrixRoom) + val presenter = createMessagesPresenter(joinedRoom = joinedRoom) presenter.testWithLifecycleOwner { val initialState = consumeItemsUntilPredicate { it.userEventPermissions.canRedactOther }.last() assertThat(initialState.userEventPermissions.canRedactOwn).isFalse() @@ -863,16 +888,18 @@ class MessagesPresenterTest { val failurePinEventLambda = lambdaRecorder { _: EventId -> Result.failure(A_THROWABLE) } val analyticsService = FakeAnalyticsService() val timeline = FakeTimeline() - val room = FakeMatrixRoom( - liveTimeline = timeline, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canUserSendMessageResult = { _, _ -> Result.success(true) }, canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, - typingNoticeResult = { Result.success(Unit) }, canUserPinUnpinResult = { Result.success(true) }, + ), + liveTimeline = timeline, + typingNoticeResult = { Result.success(Unit) }, ) - val presenter = createMessagesPresenter(matrixRoom = room, analyticsService = analyticsService) + val presenter = createMessagesPresenter(joinedRoom = room, analyticsService = analyticsService) presenter.testWithLifecycleOwner { val messageEvent = aMessageEvent( content = aTimelineItemTextContent() @@ -901,16 +928,18 @@ class MessagesPresenterTest { val failureUnpinEventLambda = lambdaRecorder { _: EventId -> Result.failure(A_THROWABLE) } val timeline = FakeTimeline() val analyticsService = FakeAnalyticsService() - val room = FakeMatrixRoom( - liveTimeline = timeline, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canUserSendMessageResult = { _, _ -> Result.success(true) }, canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, - typingNoticeResult = { Result.success(Unit) }, canUserPinUnpinResult = { Result.success(true) }, + ), + liveTimeline = timeline, + typingNoticeResult = { Result.success(Unit) }, ) - val presenter = createMessagesPresenter(matrixRoom = room, analyticsService = analyticsService) + val presenter = createMessagesPresenter(joinedRoom = room, analyticsService = analyticsService) presenter.testWithLifecycleOwner { val messageEvent = aMessageEvent( content = aTimelineItemTextContent() @@ -1058,17 +1087,19 @@ class MessagesPresenterTest { val timeline = FakeTimeline().apply { this.editCaptionLambda = editCaptionLambda } - val room = FakeMatrixRoom( - liveTimeline = timeline, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canUserSendMessageResult = { _, _ -> Result.success(true) }, canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, - typingNoticeResult = { Result.success(Unit) }, canUserPinUnpinResult = { Result.success(true) }, + ), + liveTimeline = timeline, + typingNoticeResult = { Result.success(Unit) }, ) val presenter = createMessagesPresenter( - matrixRoom = room, + joinedRoom = room, ) presenter.testWithLifecycleOwner { skipItems(1) @@ -1094,21 +1125,23 @@ class MessagesPresenterTest { @Test fun `present - when room is encrypted and a DM, the DM user's identity state is fetched onResume`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( sessionId = A_SESSION_ID, canUserSendMessageResult = { _, _ -> Result.success(true) }, canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, - typingNoticeResult = { Result.success(Unit) }, canUserPinUnpinResult = { Result.success(true) }, initialRoomInfo = aRoomInfo(isDirect = true, isEncrypted = true) ).apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(aRoomMember(userId = A_SESSION_ID), aRoomMember(userId = A_USER_ID_2)))) - } + givenRoomMembersState(RoomMembersState.Ready(persistentListOf(aRoomMember(userId = A_SESSION_ID), aRoomMember(userId = A_USER_ID_2)))) + }, + typingNoticeResult = { Result.success(Unit) }, + ) val encryptionService = FakeEncryptionService(getUserIdentityResult = { Result.success(IdentityState.Verified) }) - val presenter = createMessagesPresenter(matrixRoom = room, encryptionService = encryptionService) + val presenter = createMessagesPresenter(joinedRoom = room, encryptionService = encryptionService) val lifecycleOwner = FakeLifecycleOwner() presenter.testWithLifecycleOwner(lifecycleOwner) { val initialState = awaitItem() @@ -1124,16 +1157,19 @@ class MessagesPresenterTest { private fun TestScope.createMessagesPresenter( coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(), - matrixRoom: MatrixRoom = FakeMatrixRoom( - canUserSendMessageResult = { _, _ -> Result.success(true) }, - canRedactOwnResult = { Result.success(true) }, - canRedactOtherResult = { Result.success(true) }, - canUserJoinCallResult = { Result.success(true) }, + joinedRoom: FakeJoinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserSendMessageResult = { _, _ -> Result.success(true) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserJoinCallResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ).apply { + givenRoomInfo(aRoomInfo(id = roomId, name = "")) + }, + liveTimeline = FakeTimeline(), typingNoticeResult = { Result.success(Unit) }, - canUserPinUnpinResult = { Result.success(true) }, - ).apply { - givenRoomInfo(aRoomInfo(id = roomId, name = "")) - }, + ), navigator: FakeMessagesNavigator = FakeMessagesNavigator(), featureFlagService: FeatureFlagService = FakeFeatureFlagService(), clipboardHelper: FakeClipboardHelper = FakeClipboardHelper(), @@ -1150,7 +1186,7 @@ class MessagesPresenterTest { actionListEventSink: (ActionListEvents) -> Unit = {}, ): MessagesPresenter { return MessagesPresenter( - room = matrixRoom, + room = joinedRoom, composerPresenter = messageComposerPresenter, voiceMessageComposerPresenter = { aVoiceMessageComposerState() }, timelinePresenter = { aTimelineState(eventSink = timelineEventSink) }, @@ -1171,7 +1207,7 @@ class MessagesPresenterTest { buildMeta = aBuildMeta(), dispatchers = coroutineDispatchers, htmlConverterProvider = FakeHtmlConverterProvider(), - timelineController = TimelineController(matrixRoom), + timelineController = TimelineController(joinedRoom), permalinkParser = permalinkParser, encryptionService = encryptionService, analyticsService = analyticsService, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index e5e6ff5ea2..6e9c525214 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -29,13 +29,13 @@ import io.element.android.features.poll.api.pollcontent.aPollAnswerItemList import io.element.android.libraries.dateformatter.test.FakeDateFormatter import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_CAPTION import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.tests.testutils.WarmUpRule @@ -893,7 +893,7 @@ class ActionListPresenterTest { @Test fun `present - compute message when event is already pinned`() = runTest { - val room = FakeMatrixRoom().apply { + val room = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) } val presenter = createActionListPresenter( @@ -1251,7 +1251,7 @@ class ActionListPresenterTest { @Test fun `present - compute for verified user send failure`() = runTest { - val room = FakeMatrixRoom( + val room = FakeBaseRoom( userDisplayNameResult = { Result.success("Alice") } ) val presenter = createActionListPresenter(isDeveloperModeEnabled = false, isPinFeatureEnabled = false, room = room) @@ -1279,7 +1279,7 @@ class ActionListPresenterTest { private fun createActionListPresenter( isDeveloperModeEnabled: Boolean, isPinFeatureEnabled: Boolean, - room: MatrixRoom = FakeMatrixRoom(), + room: BaseRoom = FakeBaseRoom(), allowCaption: Boolean = true, ): ActionListPresenter { val preferencesStore = InMemoryAppPreferencesStore(isDeveloperModeEnabled = isDeveloperModeEnabled) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt index d55ea7c7a0..2124d38b56 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt @@ -29,12 +29,12 @@ import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.VideoInfo import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.message.ReplyParameters import io.element.android.libraries.matrix.test.A_CAPTION import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.api.MediaSender import io.element.android.libraries.mediaupload.api.MediaUploadInfo @@ -110,7 +110,7 @@ class AttachmentsPreviewPresenterTest { lambdaRecorder> { _, _, _, _, _, _ -> Result.success(FakeMediaUploadHandler()) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( progressCallbackValues = listOf( Pair(0, 10), Pair(5, 10), @@ -148,7 +148,7 @@ class AttachmentsPreviewPresenterTest { lambdaRecorder> { _, _, _, _, _, _ -> Result.success(FakeMediaUploadHandler()) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendFileResult = sendFileResult, ) val onDoneListener = lambdaRecorder { } @@ -184,7 +184,7 @@ class AttachmentsPreviewPresenterTest { lambdaRecorder> { _, _, _, _, _, _ -> Result.success(FakeMediaUploadHandler()) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendFileResult = sendFileResult, ) val onDoneListener = lambdaRecorder { } @@ -216,7 +216,7 @@ class AttachmentsPreviewPresenterTest { @Test fun `present - send media with pre-processing failure after user sends media`() = runTest { - val room = FakeMatrixRoom() + val room = FakeJoinedRoom() val onDoneListener = lambdaRecorder { } val processLatch = CompletableDeferred() val presenter = createAttachmentsPreviewPresenter( @@ -242,7 +242,7 @@ class AttachmentsPreviewPresenterTest { @Test fun `present - send media with pre-processing failure before user sends media`() = runTest { - val room = FakeMatrixRoom() + val room = FakeJoinedRoom() val onDoneListener = lambdaRecorder { } val processLatch = CompletableDeferred() val presenter = createAttachmentsPreviewPresenter( @@ -297,7 +297,7 @@ class AttachmentsPreviewPresenterTest { val mediaPreProcessor = FakeMediaPreProcessor().apply { givenImageResult() } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendImageResult = sendImageResult, ) val onDoneListener = lambdaRecorder { } @@ -339,7 +339,7 @@ class AttachmentsPreviewPresenterTest { val mediaPreProcessor = FakeMediaPreProcessor().apply { givenVideoResult() } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendVideoResult = sendVideoResult, ) val onDoneListener = lambdaRecorder { } @@ -381,7 +381,7 @@ class AttachmentsPreviewPresenterTest { val mediaPreProcessor = FakeMediaPreProcessor().apply { givenAudioResult() } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendAudioResult = sendAudioResult, ) val onDoneListener = lambdaRecorder { } @@ -418,7 +418,7 @@ class AttachmentsPreviewPresenterTest { lambdaRecorder> { _, _, _, _, _, _ -> Result.failure(failure) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendFileResult = sendFileResult, ) val presenter = createAttachmentsPreviewPresenter(room = room, mediaUploadOnSendQueueEnabled = false) @@ -448,7 +448,7 @@ class AttachmentsPreviewPresenterTest { Result.failure(failure) } val onDoneListenerResult = lambdaRecorder {} - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendFileResult = sendFileResult, ) val presenter = createAttachmentsPreviewPresenter(room = room, mediaUploadOnSendQueueEnabled = true, onDoneListener = onDoneListenerResult) @@ -518,7 +518,7 @@ class AttachmentsPreviewPresenterTest { localMedia: LocalMedia = aLocalMedia( uri = mockMediaUrl, ), - room: MatrixRoom = FakeMatrixRoom(), + room: JoinedRoom = FakeJoinedRoom(), permalinkBuilder: PermalinkBuilder = FakePermalinkBuilder(), mediaPreProcessor: MediaPreProcessor = FakeMediaPreProcessor(), temporaryUriDeleter: TemporaryUriDeleter = FakeTemporaryUriDeleter(), diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenterTest.kt index 2a82db690e..40da23ae29 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/identity/IdentityChangeStatePresenterTest.kt @@ -13,12 +13,12 @@ import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.tests.testutils.WarmUpRule @@ -26,6 +26,7 @@ import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.test import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -45,14 +46,15 @@ class IdentityChangeStatePresenterTest { @Test fun `present - when the room emits identity change, the presenter emits new state`() = runTest { - val room = FakeMatrixRoom().apply { + val identityStateChanges = MutableStateFlow(emptyList()) + val room = FakeJoinedRoom(identityStateChangesFlow = identityStateChanges).apply { givenRoomInfo(aRoomInfo(isEncrypted = true)) } val presenter = createIdentityChangeStatePresenter(room) presenter.test { val initialState = awaitItem() assertThat(initialState.roomMemberIdentityStateChanges).isEmpty() - room.emitIdentityStateChanges( + identityStateChanges.emit( listOf( IdentityStateChange( userId = A_USER_ID_2, @@ -70,12 +72,16 @@ class IdentityChangeStatePresenterTest { @Test fun `present - when the clear room emits identity change, the presenter does not emit new state`() = runTest { - val room = FakeMatrixRoom(enableEncryptionResult = { Result.success(Unit) }) + val identityStateChanges = MutableStateFlow(emptyList()) + val room = FakeJoinedRoom( + identityStateChangesFlow = identityStateChanges, + enableEncryptionResult = { Result.success(Unit) } + ) val presenter = createIdentityChangeStatePresenter(room) presenter.test { val initialState = awaitItem() assertThat(initialState.roomMemberIdentityStateChanges).isEmpty() - room.emitIdentityStateChanges( + identityStateChanges.emit( listOf( IdentityStateChange( userId = A_USER_ID_2, @@ -100,9 +106,10 @@ class IdentityChangeStatePresenterTest { @Test fun `present - when the room emits identity change, the presenter emits new state with member details`() = runTest { - val room = FakeMatrixRoom().apply { + val identityStateChanges = MutableStateFlow(emptyList()) + val room = FakeJoinedRoom(identityStateChangesFlow = identityStateChanges).apply { givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( listOf( aRoomMember( A_USER_ID_2, @@ -117,7 +124,7 @@ class IdentityChangeStatePresenterTest { presenter.test { val initialState = awaitItem() assertThat(initialState.roomMemberIdentityStateChanges).isEmpty() - room.emitIdentityStateChanges( + identityStateChanges.emit( listOf( IdentityStateChange( userId = A_USER_ID_2, @@ -166,7 +173,7 @@ class IdentityChangeStatePresenterTest { } private fun createIdentityChangeStatePresenter( - room: MatrixRoom = FakeMatrixRoom(), + room: JoinedRoom = FakeJoinedRoom(), encryptionService: EncryptionService = FakeEncryptionService(), ): IdentityChangeStatePresenter { return IdentityChangeStatePresenter( diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenterTest.kt index 374eebdc3b..fd2a2fafc2 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailurePresenterTest.kt @@ -13,13 +13,13 @@ import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUser import io.element.android.features.messages.impl.fixtures.aMessageEvent import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_TRANSACTION_ID import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.test import kotlinx.coroutines.test.runTest @@ -81,11 +81,13 @@ class ResolveVerifiedUserSendFailurePresenterTest { @Test fun `present - verified user unsigned device failure dismiss scenario`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( userDisplayNameResult = { userId -> Result.success(userId.value) }, ) + ) val presenter = createResolveVerifiedUserSendFailurePresenter(room) presenter.test { val failedMessage = aVerifiedUserHasUnsignedDeviceFailedMessage() @@ -107,11 +109,13 @@ class ResolveVerifiedUserSendFailurePresenterTest { @Test fun `present - verified user unsigned device failure retry scenario`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( userDisplayNameResult = { userId -> Result.success(userId.value) }, ) + ) val presenter = createResolveVerifiedUserSendFailurePresenter(room) presenter.test { val failedMessage = aVerifiedUserHasUnsignedDeviceFailedMessage() @@ -138,10 +142,12 @@ class ResolveVerifiedUserSendFailurePresenterTest { @Test fun `present - verified user unsigned device failure resolve and resend scenario`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( userDisplayNameResult = { userId -> Result.success(userId.value) }, + ), ignoreDeviceTrustAndResendResult = { _, _ -> Result.success(Unit) }, @@ -179,10 +185,12 @@ class ResolveVerifiedUserSendFailurePresenterTest { @Test fun `present - verified user unsigned device failure resolve and resend scenario with error`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( userDisplayNameResult = { userId -> Result.success(userId.value) }, + ), ignoreDeviceTrustAndResendResult = { _, _ -> Result.failure(Exception()) }, @@ -212,11 +220,13 @@ class ResolveVerifiedUserSendFailurePresenterTest { @Test fun `present - verified user changed identity failure retry scenario`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( userDisplayNameResult = { userId -> Result.success(userId.value) }, ) + ) val presenter = createResolveVerifiedUserSendFailurePresenter(room) presenter.test { val failedMessage = aVerifiedUserChangedIdentityMessage() @@ -243,10 +253,12 @@ class ResolveVerifiedUserSendFailurePresenterTest { @Test fun `present - verified user changed identity failure resolve and resend scenario`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( userDisplayNameResult = { userId -> Result.success(userId.value) }, + ), withdrawVerificationAndResendResult = { _, _ -> Result.success(Unit) }, @@ -284,10 +296,12 @@ class ResolveVerifiedUserSendFailurePresenterTest { @Test fun `present - verified user changed identity failure resolve and resend scenario with error`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( userDisplayNameResult = { userId -> Result.success(userId.value) }, + ), withdrawVerificationAndResendResult = { _, _ -> Result.failure(Exception()) }, @@ -337,7 +351,7 @@ class ResolveVerifiedUserSendFailurePresenterTest { } private fun createResolveVerifiedUserSendFailurePresenter( - room: MatrixRoom = FakeMatrixRoom(), + room: FakeJoinedRoom = FakeJoinedRoom(), ): ResolveVerifiedUserSendFailurePresenter { return ResolveVerifiedUserSendFailurePresenter( room = room, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt index 1824eeb987..2092d8d815 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt @@ -15,7 +15,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.test.AN_EVENT_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.LiveTimelineProvider @@ -49,8 +49,8 @@ class ForwardMessagesPresenterTest { val timeline = FakeTimeline().apply { this.forwardEventLambda = forwardEventLambda } - val room = FakeMatrixRoom(liveTimeline = timeline) - val presenter = aForwardMessagesPresenter(fakeMatrixRoom = room) + val room = FakeJoinedRoom(liveTimeline = timeline) + val presenter = aForwardMessagesPresenter(fakeRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -73,8 +73,8 @@ class ForwardMessagesPresenterTest { val timeline = FakeTimeline().apply { this.forwardEventLambda = forwardEventLambda } - val room = FakeMatrixRoom(liveTimeline = timeline) - val presenter = aForwardMessagesPresenter(fakeMatrixRoom = room) + val room = FakeJoinedRoom(liveTimeline = timeline) + val presenter = aForwardMessagesPresenter(fakeRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -93,11 +93,11 @@ class ForwardMessagesPresenterTest { private fun CoroutineScope.aForwardMessagesPresenter( eventId: EventId = AN_EVENT_ID, - fakeMatrixRoom: FakeMatrixRoom = FakeMatrixRoom(), + fakeRoom: FakeJoinedRoom = FakeJoinedRoom(), coroutineScope: CoroutineScope = this, ) = ForwardMessagesPresenter( eventId = eventId.value, - timelineProvider = LiveTimelineProvider(fakeMatrixRoom), + timelineProvider = LiveTimelineProvider(fakeRoom), appCoroutineScope = coroutineScope, ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt index a82df0f2aa..9528b81bf3 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt @@ -42,8 +42,8 @@ import io.element.android.libraries.matrix.api.media.VideoInfo import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.room.IntentionalMention -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.room.draft.ComposerDraft import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType @@ -65,7 +65,8 @@ import io.element.android.libraries.matrix.test.A_USER_ID_3 import io.element.android.libraries.matrix.test.A_USER_ID_4 import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.timeline.FakeTimeline @@ -267,13 +268,13 @@ class MessageComposerPresenterTest { val timeline = FakeTimeline().apply { this.editCaptionLambda = editCaptionLambda } - val fakeMatrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = timeline, typingNoticeResult = { Result.success(Unit) } ) val presenter = createPresenter( coroutineScope = this, - room = fakeMatrixRoom, + room = joinedRoom, isRichTextEditorEnabled = false, ) val permalinkBuilder = FakePermalinkBuilder(permalinkForUserLambda = { Result.success("") }) @@ -382,7 +383,7 @@ class MessageComposerPresenterTest { fun `present - send message with rich text enabled`() = runTest { val presenter = createPresenter( coroutineScope = this, - room = FakeMatrixRoom( + room = FakeJoinedRoom( sendMessageResult = { _, _, _ -> Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) } ), @@ -416,7 +417,7 @@ class MessageComposerPresenterTest { val presenter = createPresenter( coroutineScope = this, isRichTextEditorEnabled = false, - room = FakeMatrixRoom( + room = FakeJoinedRoom( sendMessageResult = { _, _, _ -> Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) } ), @@ -454,13 +455,13 @@ class MessageComposerPresenterTest { val timeline = FakeTimeline().apply { this.editMessageLambda = editMessageLambda } - val fakeMatrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = timeline, typingNoticeResult = { Result.success(Unit) } ) val presenter = createPresenter( this, - fakeMatrixRoom, + joinedRoom, ) moleculeFlow(RecompositionMode.Immediate) { val state = presenter.present() @@ -509,14 +510,14 @@ class MessageComposerPresenterTest { val roomEditMessageLambda = lambdaRecorder { _: EventId?, _: String, _: String?, _: List -> Result.success(Unit) } - val fakeMatrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = timeline, typingNoticeResult = { Result.success(Unit) }, editMessageLambda = roomEditMessageLambda, ) val presenter = createPresenter( this, - fakeMatrixRoom, + joinedRoom, ) moleculeFlow(RecompositionMode.Immediate) { val state = presenter.present() @@ -566,13 +567,13 @@ class MessageComposerPresenterTest { val timeline = FakeTimeline().apply { this.editMessageLambda = editMessageLambda } - val fakeMatrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = timeline, typingNoticeResult = { Result.success(Unit) }, ) val presenter = createPresenter( this, - fakeMatrixRoom, + joinedRoom, ) moleculeFlow(RecompositionMode.Immediate) { val state = presenter.present() @@ -618,13 +619,13 @@ class MessageComposerPresenterTest { val timeline = FakeTimeline().apply { this.replyMessageLambda = replyMessageLambda } - val fakeMatrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = timeline, typingNoticeResult = { Result.success(Unit) } ) val presenter = createPresenter( this, - fakeMatrixRoom, + joinedRoom, ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -689,7 +690,7 @@ class MessageComposerPresenterTest { @Test fun `present - Pick image from gallery`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ) val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList -> } @@ -730,7 +731,7 @@ class MessageComposerPresenterTest { @Test fun `present - Pick video from gallery`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ) val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList -> } @@ -788,7 +789,7 @@ class MessageComposerPresenterTest { @Test fun `present - Pick file from storage will open the preview`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ) val onPreviewAttachmentLambda = lambdaRecorder { _: ImmutableList -> } @@ -811,7 +812,7 @@ class MessageComposerPresenterTest { @Test fun `present - create poll`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ) val presenter = createPresenter(this, room = room) @@ -830,7 +831,7 @@ class MessageComposerPresenterTest { @Test fun `present - share location`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ) val presenter = createPresenter(this, room = room) @@ -849,7 +850,7 @@ class MessageComposerPresenterTest { @Test fun `present - Take photo`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ) val permissionPresenter = FakePermissionsPresenter().apply { setPermissionGranted() } @@ -874,7 +875,7 @@ class MessageComposerPresenterTest { @Test fun `present - Take photo with permission request`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ) val permissionPresenter = FakePermissionsPresenter() @@ -901,7 +902,7 @@ class MessageComposerPresenterTest { @Test fun `present - Record video`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ) val permissionPresenter = FakePermissionsPresenter().apply { setPermissionGranted() } @@ -926,7 +927,7 @@ class MessageComposerPresenterTest { @Test fun `present - Record video with permission request`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ) val permissionPresenter = FakePermissionsPresenter() @@ -1001,12 +1002,12 @@ class MessageComposerPresenterTest { val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN) val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN) var canUserTriggerRoomNotificationResult = true - val room = FakeMatrixRoom( - canUserTriggerRoomNotificationResult = { Result.success(canUserTriggerRoomNotificationResult) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom(canUserTriggerRoomNotificationResult = { Result.success(canUserTriggerRoomNotificationResult) }), typingNoticeResult = { Result.success(Unit) } ).apply { givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( persistentListOf(currentUser, invitedUser, bob, david), ) ) @@ -1057,12 +1058,12 @@ class MessageComposerPresenterTest { val invitedUser = aRoomMember(userId = A_USER_ID_3, membership = RoomMembershipState.INVITE) val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN) val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN) - val room = FakeMatrixRoom( - canUserTriggerRoomNotificationResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom(canUserTriggerRoomNotificationResult = { Result.success(true) }), typingNoticeResult = { Result.success(Unit) } ).apply { givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( persistentListOf(currentUser, invitedUser, bob, david), ) ) @@ -1124,7 +1125,7 @@ class MessageComposerPresenterTest { val sendMessageResult = lambdaRecorder { _: String, _: String?, _: List -> Result.success(Unit) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( liveTimeline = timeline, sendMessageResult = sendMessageResult, typingNoticeResult = { Result.success(Unit) } @@ -1206,8 +1207,8 @@ class MessageComposerPresenterTest { @Test fun `present - handle typing notice event`() = runTest { val typingNoticeResult = lambdaRecorder> { Result.success(Unit) } - val room = FakeMatrixRoom( - typingNoticeResult = typingNoticeResult + val room = FakeJoinedRoom( + typingNoticeResult = typingNoticeResult, ) val presenter = createPresenter(room = room, coroutineScope = this) moleculeFlow(RecompositionMode.Immediate) { @@ -1217,6 +1218,7 @@ class MessageComposerPresenterTest { typingNoticeResult.assertions().isNeverCalled() initialState.eventSink.invoke(MessageComposerEvents.TypingNotice(true)) initialState.eventSink.invoke(MessageComposerEvents.TypingNotice(false)) + advanceUntilIdle() typingNoticeResult.assertions().isCalledExactly(2) .withSequence( listOf(value(true)), @@ -1228,7 +1230,7 @@ class MessageComposerPresenterTest { @Test fun `present - handle typing notice event when sending typing notice is disabled`() = runTest { val typingNoticeResult = lambdaRecorder> { Result.success(Unit) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( typingNoticeResult = typingNoticeResult ) val store = InMemorySessionPreferencesStore( @@ -1383,7 +1385,7 @@ class MessageComposerPresenterTest { val timeline = FakeTimeline().apply { this.loadReplyDetailsLambda = loadReplyDetailsLambda } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( liveTimeline = timeline, typingNoticeResult = { Result.success(Unit) }, ) @@ -1524,7 +1526,7 @@ class MessageComposerPresenterTest { private fun createPresenter( coroutineScope: CoroutineScope, - room: MatrixRoom = FakeMatrixRoom( + room: JoinedRoom = FakeJoinedRoom( typingNoticeResult = { Result.success(Unit) } ), navigator: MessagesNavigator = FakeMessagesNavigator(), diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessorTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessorTest.kt index 66b8aeb152..6d7b4f8c7c 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessorTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/suggestions/SuggestionsProcessorTest.kt @@ -9,7 +9,7 @@ package io.element.android.features.messages.impl.messagecomposer.suggestions import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.test.A_ROOM_ALIAS import io.element.android.libraries.matrix.test.A_USER_ID @@ -35,7 +35,7 @@ class SuggestionsProcessorTest { fun `processing null suggestion will return empty suggestion`() = runTest { val result = suggestionsProcessor.process( suggestion = null, - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember())), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember())), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID, canSendRoomMention = { true }, @@ -47,7 +47,7 @@ class SuggestionsProcessorTest { fun `processing Command will return empty suggestion`() = runTest { val result = suggestionsProcessor.process( suggestion = aCommandSuggestion, - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember())), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember())), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID, canSendRoomMention = { true }, @@ -59,7 +59,7 @@ class SuggestionsProcessorTest { fun `processing Custom will return empty suggestion`() = runTest { val result = suggestionsProcessor.process( suggestion = aCustomSuggestion, - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember())), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember())), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID, canSendRoomMention = { true }, @@ -71,7 +71,7 @@ class SuggestionsProcessorTest { fun `processing Mention suggestion with not loaded members will return empty suggestion`() = runTest { val result = suggestionsProcessor.process( suggestion = aMentionSuggestion(""), - roomMembersState = MatrixRoomMembersState.Unknown, + roomMembersState = RoomMembersState.Unknown, roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID, canSendRoomMention = { true }, @@ -83,7 +83,7 @@ class SuggestionsProcessorTest { fun `processing Mention suggestion with no members will return empty suggestion`() = runTest { val result = suggestionsProcessor.process( suggestion = aMentionSuggestion(""), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomMembersState = RoomMembersState.Ready(persistentListOf()), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID, canSendRoomMention = { true }, @@ -95,7 +95,7 @@ class SuggestionsProcessorTest { fun `processing Room suggestion with no aliases will return empty suggestion`() = runTest { val result = suggestionsProcessor.process( suggestion = aRoomSuggestion(""), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomMembersState = RoomMembersState.Ready(persistentListOf()), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID, canSendRoomMention = { true }, @@ -108,7 +108,7 @@ class SuggestionsProcessorTest { val aRoomSummary = aRoomSummary(canonicalAlias = A_ROOM_ALIAS) val result = suggestionsProcessor.process( suggestion = aRoomSuggestion("ALI"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomMembersState = RoomMembersState.Ready(persistentListOf()), roomAliasSuggestions = listOf( RoomAliasSuggestion( roomAlias = A_ROOM_ALIAS, @@ -137,7 +137,7 @@ class SuggestionsProcessorTest { val aRoomSummary = aRoomSummary(canonicalAlias = A_ROOM_ALIAS) val result = suggestionsProcessor.process( suggestion = aRoomSuggestion("ali"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomMembersState = RoomMembersState.Ready(persistentListOf()), roomAliasSuggestions = listOf( RoomAliasSuggestion( roomAlias = A_ROOM_ALIAS, @@ -166,7 +166,7 @@ class SuggestionsProcessorTest { val aRoomSummary = aRoomSummary(canonicalAlias = A_ROOM_ALIAS) val result = suggestionsProcessor.process( suggestion = aRoomSuggestion("tot"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomMembersState = RoomMembersState.Ready(persistentListOf()), roomAliasSuggestions = listOf( RoomAliasSuggestion( roomAlias = A_ROOM_ALIAS, @@ -186,7 +186,7 @@ class SuggestionsProcessorTest { val aRoomSummary = aRoomSummary(canonicalAlias = A_ROOM_ALIAS) val result = suggestionsProcessor.process( suggestion = aRoomSuggestion("lement"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomMembersState = RoomMembersState.Ready(persistentListOf()), roomAliasSuggestions = listOf( RoomAliasSuggestion( roomAlias = A_ROOM_ALIAS, @@ -215,7 +215,7 @@ class SuggestionsProcessorTest { val aRoomSummary = aRoomSummary(canonicalAlias = A_ROOM_ALIAS) val result = suggestionsProcessor.process( suggestion = aRoomSuggestion("lement"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomMembersState = RoomMembersState.Ready(persistentListOf()), roomAliasSuggestions = listOf( RoomAliasSuggestion( roomAlias = A_ROOM_ALIAS, @@ -235,7 +235,7 @@ class SuggestionsProcessorTest { val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = null) val result = suggestionsProcessor.process( suggestion = aMentionSuggestion("ali"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember)), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID_2, canSendRoomMention = { true }, @@ -252,7 +252,7 @@ class SuggestionsProcessorTest { val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = null) val result = suggestionsProcessor.process( suggestion = aMentionSuggestion("ali"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember)), roomAliasSuggestions = emptyList(), currentUserId = UserId("@alice:server.org"), canSendRoomMention = { true }, @@ -265,7 +265,7 @@ class SuggestionsProcessorTest { val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "alice") val result = suggestionsProcessor.process( suggestion = aMentionSuggestion("bo"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember)), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID_2, canSendRoomMention = { true }, @@ -278,7 +278,7 @@ class SuggestionsProcessorTest { val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), membership = RoomMembershipState.INVITE) val result = suggestionsProcessor.process( suggestion = aMentionSuggestion("ali"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember)), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID_2, canSendRoomMention = { true }, @@ -291,7 +291,7 @@ class SuggestionsProcessorTest { val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "bob") val result = suggestionsProcessor.process( suggestion = aMentionSuggestion("bo"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember)), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID_2, canSendRoomMention = { true }, @@ -308,7 +308,7 @@ class SuggestionsProcessorTest { val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "ro") val result = suggestionsProcessor.process( suggestion = aMentionSuggestion("ro"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember)), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID_2, canSendRoomMention = { true }, @@ -326,7 +326,7 @@ class SuggestionsProcessorTest { val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "ro") val result = suggestionsProcessor.process( suggestion = aMentionSuggestion("ro"), - roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomMembersState = RoomMembersState.Ready(persistentListOf(aRoomMember)), roomAliasSuggestions = emptyList(), currentUserId = A_USER_ID_2, canSendRoomMention = { false }, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt index 5f6fa1b164..ecd069585f 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/banner/PinnedMessagesBannerPresenterTest.kt @@ -12,14 +12,14 @@ import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProv import io.element.android.libraries.eventformatter.test.FakePinnedMessagesBannerFormatter import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.A_UNIQUE_ID import io.element.android.libraries.matrix.test.A_UNIQUE_ID_2 -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.timeline.FakeTimeline @@ -54,7 +54,7 @@ class PinnedMessagesBannerPresenterTest { @Test fun `present - loading state`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( createTimelineResult = { Result.success(FakeTimeline()) } ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) @@ -85,7 +85,7 @@ class PinnedMessagesBannerPresenterTest { ) ) ) - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( createTimelineResult = { Result.success(pinnedEventsTimeline) } ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID, AN_EVENT_ID_2))) @@ -124,7 +124,7 @@ class PinnedMessagesBannerPresenterTest { ) ) ) - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( createTimelineResult = { Result.success(pinnedEventsTimeline) } ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID, AN_EVENT_ID_2))) @@ -159,7 +159,7 @@ class PinnedMessagesBannerPresenterTest { @Test fun `present - timeline failed`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( createTimelineResult = { Result.failure(Exception()) } ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) @@ -179,7 +179,7 @@ class PinnedMessagesBannerPresenterTest { } private fun TestScope.createPinnedMessagesBannerPresenter( - room: MatrixRoom = FakeMatrixRoom(), + room: JoinedRoom = FakeJoinedRoom(), itemFactory: PinnedMessagesBannerItemFactory = PinnedMessagesBannerItemFactory( coroutineDispatchers = testCoroutineDispatchers(), formatter = FakePinnedMessagesBannerFormatter( diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt index 1825373624..985e9f055f 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt @@ -20,14 +20,15 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatch import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.A_UNIQUE_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.timeline.FakeTimeline @@ -51,11 +52,13 @@ import org.junit.Test class PinnedMessagesListPresenterTest { @Test fun `present - initial state feature disabled`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) }, ) + ) val presenter = createPinnedMessagesListPresenter(room = room, isFeatureEnabled = false) presenter.test { val initialState = awaitItem() @@ -66,13 +69,15 @@ class PinnedMessagesListPresenterTest { @Test fun `present - initial state feature enabled`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) } + ) val presenter = createPinnedMessagesListPresenter(room = room, isFeatureEnabled = true) presenter.test { val initialState = awaitItem() @@ -83,14 +88,16 @@ class PinnedMessagesListPresenterTest { @Test fun `present - timeline failure state`() = runTest { - val room = FakeMatrixRoom( - createTimelineResult = { Result.failure(RuntimeException()) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) - } + }, + createTimelineResult = { Result.failure(RuntimeException()) }, + ) val presenter = createPinnedMessagesListPresenter(room = room, isFeatureEnabled = true) presenter.test { skipItems(3) @@ -102,14 +109,16 @@ class PinnedMessagesListPresenterTest { @Test fun `present - empty state`() = runTest { - val room = FakeMatrixRoom( - createTimelineResult = { Result.success(FakeTimeline()) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf())) - } + }, + createTimelineResult = { Result.success(FakeTimeline()) }, + ) val presenter = createPinnedMessagesListPresenter(room = room, isFeatureEnabled = true) presenter.test { skipItems(3) @@ -122,14 +131,16 @@ class PinnedMessagesListPresenterTest { @Test fun `present - filled state`() = runTest { val pinnedEventsTimeline = createPinnedMessagesTimeline() - val room = FakeMatrixRoom( - createTimelineResult = { Result.success(pinnedEventsTimeline) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) - } + }, + createTimelineResult = { Result.success(pinnedEventsTimeline) }, + ) val presenter = createPinnedMessagesListPresenter(room = room, isFeatureEnabled = true) presenter.test { skipItems(3) @@ -149,14 +160,16 @@ class PinnedMessagesListPresenterTest { val failureUnpinEventLambda = lambdaRecorder { _: EventId? -> Result.failure(A_THROWABLE) } val pinnedEventsTimeline = createPinnedMessagesTimeline() val analyticsService = FakeAnalyticsService() - val room = FakeMatrixRoom( - createTimelineResult = { Result.success(pinnedEventsTimeline) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) - } + }, + createTimelineResult = { Result.success(pinnedEventsTimeline) }, + ) val presenter = createPinnedMessagesListPresenter(room = room, isFeatureEnabled = true, analyticsService = analyticsService) presenter.test { skipItems(3) @@ -195,14 +208,16 @@ class PinnedMessagesListPresenterTest { this.onViewInTimelineClickLambda = onViewInTimelineClickLambda } val pinnedEventsTimeline = createPinnedMessagesTimeline() - val room = FakeMatrixRoom( - createTimelineResult = { Result.success(pinnedEventsTimeline) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) - } + }, + createTimelineResult = { Result.success(pinnedEventsTimeline) }, + ) val presenter = createPinnedMessagesListPresenter(room = room, navigator = navigator, isFeatureEnabled = true) presenter.test { skipItems(3) @@ -224,14 +239,16 @@ class PinnedMessagesListPresenterTest { this.onShowEventDebugInfoClickLambda = onShowEventDebugInfoClickLambda } val pinnedEventsTimeline = createPinnedMessagesTimeline() - val room = FakeMatrixRoom( - createTimelineResult = { Result.success(pinnedEventsTimeline) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) - } + }, + createTimelineResult = { Result.success(pinnedEventsTimeline) }, + ) val presenter = createPinnedMessagesListPresenter(room = room, navigator = navigator, isFeatureEnabled = true) presenter.test { skipItems(3) @@ -253,14 +270,16 @@ class PinnedMessagesListPresenterTest { this.onForwardEventClickLambda = onForwardEventClickLambda } val pinnedEventsTimeline = createPinnedMessagesTimeline() - val room = FakeMatrixRoom( - createTimelineResult = { Result.success(pinnedEventsTimeline) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, canRedactOtherResult = { Result.success(true) }, canUserPinUnpinResult = { Result.success(true) }, ).apply { givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) - } + }, + createTimelineResult = { Result.success(pinnedEventsTimeline) }, + ) val presenter = createPinnedMessagesListPresenter(room = room, navigator = navigator, isFeatureEnabled = true) presenter.test { skipItems(3) @@ -294,7 +313,7 @@ class PinnedMessagesListPresenterTest { private fun TestScope.createPinnedMessagesListPresenter( navigator: PinnedMessagesListNavigator = FakePinnedMessagesListNavigator(), - room: MatrixRoom = FakeMatrixRoom(), + room: JoinedRoom = FakeJoinedRoom(), syncService: SyncService = FakeSyncService(), isFeatureEnabled: Boolean = true, analyticsService: AnalyticsService = FakeAnalyticsService(), diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/report/ReportMessagePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/report/ReportMessagePresenterTest.kt index 6406b1d64d..abaa6a5653 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/report/ReportMessagePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/report/ReportMessagePresenterTest.kt @@ -15,10 +15,10 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.lambdaRecorder import kotlinx.coroutines.test.runTest @@ -78,10 +78,10 @@ class ReportMessagePresenterTest { val reportContentResult = lambdaRecorder> { _, _, _ -> Result.success(Unit) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( reportContentResult = reportContentResult ) - val presenter = createReportMessagePresenter(matrixRoom = room) + val presenter = createReportMessagePresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -100,10 +100,10 @@ class ReportMessagePresenterTest { val reportContentResult = lambdaRecorder> { _, _, _ -> Result.success(Unit) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( reportContentResult = reportContentResult ) - val presenter = createReportMessagePresenter(matrixRoom = room) + val presenter = createReportMessagePresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -120,10 +120,10 @@ class ReportMessagePresenterTest { val reportContentResult = lambdaRecorder> { _, _, _ -> Result.failure(Exception("Failed to report content")) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( reportContentResult = reportContentResult ) - val presenter = createReportMessagePresenter(matrixRoom = room) + val presenter = createReportMessagePresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -141,11 +141,11 @@ class ReportMessagePresenterTest { private fun createReportMessagePresenter( inputs: ReportMessagePresenter.Inputs = ReportMessagePresenter.Inputs(AN_EVENT_ID, A_USER_ID), - matrixRoom: MatrixRoom = FakeMatrixRoom(), + joinedRoom: JoinedRoom = FakeJoinedRoom(), snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(), ) = ReportMessagePresenter( inputs = inputs, - room = matrixRoom, + room = joinedRoom, snackbarDispatcher = snackbarDispatcher, ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt index 83cc05eb52..ab183442f2 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt @@ -14,7 +14,7 @@ import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_UNIQUE_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem import io.element.android.tests.testutils.lambda.lambdaError @@ -29,11 +29,11 @@ class TimelineControllerTest { fun `test switching between live and detached timeline`() = runTest { val liveTimeline = FakeTimeline(name = "live") val detachedTimeline = FakeTimeline(name = "detached") - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline, createTimelineResult = { Result.success(detachedTimeline) } ) - val sut = TimelineController(matrixRoom) + val sut = TimelineController(joinedRoom) sut.activeTimelineFlow().test { awaitItem().also { state -> @@ -61,7 +61,7 @@ class TimelineControllerTest { val detachedTimeline1 = FakeTimeline(name = "detached 1") val detachedTimeline2 = FakeTimeline(name = "detached 2") var callNumber = 0 - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline, createTimelineResult = { callNumber++ @@ -72,7 +72,7 @@ class TimelineControllerTest { } } ) - val sut = TimelineController(matrixRoom) + val sut = TimelineController(joinedRoom) sut.activeTimelineFlow().test { awaitItem().also { state -> @@ -97,10 +97,10 @@ class TimelineControllerTest { @Test fun `test switching to live when already in live should have no effect`() = runTest { val liveTimeline = FakeTimeline(name = "live") - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline ) - val sut = TimelineController(matrixRoom) + val sut = TimelineController(joinedRoom) sut.activeTimelineFlow().test { awaitItem().also { state -> assertThat(state).isEqualTo(liveTimeline) @@ -115,11 +115,11 @@ class TimelineControllerTest { fun `test closing the TimelineController should close the detached timeline`() = runTest { val liveTimeline = FakeTimeline(name = "live") val detachedTimeline = FakeTimeline(name = "detached") - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline, createTimelineResult = { Result.success(detachedTimeline) } ) - val sut = TimelineController(matrixRoom) + val sut = TimelineController(joinedRoom) sut.activeTimelineFlow().test { awaitItem().also { state -> assertThat(state).isEqualTo(liveTimeline) @@ -144,10 +144,10 @@ class TimelineControllerTest { ) ) ) - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline ) - val sut = TimelineController(matrixRoom) + val sut = TimelineController(joinedRoom) assertThat(sut.timelineItems().first()).hasSize(1) } @@ -165,11 +165,11 @@ class TimelineControllerTest { val detachedTimeline = FakeTimeline(name = "detached").apply { sendMessageLambda = lambdaForDetached } - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline, createTimelineResult = { Result.success(detachedTimeline) } ) - val sut = TimelineController(matrixRoom) + val sut = TimelineController(joinedRoom) sut.activeTimelineFlow().test { sut.focusOnEvent(AN_EVENT_ID) awaitItem().also { state -> @@ -190,11 +190,11 @@ class TimelineControllerTest { fun `test last forward pagination on a detached timeline should switch to live timeline`() = runTest { val liveTimeline = FakeTimeline(name = "live") val detachedTimeline = FakeTimeline(name = "detached") - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline, createTimelineResult = { Result.success(detachedTimeline) } ) - val sut = TimelineController(matrixRoom) + val sut = TimelineController(joinedRoom) sut.activeTimelineFlow().test { awaitItem().also { state -> diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index 6c81745ce4..5e9aa3e214 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -30,7 +30,7 @@ import io.element.android.features.poll.test.actions.FakeSendPollResponseAction import io.element.android.features.roomcall.api.aStandByCallState import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.api.timeline.Timeline @@ -43,7 +43,8 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.A_UNIQUE_ID import io.element.android.libraries.matrix.test.A_UNIQUE_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.aMessageContent @@ -128,9 +129,9 @@ import kotlin.time.Duration.Companion.seconds ) ) ) - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( liveTimeline = timeline, - canUserSendMessageResult = { _, _ -> Result.success(true) }, + baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }) ) val sessionPreferencesStore = InMemorySessionPreferencesStore(isSendPublicReadReceiptsEnabled = false) val presenter = createTimelinePresenter( @@ -144,7 +145,7 @@ import kotlin.time.Duration.Companion.seconds val initialState = awaitFirstItem() initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0)) runCurrent() - assertThat(room.markAsReadCalls).isNotEmpty() + assertThat(room.baseRoom.markAsReadCalls).isNotEmpty() cancelAndIgnoreRemainingEvents() } } @@ -481,10 +482,10 @@ import kotlin.time.Duration.Companion.seconds val liveTimeline = FakeTimeline( timelineItems = flowOf(emptyList()) ) - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( liveTimeline = liveTimeline, createTimelineResult = { Result.success(detachedTimeline) }, - canUserSendMessageResult = { _, _ -> Result.success(true) }, + baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }), ) val presenter = createTimelinePresenter( room = room, @@ -523,7 +524,7 @@ import kotlin.time.Duration.Companion.seconds process(listOf(aMessageEvent(eventId = AN_EVENT_ID))) } val presenter = createTimelinePresenter( - room = FakeMatrixRoom( + room = FakeJoinedRoom( liveTimeline = FakeTimeline( timelineItems = flowOf( listOf( @@ -534,7 +535,7 @@ import kotlin.time.Duration.Companion.seconds ) ) ), - canUserSendMessageResult = { _, _ -> Result.success(true) }, + baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }), ), timelineItemIndexer = timelineItemIndexer, ) @@ -557,12 +558,12 @@ import kotlin.time.Duration.Companion.seconds @Test fun `present - focus on event error case`() = runTest { val presenter = createTimelinePresenter( - room = FakeMatrixRoom( + room = FakeJoinedRoom( liveTimeline = FakeTimeline( timelineItems = flowOf(emptyList()), ), createTimelineResult = { Result.failure(Throwable("An error")) }, - canUserSendMessageResult = { _, _ -> Result.success(true) }, + baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }), ) ) moleculeFlow(RecompositionMode.Immediate) { @@ -628,11 +629,11 @@ import kotlin.time.Duration.Companion.seconds ) ) ) - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( liveTimeline = timeline, - canUserSendMessageResult = { _, _ -> Result.success(true) }, + baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }), ).apply { - givenRoomMembersState(MatrixRoomMembersState.Unknown) + givenRoomMembersState(RoomMembersState.Unknown) } val avatarUrl = "https://domain.com/avatar.jpg" @@ -647,7 +648,7 @@ import kotlin.time.Duration.Companion.seconds assertThat(event.readReceiptState.receipts.first().avatarData.url).isNull() room.givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( persistentListOf(aRoomMember(userId = A_USER_ID, avatarUrl = avatarUrl)) ) ) @@ -663,9 +664,9 @@ import kotlin.time.Duration.Companion.seconds private fun TestScope.createTimelinePresenter( timeline: Timeline = FakeTimeline(), - room: FakeMatrixRoom = FakeMatrixRoom( + room: FakeJoinedRoom = FakeJoinedRoom( liveTimeline = timeline, - canUserSendMessageResult = { _, _ -> Result.success(true) } + baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }), ), redactedVoiceMessageManager: RedactedVoiceMessageManager = FakeRedactedVoiceMessageManager(), messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(), diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenterTest.kt index ba9bc0cdd7..115c8a9690 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryPresenterTest.kt @@ -12,12 +12,12 @@ import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.features.messages.impl.timeline.model.anAggregatedReaction -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_NAME -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.tests.testutils.WarmUpRule import kotlinx.collections.immutable.persistentListOf @@ -32,8 +32,8 @@ class ReactionSummaryPresenterTest { private val aggregatedReaction = anAggregatedReaction(userId = A_USER_ID, key = "👍", isHighlighted = true) private val roomMember = aRoomMember(userId = A_USER_ID, avatarUrl = AN_AVATAR_URL, displayName = A_USER_NAME) private val summaryEvent = ReactionSummaryEvents.ShowReactionSummary(AN_EVENT_ID, listOf(aggregatedReaction), aggregatedReaction.key) - private val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember))) + private val room = FakeBaseRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(persistentListOf(roomMember))) } private val presenter = ReactionSummaryPresenter(room) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineProtectionPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineProtectionPresenterTest.kt index 6da5b38185..ac8e2a5290 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineProtectionPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/protection/TimelineProtectionPresenterTest.kt @@ -9,10 +9,10 @@ package io.element.android.features.messages.impl.timeline.protection import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.media.MediaPreviewValue -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.test.AN_EVENT_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore @@ -55,7 +55,7 @@ class TimelineProtectionPresenterTest { @Test fun `present - media preview value private in public room`() = runTest { val appPreferencesStore = InMemoryAppPreferencesStore(timelineMediaPreviewValue = MediaPreviewValue.Private) - val room = FakeMatrixRoom(initialRoomInfo = aRoomInfo(joinRule = JoinRule.Public)) + val room = FakeBaseRoom(initialRoomInfo = aRoomInfo(joinRule = JoinRule.Public)) val presenter = createPresenter(appPreferencesStore, room) presenter.test { skipItems(1) @@ -72,7 +72,7 @@ class TimelineProtectionPresenterTest { @Test fun `present - media preview value private in non public room`() = runTest { val appPreferencesStore = InMemoryAppPreferencesStore(timelineMediaPreviewValue = MediaPreviewValue.Private) - val room = FakeMatrixRoom(initialRoomInfo = aRoomInfo(joinRule = JoinRule.Invite)) + val room = FakeBaseRoom(initialRoomInfo = aRoomInfo(joinRule = JoinRule.Invite)) val presenter = createPresenter(appPreferencesStore, room) presenter.test { val initialState = awaitItem() @@ -85,7 +85,7 @@ class TimelineProtectionPresenterTest { private fun createPresenter( appPreferencesStore: AppPreferencesStore = InMemoryAppPreferencesStore(), - room: MatrixRoom = FakeMatrixRoom(), + room: BaseRoom = FakeBaseRoom(), ) = TimelineProtectionPresenter( appPreferencesStore = appPreferencesStore, room = room, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt index 505829772b..5b1f7f8654 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt @@ -13,19 +13,20 @@ import app.cash.turbine.Event import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID_3 import io.element.android.libraries.matrix.test.A_USER_ID_4 -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore import io.element.android.tests.testutils.WarmUpRule import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -50,12 +51,13 @@ class TypingNotificationPresenterTest { @Test fun `present - typing notification disabled`() = runTest { - val room = FakeMatrixRoom() + val typingMembersFlow = MutableStateFlow>(emptyList()) + val room = FakeJoinedRoom(roomTypingMembersFlow = typingMembersFlow) val sessionPreferencesStore = InMemorySessionPreferencesStore( - isRenderTypingNotificationsEnabled = false + isRenderTypingNotificationsEnabled = false, ) val presenter = createPresenter( - matrixRoom = room, + joinedRoom = room, sessionPreferencesStore = sessionPreferencesStore, ) moleculeFlow(RecompositionMode.Immediate) { @@ -65,7 +67,7 @@ class TypingNotificationPresenterTest { val initialState = awaitItem() assertThat(initialState.renderTypingNotifications).isFalse() assertThat(initialState.typingMembers).isEmpty() - room.givenRoomTypingMembers(listOf(A_USER_ID_2)) + typingMembersFlow.emit(listOf(A_USER_ID_2)) expectNoEvents() // Preferences changes sessionPreferencesStore.setRenderTypingNotifications(true) @@ -89,14 +91,15 @@ class TypingNotificationPresenterTest { @Test fun `present - state is updated when a member is typing, member is not known`() = runTest { - val room = FakeMatrixRoom() - val presenter = createPresenter(matrixRoom = room) + val typingMembersFlow = MutableStateFlow>(emptyList()) + val room = FakeJoinedRoom(roomTypingMembersFlow = typingMembersFlow) + val presenter = createPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitItem() assertThat(initialState.typingMembers).isEmpty() - room.givenRoomTypingMembers(listOf(A_USER_ID_2)) + typingMembersFlow.emit(listOf(A_USER_ID_2)) val oneMemberTypingState = awaitItem() assertThat(oneMemberTypingState.typingMembers.size).isEqualTo(1) assertThat(oneMemberTypingState.typingMembers.first()).isEqualTo( @@ -105,7 +108,7 @@ class TypingNotificationPresenterTest { ) ) // User stops typing - room.givenRoomTypingMembers(emptyList()) + typingMembersFlow.emit(emptyList()) skipItems(1) val finalState = awaitItem() assertThat(finalState.typingMembers).isEmpty() @@ -115,9 +118,10 @@ class TypingNotificationPresenterTest { @Test fun `present - state is updated when a member is typing, member is known`() = runTest { val aKnownRoomMember = createKnownRoomMember(userId = A_USER_ID_2) - val room = FakeMatrixRoom().apply { + val typingMembersFlow = MutableStateFlow>(emptyList()) + val room = FakeJoinedRoom(roomTypingMembersFlow = typingMembersFlow).apply { givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( listOf( createKnownRoomMember(A_USER_ID), aKnownRoomMember, @@ -127,13 +131,13 @@ class TypingNotificationPresenterTest { ) ) } - val presenter = createPresenter(matrixRoom = room) + val presenter = createPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitItem() assertThat(initialState.typingMembers).isEmpty() - room.givenRoomTypingMembers(listOf(A_USER_ID_2)) + typingMembersFlow.emit(listOf(A_USER_ID_2)) val oneMemberTypingState = awaitItem() assertThat(oneMemberTypingState.typingMembers.size).isEqualTo(1) assertThat(oneMemberTypingState.typingMembers.first()).isEqualTo( @@ -142,7 +146,7 @@ class TypingNotificationPresenterTest { ) ) // User stops typing - room.givenRoomTypingMembers(emptyList()) + typingMembersFlow.emit(emptyList()) skipItems(1) val finalState = awaitItem() assertThat(finalState.typingMembers).isEmpty() @@ -152,14 +156,15 @@ class TypingNotificationPresenterTest { @Test fun `present - state is updated when a member is typing, member is not known, then known`() = runTest { val aKnownRoomMember = createKnownRoomMember(A_USER_ID_2) - val room = FakeMatrixRoom() - val presenter = createPresenter(matrixRoom = room) + val typingMembersFlow = MutableStateFlow>(emptyList()) + val room = FakeJoinedRoom(roomTypingMembersFlow = typingMembersFlow) + val presenter = createPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitItem() assertThat(initialState.typingMembers).isEmpty() - room.givenRoomTypingMembers(listOf(A_USER_ID_2)) + typingMembersFlow.emit(listOf(A_USER_ID_2)) val oneMemberTypingState = awaitItem() assertThat(oneMemberTypingState.typingMembers.size).isEqualTo(1) assertThat(oneMemberTypingState.typingMembers.first()).isEqualTo( @@ -169,7 +174,7 @@ class TypingNotificationPresenterTest { ) // User is getting known room.givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( listOf(aKnownRoomMember).toImmutableList() ) ) @@ -185,19 +190,20 @@ class TypingNotificationPresenterTest { @Test fun `present - reserveSpace becomes true once we get the first typing notification with room members`() = runTest { - val room = FakeMatrixRoom() - val presenter = createPresenter(matrixRoom = room) + val typingMembersFlow = MutableStateFlow>(emptyList()) + val room = FakeJoinedRoom(roomTypingMembersFlow = typingMembersFlow) + val presenter = createPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitItem() assertThat(initialState.typingMembers).isEmpty() - room.givenRoomTypingMembers(listOf(A_USER_ID_2)) + typingMembersFlow.emit(listOf(A_USER_ID_2)) skipItems(1) val updatedTypingState = awaitItem() assertThat(updatedTypingState.reserveSpace).isTrue() // User stops typing - room.givenRoomTypingMembers(emptyList()) + typingMembersFlow.emit(emptyList()) // Is still true for all future events val futureEvents = cancelAndConsumeRemainingEvents() for (event in futureEvents) { @@ -209,14 +215,14 @@ class TypingNotificationPresenterTest { } private fun createPresenter( - matrixRoom: MatrixRoom = FakeMatrixRoom().apply { + joinedRoom: JoinedRoom = FakeJoinedRoom().apply { givenRoomInfo(aRoomInfo(id = roomId, name = "")) }, sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore( isRenderTypingNotificationsEnabled = true ), ) = TypingNotificationPresenter( - room = matrixRoom, + room = joinedRoom, sessionPreferencesStore = sessionPreferencesStore, ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenterTest.kt index 5c3e694062..b3938dd229 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenterTest.kt @@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.media.AudioInfo import io.element.android.libraries.matrix.api.room.message.ReplyParameters import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.mediaplayer.test.FakeMediaPlayer import io.element.android.libraries.mediaupload.api.MediaSender import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor @@ -64,11 +64,11 @@ class VoiceMessageComposerPresenterTest { lambdaRecorder, ProgressCallback?, ReplyParameters?, Result> { _, _, _, _, _ -> Result.success(FakeMediaUploadHandler()) } - private val matrixRoom = FakeMatrixRoom( + private val joinedRoom = FakeJoinedRoom( sendVoiceMessageResult = sendVoiceMessageResult ) private val mediaPreProcessor = FakeMediaPreProcessor().apply { givenAudioResult() } - private val mediaSender = MediaSender(mediaPreProcessor, matrixRoom, InMemorySessionPreferencesStore()) + private val mediaSender = MediaSender(mediaPreProcessor, joinedRoom, InMemorySessionPreferencesStore()) private val messageComposerContext = FakeMessageComposerContext() companion object { diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultEndPollAction.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultEndPollAction.kt index 18bb164778..33c2aa589d 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultEndPollAction.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultEndPollAction.kt @@ -12,13 +12,13 @@ import im.vector.app.features.analytics.plan.PollEnd import io.element.android.features.poll.api.actions.EndPollAction import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.services.analytics.api.AnalyticsService import javax.inject.Inject @ContributesBinding(RoomScope::class) class DefaultEndPollAction @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val analyticsService: AnalyticsService, ) : EndPollAction { override suspend fun execute(pollStartId: EventId): Result { diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultSendPollResponseAction.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultSendPollResponseAction.kt index d11be46cdc..cade3e9bef 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultSendPollResponseAction.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/actions/DefaultSendPollResponseAction.kt @@ -12,13 +12,13 @@ import im.vector.app.features.analytics.plan.PollVote import io.element.android.features.poll.api.actions.SendPollResponseAction import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.services.analytics.api.AnalyticsService import javax.inject.Inject @ContributesBinding(RoomScope::class) class DefaultSendPollResponseAction @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val analyticsService: AnalyticsService, ) : SendPollResponseAction { override suspend fun execute(pollStartId: EventId, answerId: String): Result { diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/data/PollRepository.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/data/PollRepository.kt index f258444fc3..cde6c569a9 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/data/PollRepository.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/data/PollRepository.kt @@ -9,7 +9,7 @@ package io.element.android.features.poll.impl.data import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.poll.PollKind -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.TimelineProvider import io.element.android.libraries.matrix.api.timeline.getActiveTimeline @@ -19,7 +19,7 @@ import kotlinx.coroutines.flow.first import javax.inject.Inject class PollRepository @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val timelineProvider: TimelineProvider, ) { suspend fun getPoll(eventId: EventId): Result = runCatching { diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt index d4da6a76b4..cef19ef687 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt @@ -23,7 +23,7 @@ import io.element.android.features.poll.impl.history.model.PollHistoryFilter import io.element.android.features.poll.impl.history.model.PollHistoryItems import io.element.android.features.poll.impl.history.model.PollHistoryItemsFactory import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.Timeline import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.map @@ -35,7 +35,7 @@ class PollHistoryPresenter @Inject constructor( private val sendPollResponseAction: SendPollResponseAction, private val endPollAction: EndPollAction, private val pollHistoryItemFactory: PollHistoryItemsFactory, - private val room: MatrixRoom, + private val room: JoinedRoom, ) : Presenter { @Composable override fun present(): PollHistoryState { diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt index 76ccc1ffac..6493fc30a7 100644 --- a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt +++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/create/CreatePollPresenterTest.kt @@ -21,12 +21,11 @@ import io.element.android.features.poll.impl.anOngoingPollContent import io.element.android.features.poll.impl.data.PollRepository import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.poll.PollKind -import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.timeline.item.event.PollContent import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId import io.element.android.libraries.matrix.test.AN_EVENT_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.LiveTimelineProvider import io.element.android.services.analytics.test.FakeAnalyticsService @@ -52,7 +51,7 @@ class CreatePollPresenterTest { private val timeline = FakeTimeline( timelineItems = aPollTimelineItems(mapOf(pollEventId to existingPoll)) ) - private val fakeMatrixRoom = FakeMatrixRoom( + private val fakeJoinedRoom = FakeJoinedRoom( liveTimeline = timeline ) private val fakeAnalyticsService = FakeAnalyticsService() @@ -81,7 +80,7 @@ class CreatePollPresenterTest { @Test fun `in edit mode, if poll doesn't exist, error is tracked and screen is closed`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( liveTimeline = FakeTimeline() ) val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(AN_EVENT_ID), room = room) @@ -121,7 +120,7 @@ class CreatePollPresenterTest { fun `create poll sends a poll start event`() = runTest { val createPollResult = lambdaRecorder, Int, PollKind, Result> { _, _, _, _ -> Result.success(Unit) } val presenter = createCreatePollPresenter( - room = FakeMatrixRoom( + room = FakeJoinedRoom( createPollResult = createPollResult ), mode = CreatePollMode.NewPoll, @@ -169,7 +168,7 @@ class CreatePollPresenterTest { Result.failure(error) } val presenter = createCreatePollPresenter( - room = FakeMatrixRoom( + room = FakeJoinedRoom( createPollResult = createPollResult ), mode = CreatePollMode.NewPoll, @@ -258,7 +257,7 @@ class CreatePollPresenterTest { Result.failure(error) } val presenter = createCreatePollPresenter( - room = FakeMatrixRoom( + room = FakeJoinedRoom( editPollResult = editPollResult, liveTimeline = timeline, ), @@ -551,7 +550,7 @@ class CreatePollPresenterTest { private fun createCreatePollPresenter( mode: CreatePollMode = CreatePollMode.NewPoll, - room: MatrixRoom = fakeMatrixRoom, + room: FakeJoinedRoom = fakeJoinedRoom, ): CreatePollPresenter = CreatePollPresenter( repository = PollRepository(room, LiveTimelineProvider(room)), analyticsService = fakeAnalyticsService, diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt index f4f5147f82..c20d608dff 100644 --- a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt +++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt @@ -22,12 +22,11 @@ import io.element.android.features.poll.impl.model.DefaultPollContentStateFactor import io.element.android.features.poll.test.actions.FakeEndPollAction import io.element.android.features.poll.test.actions.FakeSendPollResponseAction import io.element.android.libraries.dateformatter.test.FakeDateFormatter -import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.assert @@ -57,7 +56,7 @@ class PollHistoryPresenterTest { ), backwardPaginationStatus = backwardPaginationStatus ) - private val room = FakeMatrixRoom( + private val room = FakeJoinedRoom( liveTimeline = timeline ) @@ -155,7 +154,7 @@ class PollHistoryPresenterTest { } private fun TestScope.createPollHistoryPresenter( - room: MatrixRoom = FakeMatrixRoom(), + room: FakeJoinedRoom = FakeJoinedRoom(), appCoroutineScope: CoroutineScope = this, endPollAction: EndPollAction = FakeEndPollAction(), sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(), diff --git a/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt b/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt index d04d40b4ef..6df9f8103b 100644 --- a/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt +++ b/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt @@ -16,12 +16,12 @@ import io.element.android.features.call.api.CurrentCall import io.element.android.features.call.api.CurrentCallService import io.element.android.features.roomcall.api.RoomCallState import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.ui.room.canCall import javax.inject.Inject class RoomCallStatePresenter @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val currentCallService: CurrentCallService, ) : Presenter { @Composable diff --git a/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt b/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt index 23791eb444..9f99b9b1af 100644 --- a/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt +++ b/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt @@ -12,8 +12,9 @@ import io.element.android.features.call.api.CurrentCall import io.element.android.features.call.api.CurrentCallService import io.element.android.features.call.test.FakeCurrentCallService import io.element.android.features.roomcall.api.RoomCallState -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.tests.testutils.test import kotlinx.coroutines.flow.MutableStateFlow @@ -23,10 +24,12 @@ import org.junit.Test class RoomCallStatePresenterTest { @Test fun `present - initial state`() = runTest { - val room = FakeMatrixRoom( - canUserJoinCallResult = { Result.success(false) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserJoinCallResult = { Result.success(false) }, + ) ) - val presenter = createRoomCallStatePresenter(matrixRoom = room) + val presenter = createRoomCallStatePresenter(joinedRoom = room) presenter.test { val initialState = awaitItem() assertThat(initialState).isEqualTo( @@ -39,10 +42,12 @@ class RoomCallStatePresenterTest { @Test fun `present - initial state - user can join call`() = runTest { - val room = FakeMatrixRoom( - canUserJoinCallResult = { Result.success(true) }, + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserJoinCallResult = { Result.success(true) }, + ) ) - val presenter = createRoomCallStatePresenter(matrixRoom = room) + val presenter = createRoomCallStatePresenter(joinedRoom = room) presenter.test { skipItems(1) val initialState = awaitItem() @@ -56,11 +61,13 @@ class RoomCallStatePresenterTest { @Test fun `present - call is disabled if user cannot join it even if there is an ongoing call`() = runTest { - val room = FakeMatrixRoom( - canUserJoinCallResult = { Result.success(false) }, - initialRoomInfo = aRoomInfo(hasRoomCall = true), + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserJoinCallResult = { Result.success(false) }, + initialRoomInfo = aRoomInfo(hasRoomCall = true), + ) ) - val presenter = createRoomCallStatePresenter(matrixRoom = room) + val presenter = createRoomCallStatePresenter(joinedRoom = room) presenter.test { assertThat(awaitItem()).isEqualTo( RoomCallState.OnGoing( @@ -74,7 +81,8 @@ class RoomCallStatePresenterTest { @Test fun `present - user has joined the call on another session`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canUserJoinCallResult = { Result.success(true) }, ).apply { givenRoomInfo( @@ -84,7 +92,8 @@ class RoomCallStatePresenterTest { ) ) } - val presenter = createRoomCallStatePresenter(matrixRoom = room) + ) + val presenter = createRoomCallStatePresenter(joinedRoom = room) presenter.test { skipItems(1) assertThat(awaitItem()).isEqualTo( @@ -99,7 +108,8 @@ class RoomCallStatePresenterTest { @Test fun `present - user has joined the call locally`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canUserJoinCallResult = { Result.success(true) }, ).apply { givenRoomInfo( @@ -109,8 +119,9 @@ class RoomCallStatePresenterTest { ) ) } + ) val presenter = createRoomCallStatePresenter( - matrixRoom = room, + joinedRoom = room, currentCallService = FakeCurrentCallService(MutableStateFlow(CurrentCall.RoomCall(room.roomId))), ) presenter.test { @@ -127,7 +138,8 @@ class RoomCallStatePresenterTest { @Test fun `present - user leaves the call`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canUserJoinCallResult = { Result.success(true) }, ).apply { givenRoomInfo( @@ -137,10 +149,11 @@ class RoomCallStatePresenterTest { ) ) } + ) val currentCall = MutableStateFlow(CurrentCall.RoomCall(room.roomId)) val currentCallService = FakeCurrentCallService(currentCall = currentCall) val presenter = createRoomCallStatePresenter( - matrixRoom = room, + joinedRoom = room, currentCallService = currentCallService ) presenter.test { @@ -188,11 +201,11 @@ class RoomCallStatePresenterTest { } private fun createRoomCallStatePresenter( - matrixRoom: MatrixRoom, + joinedRoom: JoinedRoom, currentCallService: CurrentCallService = FakeCurrentCallService(), ): RoomCallStatePresenter { return RoomCallStatePresenter( - room = matrixRoom, + room = joinedRoom, currentCallService = currentCallService, ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt index b7cc8685e4..f736109363 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt @@ -50,7 +50,7 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import io.element.android.libraries.matrix.api.permalink.PermalinkData -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.verification.VerificationRequest import io.element.android.libraries.mediaviewer.api.MediaGalleryEntryPoint import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint @@ -64,7 +64,7 @@ class RoomDetailsFlowNode @AssistedInject constructor( @Assisted plugins: List, private val pollHistoryEntryPoint: PollHistoryEntryPoint, private val elementCallEntryPoint: ElementCallEntryPoint, - private val room: MatrixRoom, + private val room: BaseRoom, private val analyticsService: AnalyticsService, private val messagesEntryPoint: MessagesEntryPoint, private val knockRequestsListEntryPoint: KnockRequestsListEntryPoint, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt index c3a0a3d519..7c1efbacd5 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsNode.kt @@ -24,7 +24,7 @@ import io.element.android.anvilannotations.ContributesNode import io.element.android.libraries.androidutils.system.startSharePlainTextIntent import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.services.analytics.api.AnalyticsService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -36,7 +36,7 @@ class RoomDetailsNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: RoomDetailsPresenter, - private val room: MatrixRoom, + private val room: BaseRoom, private val analyticsService: AnalyticsService, ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt index 5c6333a290..c7a38a4731 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt @@ -35,9 +35,9 @@ import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.powerlevels.canInvite @@ -61,7 +61,7 @@ import javax.inject.Inject class RoomDetailsPresenter @Inject constructor( private val client: MatrixClient, - private val room: MatrixRoom, + private val room: JoinedRoom, private val featureFlagService: FeatureFlagService, private val notificationSettingsService: NotificationSettingsService, private val roomMembersDetailsPresenterFactory: RoomMemberDetailsPresenter.Factory, @@ -235,12 +235,12 @@ class RoomDetailsPresenter @Inject constructor( } @Composable - private fun getCanInvite(membersState: MatrixRoomMembersState) = produceState(false, membersState) { + private fun getCanInvite(membersState: RoomMembersState) = produceState(false, membersState) { value = room.canInvite().getOrElse { false } } @Composable - private fun getCanSendState(membersState: MatrixRoomMembersState, type: StateEventType) = produceState(false, membersState) { + private fun getCanSendState(membersState: RoomMembersState, type: StateEventType) = produceState(false, membersState) { value = room.canSendState(type).getOrElse { false } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/analytics/AnalyticUtils.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/analytics/AnalyticUtils.kt index 75d193aef4..48c13b80a6 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/analytics/AnalyticUtils.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/analytics/AnalyticUtils.kt @@ -9,7 +9,7 @@ package io.element.android.features.roomdetails.impl.analytics import im.vector.app.features.analytics.plan.RoomModeration import io.element.android.libraries.matrix.api.room.RoomMember -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import io.element.android.services.analytics.api.AnalyticsService internal fun RoomMember.Role.toAnalyticsMemberRole(): RoomModeration.Role = when (this) { @@ -22,7 +22,7 @@ internal fun analyticsMemberRoleForPowerLevel(powerLevel: Long): RoomModeration. return RoomMember.Role.forPowerLevel(powerLevel).toAnalyticsMemberRole() } -internal fun AnalyticsService.trackPermissionChangeAnalytics(initial: MatrixRoomPowerLevels?, updated: MatrixRoomPowerLevels) { +internal fun AnalyticsService.trackPermissionChangeAnalytics(initial: RoomPowerLevels?, updated: RoomPowerLevels) { if (updated.ban != initial?.ban) { capture(RoomModeration(RoomModeration.Action.ChangePermissionsBanMembers, analyticsMemberRoleForPowerLevel(updated.ban))) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModule.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModule.kt index e5f63332aa..15afcbc99f 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModule.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModule.kt @@ -16,14 +16,14 @@ import io.element.android.libraries.androidutils.clipboard.ClipboardHelper import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.EncryptionService -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom @Module @ContributesTo(RoomScope::class) object RoomMemberModule { @Provides fun provideRoomMemberDetailsPresenterFactory( - room: MatrixRoom, + room: JoinedRoom, userProfilePresenterFactory: UserProfilePresenterFactory, encryptionService: EncryptionService, clipboardHelper: ClipboardHelper, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenter.kt index 30e05101c8..fb77530b6d 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenter.kt @@ -25,7 +25,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.core.mimetype.MimeTypes -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.powerlevels.canSendState import io.element.android.libraries.matrix.ui.media.AvatarAction @@ -43,7 +43,7 @@ import timber.log.Timber import javax.inject.Inject class RoomDetailsEditPresenter @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val mediaPickerProvider: PickerProvider, private val mediaPreProcessor: MediaPreProcessor, private val temporaryUriDeleter: TemporaryUriDeleter, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt index 1564f53084..ebfa3dcab8 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersNode.kt @@ -20,7 +20,7 @@ import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.di.RoomScope -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.apperror.api.AppErrorStateService @@ -33,7 +33,7 @@ class RoomInviteMembersNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, coroutineDispatchers: CoroutineDispatchers, - private val room: MatrixRoom, + private val room: JoinedRoom, private val presenter: RoomInviteMembersPresenter, private val appErrorStateService: AppErrorStateService, private val analyticsService: AnalyticsService, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt index e7df374917..ef627a4992 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListDataSource.kt @@ -9,14 +9,14 @@ package io.element.android.features.roomdetails.impl.members import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.coroutine.CoroutineDispatchers -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.roomMembers import kotlinx.coroutines.withContext import javax.inject.Inject class RoomMemberListDataSource @Inject constructor( - private val room: MatrixRoom, + private val room: BaseRoom, private val coroutineDispatchers: CoroutineDispatchers, ) { suspend fun search(query: String): List = withContext(coroutineDispatchers.io) { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt index e154c7ea15..e2527444aa 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt @@ -28,9 +28,9 @@ import io.element.android.libraries.designsystem.theme.components.SearchBarResul import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.identity.IdentityState -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.ui.room.canInviteAsState @@ -45,7 +45,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.withContext class RoomMemberListPresenter @AssistedInject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val roomMemberListDataSource: RoomMemberListDataSource, private val coroutineDispatchers: CoroutineDispatchers, private val roomMembersModerationPresenter: Presenter, @@ -86,11 +86,11 @@ class RoomMemberListPresenter @AssistedInject constructor( } LaunchedEffect(membersState, roomMemberIdentityStates) { - if (membersState is MatrixRoomMembersState.Unknown) { + if (membersState is RoomMembersState.Unknown) { return@LaunchedEffect } val finalMembersState = membersState - if (finalMembersState is MatrixRoomMembersState.Error && finalMembersState.roomMembers().orEmpty().isEmpty()) { + if (finalMembersState is RoomMembersState.Error && finalMembersState.roomMembers().orEmpty().isEmpty()) { // Cannot fetch members and no cached members, display the error roomMembers = AsyncData.Failure(finalMembersState.failure) return@LaunchedEffect @@ -116,7 +116,7 @@ class RoomMemberListPresenter @AssistedInject constructor( .map { it.withIdentityState(roomMemberIdentityStates) } .toImmutableList(), ) - roomMembers = if (membersState is MatrixRoomMembersState.Pending) { + roomMembers = if (membersState is RoomMembersState.Pending) { AsyncData.Loading(result) } else { AsyncData.Success(result) @@ -147,7 +147,7 @@ class RoomMemberListPresenter @AssistedInject constructor( .toImmutableList(), ) SearchBarResultState.Results( - if (membersState is MatrixRoomMembersState.Pending) { + if (membersState is RoomMembersState.Pending) { AsyncData.Loading(result) } else { AsyncData.Success(result) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenter.kt index c5de24c603..9afe43daf2 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenter.kt @@ -28,7 +28,7 @@ import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.ui.room.getRoomMemberAsState import io.element.android.libraries.matrix.ui.room.roomMemberIdentityStateChange import io.element.android.libraries.ui.strings.CommonStrings @@ -45,7 +45,7 @@ import kotlinx.coroutines.launch */ class RoomMemberDetailsPresenter @AssistedInject constructor( @Assisted private val roomMemberId: UserId, - private val room: MatrixRoom, + private val room: JoinedRoom, private val encryptionService: EncryptionService, private val clipboardHelper: ClipboardHelper, userProfilePresenterFactory: UserProfilePresenterFactory, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/moderation/RoomMembersModerationPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/moderation/RoomMembersModerationPresenter.kt index 1fea6a8146..af71e21dff 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/moderation/RoomMembersModerationPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/moderation/RoomMembersModerationPresenter.kt @@ -22,7 +22,7 @@ import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runUpdatingState import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.ui.room.canBanAsState @@ -38,7 +38,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject class RoomMembersModerationPresenter @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val dispatchers: CoroutineDispatchers, private val analyticsService: AnalyticsService, ) : Presenter { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsPresenter.kt index 7dae51a1a2..fb7a3b03da 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsPresenter.kt @@ -26,7 +26,7 @@ import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.core.coroutine.suspendWithMinimumDuration import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationSettings import kotlinx.coroutines.CoroutineScope @@ -38,7 +38,7 @@ import kotlinx.coroutines.launch import kotlin.time.Duration.Companion.seconds class RoomNotificationSettingsPresenter @AssistedInject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val notificationSettingsService: NotificationSettingsService, @Assisted private val showUserDefinedSettingStyle: Boolean, ) : Presenter { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsNode.kt index cf6b6cb522..f0fa5e5c8d 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsNode.kt @@ -19,7 +19,7 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.libraries.di.RoomScope -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.RoomMember import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter @@ -32,7 +32,7 @@ class RolesAndPermissionsNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: RolesAndPermissionsPresenter, - private val room: MatrixRoom, + private val room: BaseRoom, ) : Node(buildContext, plugins = plugins), RolesAndPermissionsNavigator { interface Callback : Plugin, RolesAndPermissionsNavigator { override fun openAdminList() diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsPresenter.kt index 37e72d158f..2f2f14a157 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsPresenter.kt @@ -21,8 +21,8 @@ import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runUpdatingState import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.activeRoomMembers import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange @@ -32,7 +32,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject class RolesAndPermissionsPresenter @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val dispatchers: CoroutineDispatchers, private val analyticsService: AnalyticsService, ) : Presenter { @@ -109,7 +109,7 @@ class RolesAndPermissionsPresenter @Inject constructor( } } - private fun MatrixRoomInfo.userCountWithRole(userIds: List, role: RoomMember.Role): Int { + private fun RoomInfo.userCountWithRole(userIds: List, role: RoomMember.Role): Int { return this.userPowerLevels.count { (userId, level) -> RoomMember.Role.forPowerLevel(level) == role && userId in userIds } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenter.kt index 8878dc8876..36fc5a336a 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenter.kt @@ -30,7 +30,7 @@ import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.room.powerlevels.usersWithRole @@ -50,7 +50,7 @@ import kotlinx.coroutines.launch class ChangeRolesPresenter @AssistedInject constructor( @Assisted private val role: RoomMember.Role, - private val room: MatrixRoom, + private val room: JoinedRoom, private val dispatchers: CoroutineDispatchers, private val analyticsService: AnalyticsService, ) : Presenter { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsPresenter.kt index 0a059b2638..905a71a623 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsPresenter.kt @@ -21,8 +21,8 @@ import dagger.assisted.AssistedInject import io.element.android.features.roomdetails.impl.analytics.trackPermissionChangeAnalytics import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import io.element.android.services.analytics.api.AnalyticsService import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -31,7 +31,7 @@ import kotlinx.coroutines.launch class ChangeRoomPermissionsPresenter @AssistedInject constructor( @Assisted private val section: ChangeRoomPermissionsSection, - private val room: MatrixRoom, + private val room: JoinedRoom, private val analyticsService: AnalyticsService, ) : Presenter { companion object { @@ -59,8 +59,8 @@ class ChangeRoomPermissionsPresenter @AssistedInject constructor( private val items: ImmutableList = itemsForSection(section) - private var initialPermissions by mutableStateOf(null) - private var currentPermissions by mutableStateOf(null) + private var initialPermissions by mutableStateOf(null) + private var currentPermissions by mutableStateOf(null) private var saveAction by mutableStateOf>(AsyncAction.Uninitialized) private var confirmExitAction by mutableStateOf>(AsyncAction.Uninitialized) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsState.kt index 69f62e17d9..6248df0885 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsState.kt @@ -8,12 +8,12 @@ package io.element.android.features.roomdetails.impl.rolesandpermissions.permissions import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import kotlinx.collections.immutable.ImmutableList data class ChangeRoomPermissionsState( val section: ChangeRoomPermissionsSection, - val currentPermissions: MatrixRoomPowerLevels?, + val currentPermissions: RoomPowerLevels?, val items: ImmutableList, val hasChanges: Boolean, val saveAction: AsyncAction, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsStateProvider.kt index 54f07bd637..c068b69716 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsStateProvider.kt @@ -10,7 +10,7 @@ package io.element.android.features.roomdetails.impl.rolesandpermissions.permiss import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.room.RoomMember -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import kotlinx.collections.immutable.toPersistentList class ChangeRoomPermissionsStateProvider : PreviewParameterProvider { @@ -36,7 +36,7 @@ class ChangeRoomPermissionsStateProvider : PreviewParameterProvider = ChangeRoomPermissionsPresenter.itemsForSection(section), hasChanges: Boolean = false, saveAction: AsyncAction = AsyncAction.Uninitialized, @@ -52,8 +52,8 @@ internal fun aChangeRoomPermissionsState( eventSink = eventSink, ) -private fun previewPermissions(): MatrixRoomPowerLevels { - return MatrixRoomPowerLevels( +private fun previewPermissions(): RoomPowerLevels { + return RoomPowerLevels( // MembershipModeration section invite = RoomMember.Role.ADMIN.powerLevel, kick = RoomMember.Role.MODERATOR.powerLevel, diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsView.kt index d2e9c3f290..527eca483f 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsView.kt @@ -36,7 +36,7 @@ import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.matrix.api.room.RoomMember -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import io.element.android.libraries.ui.strings.CommonStrings @OptIn(ExperimentalMaterial3Api::class) @@ -133,7 +133,7 @@ fun ChangeRoomPermissionsView( private fun SelectRoleItem( permissionsItem: RoomPermissionType, role: RoomMember.Role, - currentPermissions: MatrixRoomPowerLevels?, + currentPermissions: RoomPowerLevels?, onClick: (RoomPermissionType, RoomMember.Role) -> Unit ) { val title = when (role) { @@ -153,7 +153,7 @@ private fun SelectRoleItem( ) } -private fun MatrixRoomPowerLevels.isSelected(item: RoomPermissionType, role: RoomMember.Role): Boolean { +private fun RoomPowerLevels.isSelected(item: RoomPermissionType, role: RoomMember.Role): Boolean { return when (item) { RoomPermissionType.BAN -> RoomMember.Role.forPowerLevel(ban) == role RoomPermissionType.INVITE -> RoomMember.Role.forPowerLevel(invite) == role diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt index d6f27a9a5b..35ecbc0d51 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenter.kt @@ -29,8 +29,8 @@ import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.architecture.runUpdatingState import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomAlias -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility @@ -43,7 +43,7 @@ import kotlinx.coroutines.launch class SecurityAndPrivacyPresenter @AssistedInject constructor( @Assisted private val navigator: SecurityAndPrivacyNavigator, private val matrixClient: MatrixClient, - private val room: MatrixRoom, + private val room: JoinedRoom, ) : Presenter { @AssistedFactory interface Factory { @@ -279,6 +279,6 @@ private fun SecurityAndPrivacyHistoryVisibility.map(): RoomHistoryVisibility { } } -private fun MatrixRoomInfo.firstDisplayableAlias(serverName: String): RoomAlias? { +private fun RoomInfo.firstDisplayableAlias(serverName: String): RoomAlias? { return aliases.firstOrNull { it.matchesServer(serverName) } ?: aliases.firstOrNull() } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenter.kt index 2c581e4584..32af99dc1d 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenter.kt @@ -25,8 +25,8 @@ import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomAlias -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper import io.element.android.libraries.matrix.api.roomAliasFromName import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity @@ -37,7 +37,7 @@ import kotlinx.coroutines.launch class EditRoomAddressPresenter @AssistedInject constructor( @Assisted private val navigator: SecurityAndPrivacyNavigator, private val client: MatrixClient, - private val room: MatrixRoom, + private val room: JoinedRoom, private val roomAliasHelper: RoomAliasHelper, ) : Presenter { @AssistedFactory @@ -139,7 +139,7 @@ class EditRoomAddressPresenter @AssistedInject constructor( /** * Returns the first alias that matches the given server name, or null if none match. */ -private fun MatrixRoomInfo.firstAliasMatching(serverName: String): RoomAlias? { +private fun RoomInfo.firstAliasMatching(serverName: String): RoomAlias? { // Check if the canonical alias matches the homeserver if (canonicalAlias?.matchesServer(serverName) == true) { return canonicalAlias diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/permissions/SecurityAndPrivacyPermissions.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/permissions/SecurityAndPrivacyPermissions.kt index 50a676da1e..cc052b19b1 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/permissions/SecurityAndPrivacyPermissions.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/permissions/SecurityAndPrivacyPermissions.kt @@ -11,7 +11,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.produceState import io.element.android.features.roomdetails.impl.securityandprivacy.permissions.SecurityAndPrivacyPermissions.Companion.DEFAULT -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.powerlevels.canSendState @@ -37,7 +37,7 @@ data class SecurityAndPrivacyPermissions( } @Composable -fun MatrixRoom.securityAndPrivacyPermissionsAsState(updateKey: Long): State { +fun BaseRoom.securityAndPrivacyPermissionsAsState(updateKey: Long): State { return produceState(DEFAULT, key1 = updateKey) { value = SecurityAndPrivacyPermissions( canChangeRoomAccess = canSendState(type = StateEventType.ROOM_JOIN_RULES).getOrElse { false }, diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/MatrixRoomFixture.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/MatrixRoomFixture.kt index 3cf5c02e47..1de627fd51 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/MatrixRoomFixture.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/MatrixRoomFixture.kt @@ -21,11 +21,66 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_ROOM_TOPIC import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.tests.testutils.lambda.lambdaError -fun aMatrixRoom( +fun aRoom( + sessionId: SessionId = A_SESSION_ID, + roomId: RoomId = A_ROOM_ID, + displayName: String = A_ROOM_NAME, + rawName: String? = displayName, + topic: String? = A_ROOM_TOPIC, + avatarUrl: String? = AN_AVATAR_URL, + canonicalAlias: RoomAlias? = A_ROOM_ALIAS, + isEncrypted: Boolean = true, + isPublic: Boolean = true, + isDirect: Boolean = false, + joinRule: JoinRule? = null, + activeMemberCount: Long = 1, + joinedMemberCount: Long = 1, + invitedMemberCount: Long = 0, + canInviteResult: (UserId) -> Result = { lambdaError() }, + canBanResult: (UserId) -> Result = { lambdaError() }, + canKickResult: (UserId) -> Result = { lambdaError() }, + canSendStateResult: (UserId, StateEventType) -> Result = { _, _ -> lambdaError() }, + userDisplayNameResult: (UserId) -> Result = { lambdaError() }, + userAvatarUrlResult: () -> Result = { lambdaError() }, + canUserJoinCallResult: (UserId) -> Result = { lambdaError() }, + getUpdatedMemberResult: (UserId) -> Result = { lambdaError() }, + userRoleResult: () -> Result = { lambdaError() }, + setIsFavoriteResult: (Boolean) -> Result = { lambdaError() }, +) = FakeBaseRoom( + sessionId = sessionId, + roomId = roomId, + canInviteResult = canInviteResult, + canBanResult = canBanResult, + canKickResult = canKickResult, + canSendStateResult = canSendStateResult, + userDisplayNameResult = userDisplayNameResult, + userAvatarUrlResult = userAvatarUrlResult, + canUserJoinCallResult = canUserJoinCallResult, + getUpdatedMemberResult = getUpdatedMemberResult, + userRoleResult = userRoleResult, + setIsFavoriteResult = setIsFavoriteResult, + initialRoomInfo = aRoomInfo( + name = displayName, + rawName = rawName, + topic = topic, + avatarUrl = avatarUrl, + canonicalAlias = canonicalAlias, + isDirect = isDirect, + isPublic = isPublic, + isEncrypted = isEncrypted, + joinRule = joinRule, + joinedMembersCount = joinedMemberCount, + activeMembersCount = activeMemberCount, + invitedMembersCount = invitedMemberCount, + ) +) + +fun aJoinedRoom( sessionId: SessionId = A_SESSION_ID, roomId: RoomId = A_ROOM_ID, displayName: String = A_ROOM_NAME, @@ -60,31 +115,33 @@ fun aMatrixRoom( updateCanonicalAliasResult: (RoomAlias?, List) -> Result = { _, _ -> lambdaError() }, publishRoomAliasInRoomDirectoryResult: (RoomAlias) -> Result = { lambdaError() }, removeRoomAliasFromRoomDirectoryResult: (RoomAlias) -> Result = { lambdaError() }, -) = FakeMatrixRoom( - sessionId = sessionId, - roomId = roomId, - notificationSettingsService = notificationSettingsService, - canInviteResult = canInviteResult, - canBanResult = canBanResult, - canKickResult = canKickResult, - canSendStateResult = canSendStateResult, - userDisplayNameResult = userDisplayNameResult, - userAvatarUrlResult = userAvatarUrlResult, + setIsFavoriteResult: (Boolean) -> Result = { lambdaError() }, +) = FakeJoinedRoom( + roomNotificationSettingsService = notificationSettingsService, setNameResult = setNameResult, setTopicResult = setTopicResult, updateAvatarResult = updateAvatarResult, removeAvatarResult = removeAvatarResult, - canUserJoinCallResult = canUserJoinCallResult, - getUpdatedMemberResult = getUpdatedMemberResult, - userRoleResult = userRoleResult, kickUserResult = kickUserResult, banUserResult = banUserResult, unBanUserResult = unBanUserResult, updateCanonicalAliasResult = updateCanonicalAliasResult, publishRoomAliasInRoomDirectoryResult = publishRoomAliasInRoomDirectoryResult, removeRoomAliasFromRoomDirectoryResult = removeRoomAliasFromRoomDirectoryResult, - initialRoomInfo = aRoomInfo( - name = displayName, + baseRoom = aRoom( + sessionId = sessionId, + roomId = roomId, + canInviteResult = canInviteResult, + canBanResult = canBanResult, + canKickResult = canKickResult, + canSendStateResult = canSendStateResult, + userDisplayNameResult = userDisplayNameResult, + userAvatarUrlResult = userAvatarUrlResult, + canUserJoinCallResult = canUserJoinCallResult, + getUpdatedMemberResult = getUpdatedMemberResult, + userRoleResult = userRoleResult, + setIsFavoriteResult = setIsFavoriteResult, + displayName = displayName, rawName = rawName, topic = topic, avatarUrl = avatarUrl, @@ -93,8 +150,8 @@ fun aMatrixRoom( isPublic = isPublic, isEncrypted = isEncrypted, joinRule = joinRule, - joinedMembersCount = joinedMemberCount, - activeMembersCount = activeMemberCount, - invitedMembersCount = invitedMemberCount, + joinedMemberCount = joinedMemberCount, + activeMemberCount = activeMemberCount, + invitedMemberCount = invitedMemberCount, ) ) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt index 6c88ce8c2b..c08aa93692 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt @@ -25,8 +25,8 @@ import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.join.JoinRule @@ -39,7 +39,6 @@ import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.test.FakeAnalyticsService @@ -70,7 +69,7 @@ class RoomDetailsPresenterTest { } private fun TestScope.createRoomDetailsPresenter( - room: MatrixRoom = aMatrixRoom(), + room: JoinedRoom = aJoinedRoom(), leaveRoomState: LeaveRoomState = aLeaveRoomState(), dispatchers: CoroutineDispatchers = testCoroutineDispatchers(), notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(), @@ -116,7 +115,7 @@ class RoomDetailsPresenterTest { @Test fun `present - initial state is created from initial room info`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, @@ -145,7 +144,7 @@ class RoomDetailsPresenterTest { avatarUrl = AN_AVATAR_URL, pinnedEventIds = listOf(AN_EVENT_ID), ) - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, @@ -166,7 +165,7 @@ class RoomDetailsPresenterTest { @Test fun `present - initial state with no room name`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( displayName = "", canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, @@ -185,7 +184,7 @@ class RoomDetailsPresenterTest { fun `present - initial state with DM member sets custom DM roomType`() = runTest { val myRoomMember = aRoomMember(A_SESSION_ID) val otherRoomMember = aRoomMember(A_USER_ID_2) - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, @@ -198,7 +197,7 @@ class RoomDetailsPresenterTest { }, ).apply { val roomMembers = persistentListOf(myRoomMember, otherRoomMember) - givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers)) + givenRoomMembersState(RoomMembersState.Ready(roomMembers)) givenRoomInfo( aRoomInfo( @@ -222,7 +221,7 @@ class RoomDetailsPresenterTest { @Test fun `present - initial state when user can invite others to room`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, @@ -240,7 +239,7 @@ class RoomDetailsPresenterTest { @Test fun `present - initial state when user can not invite others to room`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.success(false) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, @@ -255,7 +254,7 @@ class RoomDetailsPresenterTest { @Test fun `present - initial state when canInvite errors`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.failure(Throwable("Whoops")) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, @@ -270,7 +269,7 @@ class RoomDetailsPresenterTest { @Test fun `present - initial state when user can edit one attribute`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canSendStateResult = { _, stateEventType -> when (stateEventType) { StateEventType.ROOM_TOPIC -> Result.success(true) @@ -296,7 +295,7 @@ class RoomDetailsPresenterTest { fun `present - initial state when user can edit attributes in a DM`() = runTest { val myRoomMember = aRoomMember(A_SESSION_ID) val otherRoomMember = aRoomMember(A_USER_ID_2) - val room = aMatrixRoom( + val room = aJoinedRoom( canSendStateResult = { _, stateEventType -> when (stateEventType) { StateEventType.ROOM_TOPIC, @@ -316,7 +315,7 @@ class RoomDetailsPresenterTest { }, ).apply { val roomMembers = persistentListOf(myRoomMember, otherRoomMember) - givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers)) + givenRoomMembersState(RoomMembersState.Ready(roomMembers)) givenRoomInfo( aRoomInfo( @@ -343,7 +342,7 @@ class RoomDetailsPresenterTest { fun `present - initial state when in a DM with no topic`() = runTest { val myRoomMember = aRoomMember(A_SESSION_ID) val otherRoomMember = aRoomMember(A_USER_ID_2) - val room = aMatrixRoom( + val room = aJoinedRoom( isDirect = true, topic = null, canSendStateResult = { _, stateEventType -> @@ -365,7 +364,7 @@ class RoomDetailsPresenterTest { }, ).apply { val roomMembers = persistentListOf(myRoomMember, otherRoomMember) - givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers)) + givenRoomMembersState(RoomMembersState.Ready(roomMembers)) givenRoomInfo( aRoomInfo( @@ -378,7 +377,7 @@ class RoomDetailsPresenterTest { val presenter = createRoomDetailsPresenter(room) presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { - skipItems(1) + skipItems(2) // There's no topic, so we hide the entire UI for DMs assertThat(awaitItem().roomTopic).isEqualTo(RoomTopicState.Hidden) @@ -389,7 +388,7 @@ class RoomDetailsPresenterTest { @Test fun `present - initial state when user can edit all attributes`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canSendStateResult = { _, stateEventType -> when (stateEventType) { StateEventType.ROOM_TOPIC, @@ -416,7 +415,7 @@ class RoomDetailsPresenterTest { @Test fun `present - initial state when user can edit no attributes`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canSendStateResult = { _, stateEventType -> when (stateEventType) { StateEventType.ROOM_TOPIC, @@ -441,7 +440,7 @@ class RoomDetailsPresenterTest { @Test fun `present - topic state is hidden when no topic and user has no permission`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = null, canSendStateResult = { _, stateEventType -> when (stateEventType) { @@ -467,7 +466,7 @@ class RoomDetailsPresenterTest { @Test fun `present - topic state is 'can add topic' when no topic and user has permission`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = null, canSendStateResult = { _, stateEventType -> when (stateEventType) { @@ -499,7 +498,7 @@ class RoomDetailsPresenterTest { @Test fun `present - leave room event is passed on to leave room presenter`() = runTest { val leaveRoomEventRecorder = EventsRecorder() - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, @@ -519,7 +518,7 @@ class RoomDetailsPresenterTest { @Test fun `present - notification mode changes`() = runTest { val notificationSettingsService = FakeNotificationSettingsService() - val room = aMatrixRoom( + val room = aJoinedRoom( notificationSettingsService = notificationSettingsService, canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, @@ -548,7 +547,7 @@ class RoomDetailsPresenterTest { fun `present - mute room notifications`() = runTest { val notificationSettingsService = FakeNotificationSettingsService(initialRoomMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY) - val room = aMatrixRoom( + val room = aJoinedRoom( notificationSettingsService = notificationSettingsService, canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, @@ -576,7 +575,7 @@ class RoomDetailsPresenterTest { initialRoomMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, initialEncryptedGroupDefaultMode = RoomNotificationMode.ALL_MESSAGES ) - val room = aMatrixRoom( + val room = aJoinedRoom( notificationSettingsService = notificationSettingsService, canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, @@ -601,7 +600,7 @@ class RoomDetailsPresenterTest { @Test fun `present - when set is favorite event is emitted, then the action is called`() = runTest { val setIsFavoriteResult = lambdaRecorder> { _ -> Result.success(Unit) } - val room = FakeMatrixRoom( + val room = aJoinedRoom( setIsFavoriteResult = setIsFavoriteResult, canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, @@ -630,7 +629,7 @@ class RoomDetailsPresenterTest { @Test fun `present - changes in room info updates the is favorite flag`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, @@ -651,7 +650,7 @@ class RoomDetailsPresenterTest { @Test fun `present - show knock requests`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, @@ -677,7 +676,7 @@ class RoomDetailsPresenterTest { @Test fun `present - show security and privacy`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canInviteResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) }, diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenterTest.kt index 763f94c310..7a2ff4ee06 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/edit/RoomDetailsEditPresenterTest.kt @@ -10,11 +10,11 @@ package io.element.android.features.roomdetails.impl.edit import android.net.Uri import app.cash.turbine.ReceiveTurbine import com.google.common.truth.Truth.assertThat -import io.element.android.features.roomdetails.impl.aMatrixRoom +import io.element.android.features.roomdetails.impl.aJoinedRoom import io.element.android.libraries.androidutils.file.TemporaryUriDeleter import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.mimetype.MimeTypes -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.A_ROOM_NAME @@ -74,7 +74,7 @@ class RoomDetailsEditPresenterTest { } private fun createRoomDetailsEditPresenter( - room: MatrixRoom, + room: JoinedRoom, permissionsPresenter: PermissionsPresenter = FakePermissionsPresenter(), temporaryUriDeleter: TemporaryUriDeleter = FakeTemporaryUriDeleter(), ): RoomDetailsEditPresenter { @@ -89,7 +89,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - initial state is created from room info`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( avatarUrl = AN_AVATAR_URL, displayName = A_ROOM_NAME, rawName = A_ROOM_RAW_NAME, @@ -118,7 +118,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - sets canChangeName if user has permission`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( avatarUrl = AN_AVATAR_URL, canSendStateResult = { _, stateEventType -> when (stateEventType) { @@ -151,7 +151,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - sets canChangeAvatar if user has permission`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( avatarUrl = AN_AVATAR_URL, canSendStateResult = { _, stateEventType -> when (stateEventType) { @@ -183,7 +183,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - sets canChangeTopic if user has permission`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( avatarUrl = AN_AVATAR_URL, canSendStateResult = { _, stateEventType -> when (stateEventType) { @@ -215,7 +215,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - updates state in response to changes`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -260,7 +260,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - obtains avatar uris from gallery`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -284,7 +284,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - obtains avatar uris from camera`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -325,7 +325,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - updates save button state`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -375,7 +375,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - updates save button state when initial values are null`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = null, displayName = "fallback", avatarUrl = null, @@ -428,7 +428,7 @@ class RoomDetailsEditPresenterTest { val setNameResult = lambdaRecorder { _: String -> Result.success(Unit) } val setTopicResult = lambdaRecorder { _: String -> Result.success(Unit) } val removeAvatarResult = lambdaRecorder> { Result.success(Unit) } - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -457,7 +457,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - save doesn't change room details if they're the same trimmed`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -479,7 +479,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - save doesn't change topic if it was unset and is now blank`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = null, displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -501,7 +501,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - save doesn't change name if it's now empty`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -524,7 +524,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - save processes and sets avatar when processor returns successfully`() = runTest { val updateAvatarResult = lambdaRecorder { _: String, _: ByteArray -> Result.success(Unit) } - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -552,7 +552,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - save does not set avatar data if processor fails`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -576,7 +576,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - sets save action to failure if name update fails`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -588,7 +588,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - sets save action to failure if topic update fails`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -600,7 +600,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - sets save action to failure if removing avatar fails`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -613,7 +613,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - sets save action to failure if setting avatar fails`() = runTest { givenPickerReturnsFile() - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -626,7 +626,7 @@ class RoomDetailsEditPresenterTest { @Test fun `present - CancelSaveChanges resets save action state`() = runTest { givenPickerReturnsFile() - val room = aMatrixRoom( + val room = aJoinedRoom( topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL, @@ -650,7 +650,7 @@ class RoomDetailsEditPresenterTest { } private suspend fun saveAndAssertFailure( - room: MatrixRoom, + room: JoinedRoom, event: RoomDetailsEditEvents, deleteCallbackNumberOfInvocation: Int = 2, ) { diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt index cd14a8b513..5aae0f5d3b 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt @@ -11,19 +11,19 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.roomdetails.impl.aMatrixRoom +import io.element.android.features.roomdetails.impl.aRoom import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.roomdetails.impl.members.aRoomMemberList import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUserList import io.element.android.libraries.usersearch.api.UserSearchResult @@ -47,7 +47,7 @@ internal class RoomInviteMembersPresenterTest { fun `present - initial state has no results and no search`() = runTest { val presenter = RoomInviteMembersPresenter( userRepository = FakeUserRepository(), - roomMemberListDataSource = createDataSource(FakeMatrixRoom()), + roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers() ) @@ -69,7 +69,7 @@ internal class RoomInviteMembersPresenterTest { fun `present - updates search active state`() = runTest { val presenter = RoomInviteMembersPresenter( userRepository = FakeUserRepository(), - roomMemberListDataSource = createDataSource(FakeMatrixRoom()), + roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers() ) @@ -91,7 +91,7 @@ internal class RoomInviteMembersPresenterTest { val repository = FakeUserRepository() val presenter = RoomInviteMembersPresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeMatrixRoom()), + roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) moleculeFlow(RecompositionMode.Immediate) { @@ -118,7 +118,7 @@ internal class RoomInviteMembersPresenterTest { val repository = FakeUserRepository() val presenter = RoomInviteMembersPresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeMatrixRoom()), + roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) moleculeFlow(RecompositionMode.Immediate) { @@ -159,9 +159,9 @@ internal class RoomInviteMembersPresenterTest { val presenter = RoomInviteMembersPresenter( userRepository = repository, roomMemberListDataSource = createDataSource( - matrixRoom = FakeMatrixRoom().apply { + room = FakeBaseRoom().apply { givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( persistentListOf( aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), @@ -219,9 +219,9 @@ internal class RoomInviteMembersPresenterTest { val repository = FakeUserRepository() val presenter = RoomInviteMembersPresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeMatrixRoom().apply { + roomMemberListDataSource = createDataSource(FakeBaseRoom().apply { givenRoomMembersState( - MatrixRoomMembersState.Ready( + RoomMembersState.Ready( persistentListOf( aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), @@ -295,7 +295,7 @@ internal class RoomInviteMembersPresenterTest { val repository = FakeUserRepository() val presenter = RoomInviteMembersPresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeMatrixRoom()), + roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) moleculeFlow(RecompositionMode.Immediate) { @@ -336,7 +336,7 @@ internal class RoomInviteMembersPresenterTest { val repository = FakeUserRepository() val presenter = RoomInviteMembersPresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeMatrixRoom()), + roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) moleculeFlow(RecompositionMode.Immediate) { @@ -397,11 +397,11 @@ internal class RoomInviteMembersPresenterTest { } private fun TestScope.createDataSource( - matrixRoom: MatrixRoom = aMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + room: BaseRoom = aRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) }, coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers() - ) = RoomMemberListDataSource(matrixRoom, coroutineDispatchers) + ) = RoomMemberListDataSource(room, coroutineDispatchers) private fun SearchBarResultState>.users() = (this as? SearchBarResultState.Results>)?.results.orEmpty() diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelRoomMemberComparatorTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelBaseRoomMemberComparatorTest.kt similarity index 98% rename from features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelRoomMemberComparatorTest.kt rename to features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelBaseRoomMemberComparatorTest.kt index 496cfb3136..80ada2e7b6 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelRoomMemberComparatorTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelBaseRoomMemberComparatorTest.kt @@ -15,7 +15,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID_4 import io.element.android.libraries.matrix.test.A_USER_ID_5 import org.junit.Test -class PowerLevelRoomMemberComparatorTest { +class PowerLevelBaseRoomMemberComparatorTest { @Test fun `order is Admin, then Moderator, then User`() { val memberList = listOf( diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenterTest.kt index 91a6ba6683..82e5a910dc 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenterTest.kt @@ -17,10 +17,12 @@ import io.element.android.features.roomdetails.impl.members.moderation.aRoomMemb import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.WarmUpRule @@ -38,14 +40,16 @@ class RoomMemberListPresenterTest { @Test fun `member loading is done automatically on start, but is async`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( updateMembersResult = { Result.success(Unit) }, canInviteResult = { Result.success(true) } ).apply { // Needed to avoid discarding the loaded members as a partial and invalid result givenRoomInfo(aRoomInfo(joinedMembersCount = 2)) } - val presenter = createPresenter(matrixRoom = room) + ) + val presenter = createPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -55,7 +59,7 @@ class RoomMemberListPresenterTest { assertThat(initialState.searchQuery).isEmpty() assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(initialState.isSearchActive).isFalse() - room.givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + room.givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) // Skip item while the new members state is processed skipItems(1) val loadedMembersState = awaitItem() @@ -69,9 +73,11 @@ class RoomMemberListPresenterTest { @Test fun `open search`() = runTest { val presenter = createPresenter( - matrixRoom = FakeMatrixRoom( - updateMembersResult = { Result.success(Unit) }, - canInviteResult = { Result.success(true) } + joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + updateMembersResult = { Result.success(Unit) }, + canInviteResult = { Result.success(true) } + ) ) ) moleculeFlow(RecompositionMode.Immediate) { @@ -89,10 +95,12 @@ class RoomMemberListPresenterTest { @Test fun `search for something which is not found`() = runTest { val presenter = createPresenter( - matrixRoom = FakeMatrixRoom( + joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( updateMembersResult = { Result.success(Unit) }, canInviteResult = { Result.success(true) } ) + ) ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -113,9 +121,11 @@ class RoomMemberListPresenterTest { @Test fun `search for something which is found`() = runTest { val presenter = createPresenter( - matrixRoom = FakeMatrixRoom( - updateMembersResult = { Result.success(Unit) }, - canInviteResult = { Result.success(true) } + joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + updateMembersResult = { Result.success(Unit) }, + canInviteResult = { Result.success(true) } + ) ) ) moleculeFlow(RecompositionMode.Immediate) { @@ -139,9 +149,11 @@ class RoomMemberListPresenterTest { @Test fun `present - asynchronously sets canInvite when user has correct power level`() = runTest { val presenter = createPresenter( - matrixRoom = FakeMatrixRoom( - canInviteResult = { Result.success(true) }, - updateMembersResult = { Result.success(Unit) } + joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canInviteResult = { Result.success(true) }, + updateMembersResult = { Result.success(Unit) } + ) ) ) moleculeFlow(RecompositionMode.Immediate) { @@ -156,9 +168,11 @@ class RoomMemberListPresenterTest { @Test fun `present - asynchronously sets canInvite when user does not have correct power level`() = runTest { val presenter = createPresenter( - matrixRoom = FakeMatrixRoom( - canInviteResult = { Result.success(false) }, - updateMembersResult = { Result.success(Unit) } + joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canInviteResult = { Result.success(false) }, + updateMembersResult = { Result.success(Unit) } + ) ) ) moleculeFlow(RecompositionMode.Immediate) { @@ -173,9 +187,11 @@ class RoomMemberListPresenterTest { @Test fun `present - asynchronously sets canInvite when power level check fails`() = runTest { val presenter = createPresenter( - matrixRoom = FakeMatrixRoom( - canInviteResult = { Result.failure(Throwable("Eek")) }, - updateMembersResult = { Result.success(Unit) } + joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canInviteResult = { Result.failure(Throwable("Eek")) }, + updateMembersResult = { Result.success(Unit) } + ) ) ) moleculeFlow(RecompositionMode.Immediate) { @@ -194,9 +210,11 @@ class RoomMemberListPresenterTest { val presenter = createPresenter( roomMembersModerationStateLambda = roomMembersModerationStateLambda, navigator = navigator, - matrixRoom = FakeMatrixRoom( - updateMembersResult = { Result.success(Unit) }, - canInviteResult = { Result.success(true) } + joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + updateMembersResult = { Result.success(Unit) }, + canInviteResult = { Result.success(true) } + ) ) ) moleculeFlow(RecompositionMode.Immediate) { @@ -221,9 +239,11 @@ class RoomMemberListPresenterTest { val presenter = createPresenter( roomMembersModerationStateLambda = roomMembersModerationStateLambda, navigator = navigator, - matrixRoom = FakeMatrixRoom( - updateMembersResult = { Result.success(Unit) }, - canInviteResult = { Result.success(true) } + joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + updateMembersResult = { Result.success(Unit) }, + canInviteResult = { Result.success(true) } + ) ) ) moleculeFlow(RecompositionMode.Immediate) { @@ -247,24 +267,26 @@ private class FakeRoomMemberListNavigator : RoomMemberListNavigator { @ExperimentalCoroutinesApi private fun TestScope.createDataSource( - matrixRoom: MatrixRoom = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + room: BaseRoom = FakeBaseRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) }, coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers() -) = RoomMemberListDataSource(matrixRoom, coroutineDispatchers) +) = RoomMemberListDataSource(room, coroutineDispatchers) @ExperimentalCoroutinesApi private fun TestScope.createPresenter( coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true), - matrixRoom: MatrixRoom = FakeMatrixRoom( - updateMembersResult = { Result.success(Unit) } + joinedRoom: JoinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + updateMembersResult = { Result.success(Unit) } + ) ), roomMemberListDataSource: RoomMemberListDataSource = createDataSource(coroutineDispatchers = coroutineDispatchers), roomMembersModerationStateLambda: () -> RoomMembersModerationState = { aRoomMembersModerationState() }, encryptedService: FakeEncryptionService = FakeEncryptionService(), navigator: RoomMemberListNavigator = object : RoomMemberListNavigator {} ) = RoomMemberListPresenter( - room = matrixRoom, + room = joinedRoom, roomMemberListDataSource = roomMemberListDataSource, coroutineDispatchers = coroutineDispatchers, roomMembersModerationPresenter = { roomMembersModerationStateLambda() }, diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenterTest.kt index 41ff8706ae..17d49cfab9 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenterTest.kt @@ -11,7 +11,7 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.roomdetails.impl.aMatrixRoom +import io.element.android.features.roomdetails.impl.aJoinedRoom import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfilePresenterFactory @@ -23,12 +23,13 @@ import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.consumeItemsUntilPredicate @@ -36,6 +37,7 @@ import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.test import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -48,12 +50,12 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - returns the room member's data, then updates it if needed`() = runTest { val roomMember = aRoomMember(displayName = "Alice") - val room = aMatrixRoom( + val room = aJoinedRoom( userDisplayNameResult = { Result.success("A custom name") }, userAvatarUrlResult = { Result.success("A custom avatar") }, getUpdatedMemberResult = { Result.success(roomMember) }, ).apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember))) + givenRoomMembersState(RoomMembersState.Ready(persistentListOf(roomMember))) } val presenter = createRoomMemberDetailsPresenter( room = room, @@ -75,12 +77,12 @@ class RoomMemberDetailsPresenterTest { displayName = "Alice", avatarUrl = "Alice Avatar url", ) - val room = aMatrixRoom( + val room = aJoinedRoom( userDisplayNameResult = { Result.failure(Throwable()) }, userAvatarUrlResult = { Result.failure(Throwable()) }, getUpdatedMemberResult = { Result.failure(AN_EXCEPTION) }, ).apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember))) + givenRoomMembersState(RoomMembersState.Ready(persistentListOf(roomMember))) } val presenter = createRoomMemberDetailsPresenter( @@ -98,12 +100,12 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - will fallback to original data if the updated data is null`() = runTest { val roomMember = aRoomMember(displayName = "Alice") - val room = aMatrixRoom( + val room = aJoinedRoom( userDisplayNameResult = { Result.success(null) }, userAvatarUrlResult = { Result.success(null) }, getUpdatedMemberResult = { Result.success(roomMember) } ).apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember))) + givenRoomMembersState(RoomMembersState.Ready(persistentListOf(roomMember))) } val presenter = createRoomMemberDetailsPresenter( room = room, @@ -119,7 +121,7 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - will fallback to user profile if user is not a member of the room`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( userDisplayNameResult = { Result.failure(Exception("Not a member!")) }, userAvatarUrlResult = { Result.failure(Exception("Not a member!")) }, getUpdatedMemberResult = { Result.failure(AN_EXCEPTION) }, @@ -142,7 +144,7 @@ class RoomMemberDetailsPresenterTest { displayName = null, avatarUrl = null, ) - val room = aMatrixRoom( + val room = aJoinedRoom( userDisplayNameResult = { Result.success(null) }, userAvatarUrlResult = { Result.success(null) }, getUpdatedMemberResult = { Result.success(roomMember) }, @@ -169,12 +171,14 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - when user's identity is verified, the value in the state is VERIFIED`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( getUpdatedMemberResult = { Result.success(aRoomMember(A_USER_ID)) }, userDisplayNameResult = { Result.success("A custom name") }, userAvatarUrlResult = { Result.success("A custom avatar") }, initialRoomInfo = aRoomInfo(isEncrypted = true), ) + ) val encryptionService = FakeEncryptionService( getUserIdentityResult = { Result.success(IdentityState.Verified) }, ) @@ -188,12 +192,14 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - when user's identity is unknown, the value in the state is UNKNOWN`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( getUpdatedMemberResult = { Result.success(aRoomMember(A_USER_ID)) }, userDisplayNameResult = { Result.success("A custom name") }, userAvatarUrlResult = { Result.success("A custom avatar") }, initialRoomInfo = aRoomInfo(isEncrypted = true), ) + ) val encryptionService = FakeEncryptionService( getUserIdentityResult = { Result.success(null) }, ) @@ -207,12 +213,14 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - when user's identity is pinned, the value in the state is UNVERIFIED`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( getUpdatedMemberResult = { Result.success(aRoomMember(A_USER_ID)) }, userDisplayNameResult = { Result.success("A custom name") }, userAvatarUrlResult = { Result.success("A custom avatar") }, initialRoomInfo = aRoomInfo(isEncrypted = true), ) + ) val encryptionService = FakeEncryptionService( getUserIdentityResult = { Result.success(IdentityState.Pinned) }, ) @@ -226,12 +234,14 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - when user's identity is pin violation, the value in the state is UNVERIFIED`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( getUpdatedMemberResult = { Result.success(aRoomMember(A_USER_ID)) }, userDisplayNameResult = { Result.success("A custom name") }, userAvatarUrlResult = { Result.success("A custom avatar") }, initialRoomInfo = aRoomInfo(isEncrypted = true), ) + ) val encryptionService = FakeEncryptionService( getUserIdentityResult = { Result.success(IdentityState.PinViolation) }, ) @@ -245,12 +255,14 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - when user's identity has a verification violation, the value in the state is VERIFICATION_VIOLATION`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( getUpdatedMemberResult = { Result.success(aRoomMember(A_USER_ID)) }, userDisplayNameResult = { Result.success("A custom name") }, userAvatarUrlResult = { Result.success("A custom avatar") }, initialRoomInfo = aRoomInfo(isEncrypted = true), ) + ) val encryptionService = FakeEncryptionService( getUserIdentityResult = { Result.success(IdentityState.VerificationViolation) }, ) @@ -264,11 +276,15 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - user identity updates in real time if the room is encrypted`() = runTest { - val room = FakeMatrixRoom( + val identityStateChanges = MutableStateFlow(emptyList()) + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( getUpdatedMemberResult = { Result.success(aRoomMember(A_USER_ID)) }, userDisplayNameResult = { Result.success("A custom name") }, userAvatarUrlResult = { Result.success("A custom avatar") }, initialRoomInfo = aRoomInfo(isEncrypted = true), + ), + identityStateChangesFlow = identityStateChanges, ) val encryptionService = FakeEncryptionService( getUserIdentityResult = { Result.success(null) }, @@ -280,24 +296,28 @@ class RoomMemberDetailsPresenterTest { room.emitSyncUpdate() - room.emitIdentityStateChanges(listOf(IdentityStateChange(A_USER_ID, IdentityState.Pinned))) + identityStateChanges.emit(listOf(IdentityStateChange(A_USER_ID, IdentityState.Pinned))) consumeItemsUntilPredicate { it.verificationState == UserProfileVerificationState.UNVERIFIED } - room.emitIdentityStateChanges(listOf(IdentityStateChange(A_USER_ID, IdentityState.Verified))) + identityStateChanges.emit(listOf(IdentityStateChange(A_USER_ID, IdentityState.Verified))) consumeItemsUntilPredicate { it.verificationState == UserProfileVerificationState.VERIFIED } - room.emitIdentityStateChanges(listOf(IdentityStateChange(A_USER_ID, IdentityState.VerificationViolation))) + identityStateChanges.emit(listOf(IdentityStateChange(A_USER_ID, IdentityState.VerificationViolation))) consumeItemsUntilPredicate { it.verificationState == UserProfileVerificationState.VERIFICATION_VIOLATION } } } @Test fun `present - user identity can't update in real time if the room is not encrypted`() = runTest { - val room = FakeMatrixRoom( + val identityStateChanges = MutableStateFlow(emptyList()) + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( getUpdatedMemberResult = { Result.success(aRoomMember(A_USER_ID)) }, userDisplayNameResult = { Result.success("A custom name") }, userAvatarUrlResult = { Result.success("A custom avatar") }, initialRoomInfo = aRoomInfo(isEncrypted = false), + ), + identityStateChangesFlow = identityStateChanges, ) val encryptionService = FakeEncryptionService( getUserIdentityResult = { Result.success(null) }, @@ -308,7 +328,7 @@ class RoomMemberDetailsPresenterTest { assertThat(awaitItem().verificationState).isEqualTo(UserProfileVerificationState.UNKNOWN) room.emitSyncUpdate() - room.emitIdentityStateChanges(listOf(IdentityStateChange(A_USER_ID, IdentityState.Pinned))) + identityStateChanges.emit(listOf(IdentityStateChange(A_USER_ID, IdentityState.Pinned))) // No new events emitted ensureAllEventsConsumed() @@ -317,12 +337,14 @@ class RoomMemberDetailsPresenterTest { @Test fun `present - handles WithdrawVerification action`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( getUpdatedMemberResult = { Result.success(aRoomMember(A_USER_ID)) }, userDisplayNameResult = { Result.success("A custom name") }, userAvatarUrlResult = { Result.success("A custom avatar") }, initialRoomInfo = aRoomInfo(isEncrypted = true), ) + ) val withdrawVerificationResult = lambdaRecorder> { Result.success(Unit) } val encryptionService = FakeEncryptionService( getUserIdentityResult = { Result.success(IdentityState.VerificationViolation) }, @@ -342,7 +364,7 @@ class RoomMemberDetailsPresenterTest { } private fun createRoomMemberDetailsPresenter( - room: MatrixRoom, + room: JoinedRoom, userProfilePresenterFactory: UserProfilePresenterFactory = UserProfilePresenterFactory { Presenter { aUserProfileState( diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/moderation/RoomMembersModerationPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/moderation/RoomMembersModerationPresenterTest.kt index 66e7f6bd90..00239fdf82 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/moderation/RoomMembersModerationPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/moderation/RoomMembersModerationPresenterTest.kt @@ -12,19 +12,19 @@ import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.RoomModeration -import io.element.android.features.roomdetails.impl.aMatrixRoom +import io.element.android.features.roomdetails.impl.aJoinedRoom import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.roomdetails.impl.members.aVictor import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.test.A_REASON import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.lambda.lambdaRecorder @@ -39,7 +39,7 @@ import org.junit.Test class RoomMembersModerationPresenterTest { @Test fun `canDisplayModerationActions - when room is DM is false`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( isPublic = true, activeMemberCount = 2, canKickResult = { Result.success(true) }, @@ -48,7 +48,7 @@ class RoomMembersModerationPresenterTest { ).apply { givenRoomInfo(aRoomInfo(isDirect = true, activeMembersCount = 2)) } - val presenter = createRoomMembersModerationPresenter(matrixRoom = room) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room) presenter.test { assertThat(awaitItem().canDisplayModerationActions).isFalse() } @@ -56,13 +56,13 @@ class RoomMembersModerationPresenterTest { @Test fun `canDisplayModerationActions - when user can kick other users, FF is enabled and room is not a DM returns true`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( activeMemberCount = 10, canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, userRoleResult = { Result.success(RoomMember.Role.ADMIN) }, ) - val presenter = createRoomMembersModerationPresenter(matrixRoom = room) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room) presenter.test { skipItems(1) assertThat(awaitItem().canDisplayModerationActions).isTrue() @@ -71,13 +71,13 @@ class RoomMembersModerationPresenterTest { @Test fun `canDisplayModerationActions - when user can ban other users, FF is enabled and room is not a DM returns true`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( activeMemberCount = 10, canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, userRoleResult = { Result.success(RoomMember.Role.ADMIN) }, ) - val presenter = createRoomMembersModerationPresenter(matrixRoom = room) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room) presenter.test { skipItems(1) assertThat(awaitItem().canDisplayModerationActions).isTrue() @@ -86,13 +86,13 @@ class RoomMembersModerationPresenterTest { @Test fun `present - SelectRoomMember when the current user has permissions displays member actions`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, userRoleResult = { Result.success(RoomMember.Role.ADMIN) }, ) val selectedMember = aVictor() - val presenter = createRoomMembersModerationPresenter(matrixRoom = room) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -112,14 +112,14 @@ class RoomMembersModerationPresenterTest { @Test fun `present - SelectRoomMember displays only view profile if selected member has same power level as the current user`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( sessionId = A_USER_ID, canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, userRoleResult = { Result.success(RoomMember.Role.ADMIN) }, ) val selectedMember = aRoomMember(A_USER_ID_2, powerLevel = 100L) - val presenter = createRoomMembersModerationPresenter(matrixRoom = room) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -138,12 +138,12 @@ class RoomMembersModerationPresenterTest { @Test fun `present - SelectRoomMember displays an unban confirmation dialog when the member is banned`() = runTest { val selectedMember = aRoomMember(A_USER_ID_2, membership = RoomMembershipState.BAN) - val room = aMatrixRoom( + val room = aJoinedRoom( canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, userRoleResult = { Result.success(RoomMember.Role.ADMIN) }, ) - val presenter = createRoomMembersModerationPresenter(matrixRoom = room) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -160,14 +160,14 @@ class RoomMembersModerationPresenterTest { fun `present - Kick requires confirmation and then kicks the user`() = runTest { val analyticsService = FakeAnalyticsService() val kickUserResult = lambdaRecorder> { _, _ -> Result.success(Unit) } - val room = aMatrixRoom( + val room = aJoinedRoom( canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, userRoleResult = { Result.success(RoomMember.Role.ADMIN) }, kickUserResult = kickUserResult, ) val selectedMember = aVictor() - val presenter = createRoomMembersModerationPresenter(matrixRoom = room, analyticsService = analyticsService) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room, analyticsService = analyticsService) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -198,14 +198,14 @@ class RoomMembersModerationPresenterTest { fun `present - BanUser requires confirmation and then bans the user`() = runTest { val analyticsService = FakeAnalyticsService() val banUserResult = lambdaRecorder> { _, _ -> Result.success(Unit) } - val room = aMatrixRoom( + val room = aJoinedRoom( canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, userRoleResult = { Result.success(RoomMember.Role.ADMIN) }, banUserResult = banUserResult, ) val selectedMember = aVictor() - val presenter = createRoomMembersModerationPresenter(matrixRoom = room, analyticsService = analyticsService) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room, analyticsService = analyticsService) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -237,15 +237,15 @@ class RoomMembersModerationPresenterTest { fun `present - UnbanUser requires confirmation and then unbans the user`() = runTest { val analyticsService = FakeAnalyticsService() val selectedMember = aRoomMember(A_USER_ID_2, membership = RoomMembershipState.BAN) - val room = aMatrixRoom( + val room = aJoinedRoom( canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, userRoleResult = { Result.success(RoomMember.Role.ADMIN) }, unBanUserResult = { _, _ -> Result.success(Unit) }, ).apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(selectedMember))) + givenRoomMembersState(RoomMembersState.Ready(persistentListOf(selectedMember))) } - val presenter = createRoomMembersModerationPresenter(matrixRoom = room, analyticsService = analyticsService) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room, analyticsService = analyticsService) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -269,12 +269,12 @@ class RoomMembersModerationPresenterTest { @Test fun `present - Reset removes the selected user and actions`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, userRoleResult = { Result.success(RoomMember.Role.USER) }, ) - val presenter = createRoomMembersModerationPresenter(matrixRoom = room) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -291,7 +291,7 @@ class RoomMembersModerationPresenterTest { @Test fun `present - Reset resets any async actions`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canKickResult = { Result.success(true) }, canBanResult = { Result.success(true) }, kickUserResult = { _, _ -> Result.failure(Throwable("Eek")) }, @@ -299,7 +299,7 @@ class RoomMembersModerationPresenterTest { unBanUserResult = { _, _ -> Result.failure(Throwable("Eek")) }, userRoleResult = { Result.success(RoomMember.Role.USER) }, ) - val presenter = createRoomMembersModerationPresenter(matrixRoom = room) + val presenter = createRoomMembersModerationPresenter(joinedRoom = room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -338,12 +338,12 @@ class RoomMembersModerationPresenterTest { } private fun TestScope.createRoomMembersModerationPresenter( - matrixRoom: FakeMatrixRoom = aMatrixRoom(), + joinedRoom: FakeJoinedRoom = aJoinedRoom(), dispatchers: CoroutineDispatchers = testCoroutineDispatchers(), analyticsService: FakeAnalyticsService = FakeAnalyticsService(), ): RoomMembersModerationPresenter { return RoomMembersModerationPresenter( - room = matrixRoom, + room = joinedRoom, dispatchers = dispatchers, analyticsService = analyticsService, ) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsPresenterTest.kt index 748c4a26e2..3cfc359792 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsPresenterTest.kt @@ -11,12 +11,12 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.roomdetails.impl.aMatrixRoom +import io.element.android.features.roomdetails.impl.aJoinedRoom import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.tests.testutils.awaitLastSequentialItem import io.element.android.tests.testutils.consumeItemsUntilPredicate import kotlinx.coroutines.test.runTest @@ -158,7 +158,7 @@ class RoomNotificationSettingsPresenterTest { val notificationService = FakeNotificationSettingsService().apply { givenCanHomeServerPushEncryptedEventsToDeviceResult(Result.success(false)) } - val room = aMatrixRoom(notificationSettingsService = notificationService, isEncrypted = true) + val room = aJoinedRoom(notificationSettingsService = notificationService, isEncrypted = true) val presenter = createRoomNotificationSettingsPresenter(notificationService, room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -172,7 +172,7 @@ class RoomNotificationSettingsPresenterTest { val notificationService = FakeNotificationSettingsService().apply { givenCanHomeServerPushEncryptedEventsToDeviceResult(Result.success(false)) } - val room = aMatrixRoom(notificationSettingsService = notificationService, isEncrypted = false) + val room = aJoinedRoom(notificationSettingsService = notificationService, isEncrypted = false) val presenter = createRoomNotificationSettingsPresenter(notificationService, room) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -183,7 +183,7 @@ class RoomNotificationSettingsPresenterTest { private fun createRoomNotificationSettingsPresenter( notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(), - room: FakeMatrixRoom = aMatrixRoom(notificationSettingsService = notificationSettingsService), + room: FakeJoinedRoom = aJoinedRoom(notificationSettingsService = notificationSettingsService), ): RoomNotificationSettingsPresenter { return RoomNotificationSettingsPresenter( room = room, diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionPresenterTest.kt index 2ae6dae3aa..9ecbbe69c5 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionPresenterTest.kt @@ -15,7 +15,7 @@ import im.vector.app.features.analytics.plan.RoomModeration import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.room.RoomMember -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.defaultRoomPowerLevels import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.testCoroutineDispatchers @@ -59,7 +59,7 @@ class RolesAndPermissionPresenterTest { fun `present - DemoteSelfTo changes own role to the specified one`() = runTest(StandardTestDispatcher()) { val presenter = createRolesAndPermissionsPresenter( dispatchers = testCoroutineDispatchers(), - room = FakeMatrixRoom( + room = FakeJoinedRoom( updateUserRoleResult = { Result.success(Unit) } ), ) @@ -80,7 +80,7 @@ class RolesAndPermissionPresenterTest { @OptIn(ExperimentalCoroutinesApi::class) @Test fun `present - DemoteSelfTo can handle failures and clean them`() = runTest(StandardTestDispatcher()) { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( updateUserRoleResult = { Result.failure(Exception("Failed to update role")) } ) val presenter = createRolesAndPermissionsPresenter(room = room, dispatchers = testCoroutineDispatchers()) @@ -120,7 +120,7 @@ class RolesAndPermissionPresenterTest { val analyticsService = FakeAnalyticsService() val presenter = createRolesAndPermissionsPresenter( analyticsService = analyticsService, - room = FakeMatrixRoom( + room = FakeJoinedRoom( resetPowerLevelsResult = { Result.success(defaultRoomPowerLevels()) } ) ) @@ -153,7 +153,7 @@ class RolesAndPermissionPresenterTest { } private fun TestScope.createRolesAndPermissionsPresenter( - room: FakeMatrixRoom = FakeMatrixRoom(), + room: FakeJoinedRoom = FakeJoinedRoom(), dispatchers: CoroutineDispatchers = testCoroutineDispatchers(), analyticsService: FakeAnalyticsService = FakeAnalyticsService() ): RolesAndPermissionsPresenter { diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenterTest.kt index 035aecb40a..4c56ae3cee 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesPresenterTest.kt @@ -16,12 +16,13 @@ import io.element.android.features.roomdetails.impl.members.aRoomMemberList import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.tests.testutils.testCoroutineDispatchers @@ -54,8 +55,8 @@ class ChangeRolesPresenterTest { @Test fun `present - initial results are loaded automatically`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) } val presenter = createChangeRolesPresenter(room = room) moleculeFlow(RecompositionMode.Immediate) { @@ -68,8 +69,8 @@ class ChangeRolesPresenterTest { @Test fun `present - ToggleSearchActive changes the value`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) } val presenter = createChangeRolesPresenter(room = room) moleculeFlow(RecompositionMode.Immediate) { @@ -87,8 +88,8 @@ class ChangeRolesPresenterTest { @Test fun `present - QueryChanged produces new results`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) } val presenter = createChangeRolesPresenter(room = room) moleculeFlow(RecompositionMode.Immediate) { @@ -113,8 +114,8 @@ class ChangeRolesPresenterTest { @Test fun `present - changes in the room members produce new results`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) } val presenter = createChangeRolesPresenter(room = room) moleculeFlow(RecompositionMode.Immediate) { @@ -126,7 +127,7 @@ class ChangeRolesPresenterTest { assertThat(initialResults?.moderators).hasSize(1) assertThat(initialResults?.admins).hasSize(1) - room.givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList().take(1).toPersistentList())) + room.givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList().take(1).toPersistentList())) skipItems(1) val searchResults = (awaitItem().searchResults as? SearchBarResultState.Results)?.results @@ -139,8 +140,8 @@ class ChangeRolesPresenterTest { @Test fun `present - UserSelectionToggle adds and removes users from the selected user list`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) givenRoomInfo(aRoomInfo(userPowerLevels = persistentMapOf(A_USER_ID to 100))) } val presenter = createChangeRolesPresenter(room = room) @@ -161,8 +162,8 @@ class ChangeRolesPresenterTest { @Test fun `present - hasPendingChanges is true when the initial selected users don't match the new ones`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) givenRoomInfo(aRoomInfo(userPowerLevels = persistentMapOf(A_USER_ID to 100))) } val presenter = createChangeRolesPresenter(room = room) @@ -190,8 +191,8 @@ class ChangeRolesPresenterTest { @Test fun `present - Exit will display success if no pending changes`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) givenRoomInfo(aRoomInfo(userPowerLevels = persistentMapOf(A_USER_ID to 100))) } val presenter = createChangeRolesPresenter(room = room) @@ -210,8 +211,8 @@ class ChangeRolesPresenterTest { @Test fun `present - CancelExit will remove exit confirmation`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) givenRoomInfo(aRoomInfo(userPowerLevels = persistentMapOf(A_USER_ID to 100))) } val presenter = createChangeRolesPresenter(room = room) @@ -236,8 +237,8 @@ class ChangeRolesPresenterTest { @Test fun `present - Exit will display a confirmation dialog if there are pending changes, calling it again will actually exit`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) givenRoomInfo(aRoomInfo(userPowerLevels = persistentMapOf(A_USER_ID to 100))) } val presenter = createChangeRolesPresenter(room = room) @@ -264,11 +265,11 @@ class ChangeRolesPresenterTest { @Test fun `present - Save will display a confirmation when adding admins`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( updateUserRoleResult = { Result.success(Unit) }, - updateMembersResult = { Result.success(Unit) }, + baseRoom = FakeBaseRoom(updateMembersResult = { Result.success(Unit) }), ).apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) givenRoomInfo(aRoomInfo(userPowerLevels = persistentMapOf(A_USER_ID to 100))) } val presenter = createChangeRolesPresenter(role = RoomMember.Role.ADMIN, room = room) @@ -285,14 +286,19 @@ class ChangeRolesPresenterTest { assertThat(confirmingState.savingState).isEqualTo(AsyncAction.ConfirmingNoParams) confirmingState.eventSink(ChangeRolesEvent.Save) + + val loadingState = awaitItem() + assertThat(loadingState.savingState).isInstanceOf(AsyncAction.Loading::class.java) + skipItems(1) + assertThat(awaitItem().savingState).isEqualTo(AsyncAction.Success(Unit)) } } @Test fun `present - CancelSave will remove the confirmation dialog`() = runTest { - val room = FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + val room = FakeJoinedRoom().apply { + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) givenRoomInfo(aRoomInfo(userPowerLevels = persistentMapOf(A_USER_ID to 100))) } val presenter = createChangeRolesPresenter(role = RoomMember.Role.ADMIN, room = room) @@ -317,11 +323,11 @@ class ChangeRolesPresenterTest { @Test fun `present - Save will just save the data for moderators`() = runTest { val analyticsService = FakeAnalyticsService() - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( updateUserRoleResult = { Result.success(Unit) }, - updateMembersResult = { Result.success(Unit) }, + baseRoom = FakeBaseRoom(updateMembersResult = { Result.success(Unit) }), ).apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) givenRoomInfo(aRoomInfo(userPowerLevels = persistentMapOf(A_USER_ID to 50))) } val presenter = createChangeRolesPresenter( @@ -339,6 +345,11 @@ class ChangeRolesPresenterTest { initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) awaitItem().eventSink(ChangeRolesEvent.Save) + + val loadingState = awaitItem() + assertThat(loadingState.savingState).isInstanceOf(AsyncAction.Loading::class.java) + skipItems(1) + assertThat(awaitItem().savingState).isEqualTo(AsyncAction.Success(Unit)) assertThat(analyticsService.capturedEvents.last()).isEqualTo(RoomModeration(RoomModeration.Action.ChangeMemberRole, RoomModeration.Role.Moderator)) } @@ -346,10 +357,10 @@ class ChangeRolesPresenterTest { @Test fun `present - Save can handle failures and ClearError clears them`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( updateUserRoleResult = { Result.failure(IllegalStateException("Failed")) } ).apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) + givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) givenRoomInfo(aRoomInfo(userPowerLevels = persistentMapOf(A_USER_ID to 50))) } val presenter = createChangeRolesPresenter(role = RoomMember.Role.MODERATOR, room = room) @@ -363,6 +374,9 @@ class ChangeRolesPresenterTest { initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) awaitItem().eventSink(ChangeRolesEvent.Save) + val loadingState = awaitItem() + assertThat(loadingState.savingState).isInstanceOf(AsyncAction.Loading::class.java) + skipItems(1) val failedState = awaitItem() assertThat(failedState.savingState).isInstanceOf(AsyncAction.Failure::class.java) @@ -373,7 +387,7 @@ class ChangeRolesPresenterTest { private fun TestScope.createChangeRolesPresenter( role: RoomMember.Role = RoomMember.Role.ADMIN, - room: FakeMatrixRoom = FakeMatrixRoom(), + room: FakeJoinedRoom = FakeJoinedRoom(), dispatchers: CoroutineDispatchers = testCoroutineDispatchers(), analyticsService: FakeAnalyticsService = FakeAnalyticsService(), ): ChangeRolesPresenter { diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeBaseRoomPermissionsPresenterTest.kt similarity index 94% rename from features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsPresenterTest.kt rename to features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeBaseRoomPermissionsPresenterTest.kt index d9458c3149..8021d09c8d 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeBaseRoomPermissionsPresenterTest.kt @@ -18,14 +18,15 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.room.RoomMember.Role.ADMIN import io.element.android.libraries.matrix.api.room.RoomMember.Role.MODERATOR import io.element.android.libraries.matrix.api.room.RoomMember.Role.USER -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.defaultRoomPowerLevels import io.element.android.services.analytics.test.FakeAnalyticsService import kotlinx.coroutines.test.runTest import org.junit.Test -class ChangeRoomPermissionsPresenterTest { +class ChangeBaseRoomPermissionsPresenterTest { @Test fun `present - initial state`() = runTest { val section = ChangeRoomPermissionsSection.RoomDetails @@ -132,7 +133,7 @@ class ChangeRoomPermissionsPresenterTest { (items.last() as? Event.Item)?.value?.run { assertThat(currentPermissions).isEqualTo( - MatrixRoomPowerLevels( + RoomPowerLevels( invite = MODERATOR.powerLevel, kick = MODERATOR.powerLevel, ban = MODERATOR.powerLevel, @@ -152,9 +153,9 @@ class ChangeRoomPermissionsPresenterTest { val analyticsService = FakeAnalyticsService() val presenter = createChangeRoomPermissionsPresenter( analyticsService = analyticsService, - room = FakeMatrixRoom( + room = FakeJoinedRoom( updatePowerLevelsResult = { Result.success(Unit) }, - powerLevelsResult = { Result.success(defaultPermissions()) } + baseRoom = FakeBaseRoom(powerLevelsResult = { Result.success(defaultPermissions()) }), ), ) moleculeFlow(RecompositionMode.Immediate) { @@ -200,8 +201,8 @@ class ChangeRoomPermissionsPresenterTest { @Test fun `present - Save will fail if there are not current permissions`() = runTest { - val room = FakeMatrixRoom( - powerLevelsResult = { Result.failure(IllegalStateException("Failed to load power levels")) } + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom(powerLevelsResult = { Result.failure(IllegalStateException("Failed to load power levels")) }), ) val presenter = createChangeRoomPermissionsPresenter(room = room) moleculeFlow(RecompositionMode.Immediate) { @@ -217,9 +218,9 @@ class ChangeRoomPermissionsPresenterTest { @Test fun `present - Save can handle failures and they can be cleared`() = runTest { - val room = FakeMatrixRoom( - powerLevelsResult = { Result.success(defaultPermissions()) }, + val room = FakeJoinedRoom( updatePowerLevelsResult = { Result.failure(IllegalStateException("Failed to update power levels")) }, + baseRoom = FakeBaseRoom(powerLevelsResult = { Result.success(defaultPermissions()) }), ) val presenter = createChangeRoomPermissionsPresenter(room = room) moleculeFlow(RecompositionMode.Immediate) { @@ -285,8 +286,8 @@ class ChangeRoomPermissionsPresenterTest { private fun createChangeRoomPermissionsPresenter( section: ChangeRoomPermissionsSection = ChangeRoomPermissionsSection.RoomDetails, - room: FakeMatrixRoom = FakeMatrixRoom( - powerLevelsResult = { Result.success(defaultPermissions()) } + room: FakeJoinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom(powerLevelsResult = { Result.success(defaultPermissions()) }), ), analyticsService: FakeAnalyticsService = FakeAnalyticsService(), ) = ChangeRoomPermissionsPresenter( @@ -296,7 +297,7 @@ class ChangeRoomPermissionsPresenterTest { ) private fun defaultPermissions() = defaultRoomPowerLevels().run { - MatrixRoomPowerLevels( + RoomPowerLevels( invite = invite, kick = kick, ban = ban, diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsViewTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeBaseRoomPermissionsViewTest.kt similarity index 99% rename from features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsViewTest.kt rename to features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeBaseRoomPermissionsViewTest.kt index 7615b89d00..8ed659d31c 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeRoomPermissionsViewTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/permissions/ChangeBaseRoomPermissionsViewTest.kt @@ -31,7 +31,7 @@ import org.junit.rules.TestRule import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class ChangeRoomPermissionsViewTest { +class ChangeBaseRoomPermissionsViewTest { @get:Rule val rule = createAndroidComposeRule() @Test diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenterTest.kt index 1c419c9d1f..bc2a3f62f7 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/SecurityAndPrivacyPresenterTest.kt @@ -10,13 +10,13 @@ package io.element.android.features.roomdetails.impl.securityandprivacy import com.google.common.truth.Truth.assertThat import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility import io.element.android.libraries.matrix.test.A_ROOM_ALIAS import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.lambdaRecorder @@ -54,7 +54,8 @@ class SecurityAndPrivacyPresenterTest { @Test fun `present - room info change updates saved and edited settings`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canSendStateResult = { _, _ -> Result.success(true) }, initialRoomInfo = aRoomInfo( joinRule = JoinRule.Public, @@ -62,6 +63,7 @@ class SecurityAndPrivacyPresenterTest { canonicalAlias = A_ROOM_ALIAS, ) ) + ) val presenter = createSecurityAndPrivacyPresenter(room = room) presenter.test { skipItems(1) @@ -159,11 +161,13 @@ class SecurityAndPrivacyPresenterTest { @Test fun `present - room visibility loading and change`() = runTest { - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canSendStateResult = { _, _ -> Result.success(true) }, - roomVisibilityResult = { Result.success(RoomVisibility.Private) }, + getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared) ) + ) val presenter = createSecurityAndPrivacyPresenter(room = room) presenter.test { skipItems(1) @@ -206,14 +210,16 @@ class SecurityAndPrivacyPresenterTest { val updateJoinRuleLambda = lambdaRecorder> { Result.success(Unit) } val updateRoomVisibilityLambda = lambdaRecorder> { Result.success(Unit) } val updateRoomHistoryVisibilityLambda = lambdaRecorder> { Result.success(Unit) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canSendStateResult = { _, _ -> Result.success(true) }, + getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, + initialRoomInfo = aRoomInfo(joinRule = JoinRule.Invite, historyVisibility = RoomHistoryVisibility.Shared) + ), enableEncryptionResult = enableEncryptionLambda, updateJoinRuleResult = updateJoinRuleLambda, updateRoomVisibilityResult = updateRoomVisibilityLambda, updateRoomHistoryVisibilityResult = updateRoomHistoryVisibilityLambda, - roomVisibilityResult = { Result.success(RoomVisibility.Private) }, - initialRoomInfo = aRoomInfo(joinRule = JoinRule.Invite, historyVisibility = RoomHistoryVisibility.Shared) ) val presenter = createSecurityAndPrivacyPresenter(room = room) presenter.test { @@ -271,14 +277,16 @@ class SecurityAndPrivacyPresenterTest { Result.failure(Exception("Failed to update room visibility")) } val updateRoomHistoryVisibilityLambda = lambdaRecorder> { Result.success(Unit) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canSendStateResult = { _, _ -> Result.success(true) }, + getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, + initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private) + ), enableEncryptionResult = enableEncryptionLambda, updateJoinRuleResult = updateJoinRuleLambda, updateRoomVisibilityResult = updateRoomVisibilityLambda, updateRoomHistoryVisibilityResult = updateRoomHistoryVisibilityLambda, - roomVisibilityResult = { Result.success(RoomVisibility.Private) }, - initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private) ) val presenter = createSecurityAndPrivacyPresenter(room = room) presenter.test { @@ -329,10 +337,12 @@ class SecurityAndPrivacyPresenterTest { private fun createSecurityAndPrivacyPresenter( serverName: String = "matrix.org", - room: MatrixRoom = FakeMatrixRoom( - canSendStateResult = { _, _ -> Result.success(true) }, - roomVisibilityResult = { Result.success(RoomVisibility.Private) }, - initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private) + room: FakeJoinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canSendStateResult = { _, _ -> Result.success(true) }, + getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, + initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private) + ), ), navigator: SecurityAndPrivacyNavigator = FakeSecurityAndPrivacyNavigator(), ): SecurityAndPrivacyPresenter { diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditBaseRoomAddressPresenterTest.kt similarity index 96% rename from features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenterTest.kt rename to features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditBaseRoomAddressPresenterTest.kt index 845e2c0272..7dfc3d464e 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditBaseRoomAddressPresenterTest.kt @@ -8,17 +8,17 @@ package io.element.android.features.roomdetails.impl.securityandprivacy.editroomaddress import com.google.common.truth.Truth.assertThat -import io.element.android.features.roomdetails.impl.aMatrixRoom +import io.element.android.features.roomdetails.impl.aJoinedRoom import io.element.android.features.roomdetails.impl.securityandprivacy.FakeSecurityAndPrivacyNavigator import io.element.android.features.roomdetails.impl.securityandprivacy.SecurityAndPrivacyNavigator import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomAlias -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.alias.FakeRoomAliasHelper import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity import io.element.android.tests.testutils.lambda.assert @@ -29,11 +29,11 @@ import kotlinx.coroutines.test.runTest import org.junit.Test import java.util.Optional -class EditRoomAddressPresenterTest { +class EditBaseRoomAddressPresenterTest { @Test fun `present - initial state no address`() = runTest { val presenter = createEditRoomAddressPresenter( - room = aMatrixRoom(displayName = "") + room = aJoinedRoom(displayName = "") ) presenter.test { with(awaitItem()) { @@ -48,7 +48,7 @@ class EditRoomAddressPresenterTest { @Test fun `present - initial state address matching own homeserver`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( canonicalAlias = RoomAlias("#canonical:matrix.org"), ) val presenter = createEditRoomAddressPresenter(room = room) @@ -65,7 +65,7 @@ class EditRoomAddressPresenterTest { @Test fun `present - initial state address not matching own homeserver`() = runTest { - val room = aMatrixRoom( + val room = aJoinedRoom( displayName = "", canonicalAlias = RoomAlias("#canonical:notmatrix.org"), ) @@ -148,7 +148,7 @@ class EditRoomAddressPresenterTest { val navigator = FakeSecurityAndPrivacyNavigator( closeEditRoomAddressLambda = closeEditAddressLambda ) - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( updateCanonicalAliasResult = updateCanonicalAliasResult, publishRoomAliasInRoomDirectoryResult = publishAliasInRoomDirectoryResult ) @@ -194,7 +194,7 @@ class EditRoomAddressPresenterTest { val navigator = FakeSecurityAndPrivacyNavigator(closeEditRoomAddressLambda = closeEditAddressLambda) val canonicalAlias = RoomAlias("#canonical:matrix.org") - val room = aMatrixRoom( + val room = aJoinedRoom( canonicalAlias = canonicalAlias, updateCanonicalAliasResult = updateCanonicalAliasResult, publishRoomAliasInRoomDirectoryResult = publishAliasInRoomDirectoryResult, @@ -244,7 +244,7 @@ class EditRoomAddressPresenterTest { val navigator = FakeSecurityAndPrivacyNavigator(closeEditRoomAddressLambda = closeEditAddressLambda) val canonicalAlias = RoomAlias("#canonical:notmatrix.org") - val room = aMatrixRoom( + val room = aJoinedRoom( canonicalAlias = canonicalAlias, updateCanonicalAliasResult = updateCanonicalAliasResult, publishRoomAliasInRoomDirectoryResult = publishAliasInRoomDirectoryResult, @@ -343,7 +343,7 @@ class EditRoomAddressPresenterTest { private fun createEditRoomAddressPresenter( client: FakeMatrixClient = createMatrixClient(), - room: MatrixRoom = FakeMatrixRoom(), + room: JoinedRoom = FakeJoinedRoom(), navigator: SecurityAndPrivacyNavigator = FakeSecurityAndPrivacyNavigator(), roomAliasHelper: RoomAliasHelper = FakeRoomAliasHelper() ): EditRoomAddressPresenter { diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressViewTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditBaseRoomAddressViewTest.kt similarity index 99% rename from features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressViewTest.kt rename to features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditBaseRoomAddressViewTest.kt index 03260510a4..1d2c716710 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditRoomAddressViewTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/securityandprivacy/editroomaddress/EditBaseRoomAddressViewTest.kt @@ -28,7 +28,7 @@ import org.junit.rules.TestRule import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class EditRoomAddressViewTest { +class EditBaseRoomAddressViewTest { @get:Rule val rule = createAndroidComposeRule() @Test diff --git a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt index 3165d1f928..d6ebb6cd95 100644 --- a/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt +++ b/features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryPresenterTest.kt @@ -26,7 +26,8 @@ import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Test -@OptIn(ExperimentalCoroutinesApi::class) class RoomDirectoryPresenterTest { +@OptIn(ExperimentalCoroutinesApi::class) +class RoomDirectoryPresenterTest { @Test fun `present - initial state`() = runTest { val presenter = createRoomDirectoryPresenter() diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt index 082a662c30..e2d1ffd698 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt @@ -319,8 +319,6 @@ class RoomListPresenter @Inject constructor( private fun CoroutineScope.clearCacheOfRoom(roomId: RoomId) = launch { client.getRoom(roomId)?.use { room -> - // Ideally we wouldn't have a live timeline at this point, but right now we instantiate one when retrieving the room - room.liveTimeline.close() room.clearEventCacheStorage() } } diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt index 50e7628d09..c5e42bc96c 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt @@ -64,7 +64,7 @@ import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService @@ -275,7 +275,7 @@ class RoomListPresenterTest { @Test fun `present - show context menu`() = runTest { - val room = FakeMatrixRoom() + val room = FakeBaseRoom() val client = FakeMatrixClient().apply { givenGetRoomResult(A_ROOM_ID, room) } @@ -353,7 +353,7 @@ class RoomListPresenterTest { @Test fun `present - hide context menu`() = runTest { - val room = FakeMatrixRoom() + val room = FakeBaseRoom() val client = FakeMatrixClient().apply { givenGetRoomResult(A_ROOM_ID, room) } @@ -463,7 +463,7 @@ class RoomListPresenterTest { @Test fun `present - when set is favorite event is emitted, then the action is called`() = runTest { val setIsFavoriteResult = lambdaRecorder { _: Boolean -> Result.success(Unit) } - val room = FakeMatrixRoom( + val room = FakeBaseRoom( setIsFavoriteResult = setIsFavoriteResult ) val analyticsService = FakeAnalyticsService() @@ -510,9 +510,9 @@ class RoomListPresenterTest { @Test fun `present - check that the room is marked as read with correct RR and as unread`() = runTest { - val room = FakeMatrixRoom() - val room2 = FakeMatrixRoom(roomId = A_ROOM_ID_2) - val room3 = FakeMatrixRoom(roomId = A_ROOM_ID_3) + val room = FakeBaseRoom() + val room2 = FakeBaseRoom(roomId = A_ROOM_ID_2) + val room3 = FakeBaseRoom(roomId = A_ROOM_ID_3) val allRooms = setOf(room, room2, room3) val sessionPreferencesStore = InMemorySessionPreferencesStore() val matrixClient = FakeMatrixClient().apply { diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListBaseRoomSummaryTest.kt similarity index 99% rename from features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt rename to features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListBaseRoomSummaryTest.kt index a7940a203b..4d5ef13d0b 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/model/RoomListBaseRoomSummaryTest.kt @@ -16,7 +16,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME import kotlinx.collections.immutable.toPersistentList import org.junit.Test -class RoomListRoomSummaryTest { +class RoomListBaseRoomSummaryTest { @Test fun `test default value`() { val sut = createRoomListRoomSummary( diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt index 1642578863..483b56aaa0 100644 --- a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt +++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt @@ -72,7 +72,7 @@ class SharePresenter @AssistedInject constructor( } else { roomIds .map { roomId -> - val room = matrixClient.getRoom(roomId) ?: return@map false + val room = matrixClient.getJoinedRoom(roomId) ?: return@map false val mediaSender = MediaSender( preProcessor = mediaPreProcessor, room = room, @@ -93,7 +93,7 @@ class SharePresenter @AssistedInject constructor( onPlainText = { text -> roomIds .map { roomId -> - matrixClient.getRoom(roomId)?.sendMessage( + matrixClient.getJoinedRoom(roomId)?.sendMessage( body = text, htmlBody = null, intentionalMentions = emptyList(), diff --git a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt index 66cb147158..7a49982e2b 100644 --- a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt +++ b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt @@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.test.A_MESSAGE import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore @@ -90,11 +90,11 @@ class SharePresenterTest { @Test fun `present - send text ok`() = runTest { - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( sendMessageResult = { _, _, _ -> Result.success(Unit) }, ) val matrixClient = FakeMatrixClient().apply { - givenGetRoomResult(A_ROOM_ID, matrixRoom) + givenGetRoomResult(A_ROOM_ID, joinedRoom) } val presenter = createSharePresenter( matrixClient = matrixClient, @@ -121,11 +121,11 @@ class SharePresenterTest { lambdaRecorder> { _, _, _, _, _, _ -> Result.success(FakeMediaUploadHandler()) } - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( sendFileResult = sendFileResult, ) val matrixClient = FakeMatrixClient().apply { - givenGetRoomResult(A_ROOM_ID, matrixRoom) + givenGetRoomResult(A_ROOM_ID, joinedRoom) } val presenter = createSharePresenter( matrixClient = matrixClient, diff --git a/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt index 5a843bad81..76464b973c 100644 --- a/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt +++ b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt @@ -34,7 +34,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.awaitLastSequentialItem @@ -122,7 +122,7 @@ class UserProfilePresenterTest { canFindRoom: Boolean = true, expectedResult: Boolean, ) = runTest { - val room = FakeMatrixRoom( + val room = FakeBaseRoom( canUserJoinCallResult = { canUserJoinCallResult }, ) val client = createFakeMatrixClient().apply { diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt similarity index 99% rename from libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt rename to libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt index 11b809258e..04693562cb 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultBaseRoomLastMessageFormatterTest.kt @@ -57,7 +57,7 @@ import org.robolectric.annotation.Config @Suppress("LargeClass") @RunWith(RobolectricTestRunner::class) -class DefaultRoomLastMessageFormatterTest { +class DefaultBaseRoomLastMessageFormatterTest { private lateinit var context: Context private lateinit var fakeMatrixClient: FakeMatrixClient private lateinit var formatter: DefaultRoomLastMessageFormatter diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index 6a85cf45f5..a1b2079809 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -23,10 +23,11 @@ import io.element.android.libraries.matrix.api.notification.NotificationService import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.oidc.AccountManagementAction import io.element.android.libraries.matrix.api.pusher.PushersService -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.NotJoinedRoom +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomMembershipObserver -import io.element.android.libraries.matrix.api.room.RoomPreview import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService import io.element.android.libraries.matrix.api.roomlist.RoomListService @@ -52,8 +53,8 @@ interface MatrixClient { val mediaLoader: MatrixMediaLoader val sessionCoroutineScope: CoroutineScope val ignoredUsersFlow: StateFlow> - suspend fun getRoom(roomId: RoomId): MatrixRoom? - suspend fun getPendingRoom(roomId: RoomId): RoomPreview? + suspend fun getJoinedRoom(roomId: RoomId): JoinedRoom? + suspend fun getRoom(roomId: RoomId): BaseRoom? suspend fun findDM(userId: UserId): RoomId? suspend fun ignoreUser(userId: UserId): Result suspend fun unignoreUser(userId: UserId): Result @@ -147,7 +148,7 @@ interface MatrixClient { /** * Get a room preview for a given room ID or alias. This is especially useful for rooms that the user is not a member of, or hasn't joined yet. */ - suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List): Result + suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List): Result /** * Returns the currently used sliding sync version. @@ -168,7 +169,7 @@ interface MatrixClient { * The flow will emit a new value whenever the room info is updated. * The flow will emit Optional.empty item if the room is not found. */ -fun MatrixClient.getRoomInfoFlow(roomIdOrAlias: RoomIdOrAlias): Flow> { +fun MatrixClient.getRoomInfoFlow(roomIdOrAlias: RoomIdOrAlias): Flow> { return getRoomSummaryFlow(roomIdOrAlias) .map { roomSummary -> roomSummary.map { it.info } } .distinctUntilChanged() diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/ViewRoomExt.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/ViewRoomExt.kt index c221b2881e..3ea1bddf40 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/ViewRoomExt.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/analytics/ViewRoomExt.kt @@ -8,11 +8,11 @@ package io.element.android.libraries.matrix.api.analytics import im.vector.app.features.analytics.plan.ViewRoom -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom -fun MatrixRoom.toAnalyticsViewRoom( +fun BaseRoom.toAnalyticsViewRoom( trigger: ViewRoom.Trigger? = null, - selectedSpace: MatrixRoom? = null, + selectedSpace: BaseRoom? = null, viaKeyboard: Boolean? = null, ): ViewRoom { val activeSpace = selectedSpace?.toActiveSpace() ?: ViewRoom.ActiveSpace.Home @@ -26,6 +26,6 @@ fun MatrixRoom.toAnalyticsViewRoom( ) } -private fun MatrixRoom.toActiveSpace(): ViewRoom.ActiveSpace { +private fun BaseRoom.toActiveSpace(): ViewRoom.ActiveSpace { return if (info().isPublic) ViewRoom.ActiveSpace.Public else ViewRoom.ActiveSpace.Private } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt index 3e7266c444..703ec1205e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt @@ -8,14 +8,14 @@ package io.element.android.libraries.matrix.api.notificationsettings import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationSettings +import io.element.android.libraries.matrix.api.room.RoomNotificationSettingsState import kotlinx.coroutines.flow.SharedFlow interface NotificationSettingsService { /** - * State of the current room notification settings flow ([MatrixRoomNotificationSettingsState.Unknown] if not started). + * State of the current room notification settings flow ([RoomNotificationSettingsState.Unknown] if not started). */ val notificationSettingsChangeFlow: SharedFlow suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt new file mode 100644 index 0000000000..020dc7e449 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/BaseRoom.kt @@ -0,0 +1,231 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.room + +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.draft.ComposerDraft +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels +import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility +import io.element.android.libraries.matrix.api.timeline.ReceiptType +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.StateFlow +import java.io.Closeable + +/** + * This interface represents the common functionality for a local room, whether it's joined, invited, knocked, or left. + */ +interface BaseRoom : Closeable { + /** + * The session id of the current user. + */ + val sessionId: SessionId + + /** + * The id of the room. + */ + val roomId: RoomId + + /** + * The coroutine scope that will handle all jobs related to this room. + */ + val roomCoroutineScope: CoroutineScope + + /** + * The current loaded members as a StateFlow. + * Initial value is [RoomMembersState.Unknown]. + * To update them you should call [updateMembers]. + */ + val membersStateFlow: StateFlow + + /** + * A flow that emits the current [RoomInfo] state. + */ + val roomInfoFlow: StateFlow + + /** + * Get the latest room info we have received from the SDK stream. + */ + fun info(): RoomInfo = roomInfoFlow.value + + /** + * Try to load the room members and update the membersFlow. + */ + suspend fun updateMembers() + + /** + * Get the members of the room. Note: generally this should not be used, please use + * [membersStateFlow] and [updateMembers] instead. + */ + suspend fun getMembers(limit: Int = 5): Result> + + /** + * Will return an updated member or an error. + */ + suspend fun getUpdatedMember(userId: UserId): Result + + /** + * Adds the room to the sync subscription list. + */ + suspend fun subscribeToSync() + + /** + * Gets the power levels of the room. + */ + suspend fun powerLevels(): Result + + /** + * Gets the role of the user with the provided [userId] in the room. + */ + suspend fun userRole(userId: UserId): Result + + /** + * Gets the display name of the user with the provided [userId] in the room. + */ + suspend fun userDisplayName(userId: UserId): Result + + /** + * Gets the avatar of the user with the provided [userId] in the room. + */ + suspend fun userAvatarUrl(userId: UserId): Result + + /** + * Leaves and forgets the room. Only joined, invited or knocked rooms can be left. + */ + suspend fun leave(): Result + + /** + * Joins the room. Only invited rooms can be joined. + */ + suspend fun join(): Result + + /** + * Forgets about the room, removing it from the server and the local cache. Only left and banned rooms can be forgotten. + */ + suspend fun forget(): Result + + /** + * Returns `true` if the user with the provided [userId] can invite other users to the room. + */ + suspend fun canUserInvite(userId: UserId): Result + + /** + * Returns `true` if the user with the provided [userId] can kick other users from the room. + */ + suspend fun canUserKick(userId: UserId): Result + + /** + * Returns `true` if the user with the provided [userId] can ban other users from the room. + */ + suspend fun canUserBan(userId: UserId): Result + + /** + * Returns `true` if the user with the provided [userId] can redact their own messages. + */ + suspend fun canUserRedactOwn(userId: UserId): Result + + /** + * Returns `true` if the user with the provided [userId] can redact messages from other users. + */ + suspend fun canUserRedactOther(userId: UserId): Result + + /** + * Returns `true` if the user with the provided [userId] can send state events. + */ + suspend fun canUserSendState(userId: UserId, type: StateEventType): Result + + /** + * Returns `true` if the user with the provided [userId] can send messages. + */ + suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result + + /** + * Returns `true` if the user with the provided [userId] can trigger an `@room` notification. + */ + suspend fun canUserTriggerRoomNotification(userId: UserId): Result + + /** + * Returns `true` if the user with the provided [userId] can pin or unpin messages. + */ + suspend fun canUserPinUnpin(userId: UserId): Result + + /** + * Returns `true` if the user with the provided [userId] can join or starts calls. + */ + suspend fun canUserJoinCall(userId: UserId): Result = + canUserSendState(userId, StateEventType.CALL_MEMBER) + + /** + * Sets the room as favorite or not, based on the [isFavorite] parameter. + */ + suspend fun setIsFavorite(isFavorite: Boolean): Result + + /** + * Mark the room as read by trying to attach an unthreaded read receipt to the latest room event. + * @param receiptType The type of receipt to send. + */ + suspend fun markAsRead(receiptType: ReceiptType): Result + + /** + * Sets a flag on the room to indicate that the user has explicitly marked it as unread, or reverts the flag. + * @param isUnread true to mark the room as unread, false to remove the flag. + */ + suspend fun setUnreadFlag(isUnread: Boolean): Result + + /** + * Clear the event cache storage for the current room. + */ + suspend fun clearEventCacheStorage(): Result + + /** + * Get the permalink for the room. + */ + suspend fun getPermalink(): Result + + /** + * Get the permalink for the provided [eventId]. + * @param eventId The event id to get the permalink for. + * @return The permalink, or a failure. + */ + suspend fun getPermalinkFor(eventId: EventId): Result + + /** + * Returns the visibility for this room in the room directory. + * If the room is not published, the result will be [RoomVisibility.Private]. + */ + suspend fun getRoomVisibility(): Result + + /** + * Returns the visibility for this room in the room directory, fetching it from the homeserver if needed. + */ + suspend fun getUpdatedIsEncrypted(): Result + + /** + * Store the given `ComposerDraft` in the state store of this room. + */ + suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result + + /** + * Retrieve the `ComposerDraft` stored in the state store for this room. + */ + suspend fun loadComposerDraft(): Result + + /** + * Clear the `ComposerDraft` stored in the state store for this room. + */ + suspend fun clearComposerDraft(): Result + + /** + * Destroy the room and release all resources associated to it. + */ + fun destroy() + + override fun close() = destroy() +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt similarity index 72% rename from libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt index a2a737a019..cbc5220678 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. @@ -13,7 +13,6 @@ import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SendHandle -import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange @@ -23,35 +22,28 @@ import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.MediaUploadHandler import io.element.android.libraries.matrix.api.media.VideoInfo import io.element.android.libraries.matrix.api.poll.PollKind -import io.element.android.libraries.matrix.api.room.draft.ComposerDraft import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.knock.KnockRequest import io.element.android.libraries.matrix.api.room.location.AssetType import io.element.android.libraries.matrix.api.room.message.ReplyParameters -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility -import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -import java.io.Closeable import java.io.File -interface MatrixRoom : Closeable { - val sessionId: SessionId - val roomId: RoomId +interface JoinedRoom : BaseRoom { + val syncUpdateFlow: StateFlow - val roomCoroutineScope: CoroutineScope - - val roomInfoFlow: StateFlow val roomTypingMembersFlow: Flow> val identityStateChangesFlow: Flow> + val roomNotificationSettingsStateFlow: StateFlow /** * The current knock requests in the room as a Flow. @@ -64,40 +56,6 @@ interface MatrixRoom : Closeable { */ val isOneToOne: Boolean get() = info().activeMembersCount == 2L - /** - * The current loaded members as a StateFlow. - * Initial value is [MatrixRoomMembersState.Unknown]. - * To update them you should call [updateMembers]. - */ - val membersStateFlow: StateFlow - - val roomNotificationSettingsStateFlow: StateFlow - - /** - * Get the latest room info we have received from the SDK stream. - */ - fun info(): MatrixRoomInfo = roomInfoFlow.value - - /** - * Try to load the room members and update the membersFlow. - */ - suspend fun updateMembers() - - /** - * Get the members of the room. Note: generally this should not be used, please use - * [membersStateFlow] and [updateMembers] instead. - */ - suspend fun getMembers(limit: Int = 5): Result> - - /** - * Will return an updated member or an error. - */ - suspend fun getUpdatedMember(userId: UserId): Result - - suspend fun updateRoomNotificationSettings(): Result - - val syncUpdateFlow: StateFlow - /** * The live timeline of the room. Must be used to send Event to a room. */ @@ -111,24 +69,6 @@ interface MatrixRoom : Closeable { createTimelineParams: CreateTimelineParams, ): Result - fun destroy() - - suspend fun subscribeToSync() - - suspend fun powerLevels(): Result - - suspend fun updatePowerLevels(matrixRoomPowerLevels: MatrixRoomPowerLevels): Result - - suspend fun resetPowerLevels(): Result - - suspend fun userRole(userId: UserId): Result - - suspend fun updateUsersRoles(changes: List): Result - - suspend fun userDisplayName(userId: UserId): Result - - suspend fun userAvatarUrl(userId: UserId): Result - suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List): Result suspend fun editMessage(eventId: EventId, body: String, htmlBody: String?, intentionalMentions: List): Result @@ -198,75 +138,6 @@ interface MatrixRoom : Closeable { assetType: AssetType? = null, ): Result - suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result - - suspend fun forwardEvent(eventId: EventId, roomIds: List): Result - - suspend fun cancelSend(transactionId: TransactionId): Result - - suspend fun leave(): Result - - suspend fun join(): Result - - suspend fun inviteUserById(id: UserId): Result - - suspend fun canUserInvite(userId: UserId): Result - - suspend fun canUserKick(userId: UserId): Result - - suspend fun canUserBan(userId: UserId): Result - - suspend fun canUserRedactOwn(userId: UserId): Result - - suspend fun canUserRedactOther(userId: UserId): Result - - suspend fun canUserSendState(userId: UserId, type: StateEventType): Result - - suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result - - suspend fun canUserTriggerRoomNotification(userId: UserId): Result - - suspend fun canUserPinUnpin(userId: UserId): Result - - suspend fun canUserJoinCall(userId: UserId): Result = - canUserSendState(userId, StateEventType.CALL_MEMBER) - - suspend fun updateAvatar(mimeType: String, data: ByteArray): Result - - suspend fun removeAvatar(): Result - - suspend fun setName(name: String): Result - - suspend fun setTopic(topic: String): Result - - suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result - - suspend fun kickUser(userId: UserId, reason: String? = null): Result - - suspend fun banUser(userId: UserId, reason: String? = null): Result - - suspend fun unbanUser(userId: UserId, reason: String? = null): Result - - suspend fun setIsFavorite(isFavorite: Boolean): Result - - /** - * Mark the room as read by trying to attach an unthreaded read receipt to the latest room event. - * @param receiptType The type of receipt to send. - */ - suspend fun markAsRead(receiptType: ReceiptType): Result - - /** - * Sets a flag on the room to indicate that the user has explicitly marked it as unread, or reverts the flag. - * @param isUnread true to mark the room as unread, false to remove the flag. - * - */ - suspend fun setUnreadFlag(isUnread: Boolean): Result - - /** - * Clear the event cache storage for the current room. - */ - suspend fun clearEventCacheStorage(): Result - /** * Create a poll in the room. * @@ -321,82 +192,19 @@ interface MatrixRoom : Closeable { */ suspend fun typingNotice(isTyping: Boolean): Result - /** - * Generates a Widget url to display in a [android.webkit.WebView] given the provided parameters. - * @param widgetSettings The widget settings to use. - * @param clientId The client id to use. It should be unique per app install. - * @param languageTag The language tag to use. If null, the default language will be used. - * @param theme The theme to use. If null, the default theme will be used. - * @return The resulting url, or a failure. - */ - suspend fun generateWidgetWebViewUrl( - widgetSettings: MatrixWidgetSettings, - clientId: String, - languageTag: String?, - theme: String?, - ): Result + suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result - /** - * Get a [MatrixWidgetDriver] for the provided [widgetSettings]. - * @param widgetSettings The widget settings to use. - * @return The resulting [MatrixWidgetDriver], or a failure. - */ - fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result + suspend fun forwardEvent(eventId: EventId, roomIds: List): Result - /** - * Get the permalink for the room. - */ - suspend fun getPermalink(): Result + suspend fun cancelSend(transactionId: TransactionId): Result - /** - * Get the permalink for the provided [eventId]. - * @param eventId The event id to get the permalink for. - * @return The permalink, or a failure. - */ - suspend fun getPermalinkFor(eventId: EventId): Result + suspend fun inviteUserById(id: UserId): Result - /** - * Send an Element Call started notification if needed. - */ - suspend fun sendCallNotificationIfNeeded(): Result + suspend fun updateAvatar(mimeType: String, data: ByteArray): Result - suspend fun setSendQueueEnabled(enabled: Boolean) + suspend fun removeAvatar(): Result - /** - * Store the given `ComposerDraft` in the state store of this room. - */ - suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result - - /** - * Retrieve the `ComposerDraft` stored in the state store for this room. - */ - suspend fun loadComposerDraft(): Result - - /** - * Clear the `ComposerDraft` stored in the state store for this room. - */ - suspend fun clearComposerDraft(): Result - - /** - * Ignore the local trust for the given devices and resend messages that failed to send because said devices are unverified. - * - * @param devices The map of users identifiers to device identifiers received in the error - * @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload. - * - */ - suspend fun ignoreDeviceTrustAndResend(devices: Map>, sendHandle: SendHandle): Result - - /** - * Remove verification requirements for the given users and - * resend messages that failed to send because their identities were no longer verified. - * - * @param userIds The list of users identifiers received in the error. - * @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload. - * - */ - suspend fun withdrawVerificationAndResend(userIds: List, sendHandle: SendHandle): Result - - override fun close() = destroy() + suspend fun updateRoomNotificationSettings(): Result /** * Update the canonical alias of the room. @@ -418,12 +226,6 @@ interface MatrixRoom : Closeable { */ suspend fun updateHistoryVisibility(historyVisibility: RoomHistoryVisibility): Result - /** - * Returns the visibility for this room in the room directory. - * If the room is not published, the result will be [RoomVisibility.Private]. - */ - suspend fun getRoomVisibility(): Result - /** * Publish a new room alias for this room in the room directory. * @@ -454,5 +256,69 @@ interface MatrixRoom : Closeable { */ suspend fun updateJoinRule(joinRule: JoinRule): Result - suspend fun getUpdatedIsEncrypted(): Result + suspend fun updateUsersRoles(changes: List): Result + + suspend fun updatePowerLevels(roomPowerLevels: RoomPowerLevels): Result + + suspend fun resetPowerLevels(): Result + + suspend fun setName(name: String): Result + + suspend fun setTopic(topic: String): Result + + suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result + + suspend fun kickUser(userId: UserId, reason: String? = null): Result + + suspend fun banUser(userId: UserId, reason: String? = null): Result + + suspend fun unbanUser(userId: UserId, reason: String? = null): Result + + /** + * Generates a Widget url to display in a [android.webkit.WebView] given the provided parameters. + * @param widgetSettings The widget settings to use. + * @param clientId The client id to use. It should be unique per app install. + * @param languageTag The language tag to use. If null, the default language will be used. + * @param theme The theme to use. If null, the default theme will be used. + * @return The resulting url, or a failure. + */ + suspend fun generateWidgetWebViewUrl( + widgetSettings: MatrixWidgetSettings, + clientId: String, + languageTag: String?, + theme: String?, + ): Result + + /** + * Get a [MatrixWidgetDriver] for the provided [widgetSettings]. + * @param widgetSettings The widget settings to use. + * @return The resulting [MatrixWidgetDriver], or a failure. + */ + fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result + + /** + * Send an Element Call started notification if needed. + */ + suspend fun sendCallNotificationIfNeeded(): Result + + suspend fun setSendQueueEnabled(enabled: Boolean) + + /** + * Ignore the local trust for the given devices and resend messages that failed to send because said devices are unverified. + * + * @param devices The map of users identifiers to device identifiers received in the error + * @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload. + * + */ + suspend fun ignoreDeviceTrustAndResend(devices: Map>, sendHandle: SendHandle): Result + + /** + * Remove verification requirements for the given users and + * resend messages that failed to send because their identities were no longer verified. + * + * @param userIds The list of users identifiers received in the error. + * @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload. + * + */ + suspend fun withdrawVerificationAndResend(userIds: List, sendHandle: SendHandle): Result } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomNotificationSettingsState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomNotificationSettingsState.kt deleted file mode 100644 index 05d9abb30b..0000000000 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomNotificationSettingsState.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.api.room - -sealed interface MatrixRoomNotificationSettingsState { - data object Unknown : MatrixRoomNotificationSettingsState - data class Pending(val prevRoomNotificationSettings: RoomNotificationSettings? = null) : MatrixRoomNotificationSettingsState - data class Error(val failure: Throwable, val prevRoomNotificationSettings: RoomNotificationSettings? = null) : MatrixRoomNotificationSettingsState - data class Ready(val roomNotificationSettings: RoomNotificationSettings) : MatrixRoomNotificationSettingsState -} - -fun MatrixRoomNotificationSettingsState.roomNotificationSettings(): RoomNotificationSettings? { - return when (this) { - is MatrixRoomNotificationSettingsState.Ready -> roomNotificationSettings - is MatrixRoomNotificationSettingsState.Pending -> prevRoomNotificationSettings - is MatrixRoomNotificationSettingsState.Error -> prevRoomNotificationSettings - else -> null - } -} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomPreview.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/NotJoinedRoom.kt similarity index 60% rename from libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomPreview.kt rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/NotJoinedRoom.kt index 6dd8ac0992..b83292e0f2 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomPreview.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/NotJoinedRoom.kt @@ -7,21 +7,12 @@ package io.element.android.libraries.matrix.api.room -import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo /** A reference to a room either invited, knocked or banned. */ -interface RoomPreview : AutoCloseable { - val sessionId: SessionId - val info: RoomPreviewInfo - - /** Leave the room ie.decline invite or cancel knock. */ - suspend fun leave(): Result - - /** - * Forget the room if we had access to it, and it was left or banned. - */ - suspend fun forget(): Result +interface NotJoinedRoom : AutoCloseable { + val previewInfo: RoomPreviewInfo + val localRoom: BaseRoom? /** * Get the membership details of the user in the room, as well as from the user who sent the `m.room.member` event. diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomInfo.kt similarity index 99% rename from libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomInfo.kt index ad526c6b40..1c4957fd74 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomInfo.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomInfo.kt @@ -19,7 +19,7 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableMap @Immutable -data class MatrixRoomInfo( +data class RoomInfo( val id: RoomId, /** The room's name from the room state event if received from sync, or one that's been computed otherwise. */ val name: String?, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomIsDmCheck.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomIsDmCheck.kt index 3dd54db9b1..4f0bf2dcae 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomIsDmCheck.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomIsDmCheck.kt @@ -21,11 +21,11 @@ fun isDm(isDirect: Boolean, activeMembersCount: Int): Boolean { } /** - * Returns whether the [MatrixRoom] is a DM, with an updated state from the latest [MatrixRoomInfo]. + * Returns whether the [BaseRoom] is a DM, with an updated state from the latest [RoomInfo]. */ -suspend fun MatrixRoom.isDm() = roomInfoFlow.first().isDm +suspend fun BaseRoom.isDm() = roomInfoFlow.first().isDm /** - * Returns whether the [MatrixRoomInfo] is from a DM. + * Returns whether the [RoomInfo] is from a DM. */ -val MatrixRoomInfo.isDm get() = isDm(isDirect, activeMembersCount.toInt()) +val RoomInfo.isDm get() = isDm(isDirect, activeMembersCount.toInt()) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMembersState.kt similarity index 56% rename from libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMembersState.kt index 860367b202..ab857e5d63 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoomMembersState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomMembersState.kt @@ -11,26 +11,26 @@ import androidx.compose.runtime.Immutable import kotlinx.collections.immutable.ImmutableList @Immutable -sealed interface MatrixRoomMembersState { - data object Unknown : MatrixRoomMembersState - data class Pending(val prevRoomMembers: ImmutableList? = null) : MatrixRoomMembersState - data class Error(val failure: Throwable, val prevRoomMembers: ImmutableList? = null) : MatrixRoomMembersState - data class Ready(val roomMembers: ImmutableList) : MatrixRoomMembersState +sealed interface RoomMembersState { + data object Unknown : RoomMembersState + data class Pending(val prevRoomMembers: ImmutableList? = null) : RoomMembersState + data class Error(val failure: Throwable, val prevRoomMembers: ImmutableList? = null) : RoomMembersState + data class Ready(val roomMembers: ImmutableList) : RoomMembersState } -fun MatrixRoomMembersState.roomMembers(): List? { +fun RoomMembersState.roomMembers(): List? { return when (this) { - is MatrixRoomMembersState.Ready -> roomMembers - is MatrixRoomMembersState.Pending -> prevRoomMembers - is MatrixRoomMembersState.Error -> prevRoomMembers + is RoomMembersState.Ready -> roomMembers + is RoomMembersState.Pending -> prevRoomMembers + is RoomMembersState.Error -> prevRoomMembers else -> null } } -fun MatrixRoomMembersState.joinedRoomMembers(): List { +fun RoomMembersState.joinedRoomMembers(): List { return roomMembers().orEmpty().filter { it.membership == RoomMembershipState.JOIN } } -fun MatrixRoomMembersState.activeRoomMembers(): List { +fun RoomMembersState.activeRoomMembers(): List { return roomMembers().orEmpty().filter { it.membership.isActive() } } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomNotificationSettingsState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomNotificationSettingsState.kt new file mode 100644 index 0000000000..15c1003317 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomNotificationSettingsState.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.room + +sealed interface RoomNotificationSettingsState { + data object Unknown : RoomNotificationSettingsState + data class Pending(val prevRoomNotificationSettings: RoomNotificationSettings? = null) : RoomNotificationSettingsState + data class Error(val failure: Throwable, val prevRoomNotificationSettings: RoomNotificationSettings? = null) : RoomNotificationSettingsState + data class Ready(val roomNotificationSettings: RoomNotificationSettings) : RoomNotificationSettingsState +} + +fun RoomNotificationSettingsState.roomNotificationSettings(): RoomNotificationSettings? { + return when (this) { + is RoomNotificationSettingsState.Ready -> roomNotificationSettings + is RoomNotificationSettingsState.Pending -> prevRoomNotificationSettings + is RoomNotificationSettingsState.Error -> prevRoomNotificationSettings + else -> null + } +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/alias/MatrixRoomAlias.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/alias/MatrixRoomAlias.kt index 25adbdf3be..0b3bcdbc1c 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/alias/MatrixRoomAlias.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/alias/MatrixRoomAlias.kt @@ -8,12 +8,12 @@ package io.element.android.libraries.matrix.api.room.alias import io.element.android.libraries.matrix.api.core.RoomIdOrAlias -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom /** * Return true if the given roomIdOrAlias is the same room as this room. */ -fun MatrixRoom.matches(roomIdOrAlias: RoomIdOrAlias): Boolean { +fun BaseRoom.matches(roomIdOrAlias: RoomIdOrAlias): Boolean { return when (roomIdOrAlias) { is RoomIdOrAlias.Id -> { roomIdOrAlias.roomId == roomId diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomMembersWithRole.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomMembersWithRole.kt index 3206657f12..49bc4afcd6 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomMembersWithRole.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomMembersWithRole.kt @@ -7,7 +7,7 @@ package io.element.android.libraries.matrix.api.room.powerlevels -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.activeRoomMembers import kotlinx.collections.immutable.ImmutableList @@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.map /** * Return a flow of the list of active room members who have the given role. */ -fun MatrixRoom.usersWithRole(role: RoomMember.Role): Flow> { +fun BaseRoom.usersWithRole(role: RoomMember.Role): Flow> { return roomInfoFlow .map { it.userPowerLevels.filter { (_, powerLevel) -> RoomMember.Role.forPowerLevel(powerLevel) == role } } .combine(membersStateFlow) { powerLevels, membersState -> diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt deleted file mode 100644 index a17d4ad610..0000000000 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/MatrixRoomPowerLevels.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2023, 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.api.room.powerlevels - -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MessageEventType -import io.element.android.libraries.matrix.api.room.StateEventType - -data class MatrixRoomPowerLevels( - val ban: Long, - val invite: Long, - val kick: Long, - val sendEvents: Long, - val redactEvents: Long, - val roomName: Long, - val roomAvatar: Long, - val roomTopic: Long, -) - -/** - * Shortcut for calling [MatrixRoom.canUserInvite] with our own user. - */ -suspend fun MatrixRoom.canInvite(): Result = canUserInvite(sessionId) - -/** - * Shortcut for calling [MatrixRoom.canUserKick] with our own user. - */ -suspend fun MatrixRoom.canKick(): Result = canUserKick(sessionId) - -/** - * Shortcut for calling [MatrixRoom.canUserBan] with our own user. - */ -suspend fun MatrixRoom.canBan(): Result = canUserBan(sessionId) - -/** - * Shortcut for calling [MatrixRoom.canUserSendState] with our own user. - */ -suspend fun MatrixRoom.canSendState(type: StateEventType): Result = canUserSendState(sessionId, type) - -/** - * Shortcut for calling [MatrixRoom.canUserSendMessage] with our own user. - */ -suspend fun MatrixRoom.canSendMessage(type: MessageEventType): Result = canUserSendMessage(sessionId, type) - -/** - * Shortcut for calling [MatrixRoom.canUserRedactOwn] with our own user. - */ -suspend fun MatrixRoom.canRedactOwn(): Result = canUserRedactOwn(sessionId) - -/** - * Shortcut for calling [MatrixRoom.canRedactOther] with our own user. - */ -suspend fun MatrixRoom.canRedactOther(): Result = canUserRedactOther(sessionId) - -/** - * Shortcut for checking if current user can handle knock requests. - */ -suspend fun MatrixRoom.canHandleKnockRequests(): Result = runCatching { - canInvite().getOrThrow() || canBan().getOrThrow() || canKick().getOrThrow() -} - -/** - * Shortcut for calling [MatrixRoom.canUserPinUnpin] with our own user. - */ -suspend fun MatrixRoom.canPinUnpin(): Result = canUserPinUnpin(sessionId) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/RoomPowerLevels.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/RoomPowerLevels.kt new file mode 100644 index 0000000000..95cbf58e17 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/powerlevels/RoomPowerLevels.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.api.room.powerlevels + +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.MessageEventType +import io.element.android.libraries.matrix.api.room.StateEventType + +data class RoomPowerLevels( + val ban: Long, + val invite: Long, + val kick: Long, + val sendEvents: Long, + val redactEvents: Long, + val roomName: Long, + val roomAvatar: Long, + val roomTopic: Long, +) + +/** + * Shortcut for calling [BaseRoom.canUserInvite] with our own user. + */ +suspend fun BaseRoom.canInvite(): Result = canUserInvite(sessionId) + +/** + * Shortcut for calling [BaseRoom.canUserKick] with our own user. + */ +suspend fun BaseRoom.canKick(): Result = canUserKick(sessionId) + +/** + * Shortcut for calling [BaseRoom.canUserBan] with our own user. + */ +suspend fun BaseRoom.canBan(): Result = canUserBan(sessionId) + +/** + * Shortcut for calling [BaseRoom.canUserSendState] with our own user. + */ +suspend fun BaseRoom.canSendState(type: StateEventType): Result = canUserSendState(sessionId, type) + +/** + * Shortcut for calling [BaseRoom.canUserSendMessage] with our own user. + */ +suspend fun BaseRoom.canSendMessage(type: MessageEventType): Result = canUserSendMessage(sessionId, type) + +/** + * Shortcut for calling [BaseRoom.canUserRedactOwn] with our own user. + */ +suspend fun BaseRoom.canRedactOwn(): Result = canUserRedactOwn(sessionId) + +/** + * Shortcut for calling [BaseRoom.canRedactOther] with our own user. + */ +suspend fun BaseRoom.canRedactOther(): Result = canUserRedactOther(sessionId) + +/** + * Shortcut for checking if current user can handle knock requests. + */ +suspend fun BaseRoom.canHandleKnockRequests(): Result = runCatching { + canInvite().getOrThrow() || canBan().getOrThrow() || canKick().getOrThrow() +} + +/** + * Shortcut for calling [BaseRoom.canUserPinUnpin] with our own user. + */ +suspend fun BaseRoom.canPinUnpin(): Result = canUserPinUnpin(sessionId) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/recent/RecentDirectRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/recent/RecentDirectRoom.kt index 973b5cca0d..e0a51ef005 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/recent/RecentDirectRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/recent/RecentDirectRoom.kt @@ -10,8 +10,8 @@ package io.element.android.libraries.matrix.api.room.recent import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.CurrentUserMembership -import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.room.toMatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser @@ -52,6 +52,6 @@ suspend fun MatrixClient.getRecentDirectRooms( return result } -suspend fun MatrixRoom.isJoined(): Boolean { +suspend fun BaseRoom.isJoined(): Boolean { return roomInfoFlow.first().currentUserMembership == CurrentUserMembership.JOINED } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt index 099f2d865c..c4f1851089 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt @@ -7,11 +7,11 @@ package io.element.android.libraries.matrix.api.roomlist -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.message.RoomMessage data class RoomSummary( - val info: MatrixRoomInfo, + val info: RoomInfo, val lastMessage: RoomMessage?, ) { val roomId = info.id diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 0606318f16..6491ae03d3 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -30,11 +30,12 @@ import io.element.android.libraries.matrix.api.notification.NotificationService import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.oidc.AccountManagementAction import io.element.android.libraries.matrix.api.pusher.PushersService +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.CurrentUserMembership -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.NotJoinedRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMembershipObserver -import io.element.android.libraries.matrix.api.room.RoomPreview import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService @@ -55,13 +56,15 @@ import io.element.android.libraries.matrix.impl.notification.RustNotificationSer import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService import io.element.android.libraries.matrix.impl.oidc.toRustAction import io.element.android.libraries.matrix.impl.pushers.RustPushersService +import io.element.android.libraries.matrix.impl.room.GetRoomResult +import io.element.android.libraries.matrix.impl.room.NotJoinedRustRoom import io.element.android.libraries.matrix.impl.room.RoomContentForwarder import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber import io.element.android.libraries.matrix.impl.room.RustRoomFactory -import io.element.android.libraries.matrix.impl.room.RustRoomPreview import io.element.android.libraries.matrix.impl.room.TimelineEventTypeFilterFactory import io.element.android.libraries.matrix.impl.room.history.map import io.element.android.libraries.matrix.impl.room.join.map +import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper import io.element.android.libraries.matrix.impl.roomdirectory.RustRoomDirectoryService import io.element.android.libraries.matrix.impl.roomdirectory.map import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory @@ -186,6 +189,7 @@ class RustMatrixClient( private val roomMembershipObserver = RoomMembershipObserver() private val roomFactory = RustRoomFactory( + innerClient = innerClient, roomListService = roomListService, innerRoomListService = innerRoomListService, sessionId = sessionId, @@ -263,12 +267,17 @@ class RustMatrixClient( } } - override suspend fun getRoom(roomId: RoomId): MatrixRoom? { - return roomFactory.create(roomId) + override suspend fun getRoom(roomId: RoomId): BaseRoom? { + return roomFactory.getBaseRoom(roomId) } - override suspend fun getPendingRoom(roomId: RoomId): RoomPreview? { - return roomFactory.createRoomPreview(roomId) + override suspend fun getJoinedRoom(roomId: RoomId): JoinedRoom? { + return try { + (roomFactory.getJoinedRoomOrPreview(roomId) as GetRoomResult.Joined).joinedRoom + } catch (e: ClassCastException) { + Timber.e(e, "Room $roomId is not a joined room") + null + } } /** @@ -455,13 +464,29 @@ class RustMatrixClient( } } - override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List): Result = withContext(sessionDispatcher) { + override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List): Result = withContext(sessionDispatcher) { runCatching { - val roomPreview = when (roomIdOrAlias) { - is RoomIdOrAlias.Alias -> innerClient.getRoomPreviewFromRoomAlias(roomIdOrAlias.roomAlias.value) - is RoomIdOrAlias.Id -> innerClient.getRoomPreviewFromRoomId(roomIdOrAlias.roomId.value, serverNames) + when (roomIdOrAlias) { + is RoomIdOrAlias.Alias -> { + val roomId = innerClient.resolveRoomAlias(roomIdOrAlias.roomAlias.value)?.roomId?.let { RoomId(it) } + + var room = (roomId?.let { roomFactory.getJoinedRoomOrPreview(it) } as? GetRoomResult.NotJoined)?.notJoinedRoom + if (room == null) { + val preview = innerClient.getRoomPreviewFromRoomAlias(roomIdOrAlias.roomAlias.value) + room = NotJoinedRustRoom(sessionId, null, RoomPreviewInfoMapper.map(preview.info())) + } + room + } + is RoomIdOrAlias.Id -> { + var room = (roomFactory.getJoinedRoomOrPreview(roomIdOrAlias.roomId) as? GetRoomResult.NotJoined)?.notJoinedRoom + + if (room == null) { + val preview = innerClient.getRoomPreviewFromRoomId(roomIdOrAlias.roomId.value, serverNames) + room = NotJoinedRustRoom(sessionId, null, RoomPreviewInfoMapper.map(preview.info())) + } + room + } } - RustRoomPreview(sessionId, roomPreview, roomMembershipObserver) }.mapFailure { it.mapClientException() } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExt.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExt.kt index 1e76e69fa4..2770dc1250 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExt.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExt.kt @@ -8,7 +8,7 @@ package io.element.android.libraries.matrix.impl.analytics import im.vector.app.features.analytics.plan.JoinedRoom -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.isDm import kotlinx.coroutines.flow.first @@ -24,7 +24,7 @@ private fun Long.toAnalyticsRoomSize(): JoinedRoom.RoomSize { } } -suspend fun MatrixRoom.toAnalyticsJoinedRoom(trigger: JoinedRoom.Trigger?): JoinedRoom { +suspend fun BaseRoom.toAnalyticsJoinedRoom(trigger: JoinedRoom.Trigger?): JoinedRoom { val roomInfo = roomInfoFlow.first() return JoinedRoom( isDM = roomInfo.isDm, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt similarity index 68% rename from libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt rename to libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt index 7ed2ad5eb6..37fec422ee 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. @@ -17,7 +17,6 @@ import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SendHandle -import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange @@ -28,55 +27,43 @@ import io.element.android.libraries.matrix.api.media.MediaUploadHandler import io.element.android.libraries.matrix.api.media.VideoInfo import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.poll.PollKind +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.CreateTimelineParams import io.element.android.libraries.matrix.api.room.IntentionalMention -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState -import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState -import io.element.android.libraries.matrix.api.room.MessageEventType -import io.element.android.libraries.matrix.api.room.RoomMember -import io.element.android.libraries.matrix.api.room.RoomMembershipObserver -import io.element.android.libraries.matrix.api.room.StateEventType -import io.element.android.libraries.matrix.api.room.draft.ComposerDraft +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomNotificationSettingsState import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.knock.KnockRequest import io.element.android.libraries.matrix.api.room.location.AssetType import io.element.android.libraries.matrix.api.room.message.ReplyParameters -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.room.roomNotificationSettings import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility -import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings import io.element.android.libraries.matrix.impl.core.RustSendHandle import io.element.android.libraries.matrix.impl.mapper.map -import io.element.android.libraries.matrix.impl.room.draft.into import io.element.android.libraries.matrix.impl.room.history.map import io.element.android.libraries.matrix.impl.room.join.map import io.element.android.libraries.matrix.impl.room.knock.RustKnockRequest import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher -import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper import io.element.android.libraries.matrix.impl.room.powerlevels.RoomPowerLevelsMapper import io.element.android.libraries.matrix.impl.roomdirectory.map import io.element.android.libraries.matrix.impl.timeline.RustTimeline -import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType import io.element.android.libraries.matrix.impl.util.MessageEventContent import io.element.android.libraries.matrix.impl.util.mxCallbackFlow import io.element.android.libraries.matrix.impl.widget.RustWidgetDriver import io.element.android.libraries.matrix.impl.widget.generateWidgetWebViewUrl import io.element.android.services.toolbox.api.systemclock.SystemClock -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop @@ -89,7 +76,6 @@ import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.DateDividerMode import org.matrix.rustcomponents.sdk.IdentityStatusChangeListener import org.matrix.rustcomponents.sdk.KnockRequestsListener -import org.matrix.rustcomponents.sdk.RoomInfo import org.matrix.rustcomponents.sdk.RoomInfoListener import org.matrix.rustcomponents.sdk.RoomMessageEventMessageType import org.matrix.rustcomponents.sdk.TimelineConfiguration @@ -103,40 +89,36 @@ import org.matrix.rustcomponents.sdk.getElementCallRequiredPermissions import org.matrix.rustcomponents.sdk.use import timber.log.Timber import uniffi.matrix_sdk.RoomPowerLevelChanges -import uniffi.matrix_sdk_base.EncryptionState import java.io.File import kotlin.coroutines.cancellation.CancellationException import org.matrix.rustcomponents.sdk.IdentityStatusChange as RustIdentityStateChange import org.matrix.rustcomponents.sdk.KnockRequest as InnerKnockRequest -import org.matrix.rustcomponents.sdk.Room as InnerRoom +import org.matrix.rustcomponents.sdk.RoomInfo as InnerRoomInfo import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline -@Suppress("LargeClass") -class RustMatrixRoom( - override val sessionId: SessionId, - private val deviceId: DeviceId, - private val innerRoom: InnerRoom, - innerTimeline: InnerTimeline, +class JoinedRustRoom( + private val baseRoom: RustBaseRoom, + private val liveInnerTimeline: InnerTimeline, private val notificationSettingsService: NotificationSettingsService, - sessionCoroutineScope: CoroutineScope, private val coroutineDispatchers: CoroutineDispatchers, + private val roomInfoMapper: RoomInfoMapper, private val systemClock: SystemClock, private val roomContentForwarder: RoomContentForwarder, - private val roomSyncSubscriber: RoomSyncSubscriber, - private val matrixRoomInfoMapper: MatrixRoomInfoMapper, private val featureFlagService: FeatureFlagService, - private val roomMembershipObserver: RoomMembershipObserver, - initialRoomInfo: MatrixRoomInfo, -) : MatrixRoom { - override val roomId = RoomId(innerRoom.id()) +) : JoinedRoom, BaseRoom by baseRoom { + // Create a dispatcher for all room methods... + private val roomDispatcher = coroutineDispatchers.io.limitedParallelism(32) + private val innerRoom = baseRoom.innerRoom - override val roomInfoFlow: StateFlow = mxCallbackFlow { + override val syncUpdateFlow = MutableStateFlow(0L) + + override val roomInfoFlow: StateFlow = mxCallbackFlow { innerRoom.subscribeToRoomInfoUpdates(object : RoomInfoListener { - override fun call(roomInfo: RoomInfo) { - channel.trySend(matrixRoomInfoMapper.map(roomInfo)) + override fun call(roomInfo: InnerRoomInfo) { + channel.trySend(roomInfoMapper.map(roomInfo)) } }) - }.stateIn(sessionCoroutineScope, started = SharingStarted.Lazily, initialValue = initialRoomInfo) + }.stateIn(roomCoroutineScope, started = SharingStarted.Lazily, initialValue = baseRoom.info()) override val roomTypingMembersFlow: Flow> = mxCallbackFlow { val initial = emptyList() @@ -178,27 +160,12 @@ class RustMatrixRoom( }) } - // Create a dispatcher for all room methods... - private val roomDispatcher = coroutineDispatchers.io.limitedParallelism(32) + override val roomNotificationSettingsStateFlow = MutableStateFlow(RoomNotificationSettingsState.Unknown) - // ...except getMember methods as it could quickly fill the roomDispatcher... - private val roomMembersDispatcher = coroutineDispatchers.io.limitedParallelism(8) - - override val roomCoroutineScope = sessionCoroutineScope.childScope(coroutineDispatchers.main, "RoomScope-$roomId") - private val _syncUpdateFlow = MutableStateFlow(0L) - private val roomMemberListFetcher = RoomMemberListFetcher(innerRoom, roomMembersDispatcher) - - private val _roomNotificationSettingsStateFlow = MutableStateFlow(MatrixRoomNotificationSettingsState.Unknown) - override val roomNotificationSettingsStateFlow: StateFlow = _roomNotificationSettingsStateFlow - - override val liveTimeline = createTimeline(innerTimeline, mode = Timeline.Mode.LIVE) { - _syncUpdateFlow.value = systemClock.epochMillis() + override val liveTimeline = liveInnerTimeline.map(mode = Timeline.Mode.LIVE) { + syncUpdateFlow.value = systemClock.epochMillis() } - override val membersStateFlow: StateFlow = roomMemberListFetcher.membersFlow - - override val syncUpdateFlow: StateFlow = _syncUpdateFlow.asStateFlow() - init { val powerLevelChanges = roomInfoFlow.map { it.userPowerLevels }.distinctUntilChanged() val membershipChanges = liveTimeline.membershipChangeEventReceived.onStart { emit(Unit) } @@ -206,12 +173,13 @@ class RustMatrixRoom( // Skip initial one .drop(1) // The new events should already be in the SDK cache, no need to fetch them from the server - .onEach { roomMemberListFetcher.fetchRoomMembers(source = RoomMemberListFetcher.Source.CACHE) } + .onEach { baseRoom.roomMemberListFetcher.fetchRoomMembers(source = RoomMemberListFetcher.Source.CACHE) } .launchIn(roomCoroutineScope) + .invokeOnCompletion { + Timber.d("Observing membership changes for room $roomId stopped, reason: $it") + } } - override suspend fun subscribeToSync() = roomSyncSubscriber.subscribe(roomId) - override suspend fun createTimeline( createTimelineParams: CreateTimelineParams, ): Result = withContext(roomDispatcher) { @@ -273,17 +241,14 @@ class RustMatrixRoom( dateDividerMode = dateDividerMode, trackReadReceipts = trackReadReceipts, ) - ).let { inner -> + ).let { innerTimeline -> val mode = when (createTimelineParams) { is CreateTimelineParams.Focused -> Timeline.Mode.FOCUSED_ON_EVENT is CreateTimelineParams.MediaOnly -> Timeline.Mode.MEDIA is CreateTimelineParams.MediaOnlyFocused -> Timeline.Mode.FOCUSED_ON_EVENT CreateTimelineParams.PinnedOnly -> Timeline.Mode.PINNED_EVENTS } - createTimeline( - timeline = inner, - mode = mode, - ) + innerTimeline.map(mode = mode) } }.mapFailure { when (createTimelineParams) { @@ -299,105 +264,8 @@ class RustMatrixRoom( } } - override fun destroy() { - roomCoroutineScope.cancel() - liveTimeline.close() - } - - override suspend fun updateMembers() { - val useCache = membersStateFlow.value is MatrixRoomMembersState.Unknown - val source = if (useCache) { - RoomMemberListFetcher.Source.CACHE_AND_SERVER - } else { - RoomMemberListFetcher.Source.SERVER - } - roomMemberListFetcher.fetchRoomMembers(source = source) - } - - override suspend fun getMembers(limit: Int) = withContext(roomDispatcher) { - runCatching { - innerRoom.members().use { - it.nextChunk(limit.toUInt()).orEmpty().map { roomMember -> - RoomMemberMapper.map(roomMember) - } - } - } - } - - override suspend fun getUpdatedMember(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - RoomMemberMapper.map(innerRoom.member(userId.value)) - } - } - - override suspend fun userDisplayName(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.memberDisplayName(userId.value) - } - } - - override suspend fun updateRoomNotificationSettings(): Result = withContext(roomDispatcher) { - val currentState = _roomNotificationSettingsStateFlow.value - val currentRoomNotificationSettings = currentState.roomNotificationSettings() - _roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Pending(prevRoomNotificationSettings = currentRoomNotificationSettings) - runCatching { - val isEncrypted = roomInfoFlow.value.isEncrypted ?: getUpdatedIsEncrypted().getOrThrow() - notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow() - }.map { - _roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Ready(it) - }.onFailure { - _roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Error( - prevRoomNotificationSettings = currentRoomNotificationSettings, - failure = it - ) - } - } - - override suspend fun userRole(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - RoomMemberMapper.mapRole(innerRoom.suggestedRoleForUser(userId.value)) - } - } - - override suspend fun updateUsersRoles(changes: List): Result { - return runCatching { - val powerLevelChanges = changes.map { UserPowerLevelUpdate(it.userId.value, it.powerLevel) } - innerRoom.updatePowerLevelsForUsers(powerLevelChanges) - } - } - - override suspend fun powerLevels(): Result = withContext(roomDispatcher) { - runCatching { - RoomPowerLevelsMapper.map(innerRoom.getPowerLevels()) - } - } - - override suspend fun updatePowerLevels(matrixRoomPowerLevels: MatrixRoomPowerLevels): Result = withContext(roomDispatcher) { - runCatching { - val changes = RoomPowerLevelChanges( - ban = matrixRoomPowerLevels.ban, - invite = matrixRoomPowerLevels.invite, - kick = matrixRoomPowerLevels.kick, - redact = matrixRoomPowerLevels.redactEvents, - eventsDefault = matrixRoomPowerLevels.sendEvents, - roomName = matrixRoomPowerLevels.roomName, - roomAvatar = matrixRoomPowerLevels.roomAvatar, - roomTopic = matrixRoomPowerLevels.roomTopic, - ) - innerRoom.applyPowerLevelChanges(changes) - } - } - - override suspend fun resetPowerLevels(): Result = withContext(roomDispatcher) { - runCatching { - RoomPowerLevelsMapper.map(innerRoom.resetPowerLevels()) - } - } - - override suspend fun userAvatarUrl(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.memberAvatarUrl(userId.value) - } + override suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List): Result { + return liveTimeline.sendMessage(body, htmlBody, intentionalMentions) } override suspend fun editMessage( @@ -413,84 +281,6 @@ class RustMatrixRoom( } } - override suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List): Result { - return liveTimeline.sendMessage(body, htmlBody, intentionalMentions) - } - - override suspend fun leave(): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.leave() - }.onSuccess { - roomMembershipObserver.notifyUserLeftRoom(roomId) - } - } - - override suspend fun join(): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.join() - } - } - - override suspend fun inviteUserById(id: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.inviteUserById(id.value) - } - } - - override suspend fun canUserInvite(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.canUserInvite(userId.value) - } - } - - override suspend fun canUserKick(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.canUserKick(userId.value) - } - } - - override suspend fun canUserBan(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.canUserBan(userId.value) - } - } - - override suspend fun canUserRedactOwn(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.canUserRedactOwn(userId.value) - } - } - - override suspend fun canUserRedactOther(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.canUserRedactOther(userId.value) - } - } - - override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.canUserSendState(userId.value, type.map()) - } - } - - override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.canUserSendMessage(userId.value, type.map()) - } - } - - override suspend fun canUserTriggerRoomNotification(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.canUserTriggerRoomNotification(userId.value) - } - } - - override suspend fun canUserPinUnpin(userId: UserId): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.canUserPinUnpin(userId.value) - } - } - override suspend fun sendImage( file: File, thumbnailFile: File?, @@ -593,93 +383,6 @@ class RustMatrixRoom( return liveTimeline.sendLocation(body, geoUri, description, zoomLevel, assetType) } - override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result { - return liveTimeline.toggleReaction(emoji, eventOrTransactionId) - } - - override suspend fun forwardEvent(eventId: EventId, roomIds: List): Result { - return liveTimeline.forwardEvent(eventId, roomIds) - } - - override suspend fun cancelSend(transactionId: TransactionId): Result { - return liveTimeline.cancelSend(transactionId) - } - - override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.uploadAvatar(mimeType, data, null) - } - } - - override suspend fun removeAvatar(): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.removeAvatar() - } - } - - override suspend fun setName(name: String): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.setName(name) - } - } - - override suspend fun setTopic(topic: String): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.setTopic(topic) - } - } - - override suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.reportContent(eventId = eventId.value, score = null, reason = reason) - if (blockUserId != null) { - innerRoom.ignoreUser(blockUserId.value) - } - } - } - - override suspend fun clearEventCacheStorage(): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.clearEventCacheStorage() - } - } - - override suspend fun kickUser(userId: UserId, reason: String?): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.kickUser(userId.value, reason) - } - } - - override suspend fun banUser(userId: UserId, reason: String?): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.banUser(userId.value, reason) - } - } - - override suspend fun unbanUser(userId: UserId, reason: String?): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.unbanUser(userId.value, reason) - } - } - - override suspend fun setIsFavorite(isFavorite: Boolean): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.setIsFavourite(isFavorite, null) - } - } - - override suspend fun markAsRead(receiptType: ReceiptType): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.markAsRead(receiptType.toRustReceiptType()) - } - } - - override suspend fun setUnreadFlag(isUnread: Boolean): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.setUnreadFlag(isUnread) - } - } - override suspend fun createPoll( question: String, answers: List, @@ -719,95 +422,70 @@ class RustMatrixRoom( } } - override suspend fun generateWidgetWebViewUrl( - widgetSettings: MatrixWidgetSettings, - clientId: String, - languageTag: String?, - theme: String?, - ) = withContext(roomDispatcher) { + override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result { + return liveTimeline.toggleReaction(emoji, eventOrTransactionId) + } + + override suspend fun forwardEvent(eventId: EventId, roomIds: List): Result { + return liveTimeline.forwardEvent(eventId, roomIds) + } + + override suspend fun cancelSend(transactionId: TransactionId): Result { + return liveTimeline.cancelSend(transactionId) + } + + override suspend fun inviteUserById(id: UserId): Result = withContext(roomDispatcher) { runCatching { - widgetSettings.generateWidgetWebViewUrl(innerRoom, clientId, languageTag, theme) + innerRoom.inviteUserById(id.value) } } - override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result { - return runCatching { - RustWidgetDriver( - widgetSettings = widgetSettings, - room = innerRoom, - widgetCapabilitiesProvider = object : WidgetCapabilitiesProvider { - override fun acquireCapabilities(capabilities: WidgetCapabilities): WidgetCapabilities { - return getElementCallRequiredPermissions(sessionId.value, deviceId.value) - } - }, - ) - } - } - - override suspend fun getPermalink(): Result = withContext(roomDispatcher) { + override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result = withContext(roomDispatcher) { runCatching { - innerRoom.matrixToPermalink() + innerRoom.uploadAvatar(mimeType, data, null) } } - override suspend fun getPermalinkFor(eventId: EventId): Result = withContext(roomDispatcher) { + override suspend fun removeAvatar(): Result = withContext(roomDispatcher) { runCatching { - innerRoom.matrixToEventPermalink(eventId.value) + innerRoom.removeAvatar() } } - override suspend fun sendCallNotificationIfNeeded(): Result = withContext(roomDispatcher) { + override suspend fun setName(name: String): Result = withContext(roomDispatcher) { runCatching { - innerRoom.sendCallNotificationIfNeeded() + innerRoom.setName(name) } } - override suspend fun setSendQueueEnabled(enabled: Boolean) { - withContext(roomDispatcher) { - Timber.d("setSendQueuesEnabled: $enabled") - runCatching { - innerRoom.enableSendQueue(enabled) + override suspend fun setTopic(topic: String): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.setTopic(topic) + } + } + + override suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.reportContent(eventId = eventId.value, score = null, reason = reason) + if (blockUserId != null) { + innerRoom.ignoreUser(blockUserId.value) } } } - override suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result = withContext(roomDispatcher) { + override suspend fun updateRoomNotificationSettings(): Result = withContext(roomDispatcher) { + val currentState = roomNotificationSettingsStateFlow.value + val currentRoomNotificationSettings = currentState.roomNotificationSettings() + roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Pending(prevRoomNotificationSettings = currentRoomNotificationSettings) runCatching { - Timber.d("saveComposerDraft: $composerDraft into $roomId") - innerRoom.saveComposerDraft(composerDraft.into()) - } - } - - override suspend fun loadComposerDraft(): Result = withContext(roomDispatcher) { - runCatching { - Timber.d("loadComposerDraft for $roomId") - innerRoom.loadComposerDraft()?.into() - } - } - - override suspend fun clearComposerDraft(): Result = withContext(roomDispatcher) { - runCatching { - Timber.d("clearComposerDraft for $roomId") - innerRoom.clearComposerDraft() - } - } - - override suspend fun ignoreDeviceTrustAndResend(devices: Map>, sendHandle: SendHandle) = withContext(roomDispatcher) { - runCatching { - innerRoom.ignoreDeviceTrustAndResend( - devices = devices.entries.associate { entry -> - entry.key.value to entry.value.map { it.value } - }, - sendHandle = (sendHandle as RustSendHandle).inner, - ) - } - } - - override suspend fun withdrawVerificationAndResend(userIds: List, sendHandle: SendHandle) = withContext(roomDispatcher) { - runCatching { - innerRoom.withdrawVerificationAndResend( - userIds = userIds.map { it.value }, - sendHandle = (sendHandle as RustSendHandle).inner, + val isEncrypted = roomInfoFlow.value.isEncrypted ?: getUpdatedIsEncrypted().getOrThrow() + notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow() + }.map { + roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Ready(it) + }.onFailure { + roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Error( + prevRoomNotificationSettings = currentRoomNotificationSettings, + failure = it ) } } @@ -842,12 +520,6 @@ class RustMatrixRoom( } } - override suspend fun getRoomVisibility(): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.getRoomVisibility().map() - } - } - override suspend fun enableEncryption(): Result = withContext(roomDispatcher) { runCatching { innerRoom.enableEncryption() @@ -860,22 +532,128 @@ class RustMatrixRoom( } } - override suspend fun getUpdatedIsEncrypted(): Result = withContext(roomDispatcher) { - runCatching { - innerRoom.latestEncryptionState() == EncryptionState.ENCRYPTED + override suspend fun updateUsersRoles(changes: List): Result { + return runCatching { + val powerLevelChanges = changes.map { UserPowerLevelUpdate(it.userId.value, it.powerLevel) } + innerRoom.updatePowerLevelsForUsers(powerLevelChanges) } } - private fun createTimeline( - timeline: InnerTimeline, + override suspend fun updatePowerLevels(roomPowerLevels: RoomPowerLevels): Result = withContext(roomDispatcher) { + runCatching { + val changes = RoomPowerLevelChanges( + ban = roomPowerLevels.ban, + invite = roomPowerLevels.invite, + kick = roomPowerLevels.kick, + redact = roomPowerLevels.redactEvents, + eventsDefault = roomPowerLevels.sendEvents, + roomName = roomPowerLevels.roomName, + roomAvatar = roomPowerLevels.roomAvatar, + roomTopic = roomPowerLevels.roomTopic, + ) + innerRoom.applyPowerLevelChanges(changes) + } + } + + override suspend fun resetPowerLevels(): Result = withContext(roomDispatcher) { + runCatching { + RoomPowerLevelsMapper.map(innerRoom.resetPowerLevels()) + } + } + + override suspend fun kickUser(userId: UserId, reason: String?): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.kickUser(userId.value, reason) + } + } + + override suspend fun banUser(userId: UserId, reason: String?): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.banUser(userId.value, reason) + } + } + + override suspend fun unbanUser(userId: UserId, reason: String?): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.unbanUser(userId.value, reason) + } + } + + override suspend fun generateWidgetWebViewUrl( + widgetSettings: MatrixWidgetSettings, + clientId: String, + languageTag: String?, + theme: String?, + ) = withContext(roomDispatcher) { + runCatching { + widgetSettings.generateWidgetWebViewUrl(innerRoom, clientId, languageTag, theme) + } + } + + override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result { + return runCatching { + RustWidgetDriver( + widgetSettings = widgetSettings, + room = innerRoom, + widgetCapabilitiesProvider = object : WidgetCapabilitiesProvider { + override fun acquireCapabilities(capabilities: WidgetCapabilities): WidgetCapabilities { + return getElementCallRequiredPermissions(sessionId.value, baseRoom.deviceId.value) + } + }, + ) + } + } + + override suspend fun sendCallNotificationIfNeeded(): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.sendCallNotificationIfNeeded() + } + } + + override suspend fun setSendQueueEnabled(enabled: Boolean) { + withContext(roomDispatcher) { + Timber.d("setSendQueuesEnabled: $enabled") + runCatching { + innerRoom.enableSendQueue(enabled) + } + } + } + + override suspend fun ignoreDeviceTrustAndResend(devices: Map>, sendHandle: SendHandle) = withContext(roomDispatcher) { + runCatching { + innerRoom.ignoreDeviceTrustAndResend( + devices = devices.entries.associate { entry -> + entry.key.value to entry.value.map { it.value } + }, + sendHandle = (sendHandle as RustSendHandle).inner, + ) + } + } + + override suspend fun withdrawVerificationAndResend(userIds: List, sendHandle: SendHandle) = withContext(roomDispatcher) { + runCatching { + innerRoom.withdrawVerificationAndResend( + userIds = userIds.map { it.value }, + sendHandle = (sendHandle as RustSendHandle).inner, + ) + } + } + + override fun destroy() { + baseRoom.destroy() + liveInnerTimeline.close() + roomCoroutineScope.cancel() + } + + private fun InnerTimeline.map( mode: Timeline.Mode, onNewSyncedEvent: () -> Unit = {}, ): Timeline { - val timelineCoroutineScope = roomCoroutineScope.childScope(coroutineDispatchers.main, "TimelineScope-$roomId-$timeline") + val timelineCoroutineScope = roomCoroutineScope.childScope(coroutineDispatchers.main, "TimelineScope-$roomId-$this") return RustTimeline( mode = mode, - matrixRoom = this, - inner = timeline, + joinedRoom = this@JoinedRustRoom, + inner = this@map, systemClock = systemClock, coroutineScope = timelineCoroutineScope, dispatcher = roomDispatcher, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/NotJoinedRustRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/NotJoinedRustRoom.kt new file mode 100644 index 0000000000..3f3cb4f6cd --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/NotJoinedRustRoom.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.room + +import androidx.compose.runtime.Immutable +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.room.NotJoinedRoom +import io.element.android.libraries.matrix.api.room.RoomMembershipDetails +import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo +import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper + +@Immutable +class NotJoinedRustRoom( + private val sessionId: SessionId, + override val localRoom: RustBaseRoom?, + override val previewInfo: RoomPreviewInfo, +) : NotJoinedRoom { + override suspend fun membershipDetails(): Result = runCatching { + val room = localRoom?.innerRoom ?: return@runCatching null + val (ownMember, senderInfo) = room.memberWithSenderInfo(sessionId.value) + RoomMembershipDetails( + currentUserMember = RoomMemberMapper.map(ownMember), + senderMember = senderInfo?.let { RoomMemberMapper.map(it) }, + ) + } + + override fun close() { + localRoom?.close() + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomInfoMapper.kt similarity index 70% rename from libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt rename to libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomInfoMapper.kt index de72a54469..9ee61da9fe 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomInfoMapper.kt @@ -12,7 +12,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.CurrentUserMembership -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.impl.room.history.map @@ -28,9 +28,9 @@ import org.matrix.rustcomponents.sdk.Membership as RustMembership import org.matrix.rustcomponents.sdk.RoomInfo as RustRoomInfo import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode -class MatrixRoomInfoMapper { - fun map(rustRoomInfo: RustRoomInfo): MatrixRoomInfo = rustRoomInfo.let { - return MatrixRoomInfo( +class RoomInfoMapper { + fun map(rustRoomInfo: RustRoomInfo): RoomInfo = rustRoomInfo.let { + return RoomInfo( id = RoomId(it.id), creator = it.creator?.let(::UserId), name = it.displayName, @@ -70,44 +70,6 @@ class MatrixRoomInfoMapper { historyVisibility = it.historyVisibility.map(), ) } - -// fun map(rustRoom: Room): MatrixRoomInfo = with(rustRoom) { -// return MatrixRoomInfo( -// id = RoomId(id()), -// name = rawName(), -// rawName = displayName(), -// topic = topic(), -// avatarUrl = avatarUrl(), -// isPublic = isPublic(), -// isDirect = null, -// isEncrypted = encryptionState() == EncryptionState.ENCRYPTED, -// joinRule = null, -// isSpace = isSpace(), -// isTombstoned = isTombstoned(), -// isFavorite = null, -// canonicalAlias = canonicalAlias()?.let(::RoomAlias), -// alternativeAliases = alternativeAliases().map(::RoomAlias).toImmutableList(), -// currentUserMembership = membership().map(), -// inviter = null, -// activeMembersCount = activeMembersCount().toLong(), -// invitedMembersCount = invitedMembersCount().toLong(), -// joinedMembersCount = joinedMembersCount().toLong(), -// userPowerLevels = persistentMapOf(), -// highlightCount = 0, -// notificationCount = 0, -// userDefinedNotificationMode = null, -// hasRoomCall = hasActiveRoomCall(), -// activeRoomCallParticipants = activeRoomCallParticipants().map(::UserId).toImmutableList(), -// isMarkedUnread = false, -// numUnreadMessages = 0, -// numUnreadNotifications = 0, -// numUnreadMentions = 0, -// heroes = heroes().map(RoomHero::map).toImmutableList(), -// pinnedEventIds = persistentListOf(), -// creator = null, -// historyVisibility = null, -// ) -// } } fun RustMembership.map(): CurrentUserMembership = when (this) { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt new file mode 100644 index 0000000000..b2582f1612 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustBaseRoom.kt @@ -0,0 +1,267 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.room + +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.core.coroutine.childScope +import io.element.android.libraries.matrix.api.core.DeviceId +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.MessageEventType +import io.element.android.libraries.matrix.api.room.RoomInfo +import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembersState +import io.element.android.libraries.matrix.api.room.RoomMembershipObserver +import io.element.android.libraries.matrix.api.room.StateEventType +import io.element.android.libraries.matrix.api.room.draft.ComposerDraft +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels +import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility +import io.element.android.libraries.matrix.api.timeline.ReceiptType +import io.element.android.libraries.matrix.impl.room.draft.into +import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher +import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper +import io.element.android.libraries.matrix.impl.room.powerlevels.RoomPowerLevelsMapper +import io.element.android.libraries.matrix.impl.roomdirectory.map +import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.withContext +import org.matrix.rustcomponents.sdk.use +import timber.log.Timber +import uniffi.matrix_sdk_base.EncryptionState +import org.matrix.rustcomponents.sdk.Room as InnerRoom + +class RustBaseRoom( + override val sessionId: SessionId, + internal val deviceId: DeviceId, + internal val innerRoom: InnerRoom, + coroutineDispatchers: CoroutineDispatchers, + private val roomSyncSubscriber: RoomSyncSubscriber, + private val roomMembershipObserver: RoomMembershipObserver, + sessionCoroutineScope: CoroutineScope, + initialRoomInfo: RoomInfo, +) : BaseRoom { + override val roomId = RoomId(innerRoom.id()) + + // Create a dispatcher for all room methods... + private val roomDispatcher = coroutineDispatchers.io.limitedParallelism(32) + + // ...except getMember methods as it could quickly fill the roomDispatcher... + private val roomMembersDispatcher = coroutineDispatchers.io.limitedParallelism(8) + + internal val roomMemberListFetcher = RoomMemberListFetcher(innerRoom, roomMembersDispatcher) + + override val membersStateFlow: StateFlow = roomMemberListFetcher.membersFlow + + override val roomInfoFlow: StateFlow = MutableStateFlow(initialRoomInfo) + + override val roomCoroutineScope = sessionCoroutineScope.childScope(coroutineDispatchers.main, "RoomScope-$roomId") + + override suspend fun subscribeToSync() = roomSyncSubscriber.subscribe(roomId) + + override suspend fun updateMembers() { + val useCache = membersStateFlow.value is RoomMembersState.Unknown + val source = if (useCache) { + RoomMemberListFetcher.Source.CACHE_AND_SERVER + } else { + RoomMemberListFetcher.Source.SERVER + } + roomMemberListFetcher.fetchRoomMembers(source = source) + } + + override suspend fun getMembers(limit: Int) = withContext(roomDispatcher) { + runCatching { + innerRoom.members().use { + it.nextChunk(limit.toUInt()).orEmpty().map { roomMember -> + RoomMemberMapper.map(roomMember) + } + } + } + } + + override suspend fun getUpdatedMember(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + RoomMemberMapper.map(innerRoom.member(userId.value)) + } + } + + override fun destroy() { + innerRoom.destroy() + } + + override suspend fun userDisplayName(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.memberDisplayName(userId.value) + } + } + + override suspend fun userRole(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + RoomMemberMapper.mapRole(innerRoom.suggestedRoleForUser(userId.value)) + } + } + + override suspend fun powerLevels(): Result = withContext(roomDispatcher) { + runCatching { + RoomPowerLevelsMapper.map(innerRoom.getPowerLevels()) + } + } + + override suspend fun userAvatarUrl(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.memberAvatarUrl(userId.value) + } + } + + override suspend fun leave(): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.leave() + }.onSuccess { + roomMembershipObserver.notifyUserLeftRoom(roomId) + } + } + + override suspend fun join(): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.join() + } + } + + override suspend fun forget(): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.forget() + } + } + + override suspend fun canUserInvite(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.canUserInvite(userId.value) + } + } + + override suspend fun canUserKick(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.canUserKick(userId.value) + } + } + + override suspend fun canUserBan(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.canUserBan(userId.value) + } + } + + override suspend fun canUserRedactOwn(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.canUserRedactOwn(userId.value) + } + } + + override suspend fun canUserRedactOther(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.canUserRedactOther(userId.value) + } + } + + override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.canUserSendState(userId.value, type.map()) + } + } + + override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.canUserSendMessage(userId.value, type.map()) + } + } + + override suspend fun canUserTriggerRoomNotification(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.canUserTriggerRoomNotification(userId.value) + } + } + + override suspend fun canUserPinUnpin(userId: UserId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.canUserPinUnpin(userId.value) + } + } + + override suspend fun clearEventCacheStorage(): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.clearEventCacheStorage() + } + } + + override suspend fun setIsFavorite(isFavorite: Boolean): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.setIsFavourite(isFavorite, null) + } + } + + override suspend fun markAsRead(receiptType: ReceiptType): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.markAsRead(receiptType.toRustReceiptType()) + } + } + + override suspend fun setUnreadFlag(isUnread: Boolean): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.setUnreadFlag(isUnread) + } + } + + override suspend fun getPermalink(): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.matrixToPermalink() + } + } + + override suspend fun getPermalinkFor(eventId: EventId): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.matrixToEventPermalink(eventId.value) + } + } + + override suspend fun getRoomVisibility(): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.getRoomVisibility().map() + } + } + + override suspend fun getUpdatedIsEncrypted(): Result = withContext(roomDispatcher) { + runCatching { + innerRoom.latestEncryptionState() == EncryptionState.ENCRYPTED + } + } + + override suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result = withContext(roomDispatcher) { + runCatching { + Timber.d("saveComposerDraft: $composerDraft into $roomId") + innerRoom.saveComposerDraft(composerDraft.into()) + } + } + + override suspend fun loadComposerDraft(): Result = withContext(roomDispatcher) { + runCatching { + Timber.d("loadComposerDraft for $roomId") + innerRoom.loadComposerDraft()?.into() + } + } + + override suspend fun clearComposerDraft(): Result = withContext(roomDispatcher) { + runCatching { + Timber.d("clearComposerDraft for $roomId") + innerRoom.clearComposerDraft() + } + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt index a65112fca9..ee9592f155 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt @@ -7,20 +7,20 @@ package io.element.android.libraries.matrix.impl.room -import androidx.collection.lruCache import io.element.android.appconfig.TimelineConfig import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.matrix.api.core.DeviceId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMembershipObserver -import io.element.android.libraries.matrix.api.room.RoomPreview import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.awaitLoaded -import io.element.android.libraries.matrix.impl.roomlist.fullRoomWithTimeline +import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper import io.element.android.libraries.matrix.impl.roomlist.roomOrNull import io.element.android.services.toolbox.api.systemclock.SystemClock import kotlinx.coroutines.CoroutineScope @@ -28,17 +28,18 @@ import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext -import org.matrix.rustcomponents.sdk.Room -import org.matrix.rustcomponents.sdk.RoomListException +import org.matrix.rustcomponents.sdk.Client +import org.matrix.rustcomponents.sdk.Membership import org.matrix.rustcomponents.sdk.RoomListItem import timber.log.Timber +import java.util.concurrent.atomic.AtomicBoolean +import org.matrix.rustcomponents.sdk.Room as SdkRoom import org.matrix.rustcomponents.sdk.RoomListService as InnerRoomListService -private const val CACHE_SIZE = 16 - class RustRoomFactory( private val sessionId: SessionId, private val deviceId: DeviceId, + private val innerClient: Client, private val notificationSettingsService: NotificationSettingsService, private val sessionCoroutineScope: CoroutineScope, private val dispatchers: CoroutineDispatchers, @@ -53,23 +54,14 @@ class RustRoomFactory( ) { private val dispatcher = dispatchers.io.limitedParallelism(1) private val mutex = Mutex() - private var isDestroyed: Boolean = false + private val isDestroyed: AtomicBoolean = AtomicBoolean(false) private data class RustRoomReferences( val roomListItem: RoomListItem, - val fullRoom: Room, + val room: SdkRoom, ) - private val cache = lruCache( - maxSize = CACHE_SIZE, - onEntryRemoved = { evicted, roomId, oldRoom, _ -> - Timber.d("On room removed from cache: $roomId, evicted: $evicted") - oldRoom.roomListItem.close() - oldRoom.fullRoom.close() - } - ) - - private val matrixRoomInfoMapper = MatrixRoomInfoMapper() + private val roomInfoMapper = RoomInfoMapper() private val eventFilters = TimelineConfig.excludedEvents .takeIf { it.isNotEmpty() } @@ -81,102 +73,123 @@ class RustRoomFactory( withContext(NonCancellable + dispatcher) { mutex.withLock { Timber.d("Destroying room factory") - cache.snapshot().values.forEach { (listItem, innerRoom) -> - innerRoom.destroy() - listItem.destroy() - } - cache.evictAll() - isDestroyed = true + isDestroyed.set(true) } } } - suspend fun create(roomId: RoomId): MatrixRoom? = withContext(dispatcher) { + suspend fun getBaseRoom(roomId: RoomId): RustBaseRoom? = withContext(dispatcher) { mutex.withLock { - if (isDestroyed) { + if (isDestroyed.get()) { Timber.d("Room factory is destroyed, returning null for $roomId") return@withContext null } - var roomReferences: RustRoomReferences? = getRoomReferences(roomId) - if (roomReferences == null) { - // ... otherwise, lets wait for the SS to load all rooms and check again. - roomListService.allRooms.awaitLoaded() - roomReferences = getRoomReferences(roomId) - } - if (roomReferences == null) { - Timber.d("No room found for $roomId, returning null") - return@withContext null - } - val liveTimeline = roomReferences.fullRoom.timeline() - val initialRoomInfo = roomReferences.fullRoom.roomInfo() - RustMatrixRoom( - sessionId = sessionId, - deviceId = deviceId, - innerRoom = roomReferences.fullRoom, - innerTimeline = liveTimeline, - sessionCoroutineScope = sessionCoroutineScope, - notificationSettingsService = notificationSettingsService, - coroutineDispatchers = dispatchers, - systemClock = systemClock, - roomContentForwarder = roomContentForwarder, - roomSyncSubscriber = roomSyncSubscriber, - matrixRoomInfoMapper = matrixRoomInfoMapper, - featureFlagService = featureFlagService, - roomMembershipObserver = roomMembershipObserver, - initialRoomInfo = matrixRoomInfoMapper.map(initialRoomInfo), - ) + val roomReferences = awaitRoomReferences(roomId) ?: return@withContext null + getBaseRoom(roomReferences) } } - suspend fun createRoomPreview(roomId: RoomId): RoomPreview? = withContext(dispatcher) { - if (isDestroyed) { - Timber.d("Room factory is destroyed, returning null for $roomId") - return@withContext null - } - val roomListItem = innerRoomListService.roomOrNull(roomId.value) - if (roomListItem == null) { - Timber.d("Room not found for $roomId") - return@withContext null - } - if (roomListItem.membership() !in RustRoomPreview.ALLOWED_MEMBERSHIPS) { - Timber.d("Room $roomId is not in allowed membership") - return@withContext null - } - val innerRoom = try { - roomListItem.previewRoom(via = emptyList()) - } catch (e: Exception) { - Timber.e(e, "Failed to get room preview for $roomId") - return@withContext null - } - RustRoomPreview( + private suspend fun getBaseRoom(roomReferences: RustRoomReferences): RustBaseRoom? { + val initialRoomInfo = roomReferences.room.roomInfo() + return RustBaseRoom( sessionId = sessionId, - inner = innerRoom, + deviceId = deviceId, + innerRoom = roomReferences.room, + coroutineDispatchers = dispatchers, + roomSyncSubscriber = roomSyncSubscriber, roomMembershipObserver = roomMembershipObserver, + initialRoomInfo = roomInfoMapper.map(initialRoomInfo), + sessionCoroutineScope = sessionCoroutineScope, ) } - private suspend fun getRoomReferences(roomId: RoomId): RustRoomReferences? { - cache[roomId]?.let { - Timber.d("Room found in cache for $roomId") - return it + suspend fun getJoinedRoomOrPreview(roomId: RoomId): GetRoomResult? = withContext(dispatcher) { + mutex.withLock { + if (isDestroyed.get()) { + Timber.d("Room factory is destroyed, returning null for $roomId") + return@withContext null + } + val roomReferences = awaitRoomReferences(roomId) ?: return@withContext null + + if (roomReferences.room.membership() == Membership.JOINED) { + val baseRoom = getBaseRoom(roomReferences) ?: return@withContext null + + // Init the live timeline in the SDK from the RoomListItem + if (!roomReferences.roomListItem.isTimelineInitialized()) { + roomReferences.roomListItem.initTimeline(eventFilters, "LIVE") + } + + GetRoomResult.Joined( + JoinedRustRoom( + baseRoom = baseRoom, + notificationSettingsService = notificationSettingsService, + roomContentForwarder = roomContentForwarder, + liveInnerTimeline = roomReferences.room.timeline(), + coroutineDispatchers = dispatchers, + systemClock = systemClock, + roomInfoMapper = roomInfoMapper, + featureFlagService = featureFlagService, + ) + ) + } else { + val preview = try { + roomReferences.roomListItem.previewRoom(via = emptyList()) + } catch (e: Exception) { + Timber.e(e, "Failed to get room preview for $roomId") + return@withContext null + } + + GetRoomResult.NotJoined( + NotJoinedRustRoom( + sessionId = sessionId, + localRoom = getBaseRoom(roomReferences), + previewInfo = RoomPreviewInfoMapper.map(preview.info()), + ) + ) + } } + } + + private fun getRoomReferences(roomId: RoomId): RustRoomReferences? { val roomListItem = innerRoomListService.roomOrNull(roomId.value) if (roomListItem == null) { Timber.d("Room not found for $roomId") return null } - val fullRoom = try { - roomListItem.fullRoomWithTimeline(filter = eventFilters) - } catch (e: RoomListException) { - Timber.e(e, "Failed to get full room with timeline for $roomId") - return null - } - Timber.d("Got full room with timeline for $roomId") + val room = tryOrNull { + innerClient.getRoom(roomId.value) + } ?: error("Failed to get room for room id: $roomId") + + Timber.d("Got room for $roomId") return RustRoomReferences( roomListItem = roomListItem, - fullRoom = fullRoom, - ).also { - cache.put(roomId, it) + room = room, + ) + } + + /** + * Get the Rust room references for a room, retrying after the room list is loaded if necessary. + */ + private suspend fun awaitRoomReferences(roomId: RoomId): RustRoomReferences? { + var roomReferences = getRoomReferences(roomId) + + if (roomReferences == null) { + // ... otherwise, lets wait for the SS to load all rooms and check again. + roomListService.allRooms.awaitLoaded() + roomReferences = getRoomReferences(roomId) } + + return roomReferences } } + +sealed interface GetRoomResult { + data class Joined(val joinedRoom: JoinedRoom) : GetRoomResult + data class NotJoined(val notJoinedRoom: NotJoinedRustRoom) : GetRoomResult + + val room: BaseRoom? + get() = when (this) { + is Joined -> joinedRoom + is NotJoined -> notJoinedRoom.localRoom + } +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomPreview.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomPreview.kt deleted file mode 100644 index 44c294a707..0000000000 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomPreview.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.room - -import androidx.compose.runtime.Immutable -import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.matrix.api.room.CurrentUserMembership -import io.element.android.libraries.matrix.api.room.RoomMembershipDetails -import io.element.android.libraries.matrix.api.room.RoomMembershipObserver -import io.element.android.libraries.matrix.api.room.RoomPreview -import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo -import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper -import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper -import org.matrix.rustcomponents.sdk.Membership -import org.matrix.rustcomponents.sdk.RoomPreview as InnerRoomPreview - -@Immutable -class RustRoomPreview( - override val sessionId: SessionId, - private val inner: InnerRoomPreview, - private val roomMembershipObserver: RoomMembershipObserver?, -) : RoomPreview { - companion object { - val ALLOWED_MEMBERSHIPS = setOf(Membership.INVITED, Membership.KNOCKED, Membership.BANNED) - } - - override val info: RoomPreviewInfo = RoomPreviewInfoMapper.map(inner.info()) - - override suspend fun leave(): Result = runCatching { - inner.leave() - }.onSuccess { - when (info.membership) { - CurrentUserMembership.INVITED -> roomMembershipObserver?.notifyUserDeclinedInvite(info.roomId) - CurrentUserMembership.KNOCKED -> roomMembershipObserver?.notifyUserCanceledKnock(info.roomId) - else -> Unit - } - } - - override suspend fun forget(): Result = runCatching { - inner.forget() - } - - override suspend fun membershipDetails(): Result = runCatching { - val details = inner.ownMembershipDetails() ?: return@runCatching null - RoomMembershipDetails( - currentUserMember = RoomMemberMapper.map(details.roomMember), - senderMember = details.senderInfo?.let { RoomMemberMapper.map(it) }, - ) - } - - override fun close() { - inner.destroy() - } -} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcher.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcher.kt index b349d05e3a..187bead11e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcher.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcher.kt @@ -7,8 +7,8 @@ package io.element.android.libraries.matrix.impl.room.member -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.roomMembers import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -42,8 +42,8 @@ internal class RoomMemberListFetcher( private val updatedRoomMemberMutex = Mutex() private val roomId = room.id() - private val _membersFlow = MutableStateFlow(MatrixRoomMembersState.Unknown) - val membersFlow: StateFlow = _membersFlow + private val _membersFlow = MutableStateFlow(RoomMembersState.Unknown) + val membersFlow: StateFlow = _membersFlow /** * Fetches the room members for the given room. @@ -75,16 +75,16 @@ internal class RoomMemberListFetcher( } } - private suspend fun MutableStateFlow.fetchCachedRoomMembers(asPendingState: Boolean = true) { + private suspend fun MutableStateFlow.fetchCachedRoomMembers(asPendingState: Boolean = true) { Timber.i("Loading cached members for room $roomId") try { // Send current member list with pending state to notify the UI that we are loading new members emit(pendingWithCurrentMembers()) val members = parseAndEmitMembers(room.membersNoSync()) val newState = if (asPendingState) { - MatrixRoomMembersState.Pending(prevRoomMembers = members) + RoomMembersState.Pending(prevRoomMembers = members) } else { - MatrixRoomMembersState.Ready(members) + RoomMembersState.Ready(members) } emit(newState) } catch (exception: CancellationException) { @@ -92,22 +92,22 @@ internal class RoomMemberListFetcher( throw exception } catch (exception: Exception) { Timber.e(exception, "Failed to load cached members for room $roomId") - emit(MatrixRoomMembersState.Error(exception, _membersFlow.value.roomMembers()?.toImmutableList())) + emit(RoomMembersState.Error(exception, _membersFlow.value.roomMembers()?.toImmutableList())) } } - private suspend fun MutableStateFlow.fetchRemoteRoomMembers() { + private suspend fun MutableStateFlow.fetchRemoteRoomMembers() { try { // Send current member list with pending state to notify the UI that we are loading new members emit(pendingWithCurrentMembers()) // Start loading new members - emit(MatrixRoomMembersState.Ready(parseAndEmitMembers(room.members()))) + emit(RoomMembersState.Ready(parseAndEmitMembers(room.members()))) } catch (exception: CancellationException) { Timber.d("Cancelled loading updated members for room $roomId") throw exception } catch (exception: Exception) { Timber.e(exception, "Failed to load updated members for room $roomId") - emit(MatrixRoomMembersState.Error(exception, _membersFlow.value.roomMembers()?.toImmutableList())) + emit(RoomMembersState.Error(exception, _membersFlow.value.roomMembers()?.toImmutableList())) } } @@ -129,5 +129,5 @@ internal class RoomMemberListFetcher( } } - private fun pendingWithCurrentMembers() = MatrixRoomMembersState.Pending(_membersFlow.value.roomMembers().orEmpty().toImmutableList()) + private fun pendingWithCurrentMembers() = RoomMembersState.Pending(_membersFlow.value.roomMembers().orEmpty().toImmutableList()) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/powerlevels/RoomPowerLevelsMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/powerlevels/RoomPowerLevelsMapper.kt index d7babcfd2b..55a09030b3 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/powerlevels/RoomPowerLevelsMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/powerlevels/RoomPowerLevelsMapper.kt @@ -7,12 +7,12 @@ package io.element.android.libraries.matrix.impl.room.powerlevels -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import org.matrix.rustcomponents.sdk.RoomPowerLevels as RustRoomPowerLevels object RoomPowerLevelsMapper { - fun map(roomPowerLevels: RustRoomPowerLevels): MatrixRoomPowerLevels { - return MatrixRoomPowerLevels( + fun map(roomPowerLevels: RustRoomPowerLevels): RoomPowerLevels { + return RoomPowerLevels( ban = roomPowerLevels.ban, invite = roomPowerLevels.invite, kick = roomPowerLevels.kick, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryFactory.kt index 8dd58878c3..6eac11ce30 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryFactory.kt @@ -8,14 +8,14 @@ package io.element.android.libraries.matrix.impl.roomlist import io.element.android.libraries.matrix.api.roomlist.RoomSummary -import io.element.android.libraries.matrix.impl.room.MatrixRoomInfoMapper +import io.element.android.libraries.matrix.impl.room.RoomInfoMapper import io.element.android.libraries.matrix.impl.room.message.RoomMessageFactory import org.matrix.rustcomponents.sdk.RoomListItem import org.matrix.rustcomponents.sdk.use class RoomSummaryFactory( private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory(), - private val roomInfoMapper: MatrixRoomInfoMapper = MatrixRoomInfoMapper(), + private val roomInfoMapper: RoomInfoMapper = RoomInfoMapper(), ) { suspend fun create(roomListItem: RoomListItem): RoomSummary { val roomInfo = roomListItem.roomInfo().let(roomInfoMapper::map) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt index f13b5465fb..2c3ba422d1 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt @@ -19,7 +19,7 @@ import io.element.android.libraries.matrix.api.media.MediaUploadHandler import io.element.android.libraries.matrix.api.media.VideoInfo import io.element.android.libraries.matrix.api.poll.PollKind import io.element.android.libraries.matrix.api.room.IntentionalMention -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.room.location.AssetType import io.element.android.libraries.matrix.api.room.message.ReplyParameters @@ -86,7 +86,7 @@ class RustTimeline( private val inner: InnerTimeline, mode: Timeline.Mode, systemClock: SystemClock, - private val matrixRoom: MatrixRoom, + private val joinedRoom: JoinedRoom, private val coroutineScope: CoroutineScope, private val dispatcher: CoroutineDispatcher, private val roomContentForwarder: RoomContentForwarder, @@ -137,7 +137,10 @@ class RustTimeline( ) init { - coroutineScope.fetchMembers() + if (mode != Timeline.Mode.PINNED_EVENTS) { + coroutineScope.fetchMembers() + } + if (mode == Timeline.Mode.LIVE) { // When timeline is live, we need to listen to the back pagination status as // sdk can automatically paginate backwards. @@ -186,10 +189,10 @@ class RustTimeline( } }.onFailure { error -> if (error is TimelineException.CannotPaginate) { - Timber.d("Can't paginate $direction on room ${matrixRoom.roomId} with paginationStatus: ${backwardPaginationStatus.value}") + Timber.d("Can't paginate $direction on room ${joinedRoom.roomId} with paginationStatus: ${backwardPaginationStatus.value}") } else { updatePaginationStatus(direction) { it.copy(isPaginating = false) } - Timber.e(error, "Error paginating $direction on room ${matrixRoom.roomId}") + Timber.e(error, "Error paginating $direction on room ${joinedRoom.roomId}") } }.onSuccess { hasReachedEnd -> updatePaginationStatus(direction) { it.copy(isPaginating = false, hasMoreToLoad = !hasReachedEnd) } @@ -209,7 +212,7 @@ class RustTimeline( _timelineItems, backwardPaginationStatus, forwardPaginationStatus, - matrixRoom.roomInfoFlow.map { it.creator to it.isDm }.distinctUntilChanged(), + joinedRoom.roomInfoFlow.map { it.creator to it.isDm }.distinctUntilChanged(), isTimelineInitialized, ) { timelineItems, backwardPaginationStatus, @@ -261,7 +264,7 @@ class RustTimeline( try { inner.fetchMembers() } catch (exception: Exception) { - Timber.e(exception, "Error fetching members for room ${matrixRoom.roomId}") + Timber.e(exception, "Error fetching members for room ${joinedRoom.roomId}") } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExtKtTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedExtKtTest.kt similarity index 81% rename from libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExtKtTest.kt rename to libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedExtKtTest.kt index 1ecfb672b8..8bf86c5978 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedRoomExtKtTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/analytics/JoinedExtKtTest.kt @@ -9,12 +9,12 @@ package io.element.android.libraries.matrix.impl.analytics import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.JoinedRoom -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import kotlinx.coroutines.test.runTest import org.junit.Test -class JoinedRoomExtKtTest { +class JoinedExtKtTest { @Test fun `test room size mapping`() = runTest { mapOf( @@ -26,7 +26,7 @@ class JoinedRoomExtKtTest { listOf(1001L, 2000L) to JoinedRoom.RoomSize.MoreThanAThousand ).forEach { (joinedMemberCounts, expectedRoomSize) -> joinedMemberCounts.forEach { joinedMemberCount -> - assertThat(aMatrixRoom(joinedMemberCount = joinedMemberCount).toAnalyticsJoinedRoom(null)) + assertThat(aRoom(joinedMemberCount = joinedMemberCount).toAnalyticsJoinedRoom(null)) .isEqualTo( JoinedRoom( isDM = false, @@ -41,7 +41,7 @@ class JoinedRoomExtKtTest { @Test fun `test isDirect parameter mapping`() = runTest { - assertThat(aMatrixRoom(isDirect = true).toAnalyticsJoinedRoom(null)) + assertThat(aRoom(isDirect = true).toAnalyticsJoinedRoom(null)) .isEqualTo( JoinedRoom( isDM = true, @@ -54,7 +54,7 @@ class JoinedRoomExtKtTest { @Test fun `test isSpace parameter mapping`() = runTest { - assertThat(aMatrixRoom(isSpace = true).toAnalyticsJoinedRoom(null)) + assertThat(aRoom(isSpace = true).toAnalyticsJoinedRoom(null)) .isEqualTo( JoinedRoom( isDM = false, @@ -67,7 +67,7 @@ class JoinedRoomExtKtTest { @Test fun `test trigger parameter mapping`() = runTest { - assertThat(aMatrixRoom(isDirect = false, isSpace = false, joinedMemberCount = 1).toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite)) + assertThat(aRoom(isDirect = false, isSpace = false, joinedMemberCount = 1).toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite)) .isEqualTo( JoinedRoom( isDM = false, @@ -78,12 +78,12 @@ class JoinedRoomExtKtTest { ) } - private fun aMatrixRoom( + private fun aRoom( isDirect: Boolean = false, isSpace: Boolean = false, joinedMemberCount: Long = 0 - ): FakeMatrixRoom { - return FakeMatrixRoom().apply { + ): FakeBaseRoom { + return FakeBaseRoom().apply { givenRoomInfo(aRoomInfo(isDirect = isDirect, isSpace = isSpace, joinedMembersCount = joinedMemberCount)) } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapperTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RoomInfoMapperTest.kt similarity index 97% rename from libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapperTest.kt rename to libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RoomInfoMapperTest.kt index 33ce5c8c33..c6adaa46d1 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/MatrixRoomInfoMapperTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/RoomInfoMapperTest.kt @@ -12,7 +12,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.CurrentUserMembership -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility import io.element.android.libraries.matrix.api.room.join.JoinRule @@ -38,11 +38,11 @@ import org.matrix.rustcomponents.sdk.JoinRule as RustJoinRule import org.matrix.rustcomponents.sdk.RoomHistoryVisibility as RustRoomHistoryVisibility import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode -class MatrixRoomInfoMapperTest { +class RoomInfoMapperTest { @Test fun `mapping of RustRoomInfo should map all the fields`() { assertThat( - MatrixRoomInfoMapper().map( + RoomInfoMapper().map( aRustRoomInfo( id = A_ROOM_ID.value, displayName = "displayName", @@ -80,7 +80,7 @@ class MatrixRoomInfoMapperTest { ) ) ).isEqualTo( - MatrixRoomInfo( + RoomInfo( id = A_ROOM_ID, name = "displayName", rawName = "rawName", @@ -127,7 +127,7 @@ class MatrixRoomInfoMapperTest { @Test fun `mapping of RustRoomInfo with null members should map all the fields`() { assertThat( - MatrixRoomInfoMapper().map( + RoomInfoMapper().map( aRustRoomInfo( id = A_ROOM_ID.value, displayName = null, @@ -164,7 +164,7 @@ class MatrixRoomInfoMapperTest { ) ) ).isEqualTo( - MatrixRoomInfo( + RoomInfo( id = A_ROOM_ID, name = null, rawName = null, diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt index 9806cbb1cb..6193d229c8 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/join/DefaultJoinRoomTest.kt @@ -18,7 +18,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ALIAS import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SERVER_LIST import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.services.analytics.test.FakeAnalyticsService @@ -33,7 +33,7 @@ class DefaultJoinRoomTest { val roomSummary = aRoomSummary() val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) } val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List -> Result.success(roomSummary) } - val roomResult = FakeMatrixRoom().apply { + val roomResult = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo()) } val aTrigger = JoinedRoom.Trigger.MobilePermalink @@ -70,7 +70,7 @@ class DefaultJoinRoomTest { val roomSummary = aRoomSummary() val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) } val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List -> Result.success(roomSummary) } - val roomResult = FakeMatrixRoom().apply { + val roomResult = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo()) } val aTrigger = JoinedRoom.Trigger.MobilePermalink @@ -108,7 +108,7 @@ class DefaultJoinRoomTest { val roomSummary = aRoomSummary() val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) } val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List -> Result.success(roomSummary) } - val roomResult = FakeMatrixRoom().apply { + val roomResult = FakeBaseRoom().apply { givenRoomInfo(aRoomInfo()) } val aTrigger = JoinedRoom.Trigger.MobilePermalink diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcherTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcherTest.kt index 19a310c4be..94f786b581 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcherTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/member/RoomMemberListFetcherTest.kt @@ -9,7 +9,7 @@ package io.element.android.libraries.matrix.impl.room.member import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomMember import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoom @@ -40,16 +40,16 @@ class RoomMemberListFetcherTest { val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) fetcher.membersFlow.test { - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java) fetcher.fetchRoomMembers(source = CACHE) // Loading state - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java) val cachedItemsState = awaitItem() - assertThat(cachedItemsState).isInstanceOf(MatrixRoomMembersState.Ready::class.java) - assertThat((cachedItemsState as? MatrixRoomMembersState.Ready)?.roomMembers).hasSize(3) + assertThat(cachedItemsState).isInstanceOf(RoomMembersState.Ready::class.java) + assertThat((cachedItemsState as? RoomMembersState.Ready)?.roomMembers).hasSize(3) } } @@ -62,9 +62,9 @@ class RoomMemberListFetcherTest { val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) fetcher.membersFlow.test { fetcher.fetchRoomMembers(source = CACHE) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) - assertThat((awaitItem() as? MatrixRoomMembersState.Ready)?.roomMembers).isEmpty() + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java) + assertThat((awaitItem() as? RoomMembersState.Ready)?.roomMembers).isEmpty() } } @@ -77,9 +77,9 @@ class RoomMemberListFetcherTest { val fetcher = RoomMemberListFetcher(room, Dispatchers.Default) fetcher.membersFlow.test { fetcher.fetchRoomMembers(source = CACHE) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Error::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Error::class.java) } } @@ -100,11 +100,11 @@ class RoomMemberListFetcherTest { fetcher.fetchRoomMembers(source = CACHE) // Initial state - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java) // Started loading cached members - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java) // Finished loading cached members - assertThat((awaitItem() as? MatrixRoomMembersState.Ready)?.roomMembers).hasSize(3) + assertThat((awaitItem() as? RoomMembersState.Ready)?.roomMembers).hasSize(3) ensureAllEventsConsumed() } @@ -126,9 +126,9 @@ class RoomMemberListFetcherTest { fetcher.membersFlow.test { fetcher.fetchRoomMembers(source = SERVER) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) - assertThat((awaitItem() as? MatrixRoomMembersState.Ready)?.roomMembers?.size).isEqualTo(3) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java) + assertThat((awaitItem() as? RoomMembersState.Ready)?.roomMembers?.size).isEqualTo(3) } } @@ -140,9 +140,9 @@ class RoomMemberListFetcherTest { fetcher.membersFlow.test { fetcher.fetchRoomMembers(source = SERVER) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java) - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Error::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Error::class.java) } } @@ -167,20 +167,20 @@ class RoomMemberListFetcherTest { fetcher.membersFlow.test { fetcher.fetchRoomMembers(source = CACHE_AND_SERVER) // Initial - assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java) + assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java) // Loading cached awaitItem().let { pending -> - assertThat(pending).isInstanceOf(MatrixRoomMembersState.Pending::class.java) + assertThat(pending).isInstanceOf(RoomMembersState.Pending::class.java) assertThat(pending.roomMembers()).isEmpty() } // Loaded cached awaitItem().let { cached -> - assertThat(cached).isInstanceOf(MatrixRoomMembersState.Pending::class.java) + assertThat(cached).isInstanceOf(RoomMembersState.Pending::class.java) assertThat(cached.roomMembers()).hasSize(1) } // Start loading new awaitItem().let { ready -> - assertThat(ready).isInstanceOf(MatrixRoomMembersState.Ready::class.java) + assertThat(ready).isInstanceOf(RoomMembersState.Ready::class.java) assertThat(ready.roomMembers()).hasSize(3) } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/powerlevels/RoomPowerLevelsMapperTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/powerlevels/RoomPowerLevelsMapperTest.kt index 2a8f733bb8..aac02350e1 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/powerlevels/RoomPowerLevelsMapperTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/room/powerlevels/RoomPowerLevelsMapperTest.kt @@ -8,7 +8,7 @@ package io.element.android.libraries.matrix.impl.room.powerlevels import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomPowerLevels import org.junit.Test @@ -31,7 +31,7 @@ class RoomPowerLevelsMapperTest { ) ) ).isEqualTo( - MatrixRoomPowerLevels( + RoomPowerLevels( ban = 1, invite = 2, kick = 3, diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryListTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryListTest.kt similarity index 98% rename from libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryListTest.kt rename to libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryListTest.kt index b2931ce49e..ba3ee850c1 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryListTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryListTest.kt @@ -24,7 +24,7 @@ import org.matrix.rustcomponents.sdk.RoomDirectorySearch import org.matrix.rustcomponents.sdk.RoomDirectorySearchEntryUpdate @OptIn(ExperimentalCoroutinesApi::class) -class RustRoomDirectoryListTest { +class RustBaseRoomDirectoryListTest { @Test fun `check that the state emits the expected values`() = runTest { val roomDirectorySearch = FakeRustRoomDirectorySearch() diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryServiceTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryServiceTest.kt similarity index 94% rename from libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryServiceTest.kt rename to libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryServiceTest.kt index 76a0fac4a9..36ff2efbfc 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryServiceTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustBaseRoomDirectoryServiceTest.kt @@ -12,7 +12,7 @@ import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Test -class RustRoomDirectoryServiceTest { +class RustBaseRoomDirectoryServiceTest { @Test fun test() = runTest { val client = FakeRustClient() diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListServiceTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustBaseRoomListServiceTest.kt similarity index 98% rename from libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListServiceTest.kt rename to libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustBaseRoomListServiceTest.kt index 8279f86483..0957a06700 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListServiceTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustBaseRoomListServiceTest.kt @@ -23,7 +23,7 @@ import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicator import org.matrix.rustcomponents.sdk.RoomListService as RustRoomListService @OptIn(ExperimentalCoroutinesApi::class) -class RustRoomListServiceTest { +class RustBaseRoomListServiceTest { @Test fun `syncIndicator should emit the expected values`() = runTest { val roomListService = FakeRustRoomListService() diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt index 0dd2ba3b86..1498b70468 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimelineTest.kt @@ -12,7 +12,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.test.FakeFeatureFlagService -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem @@ -20,7 +20,7 @@ import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomListS import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimeline import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimelineDiff import io.element.android.libraries.matrix.impl.room.RoomContentForwarder -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.services.toolbox.api.systemclock.SystemClock import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP @@ -103,7 +103,7 @@ private fun TestScope.createRustTimeline( inner: InnerTimeline, mode: Timeline.Mode = Timeline.Mode.LIVE, systemClock: SystemClock = FakeSystemClock(), - matrixRoom: MatrixRoom = FakeMatrixRoom().apply { givenRoomInfo(aRoomInfo()) }, + joinedRoom: JoinedRoom = FakeJoinedRoom().apply { givenRoomInfo(aRoomInfo()) }, coroutineScope: CoroutineScope = backgroundScope, dispatcher: CoroutineDispatcher = testCoroutineDispatchers().io, roomContentForwarder: RoomContentForwarder = RoomContentForwarder(FakeRustRoomListService()), @@ -114,7 +114,7 @@ private fun TestScope.createRustTimeline( inner = inner, mode = mode, systemClock = systemClock, - matrixRoom = matrixRoom, + joinedRoom = joinedRoom, coroutineScope = coroutineScope, dispatcher = dispatcher, roomContentForwarder = roomContentForwarder, diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index 446a039bd9..20c69545e7 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -22,9 +22,10 @@ import io.element.android.libraries.matrix.api.notification.NotificationService import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.oidc.AccountManagementAction import io.element.android.libraries.matrix.api.pusher.PushersService -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.NotJoinedRoom import io.element.android.libraries.matrix.api.room.RoomMembershipObserver -import io.element.android.libraries.matrix.api.room.RoomPreview import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService import io.element.android.libraries.matrix.api.roomlist.RoomListService @@ -77,7 +78,7 @@ class FakeMatrixClient( Optional.of(ResolvedRoomAlias(A_ROOM_ID, emptyList())) ) }, - private val getRoomPreviewResult: (RoomIdOrAlias, List) -> Result = { _, _ -> Result.failure(AN_EXCEPTION) }, + private val getNotJoinedRoomResult: (RoomIdOrAlias, List) -> Result = { _, _ -> Result.failure(AN_EXCEPTION) }, private val clearCacheLambda: () -> Unit = { lambdaError() }, private val userIdServerNameLambda: () -> String = { lambdaError() }, private val getUrlLambda: (String) -> Result = { lambdaError() }, @@ -102,7 +103,7 @@ class FakeMatrixClient( private var createRoomResult: Result = Result.success(A_ROOM_ID) private var createDmResult: Result = Result.success(A_ROOM_ID) private var findDmResult: RoomId? = A_ROOM_ID - private val getRoomResults = mutableMapOf() + private val getRoomResults = mutableMapOf() private val searchUserResults = mutableMapOf>() private val getProfileResults = mutableMapOf>() private var uploadMediaResult: Result = Result.success(AN_AVATAR_URL) @@ -123,12 +124,12 @@ class FakeMatrixClient( } var logoutLambda: (Boolean, Boolean) -> Unit = { _, _ -> } - override suspend fun getRoom(roomId: RoomId): MatrixRoom? { + override suspend fun getRoom(roomId: RoomId): BaseRoom? { return getRoomResults[roomId] } - override suspend fun getPendingRoom(roomId: RoomId): RoomPreview? = simulateLongTask { - getRoomPreviewResult(RoomIdOrAlias.Id(roomId), emptyList()).getOrNull() + override suspend fun getJoinedRoom(roomId: RoomId): JoinedRoom? { + return getRoomResults[roomId] as? JoinedRoom } override suspend fun findDM(userId: UserId): RoomId? { @@ -250,7 +251,7 @@ class FakeMatrixClient( findDmResult = result } - fun givenGetRoomResult(roomId: RoomId, result: MatrixRoom?) { + fun givenGetRoomResult(roomId: RoomId, result: BaseRoom?) { if (result == null) { getRoomResults.remove(roomId) } else { @@ -294,8 +295,8 @@ class FakeMatrixClient( resolveRoomAliasResult(roomAlias) } - override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List): Result = simulateLongTask { - getRoomPreviewResult(roomIdOrAlias, serverNames) + override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List): Result = simulateLongTask { + getNotJoinedRoomResult(roomIdOrAlias, serverNames) } override suspend fun getRecentlyVisitedRooms(): Result> { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt new file mode 100644 index 0000000000..e260dbfd52 --- /dev/null +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt @@ -0,0 +1,220 @@ +/* + * Copyright 2023, 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.test.room + +import io.element.android.libraries.core.bool.orFalse +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.MessageEventType +import io.element.android.libraries.matrix.api.room.RoomInfo +import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembersState +import io.element.android.libraries.matrix.api.room.StateEventType +import io.element.android.libraries.matrix.api.room.draft.ComposerDraft +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels +import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility +import io.element.android.libraries.matrix.api.timeline.ReceiptType +import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.test.A_SESSION_ID +import io.element.android.tests.testutils.lambda.lambdaError +import io.element.android.tests.testutils.simulateLongTask +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.test.TestScope + +class FakeBaseRoom( + override val sessionId: SessionId = A_SESSION_ID, + override val roomId: RoomId = A_ROOM_ID, + initialRoomInfo: RoomInfo = aRoomInfo(), + override val roomCoroutineScope: CoroutineScope = TestScope(), + private var roomPermalinkResult: () -> Result = { lambdaError() }, + private var eventPermalinkResult: (EventId) -> Result = { lambdaError() }, + private val userDisplayNameResult: (UserId) -> Result = { lambdaError() }, + private val userAvatarUrlResult: () -> Result = { lambdaError() }, + private val userRoleResult: () -> Result = { lambdaError() }, + private val getUpdatedMemberResult: (UserId) -> Result = { lambdaError() }, + private val joinRoomResult: () -> Result = { lambdaError() }, + private val canInviteResult: (UserId) -> Result = { lambdaError() }, + private val canKickResult: (UserId) -> Result = { lambdaError() }, + private val canBanResult: (UserId) -> Result = { lambdaError() }, + private val canRedactOwnResult: (UserId) -> Result = { lambdaError() }, + private val canRedactOtherResult: (UserId) -> Result = { lambdaError() }, + private val canSendStateResult: (UserId, StateEventType) -> Result = { _, _ -> lambdaError() }, + private val canUserSendMessageResult: (UserId, MessageEventType) -> Result = { _, _ -> lambdaError() }, + private val canUserTriggerRoomNotificationResult: (UserId) -> Result = { lambdaError() }, + private val canUserJoinCallResult: (UserId) -> Result = { lambdaError() }, + private val canUserPinUnpinResult: (UserId) -> Result = { lambdaError() }, + private val setIsFavoriteResult: (Boolean) -> Result = { lambdaError() }, + private val powerLevelsResult: () -> Result = { lambdaError() }, + private val leaveRoomLambda: () -> Result = { lambdaError() }, + private val updateMembersResult: () -> Unit = { lambdaError() }, + private val getMembersResult: (Int) -> Result> = { lambdaError() }, + private val saveComposerDraftLambda: (ComposerDraft) -> Result = { _: ComposerDraft -> Result.success(Unit) }, + private val loadComposerDraftLambda: () -> Result = { Result.success(null) }, + private val clearComposerDraftLambda: () -> Result = { Result.success(Unit) }, + private val subscribeToSyncLambda: () -> Unit = { lambdaError() }, + private val getRoomVisibilityResult: () -> Result = { lambdaError() }, + private val forgetResult: () -> Result = { lambdaError() }, +) : BaseRoom { + private val _roomInfoFlow: MutableStateFlow = MutableStateFlow(initialRoomInfo) + override val roomInfoFlow: StateFlow = _roomInfoFlow + + fun givenRoomInfo(roomInfo: RoomInfo) { + _roomInfoFlow.tryEmit(roomInfo) + } + + override val membersStateFlow: MutableStateFlow = MutableStateFlow(RoomMembersState.Unknown) + + override suspend fun updateMembers() = updateMembersResult() + + override suspend fun getUpdatedMember(userId: UserId): Result { + return getUpdatedMemberResult(userId) + } + + override suspend fun getMembers(limit: Int): Result> { + return getMembersResult(limit) + } + + override suspend fun subscribeToSync() { + subscribeToSyncLambda() + } + + override suspend fun powerLevels(): Result { + return powerLevelsResult() + } + + override fun destroy() = Unit + + override suspend fun userDisplayName(userId: UserId): Result = simulateLongTask { + userDisplayNameResult(userId) + } + + override suspend fun userAvatarUrl(userId: UserId): Result = simulateLongTask { + userAvatarUrlResult() + } + + override suspend fun userRole(userId: UserId): Result { + return userRoleResult() + } + + override suspend fun getPermalink(): Result { + return roomPermalinkResult() + } + + override suspend fun getPermalinkFor(eventId: EventId): Result { + return eventPermalinkResult(eventId) + } + + override suspend fun getRoomVisibility(): Result = simulateLongTask { + getRoomVisibilityResult() + } + + override suspend fun leave(): Result = simulateLongTask { + return leaveRoomLambda() + } + + override suspend fun join(): Result { + return joinRoomResult() + } + + override suspend fun forget(): Result { + return forgetResult() + } + + override suspend fun canUserBan(userId: UserId): Result { + return canBanResult(userId) + } + + override suspend fun canUserKick(userId: UserId): Result { + return canKickResult(userId) + } + + override suspend fun canUserInvite(userId: UserId): Result { + return canInviteResult(userId) + } + + override suspend fun canUserRedactOwn(userId: UserId): Result { + return canRedactOwnResult(userId) + } + + override suspend fun canUserRedactOther(userId: UserId): Result { + return canRedactOtherResult(userId) + } + + override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result { + return canSendStateResult(userId, type) + } + + override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result { + return canUserSendMessageResult(userId, type) + } + + override suspend fun canUserTriggerRoomNotification(userId: UserId): Result { + return canUserTriggerRoomNotificationResult(userId) + } + + override suspend fun canUserJoinCall(userId: UserId): Result { + return canUserJoinCallResult(userId) + } + + override suspend fun canUserPinUnpin(userId: UserId): Result { + return canUserPinUnpinResult(userId) + } + + override suspend fun setIsFavorite(isFavorite: Boolean): Result { + return setIsFavoriteResult(isFavorite) + } + + val markAsReadCalls = mutableListOf() + + override suspend fun markAsRead(receiptType: ReceiptType): Result { + markAsReadCalls.add(receiptType) + return Result.success(Unit) + } + + var setUnreadFlagCalls = mutableListOf() + private set + + override suspend fun setUnreadFlag(isUnread: Boolean): Result { + setUnreadFlagCalls.add(isUnread) + return Result.success(Unit) + } + + override suspend fun saveComposerDraft(composerDraft: ComposerDraft) = saveComposerDraftLambda(composerDraft) + + override suspend fun loadComposerDraft() = loadComposerDraftLambda() + + override suspend fun clearComposerDraft() = clearComposerDraftLambda() + + override suspend fun getUpdatedIsEncrypted(): Result = simulateLongTask { + Result.success(info().isEncrypted.orFalse()) + } + + fun givenRoomMembersState(state: RoomMembersState) { + membersStateFlow.value = state + } + + override suspend fun clearEventCacheStorage(): Result { + return Result.success(Unit) + } +} + +fun defaultRoomPowerLevels() = RoomPowerLevels( + ban = 50, + invite = 0, + kick = 50, + sendEvents = 0, + redactEvents = 50, + roomName = 100, + roomAvatar = 100, + roomTopic = 100 +) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt similarity index 54% rename from libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt rename to libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt index b7d226d499..2cae27b291 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023, 2024 New Vector Ltd. + * Copyright 2025 New Vector Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. @@ -14,7 +14,6 @@ import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SendHandle -import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange @@ -23,33 +22,26 @@ import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.MediaUploadHandler import io.element.android.libraries.matrix.api.media.VideoInfo -import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.poll.PollKind +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.CreateTimelineParams import io.element.android.libraries.matrix.api.room.IntentionalMention -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState -import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState -import io.element.android.libraries.matrix.api.room.MessageEventType -import io.element.android.libraries.matrix.api.room.RoomMember -import io.element.android.libraries.matrix.api.room.StateEventType -import io.element.android.libraries.matrix.api.room.draft.ComposerDraft +import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.room.RoomInfo +import io.element.android.libraries.matrix.api.room.RoomMembersState +import io.element.android.libraries.matrix.api.room.RoomNotificationSettingsState import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.knock.KnockRequest import io.element.android.libraries.matrix.api.room.location.AssetType import io.element.android.libraries.matrix.api.room.message.ReplyParameters -import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility -import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings -import io.element.android.libraries.matrix.test.A_ROOM_ID -import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.timeline.FakeTimeline @@ -58,36 +50,25 @@ import io.element.android.tests.testutils.simulateLongTask import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.test.TestScope import java.io.File -class FakeMatrixRoom( - override val sessionId: SessionId = A_SESSION_ID, - override val roomId: RoomId = A_ROOM_ID, - val notificationSettingsService: NotificationSettingsService = FakeNotificationSettingsService(), +class FakeJoinedRoom( + val baseRoom: FakeBaseRoom = FakeBaseRoom(), override val liveTimeline: Timeline = FakeTimeline(), - initialRoomInfo: MatrixRoomInfo = aRoomInfo(), override val roomCoroutineScope: CoroutineScope = TestScope(), - private var roomPermalinkResult: () -> Result = { lambdaError() }, - private var eventPermalinkResult: (EventId) -> Result = { lambdaError() }, - private val sendCallNotificationIfNeededResult: () -> Result = { lambdaError() }, - private val userDisplayNameResult: (UserId) -> Result = { lambdaError() }, - private val userAvatarUrlResult: () -> Result = { lambdaError() }, - private val userRoleResult: () -> Result = { lambdaError() }, - private val getUpdatedMemberResult: (UserId) -> Result = { lambdaError() }, - private val joinRoomResult: () -> Result = { lambdaError() }, - private val inviteUserResult: (UserId) -> Result = { lambdaError() }, - private val canInviteResult: (UserId) -> Result = { lambdaError() }, - private val canKickResult: (UserId) -> Result = { lambdaError() }, - private val canBanResult: (UserId) -> Result = { lambdaError() }, - private val canRedactOwnResult: (UserId) -> Result = { lambdaError() }, - private val canRedactOtherResult: (UserId) -> Result = { lambdaError() }, - private val canSendStateResult: (UserId, StateEventType) -> Result = { _, _ -> lambdaError() }, - private val canUserSendMessageResult: (UserId, MessageEventType) -> Result = { _, _ -> lambdaError() }, + override val syncUpdateFlow: StateFlow = MutableStateFlow(0), + override val roomTypingMembersFlow: Flow> = MutableStateFlow(emptyList()), + override val identityStateChangesFlow: Flow> = MutableStateFlow(emptyList()), + override val roomNotificationSettingsStateFlow: StateFlow = + MutableStateFlow(RoomNotificationSettingsState.Unknown), + override val knockRequestsFlow: Flow> = MutableStateFlow(emptyList()), + private val roomNotificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(), + private var createTimelineResult: (CreateTimelineParams) -> Result = { lambdaError() }, + private val sendMessageResult: (String, String?, List) -> Result = { _, _, _ -> lambdaError() }, + private val editMessageLambda: (EventId, String, String?, List) -> Result = { _, _, _, _ -> lambdaError() }, private val sendImageResult: (File, File?, ImageInfo, String?, String?, ProgressCallback?, ReplyParameters?) -> Result = { _, _, _, _, _, _, _ -> lambdaError() }, private val sendVideoResult: (File, File?, VideoInfo, String?, String?, ProgressCallback?, ReplyParameters?) -> Result = @@ -98,233 +79,65 @@ class FakeMatrixRoom( { _, _, _, _, _, _ -> lambdaError() }, private val sendVoiceMessageResult: (File, AudioInfo, List, ProgressCallback?, ReplyParameters?) -> Result = { _, _, _, _, _ -> lambdaError() }, - private val setNameResult: (String) -> Result = { lambdaError() }, - private val setTopicResult: (String) -> Result = { lambdaError() }, - private val updateAvatarResult: (String, ByteArray) -> Result = { _, _ -> lambdaError() }, - private val removeAvatarResult: () -> Result = { lambdaError() }, - private val editMessageLambda: (EventId, String, String?, List) -> Result = { _, _, _, _ -> lambdaError() }, - private val sendMessageResult: (String, String?, List) -> Result = { _, _, _ -> lambdaError() }, - private val updateUserRoleResult: () -> Result = { lambdaError() }, - private val toggleReactionResult: (String, EventOrTransactionId) -> Result = { _, _ -> lambdaError() }, - private val cancelSendResult: (TransactionId) -> Result = { lambdaError() }, - private val forwardEventResult: (EventId, List) -> Result = { _, _ -> lambdaError() }, - private val reportContentResult: (EventId, String, UserId?) -> Result = { _, _, _ -> lambdaError() }, - private val kickUserResult: (UserId, String?) -> Result = { _, _ -> lambdaError() }, - private val banUserResult: (UserId, String?) -> Result = { _, _ -> lambdaError() }, - private val unBanUserResult: (UserId, String?) -> Result = { _, _ -> lambdaError() }, private val sendLocationResult: (String, String, String?, Int?, AssetType?) -> Result = { _, _, _, _, _ -> lambdaError() }, + private val sendCallNotificationIfNeededResult: () -> Result = { lambdaError() }, + private val progressCallbackValues: List> = emptyList(), private val createPollResult: (String, List, Int, PollKind) -> Result = { _, _, _, _ -> lambdaError() }, private val editPollResult: (EventId, String, List, Int, PollKind) -> Result = { _, _, _, _, _ -> lambdaError() }, private val sendPollResponseResult: (EventId, List) -> Result = { _, _ -> lambdaError() }, private val endPollResult: (EventId, String) -> Result = { _, _ -> lambdaError() }, - private val progressCallbackValues: List> = emptyList(), private val generateWidgetWebViewUrlResult: (MatrixWidgetSettings, String, String?, String?) -> Result = { _, _, _, _ -> lambdaError() }, private val getWidgetDriverResult: (MatrixWidgetSettings) -> Result = { lambdaError() }, - private val canUserTriggerRoomNotificationResult: (UserId) -> Result = { lambdaError() }, - private val canUserJoinCallResult: (UserId) -> Result = { lambdaError() }, - private val canUserPinUnpinResult: (UserId) -> Result = { lambdaError() }, - private val setIsFavoriteResult: (Boolean) -> Result = { lambdaError() }, - private val powerLevelsResult: () -> Result = { lambdaError() }, - private val updatePowerLevelsResult: () -> Result = { lambdaError() }, - private val resetPowerLevelsResult: () -> Result = { lambdaError() }, private val typingNoticeResult: (Boolean) -> Result = { lambdaError() }, - private val leaveRoomLambda: () -> Result = { lambdaError() }, - private val updateMembersResult: () -> Unit = { lambdaError() }, - private val getMembersResult: (Int) -> Result> = { lambdaError() }, - private val createTimelineResult: (CreateTimelineParams) -> Result = { lambdaError() }, - private val setSendQueueEnabledLambda: (Boolean) -> Unit = { _: Boolean -> }, - private val saveComposerDraftLambda: (ComposerDraft) -> Result = { _: ComposerDraft -> Result.success(Unit) }, - private val loadComposerDraftLambda: () -> Result = { Result.success(null) }, - private val clearComposerDraftLambda: () -> Result = { Result.success(Unit) }, - private val subscribeToSyncLambda: () -> Unit = { lambdaError() }, + private val toggleReactionResult: (String, EventOrTransactionId) -> Result = { _, _ -> lambdaError() }, + private val forwardEventResult: (EventId, List) -> Result = { _, _ -> lambdaError() }, + private val cancelSendResult: (TransactionId) -> Result = { lambdaError() }, + private val inviteUserResult: (UserId) -> Result = { lambdaError() }, + private val setNameResult: (String) -> Result = { lambdaError() }, + private val setTopicResult: (String) -> Result = { lambdaError() }, + private val updateAvatarResult: (String, ByteArray) -> Result = { _, _ -> lambdaError() }, + private val removeAvatarResult: () -> Result = { lambdaError() }, + private val updateUserRoleResult: (List) -> Result = { lambdaError() }, + private val updatePowerLevelsResult: (RoomPowerLevels) -> Result = { lambdaError() }, + private val resetPowerLevelsResult: () -> Result = { lambdaError() }, + private val reportContentResult: (EventId, String, UserId?) -> Result = { _, _, _ -> lambdaError() }, + private val kickUserResult: (UserId, String?) -> Result = { _, _ -> lambdaError() }, + private val banUserResult: (UserId, String?) -> Result = { _, _ -> lambdaError() }, + private val unBanUserResult: (UserId, String?) -> Result = { _, _ -> lambdaError() }, private val ignoreDeviceTrustAndResendResult: (Map>, SendHandle) -> Result = { _, _ -> lambdaError() }, private val withdrawVerificationAndResendResult: (List, SendHandle) -> Result = { _, _ -> lambdaError() }, private val updateCanonicalAliasResult: (RoomAlias?, List) -> Result = { _, _ -> lambdaError() }, private val updateRoomVisibilityResult: (RoomVisibility) -> Result = { lambdaError() }, private val updateRoomHistoryVisibilityResult: (RoomHistoryVisibility) -> Result = { lambdaError() }, - private val roomVisibilityResult: () -> Result = { lambdaError() }, private val publishRoomAliasInRoomDirectoryResult: (RoomAlias) -> Result = { lambdaError() }, private val removeRoomAliasFromRoomDirectoryResult: (RoomAlias) -> Result = { lambdaError() }, private val enableEncryptionResult: () -> Result = { lambdaError() }, private val updateJoinRuleResult: (JoinRule) -> Result = { lambdaError() }, -) : MatrixRoom { - private val _roomInfoFlow: MutableStateFlow = MutableStateFlow(initialRoomInfo) - override val roomInfoFlow: StateFlow = _roomInfoFlow - - fun givenRoomInfo(roomInfo: MatrixRoomInfo) { - _roomInfoFlow.tryEmit(roomInfo) + private val setSendQueueEnabledResult: (Boolean) -> Unit = { _: Boolean -> }, +) : JoinedRoom, BaseRoom by baseRoom { + fun givenRoomMembersState(state: RoomMembersState) { + baseRoom.givenRoomMembersState(state) } - private val _roomTypingMembersFlow: MutableSharedFlow> = MutableSharedFlow(replay = 1) - override val roomTypingMembersFlow: Flow> = _roomTypingMembersFlow - - fun givenRoomTypingMembers(typingMembers: List) { - _roomTypingMembersFlow.tryEmit(typingMembers) + fun givenRoomInfo(roomInfo: RoomInfo) { + baseRoom.givenRoomInfo(roomInfo) } - private val _identityStateChangesFlow: MutableSharedFlow> = MutableSharedFlow(replay = 1) - override val identityStateChangesFlow: Flow> = _identityStateChangesFlow - - fun emitIdentityStateChanges(identityStateChanges: List) { - _identityStateChangesFlow.tryEmit(identityStateChanges) - } - - private val _knockRequestsFlow: MutableSharedFlow> = MutableSharedFlow(replay = 1) - override val knockRequestsFlow: Flow> = _knockRequestsFlow - - fun emitKnockRequests(knockRequests: List) { - _knockRequestsFlow.tryEmit(knockRequests) - } - - override val membersStateFlow: MutableStateFlow = MutableStateFlow(MatrixRoomMembersState.Unknown) - - override val roomNotificationSettingsStateFlow: MutableStateFlow = - MutableStateFlow(MatrixRoomNotificationSettingsState.Unknown) - - override suspend fun updateMembers() = updateMembersResult() - - override suspend fun getUpdatedMember(userId: UserId): Result { - return getUpdatedMemberResult(userId) - } - - override suspend fun getMembers(limit: Int): Result> { - return getMembersResult(limit) - } - - override suspend fun updateRoomNotificationSettings(): Result = simulateLongTask { - val notificationSettings = notificationSettingsService.getRoomNotificationSettings(roomId, info().isEncrypted.orFalse(), isOneToOne).getOrThrow() - roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Ready(notificationSettings) - return Result.success(Unit) - } - - override suspend fun enableEncryption(): Result = simulateLongTask { - enableEncryptionResult().onSuccess { - givenRoomInfo(info().copy(isEncrypted = true)) - emitSyncUpdate() - } - } - - private val _syncUpdateFlow = MutableStateFlow(0L) - override val syncUpdateFlow: StateFlow = _syncUpdateFlow.asStateFlow() - - fun emitSyncUpdate() { - _syncUpdateFlow.tryEmit(_syncUpdateFlow.value + 1) - } - - override suspend fun createTimeline( - createTimelineParams: CreateTimelineParams, - ): Result = simulateLongTask { + override suspend fun createTimeline(createTimelineParams: CreateTimelineParams): Result = simulateLongTask { createTimelineResult(createTimelineParams) } - override suspend fun subscribeToSync() { - subscribeToSyncLambda() - } - - override suspend fun powerLevels(): Result { - return powerLevelsResult() - } - - override suspend fun updatePowerLevels(matrixRoomPowerLevels: MatrixRoomPowerLevels): Result = simulateLongTask { - updatePowerLevelsResult() - } - - override suspend fun resetPowerLevels(): Result = simulateLongTask { - resetPowerLevelsResult() - } - - override fun destroy() = Unit - - override suspend fun userDisplayName(userId: UserId): Result = simulateLongTask { - userDisplayNameResult(userId) - } - - override suspend fun userAvatarUrl(userId: UserId): Result = simulateLongTask { - userAvatarUrlResult() - } - - override suspend fun userRole(userId: UserId): Result { - return userRoleResult() - } - - override suspend fun updateUsersRoles(changes: List): Result { - return updateUserRoleResult() - } - - override suspend fun editMessage(eventId: EventId, body: String, htmlBody: String?, intentionalMentions: List) = simulateLongTask { - editMessageLambda(eventId, body, htmlBody, intentionalMentions) - } - - override suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List) = simulateLongTask { + override suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List): Result = simulateLongTask { sendMessageResult(body, htmlBody, intentionalMentions) } - override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result { - return toggleReactionResult(emoji, eventOrTransactionId) - } - - override suspend fun cancelSend(transactionId: TransactionId): Result { - return cancelSendResult(transactionId) - } - - override suspend fun getPermalink(): Result { - return roomPermalinkResult() - } - - override suspend fun getPermalinkFor(eventId: EventId): Result { - return eventPermalinkResult(eventId) - } - - override suspend fun leave(): Result { - return leaveRoomLambda() - } - - override suspend fun join(): Result { - return joinRoomResult() - } - - override suspend fun inviteUserById(id: UserId): Result = simulateLongTask { - inviteUserResult(id) - } - - override suspend fun canUserBan(userId: UserId): Result { - return canBanResult(userId) - } - - override suspend fun canUserKick(userId: UserId): Result { - return canKickResult(userId) - } - - override suspend fun canUserInvite(userId: UserId): Result { - return canInviteResult(userId) - } - - override suspend fun canUserRedactOwn(userId: UserId): Result { - return canRedactOwnResult(userId) - } - - override suspend fun canUserRedactOther(userId: UserId): Result { - return canRedactOtherResult(userId) - } - - override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result { - return canSendStateResult(userId, type) - } - - override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result { - return canUserSendMessageResult(userId, type) - } - - override suspend fun canUserTriggerRoomNotification(userId: UserId): Result { - return canUserTriggerRoomNotificationResult(userId) - } - - override suspend fun canUserJoinCall(userId: UserId): Result { - return canUserJoinCallResult(userId) - } - - override suspend fun canUserPinUnpin(userId: UserId): Result { - return canUserPinUnpinResult(userId) + override suspend fun editMessage( + eventId: EventId, + body: String, + htmlBody: String?, + intentionalMentions: List + ): Result = simulateLongTask { + editMessageLambda(eventId, body, htmlBody, intentionalMentions) } override suspend fun sendImage( @@ -440,78 +253,7 @@ class FakeMatrixRoom( ) } - private suspend fun simulateSendMediaProgress(progressCallback: ProgressCallback?) { - progressCallbackValues.forEach { (current, total) -> - progressCallback?.onProgress(current, total) - delay(1) - } - } - - override suspend fun forwardEvent(eventId: EventId, roomIds: List): Result = simulateLongTask { - forwardEventResult(eventId, roomIds) - } - - override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result = simulateLongTask { - updateAvatarResult(mimeType, data) - } - - override suspend fun removeAvatar(): Result = simulateLongTask { - removeAvatarResult() - } - - override suspend fun setName(name: String): Result = simulateLongTask { - setNameResult(name) - } - - override suspend fun setTopic(topic: String): Result = simulateLongTask { - setTopicResult(topic) - } - - override suspend fun reportContent( - eventId: EventId, - reason: String, - blockUserId: UserId? - ): Result = simulateLongTask { - return reportContentResult(eventId, reason, blockUserId) - } - - override suspend fun kickUser(userId: UserId, reason: String?): Result { - return kickUserResult(userId, reason) - } - - override suspend fun banUser(userId: UserId, reason: String?): Result { - return banUserResult(userId, reason) - } - - override suspend fun unbanUser(userId: UserId, reason: String?): Result { - return unBanUserResult(userId, reason) - } - - override suspend fun setIsFavorite(isFavorite: Boolean): Result { - return setIsFavoriteResult(isFavorite) - } - - val markAsReadCalls = mutableListOf() - - override suspend fun markAsRead(receiptType: ReceiptType): Result { - markAsReadCalls.add(receiptType) - return Result.success(Unit) - } - - var setUnreadFlagCalls = mutableListOf() - private set - - override suspend fun setUnreadFlag(isUnread: Boolean): Result { - setUnreadFlagCalls.add(isUnread) - return Result.success(Unit) - } - - override suspend fun createPoll( - question: String, - answers: List, - maxSelections: Int, - pollKind: PollKind - ): Result = simulateLongTask { + override suspend fun createPoll(question: String, answers: List, maxSelections: Int, pollKind: PollKind): Result = simulateLongTask { return createPollResult( question, answers, @@ -536,58 +278,53 @@ class FakeMatrixRoom( ) } - override suspend fun sendPollResponse( - pollStartId: EventId, - answers: List - ): Result = simulateLongTask { - return sendPollResponseResult(pollStartId, answers) + override suspend fun sendPollResponse(pollStartId: EventId, answers: List): Result = simulateLongTask { + return sendPollResponseResult( + pollStartId, + answers, + ) } - override suspend fun endPoll( - pollStartId: EventId, - text: String - ): Result = simulateLongTask { - return endPollResult(pollStartId, text) + override suspend fun endPoll(pollStartId: EventId, text: String): Result = simulateLongTask { + endPollResult( + pollStartId, + text, + ) } - override suspend fun typingNotice(isTyping: Boolean): Result { - return typingNoticeResult(isTyping) + override suspend fun typingNotice(isTyping: Boolean): Result = simulateLongTask { + typingNoticeResult(isTyping) } - override suspend fun generateWidgetWebViewUrl( - widgetSettings: MatrixWidgetSettings, - clientId: String, - languageTag: String?, - theme: String?, - ): Result = generateWidgetWebViewUrlResult( - widgetSettings, - clientId, - languageTag, - theme, - ) - - override suspend fun sendCallNotificationIfNeeded(): Result { - return sendCallNotificationIfNeededResult() + override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result = simulateLongTask { + toggleReactionResult(emoji, eventOrTransactionId) } - override suspend fun setSendQueueEnabled(enabled: Boolean) = setSendQueueEnabledLambda(enabled) - - override suspend fun saveComposerDraft(composerDraft: ComposerDraft) = saveComposerDraftLambda(composerDraft) - - override suspend fun loadComposerDraft() = loadComposerDraftLambda() - - override suspend fun clearComposerDraft() = clearComposerDraftLambda() - - override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result { - return getWidgetDriverResult(widgetSettings) + override suspend fun forwardEvent(eventId: EventId, roomIds: List): Result = simulateLongTask { + forwardEventResult(eventId, roomIds) } - override suspend fun ignoreDeviceTrustAndResend(devices: Map>, sendHandle: SendHandle): Result = simulateLongTask { - return ignoreDeviceTrustAndResendResult(devices, sendHandle) + override suspend fun cancelSend(transactionId: TransactionId): Result = simulateLongTask { + cancelSendResult(transactionId) } - override suspend fun withdrawVerificationAndResend(userIds: List, sendHandle: SendHandle): Result = simulateLongTask { - return withdrawVerificationAndResendResult(userIds, sendHandle) + override suspend fun inviteUserById(id: UserId): Result = simulateLongTask { + inviteUserResult(id) + } + + override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result = simulateLongTask { + simulateSendMediaProgress(null) + updateAvatarResult(mimeType, data) + } + + override suspend fun removeAvatar(): Result = simulateLongTask { + removeAvatarResult() + } + + override suspend fun updateRoomNotificationSettings(): Result = simulateLongTask { + val notificationSettings = roomNotificationSettingsService.getRoomNotificationSettings(roomId, info().isEncrypted.orFalse(), isOneToOne).getOrThrow() + (roomNotificationSettingsStateFlow as MutableStateFlow).value = RoomNotificationSettingsState.Ready(notificationSettings) + return Result.success(Unit) } override suspend fun updateCanonicalAlias(canonicalAlias: RoomAlias?, alternativeAliases: List): Result = simulateLongTask { @@ -602,10 +339,6 @@ class FakeMatrixRoom( updateRoomHistoryVisibilityResult(historyVisibility) } - override suspend fun getRoomVisibility(): Result = simulateLongTask { - roomVisibilityResult() - } - override suspend fun publishRoomAliasInRoomDirectory(roomAlias: RoomAlias): Result = simulateLongTask { publishRoomAliasInRoomDirectoryResult(roomAlias) } @@ -614,30 +347,90 @@ class FakeMatrixRoom( removeRoomAliasFromRoomDirectoryResult(roomAlias) } + override suspend fun enableEncryption(): Result = simulateLongTask { + enableEncryptionResult().onSuccess { + baseRoom.givenRoomInfo(info().copy(isEncrypted = true)) + emitSyncUpdate() + } + } + override suspend fun updateJoinRule(joinRule: JoinRule): Result = simulateLongTask { updateJoinRuleResult(joinRule) } - override suspend fun getUpdatedIsEncrypted(): Result = simulateLongTask { - Result.success(info().isEncrypted.orFalse()) + override suspend fun updateUsersRoles(changes: List): Result = simulateLongTask { + updateUserRoleResult(changes) } - fun givenRoomMembersState(state: MatrixRoomMembersState) { - membersStateFlow.value = state + override suspend fun updatePowerLevels(roomPowerLevels: RoomPowerLevels): Result = simulateLongTask { + updatePowerLevelsResult(roomPowerLevels) } - override suspend fun clearEventCacheStorage(): Result { - return Result.success(Unit) + override suspend fun resetPowerLevels(): Result = simulateLongTask { + resetPowerLevelsResult() + } + + override suspend fun setName(name: String): Result = simulateLongTask { + setNameResult(name) + } + + override suspend fun setTopic(topic: String): Result = simulateLongTask { + setTopicResult(topic) + } + + override suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result = simulateLongTask { + reportContentResult(eventId, reason, blockUserId) + } + + override suspend fun kickUser(userId: UserId, reason: String?): Result = simulateLongTask { + kickUserResult(userId, reason) + } + + override suspend fun banUser(userId: UserId, reason: String?): Result = simulateLongTask { + banUserResult(userId, reason) + } + + override suspend fun unbanUser(userId: UserId, reason: String?): Result = simulateLongTask { + unBanUserResult(userId, reason) + } + + override suspend fun generateWidgetWebViewUrl( + widgetSettings: MatrixWidgetSettings, + clientId: String, + languageTag: String?, + theme: String? + ): Result = simulateLongTask { + generateWidgetWebViewUrlResult(widgetSettings, clientId, languageTag, theme) + } + + override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result { + return getWidgetDriverResult(widgetSettings) + } + + override suspend fun sendCallNotificationIfNeeded(): Result = simulateLongTask { + sendCallNotificationIfNeededResult() + } + + override suspend fun setSendQueueEnabled(enabled: Boolean) = simulateLongTask { + setSendQueueEnabledResult(enabled) + } + + override suspend fun ignoreDeviceTrustAndResend(devices: Map>, sendHandle: SendHandle): Result = simulateLongTask { + ignoreDeviceTrustAndResendResult(devices, sendHandle) + } + + override suspend fun withdrawVerificationAndResend(userIds: List, sendHandle: SendHandle): Result = simulateLongTask { + withdrawVerificationAndResendResult(userIds, sendHandle) + } + + private suspend fun simulateSendMediaProgress(progressCallback: ProgressCallback?) { + progressCallbackValues.forEach { (current, total) -> + progressCallback?.onProgress(current, total) + delay(1) + } + } + + fun emitSyncUpdate() { + (syncUpdateFlow as MutableStateFlow).value = syncUpdateFlow.value + 1 } } - -fun defaultRoomPowerLevels() = MatrixRoomPowerLevels( - ban = 50, - invite = 0, - kick = 50, - sendEvents = 0, - redactEvents = 50, - roomName = 100, - roomAvatar = 100, - roomTopic = 100 -) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeRoomPreview.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeNotJoinedRoom.kt similarity index 54% rename from libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeRoomPreview.kt rename to libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeNotJoinedRoom.kt index 80908c5228..7691aa58c6 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeRoomPreview.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeNotJoinedRoom.kt @@ -8,30 +8,19 @@ package io.element.android.libraries.matrix.test.room import androidx.compose.runtime.Immutable -import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.NotJoinedRoom import io.element.android.libraries.matrix.api.room.RoomMembershipDetails -import io.element.android.libraries.matrix.api.room.RoomPreview import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo -import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.simulateLongTask @Immutable -class FakeRoomPreview( - override val sessionId: SessionId = A_SESSION_ID, - override val info: RoomPreviewInfo = aRoomPreviewInfo(), - private val declineInviteResult: () -> Result = { lambdaError() }, - private val forgetRoomResult: () -> Result = { lambdaError() }, +class FakeNotJoinedRoom( + override val localRoom: BaseRoom? = null, + override val previewInfo: RoomPreviewInfo = aRoomPreviewInfo(), private val roomMembershipDetails: () -> Result = { lambdaError() }, -) : RoomPreview { - override suspend fun leave(): Result = simulateLongTask { - declineInviteResult() - } - - override suspend fun forget(): Result = simulateLongTask { - forgetRoomResult() - } - +) : NotJoinedRoom { override suspend fun membershipDetails(): Result = simulateLongTask { roomMembershipDetails() } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt index cc56c2d32f..130d00ab24 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt @@ -12,7 +12,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.CurrentUserMembership -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility @@ -61,7 +61,7 @@ fun aRoomInfo( numUnreadNotifications: Long = 0, numUnreadMentions: Long = 0, historyVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Joined, -) = MatrixRoomInfo( +) = RoomInfo( id = id, name = name, rawName = rawName, diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomPreviewInfoFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomPreviewInfoFixture.kt index ab52880ef7..74a58354a5 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomPreviewInfoFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomPreviewInfoFixture.kt @@ -9,7 +9,6 @@ package io.element.android.libraries.matrix.test.room import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.RoomMembershipDetails import io.element.android.libraries.matrix.api.room.RoomType @@ -19,20 +18,15 @@ import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_ROOM_TOPIC -import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.tests.testutils.lambda.lambdaError fun aRoomPreview( - sessionId: SessionId = A_SESSION_ID, + localRoom: FakeBaseRoom? = null, info: RoomPreviewInfo = aRoomPreviewInfo(), - declineInviteResult: () -> Result = { lambdaError() }, - forgetRoomResult: () -> Result = { lambdaError() }, roomMembershipDetails: () -> Result = { lambdaError() }, -) = FakeRoomPreview( - sessionId = sessionId, - info = info, - declineInviteResult = declineInviteResult, - forgetRoomResult = forgetRoomResult, +) = FakeNotJoinedRoom( + localRoom = localRoom, + previewInfo = info, roomMembershipDetails = roomMembershipDetails, ) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index ac561c57d2..26e0e3afaf 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -12,7 +12,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.CurrentUserMembership -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility @@ -33,7 +33,7 @@ import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toPersistentList fun aRoomSummary( - info: MatrixRoomInfo = aRoomInfo(), + info: RoomInfo = aRoomInfo(), lastMessage: RoomMessage? = aRoomMessage(), ) = RoomSummary( info = info, @@ -76,7 +76,7 @@ fun aRoomSummary( historyVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Joined, lastMessage: RoomMessage? = aRoomMessage(), ) = RoomSummary( - info = MatrixRoomInfo( + info = RoomInfo( id = roomId, name = name, rawName = rawName, diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/LiveTimelineProvider.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/LiveTimelineProvider.kt index 327cec3b08..1723b56490 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/LiveTimelineProvider.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/timeline/LiveTimelineProvider.kt @@ -7,14 +7,14 @@ package io.element.android.libraries.matrix.test.timeline -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.TimelineProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow class LiveTimelineProvider( - private val room: MatrixRoom, + private val room: JoinedRoom, ) : TimelineProvider { override fun activeTimelineFlow(): StateFlow = MutableStateFlow(room.liveTimeline) } diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt index 413a043f79..14e64c3557 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt @@ -9,9 +9,9 @@ package io.element.android.libraries.matrix.ui.model import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize -import io.element.android.libraries.matrix.api.room.MatrixRoomInfo +import io.element.android.libraries.matrix.api.room.RoomInfo -fun MatrixRoomInfo.getAvatarData(size: AvatarSize) = AvatarData( +fun RoomInfo.getAvatarData(size: AvatarSize) = AvatarData( id = id.value, name = name, url = avatarUrl, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt index eb281f09d6..8631066482 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembers.kt @@ -14,19 +14,19 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.roomMembers @Composable -fun MatrixRoom.getRoomMemberAsState(userId: UserId): State { +fun BaseRoom.getRoomMemberAsState(userId: UserId): State { val roomMembersState by membersStateFlow.collectAsState() return getRoomMemberAsState(roomMembersState = roomMembersState, userId = userId) } @Composable -fun getRoomMemberAsState(roomMembersState: MatrixRoomMembersState, userId: UserId): State { +fun getRoomMemberAsState(roomMembersState: RoomMembersState, userId: UserId): State { val roomMembers = roomMembersState.roomMembers() return remember(roomMembers) { derivedStateOf { @@ -38,7 +38,7 @@ fun getRoomMemberAsState(roomMembersState: MatrixRoomMembersState, userId: UserI } @Composable -fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): State { +fun BaseRoom.getDirectRoomMember(roomMembersState: RoomMembersState): State { val roomMembers = roomMembersState.roomMembers() val roomInfo by roomInfoFlow.collectAsState() return remember(roomMembersState, roomInfo.isDirect) { @@ -52,6 +52,6 @@ fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): St } @Composable -fun MatrixRoom.getCurrentRoomMember(roomMembersState: MatrixRoomMembersState): State { +fun BaseRoom.getCurrentRoomMember(roomMembersState: RoomMembersState): State { return getRoomMemberAsState(roomMembersState = roomMembersState, userId = sessionId) } diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt index e820004b83..ba32d01e8a 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomState.kt @@ -12,7 +12,7 @@ import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.MessageEventType import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.isDm @@ -25,77 +25,77 @@ import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage @Composable -fun MatrixRoom.canSendMessageAsState(type: MessageEventType, updateKey: Long): State { +fun BaseRoom.canSendMessageAsState(type: MessageEventType, updateKey: Long): State { return produceState(initialValue = true, key1 = updateKey) { value = canSendMessage(type).getOrElse { true } } } @Composable -fun MatrixRoom.canInviteAsState(updateKey: Long): State { +fun BaseRoom.canInviteAsState(updateKey: Long): State { return produceState(initialValue = false, key1 = updateKey) { value = canInvite().getOrElse { false } } } @Composable -fun MatrixRoom.canRedactOwnAsState(updateKey: Long): State { +fun BaseRoom.canRedactOwnAsState(updateKey: Long): State { return produceState(initialValue = false, key1 = updateKey) { value = canRedactOwn().getOrElse { false } } } @Composable -fun MatrixRoom.canRedactOtherAsState(updateKey: Long): State { +fun BaseRoom.canRedactOtherAsState(updateKey: Long): State { return produceState(initialValue = false, key1 = updateKey) { value = canRedactOther().getOrElse { false } } } @Composable -fun MatrixRoom.canCall(updateKey: Long): State { +fun BaseRoom.canCall(updateKey: Long): State { return produceState(initialValue = false, key1 = updateKey) { value = canUserJoinCall(sessionId).getOrElse { false } } } @Composable -fun MatrixRoom.canPinUnpin(updateKey: Long): State { +fun BaseRoom.canPinUnpin(updateKey: Long): State { return produceState(initialValue = false, key1 = updateKey) { value = canUserPinUnpin(sessionId).getOrElse { false } } } @Composable -fun MatrixRoom.isDmAsState(): State { +fun BaseRoom.isDmAsState(): State { return produceState(initialValue = false) { roomInfoFlow.collect { value = it.isDm } } } @Composable -fun MatrixRoom.canKickAsState(updateKey: Long): State { +fun BaseRoom.canKickAsState(updateKey: Long): State { return produceState(initialValue = false, key1 = updateKey) { value = canKick().getOrElse { false } } } @Composable -fun MatrixRoom.canBanAsState(updateKey: Long): State { +fun BaseRoom.canBanAsState(updateKey: Long): State { return produceState(initialValue = false, key1 = updateKey) { value = canBan().getOrElse { false } } } @Composable -fun MatrixRoom.canHandleKnockRequestsAsState(updateKey: Long): State { +fun BaseRoom.canHandleKnockRequestsAsState(updateKey: Long): State { return produceState(initialValue = false, key1 = updateKey) { value = canHandleKnockRequests().getOrElse { false } } } @Composable -fun MatrixRoom.userPowerLevelAsState(updateKey: Long): State { +fun BaseRoom.userPowerLevelAsState(updateKey: Long): State { return produceState(initialValue = 0, key1 = updateKey) { value = userRole(sessionId) .getOrDefault(RoomMember.Role.USER) @@ -104,26 +104,26 @@ fun MatrixRoom.userPowerLevelAsState(updateKey: Long): State { } @Composable -fun MatrixRoom.isOwnUserAdmin(): Boolean { +fun BaseRoom.isOwnUserAdmin(): Boolean { val roomInfo by roomInfoFlow.collectAsState() val powerLevel = roomInfo.userPowerLevels[sessionId] ?: 0L return RoomMember.Role.forPowerLevel(powerLevel) == RoomMember.Role.ADMIN } @Composable -fun MatrixRoom.rawName(): String? { +fun BaseRoom.rawName(): String? { val roomInfo by roomInfoFlow.collectAsState() return roomInfo.rawName } @Composable -fun MatrixRoom.topic(): String? { +fun BaseRoom.topic(): String? { val roomInfo by roomInfoFlow.collectAsState() return roomInfo.topic } @Composable -fun MatrixRoom.avatarUrl(): String? { +fun BaseRoom.avatarUrl(): String? { val roomInfo by roomInfoFlow.collectAsState() return roomInfo.avatarUrl } diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/ObserveRoomMemberIdentityStateChange.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/ObserveRoomMemberIdentityStateChange.kt index 7610b55b20..303fae4d48 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/ObserveRoomMemberIdentityStateChange.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/room/ObserveRoomMemberIdentityStateChange.kt @@ -12,7 +12,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.encryption.identity.IdentityState -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.ui.model.getAvatarData @@ -29,7 +29,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @OptIn(ExperimentalCoroutinesApi::class) -fun MatrixRoom.roomMemberIdentityStateChange(): Flow> { +fun JoinedRoom.roomMemberIdentityStateChange(): Flow> { return roomInfoFlow .filter { // Room cannot become unencrypted, so we can just apply a filter here. @@ -52,7 +52,7 @@ fun MatrixRoom.roomMemberIdentityStateChange(): Flow>.observeRoomMemberIdentityStateChange(room: MatrixRoom) { +fun ProduceStateScope>.observeRoomMemberIdentityStateChange(room: JoinedRoom) { room.roomMemberIdentityStateChange() .onEach { roomMemberIdentityStateChanges -> value = roomMemberIdentityStateChanges.toPersistentList() diff --git a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembersTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/RoomMembersTest.kt similarity index 75% rename from libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembersTest.kt rename to libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/RoomMembersTest.kt index c54795486f..87deb9c323 100644 --- a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/MatrixRoomMembersTest.kt +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/RoomMembersTest.kt @@ -11,26 +11,26 @@ import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID_3 -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomMember import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.test.runTest import org.junit.Test -class MatrixRoomMembersTest { +class RoomMembersTest { private val roomMember1 = aRoomMember(A_USER_ID) private val roomMember2 = aRoomMember(A_USER_ID_2) private val roomMember3 = aRoomMember(A_USER_ID_3) @Test fun `getDirectRoomMember emits other member for encrypted DM with 2 joined members`() = runTest { - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeBaseRoom( sessionId = A_USER_ID, initialRoomInfo = aRoomInfo( isDirect = true, @@ -38,8 +38,8 @@ class MatrixRoomMembersTest { ) ) moleculeFlow(RecompositionMode.Immediate) { - matrixRoom.getDirectRoomMember( - MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2)) + joinedRoom.getDirectRoomMember( + RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2)) ) }.test { assertThat(awaitItem().value).isEqualTo(roomMember2) @@ -48,13 +48,13 @@ class MatrixRoomMembersTest { @Test fun `getDirectRoomMember emit null if the room is not a dm`() = runTest { - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeBaseRoom( sessionId = A_USER_ID, initialRoomInfo = aRoomInfo(isDirect = false) ) moleculeFlow(RecompositionMode.Immediate) { - matrixRoom.getDirectRoomMember( - MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2)) + joinedRoom.getDirectRoomMember( + RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2)) ) }.test { assertThat(awaitItem().value).isNull() @@ -63,7 +63,7 @@ class MatrixRoomMembersTest { @Test fun `getDirectRoomMember emits other member even if the room is not encrypted`() = runTest { - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeBaseRoom( sessionId = A_USER_ID, initialRoomInfo = aRoomInfo( isDirect = true, @@ -71,8 +71,8 @@ class MatrixRoomMembersTest { ) ) moleculeFlow(RecompositionMode.Immediate) { - matrixRoom.getDirectRoomMember( - MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2)) + joinedRoom.getDirectRoomMember( + RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2)) ) }.test { assertThat(awaitItem().value).isEqualTo(roomMember2) @@ -81,13 +81,13 @@ class MatrixRoomMembersTest { @Test fun `getDirectRoomMember emit null if the room has only 1 member`() = runTest { - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeBaseRoom( sessionId = A_USER_ID, initialRoomInfo = aRoomInfo(isDirect = true) ) moleculeFlow(RecompositionMode.Immediate) { - matrixRoom.getDirectRoomMember( - MatrixRoomMembersState.Ready(persistentListOf(roomMember1)) + joinedRoom.getDirectRoomMember( + RoomMembersState.Ready(persistentListOf(roomMember1)) ) }.test { assertThat(awaitItem().value).isNull() @@ -96,14 +96,14 @@ class MatrixRoomMembersTest { @Test fun `getDirectRoomMember emit null if the room has only 3 members`() = runTest { - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeBaseRoom( sessionId = A_USER_ID, ).apply { givenRoomInfo(aRoomInfo(isDirect = true)) } moleculeFlow(RecompositionMode.Immediate) { - matrixRoom.getDirectRoomMember( - MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2, roomMember3)) + joinedRoom.getDirectRoomMember( + RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2, roomMember3)) ) }.test { assertThat(awaitItem().value).isNull() @@ -112,13 +112,13 @@ class MatrixRoomMembersTest { @Test fun `getDirectRoomMember emit null if the other member is not active`() = runTest { - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeBaseRoom( sessionId = A_USER_ID, initialRoomInfo = aRoomInfo(isDirect = true), ) moleculeFlow(RecompositionMode.Immediate) { - matrixRoom.getDirectRoomMember( - MatrixRoomMembersState.Ready( + joinedRoom.getDirectRoomMember( + RoomMembersState.Ready( persistentListOf( roomMember1, roomMember2.copy(membership = RoomMembershipState.BAN), @@ -132,7 +132,7 @@ class MatrixRoomMembersTest { @Test fun `getDirectRoomMember emit the other member if there are 2 active members`() = runTest { - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeBaseRoom( sessionId = A_USER_ID, initialRoomInfo = aRoomInfo( isDirect = true, @@ -140,8 +140,8 @@ class MatrixRoomMembersTest { ) ) moleculeFlow(RecompositionMode.Immediate) { - matrixRoom.getDirectRoomMember( - MatrixRoomMembersState.Ready( + joinedRoom.getDirectRoomMember( + RoomMembersState.Ready( persistentListOf( roomMember1, roomMember2, @@ -156,10 +156,10 @@ class MatrixRoomMembersTest { @Test fun `getCurrentRoomMember returns the current user`() = runTest { - val matrixRoom = FakeMatrixRoom(sessionId = A_USER_ID) + val joinedRoom = FakeBaseRoom(sessionId = A_USER_ID) moleculeFlow(RecompositionMode.Immediate) { - matrixRoom.getCurrentRoomMember( - MatrixRoomMembersState.Ready( + joinedRoom.getCurrentRoomMember( + RoomMembersState.Ready( persistentListOf( roomMember1, roomMember2, @@ -174,10 +174,10 @@ class MatrixRoomMembersTest { @Test fun `getCurrentRoomMember returns null if the member is not found`() = runTest { - val matrixRoom = FakeMatrixRoom(sessionId = A_USER_ID) + val joinedRoom = FakeBaseRoom(sessionId = A_USER_ID) moleculeFlow(RecompositionMode.Immediate) { - matrixRoom.getCurrentRoomMember( - MatrixRoomMembersState.Ready( + joinedRoom.getCurrentRoomMember( + RoomMembersState.Ready( persistentListOf( roomMember2, roomMember3, diff --git a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt index b68f077df9..b9508bcfe7 100644 --- a/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt +++ b/libraries/mediaupload/api/src/main/kotlin/io/element/android/libraries/mediaupload/api/MediaSender.kt @@ -11,7 +11,7 @@ import android.net.Uri import io.element.android.libraries.core.extensions.flatMapCatching import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.media.MediaUploadHandler -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.message.ReplyParameters import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import kotlinx.coroutines.CancellationException @@ -22,7 +22,7 @@ import javax.inject.Inject class MediaSender @Inject constructor( private val preProcessor: MediaPreProcessor, - private val room: MatrixRoom, + private val room: JoinedRoom, private val sessionPreferencesStore: SessionPreferencesStore, ) { private val ongoingUploadJobs = ConcurrentHashMap() @@ -130,7 +130,7 @@ class MediaSender @Inject constructor( ongoingUploadJobs.remove(Job) } - private suspend fun MatrixRoom.sendMedia( + private suspend fun JoinedRoom.sendMedia( uploadInfo: MediaUploadInfo, progressCallback: ProgressCallback?, caption: String?, diff --git a/libraries/mediaupload/api/src/test/kotlin/io/element/android/libraries/mediaupload/api/MediaSenderTest.kt b/libraries/mediaupload/api/src/test/kotlin/io/element/android/libraries/mediaupload/api/MediaSenderTest.kt index bd5795af51..80530c69ab 100644 --- a/libraries/mediaupload/api/src/test/kotlin/io/element/android/libraries/mediaupload/api/MediaSenderTest.kt +++ b/libraries/mediaupload/api/src/test/kotlin/io/element/android/libraries/mediaupload/api/MediaSenderTest.kt @@ -13,10 +13,10 @@ import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.matrix.api.media.ImageInfo -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.message.ReplyParameters import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore @@ -45,12 +45,12 @@ class MediaSenderTest { } @Test - fun `given an attachment when sending it the MatrixRoom will call sendMedia`() = runTest { + fun `given an attachment when sending it the Room will call sendMedia`() = runTest { val sendImageResult = lambdaRecorder { _: File, _: File?, _: ImageInfo, _: String?, _: String?, _: ProgressCallback?, _: ReplyParameters? -> Result.success(FakeMediaUploadHandler()) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendImageResult = sendImageResult ) val sender = createMediaSender(room = room) @@ -78,7 +78,7 @@ class MediaSenderTest { lambdaRecorder { _: File, _: File?, _: ImageInfo, _: String?, _: String?, _: ProgressCallback?, _: ReplyParameters? -> Result.failure(Exception()) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendImageResult = sendImageResult ) val sender = createMediaSender(room = room) @@ -96,7 +96,7 @@ class MediaSenderTest { lambdaRecorder> { _, _, _, _, _, _ -> Result.success(FakeMediaUploadHandler()) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( sendFileResult = sendFileResult ) val sender = createMediaSender(room = room) @@ -123,7 +123,7 @@ class MediaSenderTest { private fun createMediaSender( preProcessor: MediaPreProcessor = FakeMediaPreProcessor(), - room: MatrixRoom = FakeMatrixRoom(), + room: JoinedRoom = FakeJoinedRoom(), sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(), ) = MediaSender( preProcessor = preProcessor, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedTimelineMediaGalleryDataSourceFactory.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedTimelineMediaGalleryDataSourceFactory.kt index f776b35016..bdbffbfd1a 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedTimelineMediaGalleryDataSourceFactory.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedTimelineMediaGalleryDataSourceFactory.kt @@ -10,7 +10,7 @@ package io.element.android.libraries.mediaviewer.impl.datasource import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.mediaviewer.impl.model.MediaItem import javax.inject.Inject @@ -24,7 +24,7 @@ interface FocusedTimelineMediaGalleryDataSourceFactory { @ContributesBinding(RoomScope::class) class DefaultFocusedTimelineMediaGalleryDataSourceFactory @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, private val timelineMediaItemsFactory: TimelineMediaItemsFactory, private val mediaItemsPostProcessor: MediaItemsPostProcessor, ) : FocusedTimelineMediaGalleryDataSourceFactory { diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaGalleryDataSource.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaGalleryDataSource.kt index 1dc81a11e3..a7ee01aa57 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaGalleryDataSource.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaGalleryDataSource.kt @@ -12,7 +12,7 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SingleIn import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems @@ -40,7 +40,7 @@ interface MediaGalleryDataSource { @SingleIn(RoomScope::class) @ContributesBinding(RoomScope::class) class TimelineMediaGalleryDataSource @Inject constructor( - private val room: MatrixRoom, + private val room: BaseRoom, private val mediaTimeline: MediaTimeline, private val timelineMediaItemsFactory: TimelineMediaItemsFactory, private val mediaItemsPostProcessor: MediaItemsPostProcessor, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt index 2d7739cc32..c014689003 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/MediaTimeline.kt @@ -13,7 +13,7 @@ import io.element.android.libraries.di.SingleIn import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.room.CreateTimelineParams -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.libraries.mediaviewer.impl.model.MediaItem @@ -37,7 +37,7 @@ interface MediaTimeline { @SingleIn(RoomScope::class) @ContributesBinding(RoomScope::class) class LiveMediaTimeline @Inject constructor( - private val room: MatrixRoom, + private val room: JoinedRoom, ) : MediaTimeline { private var timeline: Timeline? = null private val mutex = Mutex() @@ -62,7 +62,7 @@ class LiveMediaTimeline @Inject constructor( * Optionally, the timeline will only contain the pinned events. */ class FocusedMediaTimeline( - private val room: MatrixRoom, + private val room: JoinedRoom, private val eventId: EventId, private val onlyPinnedEvents: Boolean, initialMediaItem: MediaItem.Event, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt index f79157e858..f4764e2d6b 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenter.kt @@ -27,7 +27,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MatrixMediaLoader -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn import io.element.android.libraries.mediaviewer.api.local.LocalMedia @@ -45,7 +45,7 @@ import kotlinx.coroutines.launch class MediaGalleryPresenter @AssistedInject constructor( @Assisted private val navigator: MediaGalleryNavigator, - private val room: MatrixRoom, + private val room: BaseRoom, private val mediaGalleryDataSource: MediaGalleryDataSource, private val localMediaFactory: LocalMediaFactory, private val mediaLoader: MatrixMediaLoader, diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt index 858e3e7916..f900510321 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenter.kt @@ -30,7 +30,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatch import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId @@ -53,7 +53,7 @@ class MediaViewerPresenter @AssistedInject constructor( @Assisted private val inputs: MediaViewerEntryPoint.Params, @Assisted private val navigator: MediaViewerNavigator, @Assisted private val dataSource: MediaViewerDataSource, - private val room: MatrixRoom, + private val room: JoinedRoom, private val localMediaActions: LocalMediaActions, ) : Presenter { @AssistedFactory diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt index 7496b01324..9edc2d0a75 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest.kt @@ -9,7 +9,7 @@ package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.AN_EVENT_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage import kotlinx.coroutines.test.runTest import org.junit.Test @@ -18,7 +18,7 @@ class DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest { @Test fun `createFor should create a TimelineMediaGalleryDataSource`() = runTest { val sut = DefaultFocusedTimelineMediaGalleryDataSourceFactory( - room = FakeMatrixRoom(), + room = FakeJoinedRoom(), timelineMediaItemsFactory = createTimelineMediaItemsFactory(), mediaItemsPostProcessor = MediaItemsPostProcessor(), ) diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt index 5c46ffd910..1f2ab92dfc 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/FocusedMediaTimelineTest.kt @@ -10,10 +10,10 @@ package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.room.CreateTimelineParams -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.test.AN_EVENT_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.libraries.mediaviewer.impl.model.MediaItem @@ -79,7 +79,7 @@ class FocusedMediaTimelineTest { val createTimelineResult = lambdaRecorder> { Result.success(FakeTimeline()) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( createTimelineResult = createTimelineResult, ) val sut = createFocusedMediaTimeline( @@ -96,7 +96,7 @@ class FocusedMediaTimelineTest { val createTimelineResult = lambdaRecorder> { Result.success(FakeTimeline()) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( createTimelineResult = createTimelineResult, ) val sut = createFocusedMediaTimeline( @@ -110,7 +110,7 @@ class FocusedMediaTimelineTest { } private fun createFocusedMediaTimeline( - room: MatrixRoom = FakeMatrixRoom(), + room: JoinedRoom = FakeJoinedRoom(), eventId: EventId = AN_EVENT_ID, initialMediaItem: MediaItem.Event = aMediaItemImage(), onlyPinnedEvent: Boolean = false, diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/LiveMediaTimelineTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/LiveMediaTimelineTest.kt index 839f8798d2..4d59b88c09 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/LiveMediaTimelineTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/LiveMediaTimelineTest.kt @@ -9,9 +9,9 @@ package io.element.android.libraries.mediaviewer.impl.datasource import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.room.CreateTimelineParams -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.Timeline -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems import io.element.android.tests.testutils.lambda.lambdaRecorder @@ -31,7 +31,7 @@ class LiveMediaTimelineTest { val createTimelineResult = lambdaRecorder> { Result.success(FakeTimeline()) } - val room = FakeMatrixRoom( + val room = FakeJoinedRoom( createTimelineResult = createTimelineResult, ) val sut = createLiveMediaTimeline( @@ -47,7 +47,7 @@ class LiveMediaTimelineTest { } private fun createLiveMediaTimeline( - room: MatrixRoom = FakeMatrixRoom(), + room: JoinedRoom = FakeJoinedRoom(), ) = LiveMediaTimeline( room = room, ) diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaGalleryDataSourceTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaGalleryDataSourceTest.kt index 8e673ce7aa..20208a55dc 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaGalleryDataSourceTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/TimelineMediaGalleryDataSourceTest.kt @@ -16,7 +16,7 @@ import io.element.android.libraries.dateformatter.test.FakeDateFormatter import io.element.android.libraries.matrix.api.media.ImageInfo import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.media.ThumbnailInfo -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId @@ -28,7 +28,7 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.A_UNIQUE_ID import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.aMessageContent import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem @@ -56,7 +56,7 @@ class TimelineMediaGalleryDataSourceTest { fun `test - not started TimelineMediaGalleryDataSource emits no events`() = runTest { val fakeTimeline = FakeTimeline() val sut = createTimelineMediaGalleryDataSource( - room = FakeMatrixRoom( + room = FakeJoinedRoom( createTimelineResult = { Result.success(fakeTimeline) }, roomCoroutineScope = backgroundScope, ) @@ -74,7 +74,7 @@ class TimelineMediaGalleryDataSourceTest { val fakeTimeline = FakeTimeline() runTest { val sut = createTimelineMediaGalleryDataSource( - room = FakeMatrixRoom( + room = FakeJoinedRoom( createTimelineResult = { Result.success(fakeTimeline) }, roomCoroutineScope = backgroundScope, ) @@ -111,7 +111,7 @@ class TimelineMediaGalleryDataSourceTest { paginateLambda = paginateLambdaRecorder } val sut = createTimelineMediaGalleryDataSource( - room = FakeMatrixRoom( + room = FakeJoinedRoom( createTimelineResult = { Result.success(fakeTimeline) }, roomCoroutineScope = backgroundScope, ) @@ -134,7 +134,7 @@ class TimelineMediaGalleryDataSourceTest { redactEventLambda = redactEventLambdaRecorder } val sut = createTimelineMediaGalleryDataSource( - room = FakeMatrixRoom( + room = FakeJoinedRoom( createTimelineResult = { Result.success(fakeTimeline) }, roomCoroutineScope = backgroundScope, ) @@ -153,7 +153,7 @@ class TimelineMediaGalleryDataSourceTest { @Test fun `test - failing to load timeline should emit an error`() = runTest { val sut = createTimelineMediaGalleryDataSource( - room = FakeMatrixRoom( + room = FakeJoinedRoom( createTimelineResult = { Result.failure(AN_EXCEPTION) }, roomCoroutineScope = backgroundScope, ) @@ -175,7 +175,7 @@ class TimelineMediaGalleryDataSourceTest { timelineItems = timelineItems, ) val sut = createTimelineMediaGalleryDataSource( - room = FakeMatrixRoom( + room = FakeJoinedRoom( createTimelineResult = { Result.success(fakeTimeline) }, roomCoroutineScope = backgroundScope, ) @@ -256,7 +256,7 @@ class TimelineMediaGalleryDataSourceTest { } private fun TestScope.createTimelineMediaGalleryDataSource( - room: MatrixRoom = FakeMatrixRoom( + room: JoinedRoom = FakeJoinedRoom( liveTimeline = FakeTimeline(), ), ): TimelineMediaGalleryDataSource { diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt index 56396ca2a6..80005facd4 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/MediaGalleryPresenterTest.kt @@ -12,14 +12,15 @@ import app.cash.turbine.ReceiveTurbine import com.google.common.truth.Truth.assertThat import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource @@ -51,8 +52,8 @@ class MediaGalleryPresenterTest { mediaGalleryDataSource = FakeMediaGalleryDataSource( startLambda = startLambda, ), - room = FakeMatrixRoom( - initialRoomInfo = aRoomInfo(name = A_ROOM_NAME), + room = FakeJoinedRoom( + baseRoom = FakeBaseRoom(initialRoomInfo = aRoomInfo(name = A_ROOM_NAME)), createTimelineResult = { Result.success(FakeTimeline()) }, ) ) @@ -70,8 +71,8 @@ class MediaGalleryPresenterTest { @Test fun `present - change mode`() = runTest { val presenter = createMediaGalleryPresenter( - room = FakeMatrixRoom( - initialRoomInfo = aRoomInfo(name = A_ROOM_NAME), + room = FakeJoinedRoom( + baseRoom = FakeBaseRoom(initialRoomInfo = aRoomInfo(name = A_ROOM_NAME)), createTimelineResult = { Result.success(FakeTimeline()) }, ) ) @@ -99,11 +100,13 @@ class MediaGalleryPresenterTest { private suspend fun `present - bottom sheet state - own message`(canDeleteOwn: Boolean) { val presenter = createMediaGalleryPresenter( - room = FakeMatrixRoom( - sessionId = A_USER_ID, - initialRoomInfo = aRoomInfo(name = A_ROOM_NAME), + room = FakeJoinedRoom( createTimelineResult = { Result.success(FakeTimeline()) }, - canRedactOwnResult = { Result.success(canDeleteOwn) } + baseRoom = FakeBaseRoom( + sessionId = A_USER_ID, + initialRoomInfo = aRoomInfo(name = A_ROOM_NAME), + canRedactOwnResult = { Result.success(canDeleteOwn) } + ), ) ) presenter.test { @@ -142,11 +145,13 @@ class MediaGalleryPresenterTest { private suspend fun `present - bottom sheet state - other message`(canDeleteOther: Boolean) { val presenter = createMediaGalleryPresenter( - room = FakeMatrixRoom( + room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( sessionId = A_USER_ID, initialRoomInfo = aRoomInfo(name = A_ROOM_NAME), - createTimelineResult = { Result.success(FakeTimeline()) }, - canRedactOtherResult = { Result.success(canDeleteOther) } + canRedactOtherResult = { Result.success(canDeleteOther) }, + ), + createTimelineResult = { Result.success(FakeTimeline()) } ) ) presenter.test { @@ -176,8 +181,8 @@ class MediaGalleryPresenterTest { @Test fun `present - delete bottom sheet`() = runTest { val presenter = createMediaGalleryPresenter( - room = FakeMatrixRoom( - initialRoomInfo = aRoomInfo(name = A_ROOM_NAME), + room = FakeJoinedRoom( + baseRoom = FakeBaseRoom(initialRoomInfo = aRoomInfo(name = A_ROOM_NAME)), createTimelineResult = { Result.success(FakeTimeline()) }, ) ) @@ -244,7 +249,7 @@ class MediaGalleryPresenterTest { onViewInTimelineClickLambda = onViewInTimelineClickLambda, ) val presenter = createMediaGalleryPresenter( - room = FakeMatrixRoom( + room = FakeJoinedRoom( createTimelineResult = { Result.success(FakeTimeline()) }, ), navigator = navigator, @@ -284,7 +289,7 @@ class MediaGalleryPresenterTest { localMediaActions: FakeLocalMediaActions = FakeLocalMediaActions(), snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(), navigator: MediaGalleryNavigator = FakeMediaGalleryNavigator(), - room: MatrixRoom = FakeMatrixRoom( + room: JoinedRoom = FakeJoinedRoom( liveTimeline = FakeTimeline(), ), ): MediaGalleryPresenter { diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt index 06418da15e..a4f72aa474 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt @@ -15,7 +15,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MediaSource -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId @@ -24,7 +24,8 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader import io.element.android.libraries.matrix.test.media.aMediaSource -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.api.anApkMediaInfo @@ -77,10 +78,12 @@ class MediaViewerPresenterTest { @Test fun `present - initial state null Event`() = runTest { val presenter = createMediaViewerPresenter( - room = FakeMatrixRoom( + room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, ) ) + ) presenter.test { val initialState = awaitFirstItem() assertThat(initialState.listData).isEmpty() @@ -95,10 +98,12 @@ class MediaViewerPresenterTest { fun `present - initial state cannot show info`() = runTest { val presenter = createMediaViewerPresenter( canShowInfo = false, - room = FakeMatrixRoom( + room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, ) ) + ) presenter.test { val initialState = awaitFirstItem() assertThat(initialState.listData).isEmpty() @@ -113,10 +118,12 @@ class MediaViewerPresenterTest { fun `present - initial state Event`() = runTest { val presenter = createMediaViewerPresenter( eventId = AN_EVENT_ID, - room = FakeMatrixRoom( + room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, ) ) + ) presenter.test { val initialState = awaitFirstItem() assertThat(initialState.listData).isEmpty() @@ -131,11 +138,13 @@ class MediaViewerPresenterTest { fun `present - initial state Event from other`() = runTest { val presenter = createMediaViewerPresenter( eventId = AN_EVENT_ID, - room = FakeMatrixRoom( + room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( sessionId = A_SESSION_ID_2, canRedactOtherResult = { Result.success(false) }, ) ) + ) presenter.test { val initialState = awaitFirstItem() assertThat(initialState.listData).isEmpty() @@ -216,9 +225,9 @@ class MediaViewerPresenterTest { ) val presenter = createMediaViewerPresenter( mediaGalleryDataSource = mediaGalleryDataSource, - room = FakeMatrixRoom( + room = FakeJoinedRoom(baseRoom = FakeBaseRoom( canRedactOwnResult = { Result.success(true) }, - ) + )) ) val anImage = aMediaItemImage( mediaSourceUrl = aUrl, @@ -432,9 +441,9 @@ class MediaViewerPresenterTest { startLambda = { }, ) val presenter = createMediaViewerPresenter( - room = FakeMatrixRoom( + room = FakeJoinedRoom( liveTimeline = timeline, - canRedactOwnResult = { Result.success(true) }, + baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }), ), mediaGalleryDataSource = mediaGalleryDataSource, mediaViewerNavigator = FakeMediaViewerNavigator( @@ -736,8 +745,8 @@ class MediaViewerPresenterTest { ) val presenter = createMediaViewerPresenter( mediaViewerNavigator = navigator, - room = FakeMatrixRoom( - canRedactOwnResult = { Result.success(true) }, + room = FakeJoinedRoom( + baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }), ) ) presenter.test { @@ -766,7 +775,7 @@ class MediaViewerPresenterTest { ), canShowInfo: Boolean = true, mediaViewerNavigator: MediaViewerNavigator = FakeMediaViewerNavigator(), - room: MatrixRoom = FakeMatrixRoom( + room: JoinedRoom = FakeJoinedRoom( liveTimeline = FakeTimeline(), ), ): MediaViewerPresenter { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandler.kt index 90ed3a3d05..9c899c9dfd 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandler.kt @@ -14,7 +14,7 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.ThreadId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.isDm import io.element.android.libraries.matrix.api.room.message.replyInThread import io.element.android.libraries.matrix.api.timeline.ReceiptType @@ -117,7 +117,7 @@ class NotificationBroadcastReceiverHandler @Inject constructor( return@launch } val client = matrixClientProvider.getOrRestore(sessionId).getOrNull() ?: return@launch - client.getRoom(roomId)?.let { room -> + client.getJoinedRoom(roomId)?.let { room -> sendMatrixEvent( sessionId = sessionId, roomId = roomId, @@ -134,7 +134,7 @@ class NotificationBroadcastReceiverHandler @Inject constructor( roomId: RoomId, threadId: ThreadId?, replyToEventId: EventId?, - room: MatrixRoom, + room: JoinedRoom, message: String, ) { // Create a new event to be displayed in the notification drawer, right now diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEvent.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEvent.kt index 8d1d866edd..4c5eee260b 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEvent.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEvent.kt @@ -12,7 +12,8 @@ import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom +import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent @@ -37,7 +38,7 @@ class SyncOnNotifiableEvent @Inject constructor( } val client = matrixClientProvider.getOrRestore(notifiableEvent.sessionId).getOrNull() ?: return@withContext - client.getRoom(notifiableEvent.roomId)?.use { room -> + client.getJoinedRoom(notifiableEvent.roomId)?.use { room -> room.subscribeToSync() // If the app is in foreground, sync is already running, so we just add the subscription above. @@ -60,7 +61,7 @@ class SyncOnNotifiableEvent @Inject constructor( * User can be in the call if they answer using another session. * If the user does not join the call, the timeout will be reached. */ - private suspend fun MatrixRoom.waitsUntilUserIsInTheCall(timeout: Duration) { + private suspend fun BaseRoom.waitsUntilUserIsInTheCall(timeout: Duration) { withTimeoutOrNull(timeout) { roomInfoFlow.first { sessionId in it.activeRoomCallParticipants @@ -68,7 +69,7 @@ class SyncOnNotifiableEvent @Inject constructor( } } - private suspend fun MatrixRoom.waitsUntilEventIsKnown(eventId: EventId, timeout: Duration) { + private suspend fun JoinedRoom.waitsUntilEventIsKnown(eventId: EventId, timeout: Duration) { withTimeoutOrNull(timeout) { liveTimeline.timelineItems.first { timelineItems -> timelineItems.any { timelineItem -> diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultBaseRoomGroupMessageCreatorTest.kt similarity index 99% rename from libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt rename to libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultBaseRoomGroupMessageCreatorTest.kt index ca675c8f8b..ba4e1657a7 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultRoomGroupMessageCreatorTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultBaseRoomGroupMessageCreatorTest.kt @@ -37,7 +37,7 @@ private const val A_USER_AVATAR_1 = "mxc://userAvatar1" private const val A_USER_AVATAR_2 = "mxc://userAvatar2" @RunWith(RobolectricTestRunner::class) -class DefaultRoomGroupMessageCreatorTest { +class DefaultBaseRoomGroupMessageCreatorTest { @Test fun `test createRoomMessage with one Event`() = runTest { val sut = createRoomGroupMessageCreator() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt index 9405e19464..dfa440bcf0 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandlerTest.kt @@ -27,7 +27,8 @@ import io.element.android.libraries.matrix.test.A_THREAD_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider import io.element.android.libraries.matrix.test.core.aBuildMeta -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.timeline.FakeTimeline @@ -50,6 +51,7 @@ import io.element.android.tests.testutils.lambda.value import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test @@ -221,13 +223,13 @@ class NotificationBroadcastReceiverHandlerTest { getLambda = getLambda ) val clearMessagesForRoomLambda = lambdaRecorder { _, _ -> } - val matrixRoom = FakeMatrixRoom() + val joinedRoom = FakeJoinedRoom() val fakeNotificationCleaner = FakeNotificationCleaner( clearMessagesForRoomLambda = clearMessagesForRoomLambda, ) val sut = createNotificationBroadcastReceiverHandler( sessionPreferencesStore = sessionPreferencesStore, - matrixRoom = matrixRoom, + joinedRoom = joinedRoom, notificationCleaner = fakeNotificationCleaner ) sut.onReceive( @@ -240,7 +242,7 @@ class NotificationBroadcastReceiverHandlerTest { clearMessagesForRoomLambda.assertions() .isCalledOnce() .with(value(A_SESSION_ID), value(A_ROOM_ID)) - assertThat(matrixRoom.markAsReadCalls).isEqualTo(listOf(expectedReceiptType)) + assertThat(joinedRoom.baseRoom.markAsReadCalls).isEqualTo(listOf(expectedReceiptType)) } @Test @@ -292,15 +294,15 @@ class NotificationBroadcastReceiverHandlerTest { @Test fun `Test reject room`() = runTest { val leaveRoom = lambdaRecorder> { Result.success(Unit) } - val matrixRoom = FakeMatrixRoom( - leaveRoomLambda = leaveRoom + val joinedRoom = FakeJoinedRoom( + baseRoom = FakeBaseRoom(leaveRoomLambda = leaveRoom), ) val clearMembershipNotificationForRoomLambda = lambdaRecorder { _, _ -> } val fakeNotificationCleaner = FakeNotificationCleaner( clearMembershipNotificationForRoomLambda = clearMembershipNotificationForRoomLambda, ) val sut = createNotificationBroadcastReceiverHandler( - matrixRoom = matrixRoom, + joinedRoom = joinedRoom, notificationCleaner = fakeNotificationCleaner ) sut.onReceive( @@ -313,6 +315,9 @@ class NotificationBroadcastReceiverHandlerTest { clearMembershipNotificationForRoomLambda.assertions() .isCalledOnce() .with(value(A_SESSION_ID), value(A_ROOM_ID)) + + advanceUntilIdle() + leaveRoom.assertions() .isCalledOnce() .with() @@ -337,9 +342,9 @@ class NotificationBroadcastReceiverHandlerTest { sendMessageLambda = sendMessage replyMessageLambda = replyMessage } - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline, - getUpdatedMemberResult = { Result.success(aRoomMember()) }, + baseRoom = FakeBaseRoom(getUpdatedMemberResult = { Result.success(aRoomMember()) }), ).apply { givenRoomInfo( aRoomInfo( @@ -351,7 +356,7 @@ class NotificationBroadcastReceiverHandlerTest { val onNotifiableEventReceivedResult = lambdaRecorder { _ -> } val onNotifiableEventReceived = FakeOnNotifiableEventReceived(onNotifiableEventReceivedResult = onNotifiableEventReceivedResult) val sut = createNotificationBroadcastReceiverHandler( - matrixRoom = matrixRoom, + joinedRoom = joinedRoom, onNotifiableEventReceived = onNotifiableEventReceived, replyMessageExtractor = FakeReplyMessageExtractor(A_MESSAGE) ) @@ -377,11 +382,11 @@ class NotificationBroadcastReceiverHandlerTest { val liveTimeline = FakeTimeline().apply { sendMessageLambda = sendMessage } - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline ) val sut = createNotificationBroadcastReceiverHandler( - matrixRoom = matrixRoom, + joinedRoom = joinedRoom, replyMessageExtractor = FakeReplyMessageExtractor(" "), ) sut.onReceive( @@ -404,9 +409,9 @@ class NotificationBroadcastReceiverHandlerTest { sendMessageLambda = sendMessage replyMessageLambda = replyMessage } - val matrixRoom = FakeMatrixRoom( + val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline, - getUpdatedMemberResult = { Result.success(aRoomMember()) }, + baseRoom = FakeBaseRoom(getUpdatedMemberResult = { Result.success(aRoomMember()) }), ).apply { givenRoomInfo( aRoomInfo( @@ -418,7 +423,7 @@ class NotificationBroadcastReceiverHandlerTest { val onNotifiableEventReceivedResult = lambdaRecorder { _ -> } val onNotifiableEventReceived = FakeOnNotifiableEventReceived(onNotifiableEventReceivedResult = onNotifiableEventReceivedResult) val sut = createNotificationBroadcastReceiverHandler( - matrixRoom = matrixRoom, + joinedRoom = joinedRoom, onNotifiableEventReceived = onNotifiableEventReceived, replyMessageExtractor = FakeReplyMessageExtractor(A_MESSAGE) ) @@ -460,10 +465,10 @@ class NotificationBroadcastReceiverHandlerTest { } private fun TestScope.createNotificationBroadcastReceiverHandler( - matrixRoom: FakeMatrixRoom? = FakeMatrixRoom(), + joinedRoom: FakeJoinedRoom? = FakeJoinedRoom(), joinRoom: (RoomId) -> Result = { lambdaError() }, matrixClient: MatrixClient? = FakeMatrixClient().apply { - givenGetRoomResult(A_ROOM_ID, matrixRoom) + givenGetRoomResult(A_ROOM_ID, joinedRoom) joinRoomLambda = joinRoom }, sessionPreferencesStore: SessionPreferencesStoreFactory = FakeSessionPreferencesStoreFactory(), diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEventTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEventTest.kt index 35dddbce6f..8b3907be0b 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEventTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/SyncOnNotifiableEventTest.kt @@ -18,7 +18,8 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_UNIQUE_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClientProvider -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import io.element.android.libraries.matrix.test.room.FakeBaseRoom +import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.timeline.FakeTimeline @@ -49,10 +50,12 @@ class SyncOnNotifiableEventTest { private val liveTimeline = FakeTimeline( timelineItems = timelineItems, ) - private val room = FakeMatrixRoom( - roomId = A_ROOM_ID, + private val room = FakeJoinedRoom( liveTimeline = liveTimeline, - subscribeToSyncLambda = subscribeToSyncLambda + baseRoom = FakeBaseRoom( + roomId = A_ROOM_ID, + subscribeToSyncLambda = subscribeToSyncLambda, + ), ) private val syncService = FakeSyncService(SyncState.Idle).also { it.startSyncLambda = startSyncLambda diff --git a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/file/DefaultVoiceFileManager.kt b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/file/DefaultVoiceFileManager.kt index 12ad5f65b2..8dc6bf2dbe 100644 --- a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/file/DefaultVoiceFileManager.kt +++ b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/file/DefaultVoiceFileManager.kt @@ -12,7 +12,7 @@ import io.element.android.libraries.core.hash.md5 import io.element.android.libraries.di.CacheDirectory import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.room.MatrixRoom +import io.element.android.libraries.matrix.api.room.BaseRoom import java.io.File import java.util.UUID import javax.inject.Inject @@ -21,7 +21,7 @@ import javax.inject.Inject class DefaultVoiceFileManager @Inject constructor( @CacheDirectory private val cacheDir: File, private val config: VoiceFileConfig, - room: MatrixRoom, + room: BaseRoom, ) : VoiceFileManager { private val roomId: RoomId = room.roomId diff --git a/plugins/src/main/kotlin/extension/KoverExtension.kt b/plugins/src/main/kotlin/extension/KoverExtension.kt index fff0e3a22a..df927f48d6 100644 --- a/plugins/src/main/kotlin/extension/KoverExtension.kt +++ b/plugins/src/main/kotlin/extension/KoverExtension.kt @@ -175,7 +175,7 @@ fun Project.setupKover() { "io.element.android.libraries.maplibre.compose.SaveableCameraPositionState", "io.element.android.libraries.maplibre.compose.SymbolState", "io.element.android.libraries.matrix.api.room.RoomMembershipState", - "io.element.android.libraries.matrix.api.room.MatrixRoomMembersState", + "io.element.android.libraries.matrix.api.room.RoomMembersState", "io.element.android.libraries.matrix.api.timeline.item.event.OtherState$*", "io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState*", "io.element.android.libraries.mediaviewer.impl.local.pdf.PdfViewerState",