From 1170a4411688d3dcc21a05fdf7e8e77cc325f8b8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 11 Jul 2025 18:18:17 +0200 Subject: [PATCH 01/30] refactor (start chat) : start splitting things (create room, invite people, start chat) --- .../android/appnav/LoggedInFlowNode.kt | 19 +- .../createroom/api/CreateRoomEntryPoint.kt | 21 +- features/createroom/impl/build.gradle.kts | 2 +- .../createroom/impl/CreateRoomFlowNode.kt | 64 +--- .../impl/DefaultCreateRoomEntryPoint.kt | 23 +- .../impl/addpeople/AddPeopleNode.kt | 38 +- .../impl/configureroom/ConfigureRoomEvents.kt | 1 - .../impl/configureroom/ConfigureRoomNode.kt | 10 +- .../configureroom/ConfigureRoomPresenter.kt | 7 +- .../impl/configureroom/ConfigureRoomState.kt | 1 - .../ConfigureRoomStateProvider.kt | 1 - .../impl/configureroom/ConfigureRoomView.kt | 12 - .../{ => configureroom}/CreateRoomConfig.kt | 3 +- .../configureroom/CreateRoomConfigStore.kt | 119 ++++++ .../impl/root/CreateRoomRootEvents.kt | 15 - .../features/home/api/HomeEntryPoint.kt | 2 +- .../features/home/impl/HomeFlowNode.kt | 6 +- .../android/features/home/impl/HomeView.kt | 12 +- .../home/impl/roomlist/RoomListViewTest.kt | 2 +- features/invitepeople/api/build.gradle.kts | 18 + .../invitepeople/api/InvitePeoplePresenter.kt | 15 + .../invitepeople/api/InvitePeopleRenderer.kt | 16 + .../invitepeople/api/InvitePeopleState.kt | 10 + features/invitepeople/impl/build.gradle.kts | 64 ++++ features/roomdetails/impl/build.gradle.kts | 4 +- features/startchat/api/build.gradle.kts | 18 + .../api/ConfirmingStartDmWithMatrixUser.kt | 2 +- .../startchat/api/StartChatEntryPoint.kt | 27 ++ .../features/startchat}/api/StartDMAction.kt | 2 +- features/startchat/impl/build.gradle.kts | 64 ++++ .../features/startchat/StartChatNavigator.kt} | 10 +- .../startchat/impl/CreateRoomConfig.kt | 22 ++ .../startchat}/impl/CreateRoomDataStore.kt | 18 +- .../startchat/impl/CreateRoomFlowNode.kt} | 24 +- .../impl/DefaultStartChatEntryPoint.kt | 35 ++ .../startchat}/impl/DefaultStartDMAction.kt | 6 +- .../startchat/impl/StartChatFlowNode.kt | 90 +++++ .../startchat/impl/addpeople/AddPeopleNode.kt | 45 +++ .../impl/addpeople/AddPeoplePresenter.kt | 14 +- .../AddPeopleUserListStateProvider.kt | 12 +- .../impl/addpeople/AddPeopleView.kt | 18 +- .../SearchMultipleUsersResultItem.kt | 2 +- .../components/SearchSingleUserResultItem.kt | 2 +- .../impl/components/SearchUserBar.kt | 2 +- .../impl/components/UserListView.kt | 10 +- .../impl/configureroom/ConfigureRoomEvents.kt | 23 ++ .../impl/configureroom/ConfigureRoomNode.kt | 55 +++ .../configureroom/ConfigureRoomPresenter.kt | 209 +++++++++++ .../ConfigureRoomPresenterArgs.kt | 14 + .../impl/configureroom/ConfigureRoomState.kt | 30 ++ .../ConfigureRoomStateProvider.kt | 102 ++++++ .../impl/configureroom/ConfigureRoomView.kt | 339 ++++++++++++++++++ .../impl/configureroom/RoomAccess.kt | 22 ++ .../impl/configureroom/RoomAccessItem.kt | 25 ++ .../impl/configureroom/RoomAddress.kt | 13 + .../impl/configureroom/RoomVisibilityItem.kt | 30 ++ .../impl/configureroom/RoomVisibilityState.kt | 26 ++ .../startchat}/impl/di/CreateRoomComponent.kt | 2 +- .../startchat}/impl/di/CreateRoomScope.kt | 2 +- .../joinbyaddress/JoinRoomByAddressEvents.kt | 2 +- .../joinbyaddress/JoinRoomByAddressNode.kt | 6 +- .../JoinRoomByAddressPresenter.kt | 8 +- .../joinbyaddress/JoinRoomByAddressState.kt | 2 +- .../JoinRoomByAddressStateProvider.kt | 2 +- .../joinbyaddress/JoinRoomByAddressView.kt | 4 +- .../startchat/impl/root/StartChatEvents.kt | 15 + .../startchat/impl/root/StartChatNode.kt} | 12 +- .../impl/root/StartChatPresenter.kt} | 28 +- .../startchat/impl/root/StartChatState.kt} | 10 +- .../impl/root/StartChatStateProvider.kt} | 20 +- .../startchat/impl/root/StartChatView.kt} | 28 +- .../impl/userlist/DefaultUserListPresenter.kt | 2 +- .../impl/userlist/UserListDataStore.kt | 2 +- .../impl/userlist/UserListEvents.kt | 2 +- .../impl/userlist/UserListPresenter.kt | 2 +- .../impl/userlist/UserListPresenterArgs.kt | 2 +- .../startchat}/impl/userlist/UserListState.kt | 2 +- .../impl/userlist/UserListStateProvider.kt | 2 +- .../src/main/res/values-be/translations.xml | 19 + .../src/main/res/values-bg/translations.xml | 23 ++ .../src/main/res/values-cs/translations.xml | 30 ++ .../src/main/res/values-cy/translations.xml | 30 ++ .../src/main/res/values-da/translations.xml | 30 ++ .../src/main/res/values-de/translations.xml | 30 ++ .../src/main/res/values-el/translations.xml | 30 ++ .../src/main/res/values-es/translations.xml | 30 ++ .../src/main/res/values-et/translations.xml | 30 ++ .../src/main/res/values-eu/translations.xml | 23 ++ .../src/main/res/values-fa/translations.xml | 28 ++ .../src/main/res/values-fi/translations.xml | 30 ++ .../src/main/res/values-fr/translations.xml | 30 ++ .../src/main/res/values-hu/translations.xml | 30 ++ .../src/main/res/values-in/translations.xml | 30 ++ .../src/main/res/values-it/translations.xml | 30 ++ .../src/main/res/values-ka/translations.xml | 15 + .../src/main/res/values-lt/translations.xml | 14 + .../src/main/res/values-nb/translations.xml | 30 ++ .../src/main/res/values-nl/translations.xml | 21 ++ .../src/main/res/values-pl/translations.xml | 30 ++ .../main/res/values-pt-rBR/translations.xml | 30 ++ .../src/main/res/values-pt/translations.xml | 30 ++ .../src/main/res/values-ro/translations.xml | 22 ++ .../src/main/res/values-ru/translations.xml | 30 ++ .../src/main/res/values-sk/translations.xml | 30 ++ .../src/main/res/values-sv/translations.xml | 30 ++ .../src/main/res/values-tr/translations.xml | 24 ++ .../src/main/res/values-uk/translations.xml | 30 ++ .../src/main/res/values-ur/translations.xml | 16 + .../src/main/res/values-uz/translations.xml | 13 + .../main/res/values-zh-rTW/translations.xml | 30 ++ .../src/main/res/values-zh/translations.xml | 24 ++ .../impl/src/main/res/values/localazy.xml | 30 ++ .../impl/DefaultStartDMActionTest.kt | 4 +- .../startchat/impl/FakeStartChatNavigator.kt} | 8 +- .../impl/addpeople/AddPeoplePresenterTest.kt | 10 +- .../impl/addpeople/AddPeopleViewTest.kt | 10 +- .../ConfigureBaseRoomPresenterTest.kt | 8 +- .../JoinBaseRoomByAddressPresenterTest.kt | 12 +- .../JoinBaseRoomByAddressViewTest.kt | 4 +- .../root/CreateBaseRoomRootPresenterTest.kt | 34 +- .../impl/root/CreateBaseRoomRootViewTest.kt | 25 +- .../userlist/DefaultUserListPresenterTest.kt | 2 +- .../impl/userlist/FakeUserListPresenter.kt | 2 +- .../userlist/FakeUserListPresenterFactory.kt | 2 +- .../test/build.gradle.kts | 4 +- .../invitepeople}/test/FakeStartDMAction.kt | 4 +- features/userprofile/impl/build.gradle.kts | 4 +- .../impl/root/UserProfilePresenter.kt | 2 +- .../impl/UserProfilePresenterTest.kt | 6 +- features/userprofile/shared/build.gradle.kts | 2 +- .../shared/UserProfileStateProvider.kt | 2 +- .../userprofile/shared/UserProfileView.kt | 2 +- tools/localazy/config.json | 10 + 133 files changed, 2613 insertions(+), 397 deletions(-) rename features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/{ => configureroom}/CreateRoomConfig.kt (82%) create mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfigStore.kt delete mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootEvents.kt create mode 100644 features/invitepeople/api/build.gradle.kts create mode 100644 features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt create mode 100644 features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt create mode 100644 features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt create mode 100644 features/invitepeople/impl/build.gradle.kts create mode 100644 features/startchat/api/build.gradle.kts rename features/{createroom/api/src/main/kotlin/io/element/android/features/createroom => startchat/api/src/main/kotlin/io/element/android/features/startchat}/api/ConfirmingStartDmWithMatrixUser.kt (89%) create mode 100644 features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartChatEntryPoint.kt rename features/{createroom/api/src/main/kotlin/io/element/android/features/createroom => startchat/api/src/main/kotlin/io/element/android/features/startchat}/api/StartDMAction.kt (95%) create mode 100644 features/startchat/impl/build.gradle.kts rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom/CreateRoomNavigator.kt => startchat/impl/src/main/kotlin/io/element/android/features/startchat/StartChatNavigator.kt} (86%) create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomConfig.kt rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/CreateRoomDataStore.kt (87%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt => startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomFlowNode.kt} (78%) create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPoint.kt rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/DefaultStartDMAction.kt (90%) create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleNode.kt rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/addpeople/AddPeoplePresenter.kt (65%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/addpeople/AddPeopleUserListStateProvider.kt (80%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/addpeople/AddPeopleView.kt (85%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/components/SearchMultipleUsersResultItem.kt (98%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/components/SearchSingleUserResultItem.kt (97%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/components/SearchUserBar.kt (98%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/components/UserListView.kt (94%) create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomEvents.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomNode.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenter.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterArgs.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomState.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomStateProvider.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomView.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccess.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccessItem.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAddress.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityItem.kt create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityState.kt rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/di/CreateRoomComponent.kt (93%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/di/CreateRoomScope.kt (81%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/joinbyaddress/JoinRoomByAddressEvents.kt (86%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/joinbyaddress/JoinRoomByAddressNode.kt (85%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/joinbyaddress/JoinRoomByAddressPresenter.kt (95%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/joinbyaddress/JoinRoomByAddressState.kt (92%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt (95%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/joinbyaddress/JoinRoomByAddressView.kt (97%) create mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatEvents.kt rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt => startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt} (87%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt => startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenter.kt} (73%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootState.kt => startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatState.kt} (63%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootStateProvider.kt => startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt} (82%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt => startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt} (90%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/userlist/DefaultUserListPresenter.kt (98%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/userlist/UserListDataStore.kt (93%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/userlist/UserListEvents.kt (90%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/userlist/UserListPresenter.kt (90%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/userlist/UserListPresenterArgs.kt (84%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/userlist/UserListState.kt (94%) rename features/{createroom/impl/src/main/kotlin/io/element/android/features/createroom => startchat/impl/src/main/kotlin/io/element/android/features/startchat}/impl/userlist/UserListStateProvider.kt (98%) create mode 100644 features/startchat/impl/src/main/res/values-be/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-bg/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-cs/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-cy/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-da/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-de/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-el/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-es/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-et/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-eu/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-fa/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-fi/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-fr/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-hu/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-in/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-it/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-ka/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-lt/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-nb/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-nl/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-pl/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-pt-rBR/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-pt/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-ro/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-ru/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-sk/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-sv/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-tr/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-uk/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-ur/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-uz/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-zh-rTW/translations.xml create mode 100644 features/startchat/impl/src/main/res/values-zh/translations.xml create mode 100644 features/startchat/impl/src/main/res/values/localazy.xml rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/DefaultStartDMActionTest.kt (97%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/FakeCreateRoomNavigator.kt => startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt} (86%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/addpeople/AddPeoplePresenterTest.kt (79%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/addpeople/AddPeopleViewTest.kt (89%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/configureroom/ConfigureBaseRoomPresenterTest.kt (98%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt (93%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt (94%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/root/CreateBaseRoomRootPresenterTest.kt (87%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/root/CreateBaseRoomRootViewTest.kt (85%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/userlist/DefaultUserListPresenterTest.kt (99%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/userlist/FakeUserListPresenter.kt (89%) rename features/{createroom/impl/src/test/kotlin/io/element/android/features/createroom => startchat/impl/src/test/kotlin/io/element/android/features/startchat}/impl/userlist/FakeUserListPresenterFactory.kt (91%) rename features/{createroom => startchat}/test/build.gradle.kts (83%) rename features/{createroom/test/src/main/kotlin/io/element/android/features/createroom => startchat/test/src/main/kotlin/io/element/android/features/invitepeople}/test/FakeStartDMAction.kt (88%) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index fb9b38352c..ae22e5aa97 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -46,7 +46,6 @@ import io.element.android.appnav.loggedin.SendQueues import io.element.android.appnav.room.RoomFlowNode import io.element.android.appnav.room.RoomNavigationTarget import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode -import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.features.enterprise.api.SessionEnterpriseService import io.element.android.features.ftue.api.FtueEntryPoint import io.element.android.features.ftue.api.state.FtueService @@ -60,6 +59,7 @@ import io.element.android.features.roomdirectory.api.RoomDescription import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint import io.element.android.features.securebackup.api.SecureBackupEntryPoint import io.element.android.features.share.api.ShareEntryPoint +import io.element.android.features.startchat.api.StartChatEntryPoint import io.element.android.features.userprofile.api.UserProfileEntryPoint import io.element.android.features.verifysession.api.IncomingVerificationEntryPoint import io.element.android.libraries.architecture.BackstackView @@ -94,15 +94,6 @@ import java.time.Duration import java.time.Instant import java.util.Optional import java.util.UUID -import kotlin.collections.List -import kotlin.collections.any -import kotlin.collections.emptyList -import kotlin.collections.first -import kotlin.collections.forEach -import kotlin.collections.listOf -import kotlin.collections.mapNotNull -import kotlin.collections.plus -import kotlin.collections.setOf import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds import kotlin.time.toKotlinDuration @@ -113,7 +104,7 @@ class LoggedInFlowNode @AssistedInject constructor( @Assisted plugins: List, private val homeEntryPoint: HomeEntryPoint, private val preferencesEntryPoint: PreferencesEntryPoint, - private val createRoomEntryPoint: CreateRoomEntryPoint, + private val startChatEntryPoint: StartChatEntryPoint, private val appNavigationStateService: AppNavigationStateService, private val secureBackupEntryPoint: SecureBackupEntryPoint, private val userProfileEntryPoint: UserProfileEntryPoint, @@ -304,7 +295,7 @@ class LoggedInFlowNode @AssistedInject constructor( backstack.push(NavTarget.Settings()) } - override fun onCreateRoomClick() { + override fun onStartChatClick() { backstack.push(NavTarget.CreateRoom) } @@ -422,7 +413,7 @@ class LoggedInFlowNode @AssistedInject constructor( .build() } NavTarget.CreateRoom -> { - val callback = object : CreateRoomEntryPoint.Callback { + val callback = object : StartChatEntryPoint.Callback { override fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) { backstack.replace(NavTarget.Room(roomIdOrAlias = roomIdOrAlias, serverNames = serverNames)) } @@ -432,7 +423,7 @@ class LoggedInFlowNode @AssistedInject constructor( } } - createRoomEntryPoint + startChatEntryPoint .nodeBuilder(this, buildContext) .callback(callback) .build() diff --git a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt b/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt index 3b35d0a3e1..6b4f02c033 100644 --- a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt +++ b/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.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. @@ -7,21 +7,6 @@ package io.element.android.features.createroom.api -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.plugin.Plugin -import io.element.android.libraries.architecture.FeatureEntryPoint -import io.element.android.libraries.matrix.api.core.RoomIdOrAlias +import io.element.android.libraries.architecture.SimpleFeatureEntryPoint -interface CreateRoomEntryPoint : FeatureEntryPoint { - fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder - interface NodeBuilder { - fun callback(callback: Callback): NodeBuilder - fun build(): Node - } - - interface Callback : Plugin { - fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) - fun onOpenRoomDirectory() - } -} +interface CreateRoomEntryPoint: SimpleFeatureEntryPoint diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index 769f7b5628..dfc503dfbf 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -56,7 +56,7 @@ dependencies { testImplementation(projects.libraries.mediaupload.test) testImplementation(projects.libraries.permissions.test) testImplementation(projects.libraries.usersearch.test) - testImplementation(projects.features.createroom.test) + testImplementation(projects.features.startchat.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.tests.testutils) testImplementation(libs.androidx.compose.ui.test.junit) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt index b8b755a0b3..f1628e754b 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.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. @@ -8,28 +8,19 @@ package io.element.android.features.createroom.impl import android.os.Parcelable -import androidx.compose.foundation.layout.Box -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.navigation.transition.JumpToEndTransitionHandler import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin -import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.DefaultCreateRoomNavigator -import io.element.android.features.createroom.api.CreateRoomEntryPoint -import io.element.android.features.createroom.impl.joinbyaddress.JoinRoomByAddressNode -import io.element.android.features.createroom.impl.root.CreateRoomRootNode -import io.element.android.libraries.architecture.BackstackView +import io.element.android.features.createroom.impl.addpeople.AddPeopleNode +import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode import io.element.android.libraries.architecture.BaseFlowNode -import io.element.android.libraries.architecture.OverlayView import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.core.RoomId import kotlinx.parcelize.Parcelize @ContributesNode(SessionScope::class) @@ -38,53 +29,24 @@ class CreateRoomFlowNode @AssistedInject constructor( @Assisted plugins: List, ) : BaseFlowNode( backstack = BackStack( - initialElement = NavTarget.Root, + initialElement = NavTarget.ConfigureRoom, savedStateMap = buildContext.savedStateMap, ), buildContext = buildContext, plugins = plugins ) { - sealed interface NavTarget : Parcelable { - @Parcelize - data object Root : NavTarget - - @Parcelize - data object NewRoom : NavTarget - - @Parcelize - data object JoinByAddress : NavTarget - } - - private val navigator = DefaultCreateRoomNavigator( - backstack = backstack, - overlay = overlay, - openRoom = { roomIdOrAlias, viaServers -> - plugins().forEach { it.onOpenRoom(roomIdOrAlias, viaServers) } - }, - openRoomDirectory = { - plugins().forEach { it.onOpenRoomDirectory() } - } - ) - override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { - NavTarget.Root -> { - createNode(buildContext = buildContext, plugins = listOf(navigator)) - } - NavTarget.NewRoom -> { - createNode(buildContext = buildContext, plugins = listOf(navigator)) - } - NavTarget.JoinByAddress -> { - createNode(buildContext = buildContext, plugins = listOf(navigator)) - } + NavTarget.ConfigureRoom -> createNode(buildContext) + is NavTarget.AddPeople -> createNode(buildContext) } } - @Composable - override fun View(modifier: Modifier) { - Box(modifier = modifier) { - BackstackView() - OverlayView(transitionHandler = remember { JumpToEndTransitionHandler() }) - } + sealed interface NavTarget : Parcelable { + @Parcelize + data object ConfigureRoom : NavTarget + + @Parcelize + data class AddPeople(val roomId: RoomId) : NavTarget } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt index 161d67e817..33854be08e 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.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. @@ -9,27 +9,12 @@ package io.element.android.features.createroom.impl import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.plugin.Plugin -import com.squareup.anvil.annotations.ContributesBinding import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.libraries.architecture.createNode -import io.element.android.libraries.di.AppScope import javax.inject.Inject -@ContributesBinding(AppScope::class) -class DefaultCreateRoomEntryPoint @Inject constructor() : CreateRoomEntryPoint { - override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): CreateRoomEntryPoint.NodeBuilder { - val plugins = ArrayList() - - return object : CreateRoomEntryPoint.NodeBuilder { - override fun callback(callback: CreateRoomEntryPoint.Callback): CreateRoomEntryPoint.NodeBuilder { - plugins += callback - return this - } - - override fun build(): Node { - return parentNode.createNode(buildContext, plugins) - } - } +class DefaultCreateRoomEntryPoint @Inject constructor(): CreateRoomEntryPoint { + override fun createNode(parentNode: Node, buildContext: BuildContext): Node { + return parentNode.createNode(buildContext) } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt index ba9eb82073..df215c005e 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.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. @@ -7,39 +7,11 @@ package io.element.android.features.createroom.impl.addpeople -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin -import com.bumble.appyx.core.plugin.plugins -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject -import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.impl.di.CreateRoomScope -@ContributesNode(CreateRoomScope::class) -class AddPeopleNode @AssistedInject constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, - private val presenter: AddPeoplePresenter, -) : Node(buildContext, plugins = plugins) { - interface Callback : Plugin { - fun onContinue() - } - - private fun onContinue() { - plugins().forEach { it.onContinue() } - } - - @Composable - override fun View(modifier: Modifier) { - val state = presenter.present() - AddPeopleView( - state = state, - modifier = modifier, - onBackClick = this::navigateUp, - onNextClick = this::onContinue, - ) - } -} +class AddPeopleNode( + buildContext: BuildContext, + plugins: List, +) : Node(buildContext, plugins = plugins) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt index 6885123f63..ae23149fee 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt @@ -16,7 +16,6 @@ sealed interface ConfigureRoomEvents { data class RoomVisibilityChanged(val visibilityItem: RoomVisibilityItem) : ConfigureRoomEvents data class RoomAccessChanged(val roomAccess: RoomAccessItem) : ConfigureRoomEvents data class RoomAddressChanged(val roomAddress: String) : ConfigureRoomEvents - data class RemoveUserFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents data object CreateRoom : ConfigureRoomEvents data class HandleAvatarAction(val action: AvatarAction) : ConfigureRoomEvents data object CancelCreateRoom : ConfigureRoomEvents diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt index e718825163..fcc85afcb7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt @@ -13,24 +13,20 @@ import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin -import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.CreateRoomNavigator -import io.element.android.features.createroom.impl.di.CreateRoomScope -import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias +import io.element.android.libraries.di.SessionScope import io.element.android.services.analytics.api.AnalyticsService -@ContributesNode(CreateRoomScope::class) +@ContributesNode(SessionScope::class) class ConfigureRoomNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: ConfigureRoomPresenter, private val analyticsService: AnalyticsService, ) : Node(buildContext, plugins = plugins) { - private val navigator = plugins().first() init { lifecycle.subscribe( @@ -48,7 +44,7 @@ class ConfigureRoomNode @AssistedInject constructor( modifier = modifier, onBackClick = this::navigateUp, onCreateRoomSuccess = { - navigator.onOpenRoom(roomIdOrAlias = it.toRoomIdOrAlias(), serverNames = emptyList()) + }, ) } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index a3e8f67edf..397ae74186 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -18,8 +18,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.createroom.impl.CreateRoomConfig -import io.element.android.features.createroom.impl.CreateRoomDataStore import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState @@ -50,7 +48,7 @@ import javax.inject.Inject import kotlin.jvm.optionals.getOrDefault class ConfigureRoomPresenter @Inject constructor( - private val dataStore: CreateRoomDataStore, + private val dataStore: CreateRoomConfigStore, private val matrixClient: MatrixClient, private val mediaPickerProvider: PickerProvider, private val mediaPreProcessor: MediaPreProcessor, @@ -66,7 +64,7 @@ class ConfigureRoomPresenter @Inject constructor( @Composable override fun present(): ConfigureRoomState { val cameraPermissionState = cameraPermissionPresenter.present() - val createRoomConfig by dataStore.createRoomConfigWithInvites.collectAsState(CreateRoomConfig()) + val createRoomConfig by dataStore.getCreateRoomConfigFlow().collectAsState(CreateRoomConfig()) val homeserverName = remember { matrixClient.userIdServerName() } val isKnockFeatureEnabled by remember { featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock) @@ -121,7 +119,6 @@ class ConfigureRoomPresenter @Inject constructor( is ConfigureRoomEvents.RoomNameChanged -> dataStore.setRoomName(event.name) is ConfigureRoomEvents.TopicChanged -> dataStore.setTopic(event.topic) is ConfigureRoomEvents.RoomVisibilityChanged -> dataStore.setRoomVisibility(event.visibilityItem) - is ConfigureRoomEvents.RemoveUserFromSelection -> dataStore.selectedUserListDataStore.removeUserFromSelection(event.matrixUser) is ConfigureRoomEvents.RoomAccessChanged -> dataStore.setRoomAccess(event.roomAccess) is ConfigureRoomEvents.RoomAddressChanged -> dataStore.setRoomAddress(event.roomAddress) is ConfigureRoomEvents.CreateRoom -> createRoom(createRoomConfig) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt index 6651d16604..90022a9204 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomState.kt @@ -7,7 +7,6 @@ package io.element.android.features.createroom.impl.configureroom -import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.media.AvatarAction diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt index 71568dbbc7..7db8744408 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomStateProvider.kt @@ -8,7 +8,6 @@ package io.element.android.features.createroom.impl.configureroom import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.components.aMatrixUserList diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index f639704890..8c56607a22 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -12,7 +12,6 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.consumeWindowInsets @@ -58,7 +57,6 @@ import io.element.android.libraries.designsystem.theme.components.TextField import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet -import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList import io.element.android.libraries.matrix.ui.components.UnsavedAvatar import io.element.android.libraries.matrix.ui.room.address.RoomAddressField import io.element.android.libraries.permissions.api.PermissionsView @@ -112,16 +110,6 @@ fun ConfigureRoomView( topic = state.config.topic.orEmpty(), onTopicChange = { state.eventSink(ConfigureRoomEvents.TopicChanged(it)) }, ) - if (state.config.invites.isNotEmpty()) { - SelectedUsersRowList( - contentPadding = PaddingValues(horizontal = 24.dp), - selectedUsers = state.config.invites, - onUserRemove = { - focusManager.clearFocus() - state.eventSink(ConfigureRoomEvents.RemoveUserFromSelection(it)) - }, - ) - } RoomVisibilityOptions( selected = when (state.config.roomVisibility) { is RoomVisibilityState.Private -> RoomVisibilityItem.Private diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfig.kt similarity index 82% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt rename to features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfig.kt index 4cfa6158b8..9ec71f5b76 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfig.kt @@ -5,10 +5,9 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl +package io.element.android.features.createroom.impl.configureroom import android.net.Uri -import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfigStore.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfigStore.kt new file mode 100644 index 0000000000..ef5b632306 --- /dev/null +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfigStore.kt @@ -0,0 +1,119 @@ +/* + * 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.features.createroom.impl.configureroom + +import android.net.Uri +import io.element.android.libraries.androidutils.file.safeDelete +import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.getAndUpdate +import java.io.File +import javax.inject.Inject + +class CreateRoomConfigStore @Inject constructor( + private val roomAliasHelper: RoomAliasHelper, +) { + private val createRoomConfigFlow: MutableStateFlow = MutableStateFlow(CreateRoomConfig()) + + private var cachedAvatarUri: Uri? = null + set(value) { + field?.path?.let { File(it) }?.safeDelete() + field = value + } + + fun getCreateRoomConfigFlow(): StateFlow = createRoomConfigFlow + + fun setRoomName(roomName: String) { + createRoomConfigFlow.getAndUpdate { config -> + val newVisibility = when (config.roomVisibility) { + is RoomVisibilityState.Public -> { + val roomAddress = config.roomVisibility.roomAddress + if (roomAddress is RoomAddress.AutoFilled || roomName.isEmpty()) { + val roomAliasName = roomAliasHelper.roomAliasNameFromRoomDisplayName(roomName) + config.roomVisibility.copy( + roomAddress = RoomAddress.AutoFilled(roomAliasName), + ) + } else { + config.roomVisibility + } + } + else -> config.roomVisibility + } + config.copy( + roomName = roomName.takeIf { it.isNotEmpty() }, + roomVisibility = newVisibility, + ) + } + } + + fun setTopic(topic: String) { + createRoomConfigFlow.getAndUpdate { config -> + config.copy(topic = topic.takeIf { it.isNotEmpty() }) + } + } + + fun setAvatarUri(uri: Uri?, cached: Boolean = false) { + cachedAvatarUri = uri.takeIf { cached } + createRoomConfigFlow.getAndUpdate { config -> + config.copy(avatarUri = uri) + } + } + + fun setRoomVisibility(visibility: RoomVisibilityItem) { + createRoomConfigFlow.getAndUpdate { config -> + config.copy( + roomVisibility = when (visibility) { + RoomVisibilityItem.Private -> RoomVisibilityState.Private + RoomVisibilityItem.Public -> { + val roomAliasName = roomAliasHelper.roomAliasNameFromRoomDisplayName(config.roomName.orEmpty()) + RoomVisibilityState.Public( + roomAddress = RoomAddress.AutoFilled(roomAliasName), + roomAccess = RoomAccess.Anyone, + ) + } + } + ) + } + } + + fun setRoomAddress(address: String) { + createRoomConfigFlow.getAndUpdate { config -> + config.copy( + roomVisibility = when (config.roomVisibility) { + is RoomVisibilityState.Public -> { + val sanitizedAddress = address.lowercase() + config.roomVisibility.copy(roomAddress = RoomAddress.Edited(sanitizedAddress)) + } + else -> config.roomVisibility + } + ) + } + } + + fun setRoomAccess(access: RoomAccessItem) { + createRoomConfigFlow.getAndUpdate { config -> + config.copy( + roomVisibility = when (config.roomVisibility) { + is RoomVisibilityState.Public -> { + when (access) { + RoomAccessItem.Anyone -> config.roomVisibility.copy(roomAccess = RoomAccess.Anyone) + RoomAccessItem.AskToJoin -> config.roomVisibility.copy(roomAccess = RoomAccess.Knocking) + } + } + else -> config.roomVisibility + } + ) + } + } + + fun clearCachedData() { + cachedAvatarUri = null + } +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootEvents.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootEvents.kt deleted file mode 100644 index bc3c4a39b9..0000000000 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootEvents.kt +++ /dev/null @@ -1,15 +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.features.createroom.impl.root - -import io.element.android.libraries.matrix.api.user.MatrixUser - -sealed interface CreateRoomRootEvents { - data class StartDM(val matrixUser: MatrixUser) : CreateRoomRootEvents - data object CancelStartDM : CreateRoomRootEvents -} diff --git a/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt b/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt index 0f6ee581bb..88b55d4e02 100644 --- a/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt +++ b/features/home/api/src/main/kotlin/io/element/android/features/home/api/HomeEntryPoint.kt @@ -22,7 +22,7 @@ interface HomeEntryPoint : FeatureEntryPoint { interface Callback : Plugin { fun onRoomClick(roomId: RoomId) - fun onCreateRoomClick() + fun onStartChatClick() fun onSettingsClick() fun onSetUpRecoveryClick() fun onSessionConfirmRecoveryKeyClick() diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt index 54c58d7387..d08abb6891 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt @@ -120,8 +120,8 @@ class HomeFlowNode @AssistedInject constructor( plugins().forEach { it.onSettingsClick() } } - private fun onCreateRoomClick() { - plugins().forEach { it.onCreateRoomClick() } + private fun onStartChatClick() { + plugins().forEach { it.onStartChatClick() } } private fun onSetUpRecoveryClick() { @@ -171,7 +171,7 @@ class HomeFlowNode @AssistedInject constructor( homeState = state, onRoomClick = this::onRoomClick, onSettingsClick = this::onOpenSettings, - onCreateRoomClick = this::onCreateRoomClick, + onStartChatClick = this::onStartChatClick, onSetUpRecoveryClick = this::onSetUpRecoveryClick, onConfirmRecoveryKeyClick = this::onSessionConfirmRecoveryKeyClick, onRoomSettingsClick = this::onRoomSettingsClick, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt index c2ef2e4bc5..c0e999e7f5 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt @@ -72,7 +72,7 @@ fun HomeView( onSettingsClick: () -> Unit, onSetUpRecoveryClick: () -> Unit, onConfirmRecoveryKeyClick: () -> Unit, - onCreateRoomClick: () -> Unit, + onStartChatClick: () -> Unit, onRoomSettingsClick: (roomId: RoomId) -> Unit, onMenuActionClick: (RoomListMenuAction) -> Unit, onReportRoomClick: (roomId: RoomId) -> Unit, @@ -116,7 +116,7 @@ fun HomeView( onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick, onRoomClick = { if (firstThrottler.canHandle()) onRoomClick(it) }, onOpenSettings = { if (firstThrottler.canHandle()) onSettingsClick() }, - onCreateRoomClick = { if (firstThrottler.canHandle()) onCreateRoomClick() }, + onStartChatClick = { if (firstThrottler.canHandle()) onStartChatClick() }, onMenuActionClick = onMenuActionClick, modifier = Modifier.padding(top = topPadding), ) @@ -145,7 +145,7 @@ private fun HomeScaffold( onConfirmRecoveryKeyClick: () -> Unit, onRoomClick: (RoomId) -> Unit, onOpenSettings: () -> Unit, - onCreateRoomClick: () -> Unit, + onStartChatClick: () -> Unit, onMenuActionClick: (RoomListMenuAction) -> Unit, modifier: Modifier = Modifier, ) { @@ -236,7 +236,7 @@ private fun HomeScaffold( onSetUpRecoveryClick = onSetUpRecoveryClick, onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick, onRoomClick = ::onRoomClick, - onCreateRoomClick = onCreateRoomClick, + onCreateRoomClick = onStartChatClick, contentPadding = PaddingValues( // FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80, // and include provided bottom padding @@ -280,7 +280,7 @@ private fun HomeScaffold( floatingActionButton = { if (state.displayActions) { FloatingActionButton( - onClick = onCreateRoomClick, + onClick = onStartChatClick, ) { Icon( imageVector = CompoundIcons.Plus(), @@ -304,7 +304,7 @@ internal fun HomeViewPreview(@PreviewParameter(HomeStateProvider::class) state: onSettingsClick = {}, onSetUpRecoveryClick = {}, onConfirmRecoveryKeyClick = {}, - onCreateRoomClick = {}, + onStartChatClick = {}, onRoomSettingsClick = {}, onReportRoomClick = {}, onMenuActionClick = {}, diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt index e29b2cf580..4fcbcd170b 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListViewTest.kt @@ -284,7 +284,7 @@ private fun AndroidComposeTestRule.setRoomL onSettingsClick = onSettingsClick, onSetUpRecoveryClick = onSetUpRecoveryClick, onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick, - onCreateRoomClick = onCreateRoomClick, + onStartChatClick = onCreateRoomClick, onRoomSettingsClick = onRoomSettingsClick, onMenuActionClick = onMenuActionClick, onDeclineInviteAndBlockUser = onDeclineInviteAndBlockUser, diff --git a/features/invitepeople/api/build.gradle.kts b/features/invitepeople/api/build.gradle.kts new file mode 100644 index 0000000000..85ce7164b9 --- /dev/null +++ b/features/invitepeople/api/build.gradle.kts @@ -0,0 +1,18 @@ +/* + * 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. + */ +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.invitepeople.api" +} + +dependencies { + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt new file mode 100644 index 0000000000..d41b4db093 --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt @@ -0,0 +1,15 @@ +/* + * 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. + */ + +package io.element.android.features.invitepeople.api + +import androidx.compose.runtime.Composable + +interface InvitePeoplePresenter { + @Composable + fun present(): InvitePeopleState +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt new file mode 100644 index 0000000000..70523653ed --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt @@ -0,0 +1,16 @@ +/* + * 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. + */ + +package io.element.android.features.invitepeople.api + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +interface InvitePeopleRenderer { + @Composable + fun Render(state: InvitePeopleState, modifier: Modifier) +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt new file mode 100644 index 0000000000..059c360df6 --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt @@ -0,0 +1,10 @@ +/* + * 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. + */ + +package io.element.android.features.invitepeople.api + +interface InvitePeopleState diff --git a/features/invitepeople/impl/build.gradle.kts b/features/invitepeople/impl/build.gradle.kts new file mode 100644 index 0000000000..42c96fee18 --- /dev/null +++ b/features/invitepeople/impl/build.gradle.kts @@ -0,0 +1,64 @@ +import extension.ComponentMergingStrategy +import extension.setupAnvil + +/* + * Copyright 2022-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. + */ + +plugins { + id("io.element.android-compose-library") + id("kotlin-parcelize") +} + +android { + namespace = "io.element.android.features.invitepeople.impl" + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } +} + +setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP) + +dependencies { + implementation(projects.libraries.core) + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) + implementation(projects.libraries.matrixui) + implementation(projects.libraries.designsystem) + implementation(projects.libraries.uiStrings) + implementation(projects.libraries.androidutils) + implementation(projects.libraries.deeplink) + implementation(projects.libraries.mediapickers.api) + implementation(projects.libraries.mediaupload.api) + implementation(projects.libraries.permissions.api) + implementation(projects.libraries.usersearch.impl) + implementation(projects.services.analytics.api) + implementation(libs.coil.compose) + implementation(projects.libraries.featureflag.api) + api(projects.features.invitepeople.api) + + testImplementation(libs.test.junit) + testImplementation(libs.test.mockk) + testImplementation(libs.coroutines.test) + testImplementation(libs.molecule.runtime) + testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) + testImplementation(libs.test.robolectric) + testImplementation(projects.services.analytics.test) + testImplementation(projects.libraries.matrix.test) + testImplementation(projects.libraries.mediapickers.test) + testImplementation(projects.libraries.mediaupload.test) + testImplementation(projects.libraries.permissions.test) + testImplementation(projects.libraries.usersearch.test) + testImplementation(projects.features.startchat.test) + testImplementation(projects.libraries.featureflag.test) + testImplementation(projects.tests.testutils) + testImplementation(libs.androidx.compose.ui.test.junit) + testReleaseImplementation(libs.androidx.compose.ui.test.manifest) +} diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts index ad45eda8fc..91bb79c8b7 100644 --- a/features/roomdetails/impl/build.gradle.kts +++ b/features/roomdetails/impl/build.gradle.kts @@ -44,7 +44,7 @@ dependencies { api(projects.services.apperror.api) implementation(libs.coil.compose) implementation(projects.features.call.api) - implementation(projects.features.createroom.api) + implementation(projects.features.startchat.api) implementation(projects.features.leaveroom.api) implementation(projects.features.userprofile.shared) implementation(projects.services.analytics.compose) @@ -72,7 +72,7 @@ dependencies { testImplementation(projects.libraries.usersearch.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.tests.testutils) - testImplementation(projects.features.createroom.test) + testImplementation(projects.features.startchat.test) testImplementation(projects.services.analytics.test) testImplementation(libs.androidx.compose.ui.test.junit) testReleaseImplementation(libs.androidx.compose.ui.test.manifest) diff --git a/features/startchat/api/build.gradle.kts b/features/startchat/api/build.gradle.kts new file mode 100644 index 0000000000..77822f1a15 --- /dev/null +++ b/features/startchat/api/build.gradle.kts @@ -0,0 +1,18 @@ +/* + * 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. + */ +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.startchat.api" +} + +dependencies { + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) +} diff --git a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/ConfirmingStartDmWithMatrixUser.kt b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/ConfirmingStartDmWithMatrixUser.kt similarity index 89% rename from features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/ConfirmingStartDmWithMatrixUser.kt rename to features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/ConfirmingStartDmWithMatrixUser.kt index af19408324..192c32fee7 100644 --- a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/ConfirmingStartDmWithMatrixUser.kt +++ b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/ConfirmingStartDmWithMatrixUser.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.api +package io.element.android.features.startchat.api import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.user.MatrixUser diff --git a/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartChatEntryPoint.kt b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartChatEntryPoint.kt new file mode 100644 index 0000000000..17b9b902e2 --- /dev/null +++ b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartChatEntryPoint.kt @@ -0,0 +1,27 @@ +/* + * 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.features.startchat.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import io.element.android.libraries.architecture.FeatureEntryPoint +import io.element.android.libraries.matrix.api.core.RoomIdOrAlias + +interface StartChatEntryPoint : FeatureEntryPoint { + fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + interface NodeBuilder { + fun callback(callback: Callback): NodeBuilder + fun build(): Node + } + + interface Callback : Plugin { + fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) + fun onOpenRoomDirectory() + } +} diff --git a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/StartDMAction.kt b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartDMAction.kt similarity index 95% rename from features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/StartDMAction.kt rename to features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartDMAction.kt index e64be9f923..b49a9fbdfd 100644 --- a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/StartDMAction.kt +++ b/features/startchat/api/src/main/kotlin/io/element/android/features/startchat/api/StartDMAction.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.api +package io.element.android.features.startchat.api import androidx.compose.runtime.MutableState import io.element.android.libraries.architecture.AsyncAction diff --git a/features/startchat/impl/build.gradle.kts b/features/startchat/impl/build.gradle.kts new file mode 100644 index 0000000000..b53f3d8c89 --- /dev/null +++ b/features/startchat/impl/build.gradle.kts @@ -0,0 +1,64 @@ +import extension.ComponentMergingStrategy +import extension.setupAnvil + +/* + * Copyright 2022-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. + */ + +plugins { + id("io.element.android-compose-library") + id("kotlin-parcelize") +} + +android { + namespace = "io.element.android.features.startchat.impl" + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } +} + +setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP) + +dependencies { + implementation(projects.libraries.core) + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) + implementation(projects.libraries.matrixui) + implementation(projects.libraries.designsystem) + implementation(projects.libraries.uiStrings) + implementation(projects.libraries.androidutils) + implementation(projects.libraries.deeplink) + implementation(projects.libraries.mediapickers.api) + implementation(projects.libraries.mediaupload.api) + implementation(projects.libraries.permissions.api) + implementation(projects.libraries.usersearch.impl) + implementation(projects.services.analytics.api) + implementation(libs.coil.compose) + implementation(projects.libraries.featureflag.api) + api(projects.features.startchat.api) + + testImplementation(libs.test.junit) + testImplementation(libs.test.mockk) + testImplementation(libs.coroutines.test) + testImplementation(libs.molecule.runtime) + testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) + testImplementation(libs.test.robolectric) + testImplementation(projects.services.analytics.test) + testImplementation(projects.libraries.matrix.test) + testImplementation(projects.libraries.mediapickers.test) + testImplementation(projects.libraries.mediaupload.test) + testImplementation(projects.libraries.permissions.test) + testImplementation(projects.libraries.usersearch.test) + testImplementation(projects.features.startchat.test) + testImplementation(projects.libraries.featureflag.test) + testImplementation(projects.tests.testutils) + testImplementation(libs.androidx.compose.ui.test.junit) + testReleaseImplementation(libs.androidx.compose.ui.test.manifest) +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/CreateRoomNavigator.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/StartChatNavigator.kt similarity index 86% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/CreateRoomNavigator.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/StartChatNavigator.kt index 69eac7d369..a45b4dddab 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/CreateRoomNavigator.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/StartChatNavigator.kt @@ -5,18 +5,18 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom +package io.element.android.features.startchat import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.push -import io.element.android.features.createroom.impl.CreateRoomFlowNode.NavTarget +import io.element.android.features.startchat.impl.StartChatFlowNode.NavTarget import io.element.android.libraries.architecture.overlay.Overlay import io.element.android.libraries.architecture.overlay.operation.hide import io.element.android.libraries.architecture.overlay.operation.show import io.element.android.libraries.matrix.api.core.RoomIdOrAlias -interface CreateRoomNavigator : Plugin { +interface StartChatNavigator : Plugin { fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) fun onCreateNewRoom() fun onShowJoinRoomByAddress() @@ -24,12 +24,12 @@ interface CreateRoomNavigator : Plugin { fun onOpenRoomDirectory() } -class DefaultCreateRoomNavigator( +class DefaultStartChatNavigator( private val backstack: BackStack, private val overlay: Overlay, private val openRoom: (RoomIdOrAlias, List) -> Unit, private val openRoomDirectory: () -> Unit, -) : CreateRoomNavigator { +) : StartChatNavigator { override fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) = openRoom(roomIdOrAlias, serverNames) override fun onOpenRoomDirectory() = openRoomDirectory() diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomConfig.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomConfig.kt new file mode 100644 index 0000000000..2cbd961dad --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomConfig.kt @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl + +import android.net.Uri +import io.element.android.features.startchat.impl.configureroom.RoomVisibilityState +import io.element.android.libraries.matrix.api.user.MatrixUser +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +data class CreateRoomConfig( + val roomName: String? = null, + val topic: String? = null, + val avatarUri: Uri? = null, + val invites: ImmutableList = persistentListOf(), + val roomVisibility: RoomVisibilityState = RoomVisibilityState.Private, +) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomDataStore.kt similarity index 87% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomDataStore.kt index 29b1525f51..ff0746c1b3 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomDataStore.kt @@ -1,20 +1,20 @@ /* - * 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. */ -package io.element.android.features.createroom.impl +package io.element.android.features.startchat.impl import android.net.Uri -import io.element.android.features.createroom.impl.configureroom.RoomAccess -import io.element.android.features.createroom.impl.configureroom.RoomAccessItem -import io.element.android.features.createroom.impl.configureroom.RoomAddress -import io.element.android.features.createroom.impl.configureroom.RoomVisibilityItem -import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState -import io.element.android.features.createroom.impl.di.CreateRoomScope -import io.element.android.features.createroom.impl.userlist.UserListDataStore +import io.element.android.features.startchat.impl.configureroom.RoomAccess +import io.element.android.features.startchat.impl.configureroom.RoomAccessItem +import io.element.android.features.startchat.impl.configureroom.RoomAddress +import io.element.android.features.startchat.impl.configureroom.RoomVisibilityItem +import io.element.android.features.startchat.impl.configureroom.RoomVisibilityState +import io.element.android.features.startchat.impl.di.CreateRoomScope +import io.element.android.features.startchat.impl.userlist.UserListDataStore import io.element.android.libraries.androidutils.file.safeDelete import io.element.android.libraries.di.SingleIn import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomFlowNode.kt similarity index 78% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomFlowNode.kt index a7678f130f..1124314250 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomFlowNode.kt @@ -1,11 +1,11 @@ /* - * 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. */ -package io.element.android.features.createroom.impl +package io.element.android.features.startchat.impl import android.os.Parcelable import androidx.compose.runtime.Composable @@ -19,10 +19,10 @@ import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.CreateRoomNavigator -import io.element.android.features.createroom.impl.addpeople.AddPeopleNode -import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode -import io.element.android.features.createroom.impl.di.CreateRoomComponent +import io.element.android.features.startchat.StartChatNavigator +import io.element.android.features.startchat.impl.addpeople.AddPeopleNode +import io.element.android.features.startchat.impl.configureroom.ConfigureRoomNode +import io.element.android.features.startchat.impl.di.CreateRoomComponent import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.bindings @@ -32,13 +32,13 @@ import io.element.android.libraries.di.SessionScope import kotlinx.parcelize.Parcelize @ContributesNode(SessionScope::class) -class ConfigureRoomFlowNode @AssistedInject constructor( +class CreateRoomFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, ) : DaggerComponentOwner, - BaseFlowNode( + BaseFlowNode( backstack = BackStack( - initialElement = NavTarget.Root, + initialElement = NavTarget.ConfigureRoom, savedStateMap = buildContext.savedStateMap, ), buildContext = buildContext, @@ -47,14 +47,14 @@ class ConfigureRoomFlowNode @AssistedInject constructor( private val component by lazy { parent!!.bindings().createRoomComponentBuilder().build() } - private val navigator = plugins().first() + private val navigator = plugins().first() override val daggerComponent: Any get() = component sealed interface NavTarget : Parcelable { @Parcelize - data object Root : NavTarget + data object AddPeople : NavTarget @Parcelize data object ConfigureRoom : NavTarget @@ -62,7 +62,7 @@ class ConfigureRoomFlowNode @AssistedInject constructor( override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { - NavTarget.Root -> { + NavTarget.AddPeople -> { val callback = object : AddPeopleNode.Callback { override fun onContinue() { backstack.push(NavTarget.ConfigureRoom) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPoint.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPoint.kt new file mode 100644 index 0000000000..9f9073f1d7 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartChatEntryPoint.kt @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.startchat.api.StartChatEntryPoint +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.AppScope +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class DefaultStartChatEntryPoint @Inject constructor() : StartChatEntryPoint { + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): StartChatEntryPoint.NodeBuilder { + val plugins = ArrayList() + + return object : StartChatEntryPoint.NodeBuilder { + override fun callback(callback: StartChatEntryPoint.Callback): StartChatEntryPoint.NodeBuilder { + plugins += callback + return this + } + + override fun build(): Node { + return parentNode.createNode(buildContext, plugins) + } + } + } +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultStartDMAction.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartDMAction.kt similarity index 90% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultStartDMAction.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartDMAction.kt index c9b60786bd..b09c5ea174 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultStartDMAction.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/DefaultStartDMAction.kt @@ -5,13 +5,13 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl +package io.element.android.features.startchat.impl import androidx.compose.runtime.MutableState import com.squareup.anvil.annotations.ContributesBinding import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.api.StartDMAction +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.StartDMAction import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt new file mode 100644 index 0000000000..c635023df3 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl + +import android.os.Parcelable +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.navigation.transition.JumpToEndTransitionHandler +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins +import com.bumble.appyx.navmodel.backstack.BackStack +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.startchat.DefaultStartChatNavigator +import io.element.android.features.startchat.api.StartChatEntryPoint +import io.element.android.features.startchat.impl.joinbyaddress.JoinRoomByAddressNode +import io.element.android.features.startchat.impl.root.StartChatNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode +import io.element.android.libraries.architecture.OverlayView +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.SessionScope +import kotlinx.parcelize.Parcelize + +@ContributesNode(SessionScope::class) +class StartChatFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, +) : BaseFlowNode( + backstack = BackStack( + initialElement = NavTarget.Root, + savedStateMap = buildContext.savedStateMap, + ), + buildContext = buildContext, + plugins = plugins +) { + sealed interface NavTarget : Parcelable { + @Parcelize + data object Root : NavTarget + + @Parcelize + data object NewRoom : NavTarget + + @Parcelize + data object JoinByAddress : NavTarget + } + + private val navigator = DefaultStartChatNavigator( + backstack = backstack, + overlay = overlay, + openRoom = { roomIdOrAlias, viaServers -> + plugins().forEach { it.onOpenRoom(roomIdOrAlias, viaServers) } + }, + openRoomDirectory = { + plugins().forEach { it.onOpenRoomDirectory() } + } + ) + + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { + return when (navTarget) { + NavTarget.Root -> { + createNode(buildContext = buildContext, plugins = listOf(navigator)) + } + NavTarget.NewRoom -> { + createNode(buildContext = buildContext, plugins = listOf(navigator)) + } + NavTarget.JoinByAddress -> { + createNode(buildContext = buildContext, plugins = listOf(navigator)) + } + } + } + + @Composable + override fun View(modifier: Modifier) { + Box(modifier = modifier) { + BackstackView() + OverlayView(transitionHandler = remember { JumpToEndTransitionHandler() }) + } + } +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleNode.kt new file mode 100644 index 0000000000..441ba8cc76 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleNode.kt @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.addpeople + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.startchat.impl.di.CreateRoomScope + +@ContributesNode(CreateRoomScope::class) +class AddPeopleNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val presenter: AddPeoplePresenter, +) : Node(buildContext, plugins = plugins) { + interface Callback : Plugin { + fun onContinue() + } + + private fun onContinue() { + plugins().forEach { it.onContinue() } + } + + @Composable + override fun View(modifier: Modifier) { + val state = presenter.present() + AddPeopleView( + state = state, + modifier = modifier, + onBackClick = this::navigateUp, + onSkipClick = this::onContinue, + ) + } +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenter.kt similarity index 65% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenter.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenter.kt index e050a0738e..aacd80fca3 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenter.kt @@ -1,18 +1,18 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.addpeople +package io.element.android.features.startchat.impl.addpeople import androidx.compose.runtime.Composable -import io.element.android.features.createroom.impl.CreateRoomDataStore -import io.element.android.features.createroom.impl.userlist.SelectionMode -import io.element.android.features.createroom.impl.userlist.UserListPresenter -import io.element.android.features.createroom.impl.userlist.UserListPresenterArgs -import io.element.android.features.createroom.impl.userlist.UserListState +import io.element.android.features.startchat.impl.CreateRoomDataStore +import io.element.android.features.startchat.impl.userlist.SelectionMode +import io.element.android.features.startchat.impl.userlist.UserListPresenter +import io.element.android.features.startchat.impl.userlist.UserListPresenterArgs +import io.element.android.features.startchat.impl.userlist.UserListState import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.usersearch.api.UserRepository import javax.inject.Inject diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleUserListStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleUserListStateProvider.kt similarity index 80% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleUserListStateProvider.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleUserListStateProvider.kt index 9e0ddd04c8..57b3a93d57 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleUserListStateProvider.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleUserListStateProvider.kt @@ -1,17 +1,17 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.addpeople +package io.element.android.features.startchat.impl.addpeople import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.createroom.impl.userlist.SelectionMode -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.features.createroom.impl.userlist.aRecentDirectRoomList -import io.element.android.features.createroom.impl.userlist.aUserListState +import io.element.android.features.startchat.impl.userlist.SelectionMode +import io.element.android.features.startchat.impl.userlist.UserListState +import io.element.android.features.startchat.impl.userlist.aRecentDirectRoomList +import io.element.android.features.startchat.impl.userlist.aUserListState import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.ui.components.aMatrixUserList import io.element.android.libraries.usersearch.api.UserSearchResult diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleView.kt similarity index 85% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleView.kt index d39ac4d250..ac457955d5 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleView.kt @@ -1,11 +1,11 @@ /* - * Copyright 2022-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. */ -package io.element.android.features.createroom.impl.addpeople +package io.element.android.features.startchat.impl.addpeople import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize @@ -15,10 +15,10 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter -import io.element.android.features.createroom.impl.R -import io.element.android.features.createroom.impl.components.UserListView -import io.element.android.features.createroom.impl.userlist.UserListEvents -import io.element.android.features.createroom.impl.userlist.UserListState +import io.element.android.features.startchat.impl.R +import io.element.android.features.startchat.impl.components.UserListView +import io.element.android.features.startchat.impl.userlist.UserListEvents +import io.element.android.features.startchat.impl.userlist.UserListState import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight @@ -31,7 +31,7 @@ import io.element.android.libraries.ui.strings.CommonStrings fun AddPeopleView( state: UserListState, onBackClick: () -> Unit, - onNextClick: () -> Unit, + onSkipClick: () -> Unit, modifier: Modifier = Modifier, ) { Scaffold( @@ -46,7 +46,7 @@ fun AddPeopleView( onBackClick() } }, - onNextClick = onNextClick, + onNextClick = onSkipClick, ) } ) { padding -> @@ -89,6 +89,6 @@ internal fun AddPeopleViewPreview(@PreviewParameter(AddPeopleUserListStateProvid AddPeopleView( state = state, onBackClick = {}, - onNextClick = {}, + onSkipClick = {}, ) } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchMultipleUsersResultItem.kt similarity index 98% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchMultipleUsersResultItem.kt index af12895fff..867ac9d918 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchMultipleUsersResultItem.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchMultipleUsersResultItem.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.components +package io.element.android.features.startchat.impl.components import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchSingleUserResultItem.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchSingleUserResultItem.kt similarity index 97% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchSingleUserResultItem.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchSingleUserResultItem.kt index eb922f1ae3..bd94d136af 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchSingleUserResultItem.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchSingleUserResultItem.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.components +package io.element.android.features.startchat.impl.components import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchUserBar.kt similarity index 98% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchUserBar.kt index 290c1aff0c..3d42c40067 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/SearchUserBar.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/SearchUserBar.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.components +package io.element.android.features.startchat.impl.components import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.Spring diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/UserListView.kt similarity index 94% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/UserListView.kt index a660480258..753bebec83 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/components/UserListView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/components/UserListView.kt @@ -1,11 +1,11 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.components +package io.element.android.features.startchat.impl.components import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -16,9 +16,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import io.element.android.features.createroom.impl.userlist.UserListEvents -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.features.createroom.impl.userlist.UserListStateProvider +import io.element.android.features.startchat.impl.userlist.UserListEvents +import io.element.android.features.startchat.impl.userlist.UserListState +import io.element.android.features.startchat.impl.userlist.UserListStateProvider import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomEvents.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomEvents.kt new file mode 100644 index 0000000000..13ce502559 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomEvents.kt @@ -0,0 +1,23 @@ +/* + * 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.features.startchat.impl.configureroom + +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.ui.media.AvatarAction + +sealed interface ConfigureRoomEvents { + data class RoomNameChanged(val name: String) : ConfigureRoomEvents + data class TopicChanged(val topic: String) : ConfigureRoomEvents + data class RoomVisibilityChanged(val visibilityItem: RoomVisibilityItem) : ConfigureRoomEvents + data class RoomAccessChanged(val roomAccess: RoomAccessItem) : ConfigureRoomEvents + data class RoomAddressChanged(val roomAddress: String) : ConfigureRoomEvents + data class RemoveUserFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents + data object CreateRoom : ConfigureRoomEvents + data class HandleAvatarAction(val action: AvatarAction) : ConfigureRoomEvents + data object CancelCreateRoom : ConfigureRoomEvents +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomNode.kt new file mode 100644 index 0000000000..3251fbff8d --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomNode.kt @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.configureroom + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.lifecycle.subscribe +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import im.vector.app.features.analytics.plan.MobileScreen +import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.startchat.StartChatNavigator +import io.element.android.features.startchat.impl.di.CreateRoomScope +import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias +import io.element.android.services.analytics.api.AnalyticsService + +@ContributesNode(CreateRoomScope::class) +class ConfigureRoomNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val presenter: ConfigureRoomPresenter, + private val analyticsService: AnalyticsService, +) : Node(buildContext, plugins = plugins) { + private val navigator = plugins().first() + + init { + lifecycle.subscribe( + onResume = { + analyticsService.screen(MobileScreen(screenName = MobileScreen.ScreenName.CreateRoom)) + } + ) + } + + @Composable + override fun View(modifier: Modifier) { + val state = presenter.present() + ConfigureRoomView( + state = state, + modifier = modifier, + onBackClick = this::navigateUp, + onCreateRoomSuccess = { + navigator.onOpenRoom(roomIdOrAlias = it.toRoomIdOrAlias(), serverNames = emptyList()) + }, + ) + } +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenter.kt new file mode 100644 index 0000000000..a715bf568d --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenter.kt @@ -0,0 +1,209 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.configureroom + +import android.net.Uri +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import im.vector.app.features.analytics.plan.CreatedRoom +import io.element.android.features.startchat.impl.CreateRoomConfig +import io.element.android.features.startchat.impl.CreateRoomDataStore +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.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters +import io.element.android.libraries.matrix.api.createroom.RoomPreset +import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper +import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility +import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility +import io.element.android.libraries.matrix.ui.media.AvatarAction +import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity +import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidityEffect +import io.element.android.libraries.mediapickers.api.PickerProvider +import io.element.android.libraries.mediaupload.api.MediaPreProcessor +import io.element.android.libraries.permissions.api.PermissionsEvents +import io.element.android.libraries.permissions.api.PermissionsPresenter +import io.element.android.services.analytics.api.AnalyticsService +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject +import kotlin.jvm.optionals.getOrDefault + +class ConfigureRoomPresenter @Inject constructor( + private val dataStore: CreateRoomDataStore, + private val matrixClient: MatrixClient, + private val mediaPickerProvider: PickerProvider, + private val mediaPreProcessor: MediaPreProcessor, + private val analyticsService: AnalyticsService, + permissionsPresenterFactory: PermissionsPresenter.Factory, + private val featureFlagService: FeatureFlagService, + private val roomAliasHelper: RoomAliasHelper, +) : Presenter { + private val cameraPermissionPresenter: PermissionsPresenter = permissionsPresenterFactory.create(android.Manifest.permission.CAMERA) + private var pendingPermissionRequest = false + + @Composable + override fun present(): ConfigureRoomState { + val cameraPermissionState = cameraPermissionPresenter.present() + val createRoomConfig by dataStore.createRoomConfigWithInvites.collectAsState(CreateRoomConfig()) + val homeserverName = remember { matrixClient.userIdServerName() } + val isKnockFeatureEnabled by remember { + featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock) + }.collectAsState(initial = false) + val roomAddressValidity = remember { + mutableStateOf(RoomAddressValidity.Unknown) + } + + val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker( + onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri, cached = true) }, + ) + val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker( + onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri) } + ) + + val avatarActions by remember(createRoomConfig.avatarUri) { + derivedStateOf { + listOfNotNull( + AvatarAction.TakePhoto, + AvatarAction.ChoosePhoto, + AvatarAction.Remove.takeIf { createRoomConfig.avatarUri != null }, + ).toImmutableList() + } + } + + LaunchedEffect(cameraPermissionState.permissionGranted) { + if (cameraPermissionState.permissionGranted && pendingPermissionRequest) { + pendingPermissionRequest = false + cameraPhotoPicker.launch() + } + } + + RoomAddressValidityEffect( + client = matrixClient, + roomAliasHelper = roomAliasHelper, + newRoomAddress = createRoomConfig.roomVisibility.roomAddress().getOrDefault(""), + knownRoomAddress = null, + ) { newRoomAddressValidity -> + roomAddressValidity.value = newRoomAddressValidity + } + + val localCoroutineScope = rememberCoroutineScope() + val createRoomAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) } + + fun createRoom(config: CreateRoomConfig) { + createRoomAction.value = AsyncAction.Uninitialized + localCoroutineScope.createRoom(config, createRoomAction) + } + + fun handleEvents(event: ConfigureRoomEvents) { + when (event) { + is ConfigureRoomEvents.RoomNameChanged -> dataStore.setRoomName(event.name) + is ConfigureRoomEvents.TopicChanged -> dataStore.setTopic(event.topic) + is ConfigureRoomEvents.RoomVisibilityChanged -> dataStore.setRoomVisibility(event.visibilityItem) + is ConfigureRoomEvents.RemoveUserFromSelection -> dataStore.selectedUserListDataStore.removeUserFromSelection(event.matrixUser) + is ConfigureRoomEvents.RoomAccessChanged -> dataStore.setRoomAccess(event.roomAccess) + is ConfigureRoomEvents.RoomAddressChanged -> dataStore.setRoomAddress(event.roomAddress) + is ConfigureRoomEvents.CreateRoom -> createRoom(createRoomConfig) + is ConfigureRoomEvents.HandleAvatarAction -> { + when (event.action) { + AvatarAction.ChoosePhoto -> galleryImagePicker.launch() + AvatarAction.TakePhoto -> if (cameraPermissionState.permissionGranted) { + cameraPhotoPicker.launch() + } else { + pendingPermissionRequest = true + cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions) + } + AvatarAction.Remove -> dataStore.setAvatarUri(uri = null) + } + } + + ConfigureRoomEvents.CancelCreateRoom -> createRoomAction.value = AsyncAction.Uninitialized + } + } + + return ConfigureRoomState( + isKnockFeatureEnabled = isKnockFeatureEnabled, + config = createRoomConfig, + avatarActions = avatarActions, + createRoomAction = createRoomAction.value, + cameraPermissionState = cameraPermissionState, + homeserverName = homeserverName, + roomAddressValidity = roomAddressValidity.value, + eventSink = ::handleEvents, + ) + } + + private fun CoroutineScope.createRoom( + config: CreateRoomConfig, + createRoomAction: MutableState> + ) = launch { + suspend { + val avatarUrl = config.avatarUri?.let { uploadAvatar(it) } + val params = if (config.roomVisibility is RoomVisibilityState.Public) { + CreateRoomParameters( + name = config.roomName, + topic = config.topic, + isEncrypted = false, + isDirect = false, + visibility = RoomVisibility.Public, + joinRuleOverride = config.roomVisibility.roomAccess.toJoinRule(), + preset = RoomPreset.PUBLIC_CHAT, + invite = config.invites.map { it.userId }, + avatar = avatarUrl, + roomAliasName = config.roomVisibility.roomAddress() + ) + } else { + CreateRoomParameters( + name = config.roomName, + topic = config.topic, + isEncrypted = config.roomVisibility is RoomVisibilityState.Private, + isDirect = false, + visibility = RoomVisibility.Private, + historyVisibilityOverride = RoomHistoryVisibility.Invited, + preset = RoomPreset.PRIVATE_CHAT, + invite = config.invites.map { it.userId }, + avatar = avatarUrl, + ) + } + matrixClient.createRoom(params) + .onFailure { failure -> + Timber.e(failure, "Failed to create room") + } + .onSuccess { + dataStore.clearCachedData() + analyticsService.capture(CreatedRoom(isDM = false)) + } + .getOrThrow() + }.runCatchingUpdatingState(createRoomAction) + } + + private suspend fun uploadAvatar(avatarUri: Uri): String { + val preprocessed = mediaPreProcessor.process( + uri = avatarUri, + mimeType = MimeTypes.Jpeg, + deleteOriginal = false, + compressIfPossible = false, + ).getOrThrow() + val byteArray = preprocessed.file.readBytes() + return matrixClient.uploadMedia(MimeTypes.Jpeg, byteArray, null).getOrThrow() + } +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterArgs.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterArgs.kt new file mode 100644 index 0000000000..2ee98b2a35 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterArgs.kt @@ -0,0 +1,14 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.configureroom + +import io.element.android.libraries.matrix.api.user.MatrixUser + +data class ConfigureRoomPresenterArgs( + val selectedUsers: List, +) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomState.kt new file mode 100644 index 0000000000..e94066caed --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomState.kt @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.configureroom + +import io.element.android.features.startchat.impl.CreateRoomConfig +import io.element.android.libraries.architecture.AsyncAction +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.ui.media.AvatarAction +import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity +import io.element.android.libraries.permissions.api.PermissionsState +import kotlinx.collections.immutable.ImmutableList + +data class ConfigureRoomState( + val isKnockFeatureEnabled: Boolean, + val config: CreateRoomConfig, + val avatarActions: ImmutableList, + val createRoomAction: AsyncAction, + val cameraPermissionState: PermissionsState, + val roomAddressValidity: RoomAddressValidity, + val homeserverName: String, + val eventSink: (ConfigureRoomEvents) -> Unit +) { + val isValid: Boolean = config.roomName?.isNotEmpty() == true && + (config.roomVisibility is RoomVisibilityState.Private || roomAddressValidity == RoomAddressValidity.Valid) +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomStateProvider.kt new file mode 100644 index 0000000000..09d801440b --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomStateProvider.kt @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.configureroom + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.features.startchat.impl.CreateRoomConfig +import io.element.android.libraries.architecture.AsyncAction +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.ui.components.aMatrixUserList +import io.element.android.libraries.matrix.ui.media.AvatarAction +import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity +import io.element.android.libraries.permissions.api.PermissionsState +import io.element.android.libraries.permissions.api.aPermissionsState +import kotlinx.collections.immutable.toImmutableList + +open class ConfigureRoomStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aConfigureRoomState(), + aConfigureRoomState( + isKnockFeatureEnabled = false, + config = CreateRoomConfig( + roomName = "Room 101", + topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", + invites = aMatrixUserList().toImmutableList(), + roomVisibility = RoomVisibilityState.Public( + roomAddress = RoomAddress.AutoFilled("Room-101"), + roomAccess = RoomAccess.Knocking, + ), + ), + ), + aConfigureRoomState( + config = CreateRoomConfig( + roomName = "Room 101", + topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", + invites = aMatrixUserList().toImmutableList(), + roomVisibility = RoomVisibilityState.Public( + roomAddress = RoomAddress.AutoFilled("Room-101"), + roomAccess = RoomAccess.Knocking, + ), + ), + ), + aConfigureRoomState( + config = CreateRoomConfig( + roomName = "Room 101", + topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", + roomVisibility = RoomVisibilityState.Public( + roomAddress = RoomAddress.AutoFilled("Room-101"), + roomAccess = RoomAccess.Knocking, + ), + ), + roomAddressValidity = RoomAddressValidity.NotAvailable, + ), + aConfigureRoomState( + config = CreateRoomConfig( + roomName = "Room 101", + topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", + roomVisibility = RoomVisibilityState.Public( + roomAddress = RoomAddress.AutoFilled("Room-101"), + roomAccess = RoomAccess.Knocking, + ), + ), + roomAddressValidity = RoomAddressValidity.InvalidSymbols, + ), + aConfigureRoomState( + config = CreateRoomConfig( + roomName = "Room 101", + topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", + roomVisibility = RoomVisibilityState.Public( + roomAddress = RoomAddress.AutoFilled("Room-101"), + roomAccess = RoomAccess.Knocking, + ), + ), + roomAddressValidity = RoomAddressValidity.Valid, + ), + ) +} + +fun aConfigureRoomState( + config: CreateRoomConfig = CreateRoomConfig(), + isKnockFeatureEnabled: Boolean = true, + avatarActions: List = emptyList(), + createRoomAction: AsyncAction = AsyncAction.Uninitialized, + cameraPermissionState: PermissionsState = aPermissionsState(showDialog = false), + homeserverName: String = "matrix.org", + roomAddressValidity: RoomAddressValidity = RoomAddressValidity.Valid, + eventSink: (ConfigureRoomEvents) -> Unit = { }, +) = ConfigureRoomState( + config = config, + isKnockFeatureEnabled = isKnockFeatureEnabled, + avatarActions = avatarActions.toImmutableList(), + createRoomAction = createRoomAction, + cameraPermissionState = cameraPermissionState, + homeserverName = homeserverName, + roomAddressValidity = roomAddressValidity, + eventSink = eventSink, +) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomView.kt new file mode 100644 index 0000000000..c056570913 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomView.kt @@ -0,0 +1,339 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.configureroom + +import android.net.Uri +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardCapitalization +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.features.startchat.impl.R +import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage +import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtom +import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize +import io.element.android.libraries.designsystem.components.async.AsyncActionView +import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.designsystem.components.avatar.AvatarType +import io.element.android.libraries.designsystem.components.button.BackButton +import io.element.android.libraries.designsystem.components.list.ListItemContent +import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap +import io.element.android.libraries.designsystem.preview.ElementPreviewDark +import io.element.android.libraries.designsystem.preview.ElementPreviewLight +import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight +import io.element.android.libraries.designsystem.theme.components.ListItem +import io.element.android.libraries.designsystem.theme.components.Scaffold +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.TextField +import io.element.android.libraries.designsystem.theme.components.TopAppBar +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet +import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList +import io.element.android.libraries.matrix.ui.components.UnsavedAvatar +import io.element.android.libraries.matrix.ui.room.address.RoomAddressField +import io.element.android.libraries.permissions.api.PermissionsView +import io.element.android.libraries.ui.strings.CommonStrings + +@Composable +fun ConfigureRoomView( + state: ConfigureRoomState, + onBackClick: () -> Unit, + onCreateRoomSuccess: (RoomId) -> Unit, + modifier: Modifier = Modifier, +) { + val focusManager = LocalFocusManager.current + val isAvatarActionsSheetVisible = remember { mutableStateOf(false) } + + fun onAvatarClick() { + focusManager.clearFocus() + isAvatarActionsSheetVisible.value = true + } + + Scaffold( + modifier = modifier.clearFocusOnTap(focusManager), + topBar = { + ConfigureRoomToolbar( + isNextActionEnabled = state.isValid, + onBackClick = onBackClick, + onNextClick = { + focusManager.clearFocus() + state.eventSink(ConfigureRoomEvents.CreateRoom) + }, + ) + } + ) { padding -> + Column( + modifier = Modifier + .padding(padding) + .imePadding() + .verticalScroll(rememberScrollState()) + .consumeWindowInsets(padding), + verticalArrangement = Arrangement.spacedBy(24.dp), + ) { + RoomNameWithAvatar( + modifier = Modifier.padding(horizontal = 16.dp), + avatarUri = state.config.avatarUri, + roomName = state.config.roomName.orEmpty(), + onAvatarClick = ::onAvatarClick, + onChangeRoomName = { state.eventSink(ConfigureRoomEvents.RoomNameChanged(it)) }, + ) + RoomTopic( + modifier = Modifier.padding(horizontal = 16.dp), + topic = state.config.topic.orEmpty(), + onTopicChange = { state.eventSink(ConfigureRoomEvents.TopicChanged(it)) }, + ) + if (state.config.invites.isNotEmpty()) { + SelectedUsersRowList( + contentPadding = PaddingValues(horizontal = 24.dp), + selectedUsers = state.config.invites, + onUserRemove = { + focusManager.clearFocus() + state.eventSink(ConfigureRoomEvents.RemoveUserFromSelection(it)) + }, + ) + } + RoomVisibilityOptions( + selected = when (state.config.roomVisibility) { + is RoomVisibilityState.Private -> RoomVisibilityItem.Private + is RoomVisibilityState.Public -> RoomVisibilityItem.Public + }, + onOptionClick = { + focusManager.clearFocus() + state.eventSink(ConfigureRoomEvents.RoomVisibilityChanged(it)) + }, + ) + if (state.config.roomVisibility is RoomVisibilityState.Public && state.isKnockFeatureEnabled) { + RoomAccessOptions( + selected = when (state.config.roomVisibility.roomAccess) { + RoomAccess.Anyone -> RoomAccessItem.Anyone + RoomAccess.Knocking -> RoomAccessItem.AskToJoin + }, + onOptionClick = { + focusManager.clearFocus() + state.eventSink(ConfigureRoomEvents.RoomAccessChanged(it)) + }, + ) + RoomAddressField( + modifier = Modifier.padding(horizontal = 16.dp), + address = state.config.roomVisibility.roomAddress.value, + homeserverName = state.homeserverName, + addressValidity = state.roomAddressValidity, + onAddressChange = { state.eventSink(ConfigureRoomEvents.RoomAddressChanged(it)) }, + label = stringResource(R.string.screen_create_room_room_address_section_title), + supportingText = stringResource(R.string.screen_create_room_room_address_section_footer), + ) + Spacer(Modifier) + } + } + } + + AvatarActionBottomSheet( + actions = state.avatarActions, + isVisible = isAvatarActionsSheetVisible.value, + onDismiss = { isAvatarActionsSheetVisible.value = false }, + onSelectAction = { state.eventSink(ConfigureRoomEvents.HandleAvatarAction(it)) } + ) + + AsyncActionView( + async = state.createRoomAction, + progressDialog = { + AsyncActionViewDefaults.ProgressDialog( + progressText = stringResource(CommonStrings.common_creating_room), + ) + }, + onSuccess = { onCreateRoomSuccess(it) }, + errorMessage = { stringResource(R.string.screen_create_room_error_creating_room) }, + onRetry = { state.eventSink(ConfigureRoomEvents.CreateRoom) }, + onErrorDismiss = { state.eventSink(ConfigureRoomEvents.CancelCreateRoom) }, + ) + + PermissionsView( + state = state.cameraPermissionState, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun ConfigureRoomToolbar( + isNextActionEnabled: Boolean, + onBackClick: () -> Unit, + onNextClick: () -> Unit, +) { + TopAppBar( + titleStr = stringResource(R.string.screen_create_room_title), + navigationIcon = { BackButton(onClick = onBackClick) }, + actions = { + TextButton( + text = stringResource(CommonStrings.action_create), + enabled = isNextActionEnabled, + onClick = onNextClick, + ) + } + ) +} + +@Composable +private fun RoomNameWithAvatar( + avatarUri: Uri?, + roomName: String, + onAvatarClick: () -> Unit, + onChangeRoomName: (String) -> Unit, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier, + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + UnsavedAvatar( + avatarUri = avatarUri, + avatarSize = AvatarSize.EditRoomDetails, + avatarType = AvatarType.Room(), + modifier = Modifier.clickable(onClick = onAvatarClick), + ) + + TextField( + label = stringResource(R.string.screen_create_room_room_name_label), + value = roomName, + placeholder = stringResource(CommonStrings.common_room_name_placeholder), + singleLine = true, + onValueChange = onChangeRoomName, + ) + } +} + +@Composable +private fun RoomTopic( + topic: String, + onTopicChange: (String) -> Unit, + modifier: Modifier = Modifier, +) { + TextField( + modifier = modifier, + label = stringResource(R.string.screen_create_room_topic_label), + value = topic, + onValueChange = onTopicChange, + maxLines = 3, + supportingText = stringResource(CommonStrings.common_topic_placeholder), + keyboardOptions = KeyboardOptions( + capitalization = KeyboardCapitalization.Sentences, + ), + ) +} + +@Composable +private fun ConfigureRoomOptions( + title: String, + modifier: Modifier = Modifier, + content: @Composable ColumnScope.() -> Unit, +) { + Column( + modifier = modifier.selectableGroup() + ) { + Text( + text = title, + style = ElementTheme.typography.fontBodyLgMedium, + color = ElementTheme.colors.textPrimary, + modifier = Modifier.padding(horizontal = 16.dp), + ) + content() + } +} + +@Composable +private fun RoomVisibilityOptions( + selected: RoomVisibilityItem, + onOptionClick: (RoomVisibilityItem) -> Unit, + modifier: Modifier = Modifier, +) { + ConfigureRoomOptions( + title = stringResource(R.string.screen_create_room_room_visibility_section_title), + modifier = modifier, + ) { + RoomVisibilityItem.entries.forEach { item -> + val isSelected = item == selected + ListItem( + leadingContent = ListItemContent.Custom { + RoundedIconAtom( + size = RoundedIconAtomSize.Big, + resourceId = item.icon, + tint = if (isSelected) ElementTheme.colors.iconPrimary else ElementTheme.colors.iconSecondary, + ) + }, + headlineContent = { Text(text = stringResource(item.title)) }, + supportingContent = { Text(text = stringResource(item.description)) }, + trailingContent = ListItemContent.RadioButton(selected = isSelected), + onClick = { onOptionClick(item) }, + ) + } + } +} + +@Composable +private fun RoomAccessOptions( + selected: RoomAccessItem, + onOptionClick: (RoomAccessItem) -> Unit, + modifier: Modifier = Modifier, +) { + ConfigureRoomOptions( + title = stringResource(R.string.screen_create_room_room_access_section_header), + modifier = modifier, + ) { + RoomAccessItem.entries.forEach { item -> + ListItem( + headlineContent = { Text(text = stringResource(item.title)) }, + supportingContent = { Text(text = stringResource(item.description)) }, + trailingContent = ListItemContent.RadioButton(selected = item == selected), + onClick = { onOptionClick(item) }, + ) + } + } +} + +@PreviewWithLargeHeight +@Composable +internal fun ConfigureRoomViewLightPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) = + ElementPreviewLight { ContentToPreview(state) } + +@PreviewWithLargeHeight +@Composable +internal fun ConfigureRoomViewDarkPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) = + ElementPreviewDark { ContentToPreview(state) } + +@ExcludeFromCoverage +@Composable +private fun ContentToPreview(state: ConfigureRoomState) { + ConfigureRoomView( + state = state, + onBackClick = {}, + onCreateRoomSuccess = {}, + ) +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccess.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccess.kt new file mode 100644 index 0000000000..bf75d9605e --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccess.kt @@ -0,0 +1,22 @@ +/* + * 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.features.startchat.impl.configureroom + +import io.element.android.libraries.matrix.api.room.join.JoinRule + +enum class RoomAccess { + Anyone, + Knocking +} + +fun RoomAccess.toJoinRule(): JoinRule? { + return when (this) { + RoomAccess.Anyone -> null + RoomAccess.Knocking -> JoinRule.Knock + } +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccessItem.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccessItem.kt new file mode 100644 index 0000000000..0a48afe849 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccessItem.kt @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.configureroom + +import androidx.annotation.StringRes +import io.element.android.features.startchat.impl.R + +enum class RoomAccessItem( + @StringRes val title: Int, + @StringRes val description: Int +) { + Anyone( + title = R.string.screen_create_room_room_access_section_anyone_option_title, + description = R.string.screen_create_room_room_access_section_anyone_option_description, + ), + AskToJoin( + title = R.string.screen_create_room_room_access_section_knocking_option_title, + description = R.string.screen_create_room_room_access_section_knocking_option_description, + ), +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAddress.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAddress.kt new file mode 100644 index 0000000000..51e02d881a --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAddress.kt @@ -0,0 +1,13 @@ +/* + * 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.features.startchat.impl.configureroom + +sealed class RoomAddress(open val value: String) { + data class AutoFilled(override val value: String) : RoomAddress(value) + data class Edited(override val value: String) : RoomAddress(value) +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityItem.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityItem.kt new file mode 100644 index 0000000000..4ca8b51601 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityItem.kt @@ -0,0 +1,30 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.configureroom + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import io.element.android.features.startchat.impl.R +import io.element.android.libraries.designsystem.icons.CompoundDrawables + +enum class RoomVisibilityItem( + @DrawableRes val icon: Int, + @StringRes val title: Int, + @StringRes val description: Int +) { + Private( + icon = CompoundDrawables.ic_compound_lock, + title = R.string.screen_create_room_private_option_title, + description = R.string.screen_create_room_private_option_description, + ), + Public( + icon = CompoundDrawables.ic_compound_public, + title = R.string.screen_create_room_public_option_title, + description = R.string.screen_create_room_public_option_description, + ) +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityState.kt new file mode 100644 index 0000000000..5a9a3126f6 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityState.kt @@ -0,0 +1,26 @@ +/* + * 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.features.startchat.impl.configureroom + +import java.util.Optional + +sealed interface RoomVisibilityState { + data object Private : RoomVisibilityState + + data class Public( + val roomAddress: RoomAddress, + val roomAccess: RoomAccess, + ) : RoomVisibilityState + + fun roomAddress(): Optional { + return when (this) { + is Private -> Optional.empty() + is Public -> Optional.of(roomAddress.value) + } + } +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomComponent.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomComponent.kt similarity index 93% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomComponent.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomComponent.kt index b47b8c30e5..6f6569bcb3 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomComponent.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomComponent.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.di +package io.element.android.features.startchat.impl.di import com.squareup.anvil.annotations.ContributesTo import com.squareup.anvil.annotations.MergeSubcomponent diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomScope.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomScope.kt similarity index 81% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomScope.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomScope.kt index b0a011424a..a164ba50b8 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/di/CreateRoomScope.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomScope.kt @@ -5,6 +5,6 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.di +package io.element.android.features.startchat.impl.di abstract class CreateRoomScope private constructor() diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressEvents.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressEvents.kt similarity index 86% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressEvents.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressEvents.kt index dbbcef56fa..648146fbd7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressEvents.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressEvents.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress sealed interface JoinRoomByAddressEvents { data object Dismiss : JoinRoomByAddressEvents diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressNode.kt similarity index 85% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressNode.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressNode.kt index d6338ab43c..67dba8b46e 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressNode.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressNode.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -16,7 +16,7 @@ import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.CreateRoomNavigator +import io.element.android.features.startchat.StartChatNavigator import io.element.android.libraries.di.SessionScope @ContributesNode(SessionScope::class) @@ -25,7 +25,7 @@ class JoinRoomByAddressNode @AssistedInject constructor( @Assisted plugins: List, presenterFactory: JoinRoomByAddressPresenter.Factory, ) : Node(buildContext, plugins = plugins) { - private val navigator = plugins().first() + private val navigator = plugins().first() private val presenter = presenterFactory.create(navigator) @Composable diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt similarity index 95% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressPresenter.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt index cf4788cbbf..4e1f9f9ab0 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressPresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressPresenter.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -18,7 +18,7 @@ import androidx.compose.runtime.setValue import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import io.element.android.features.createroom.CreateRoomNavigator +import io.element.android.features.startchat.StartChatNavigator import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.matrix.api.MatrixClient @@ -32,13 +32,13 @@ import kotlin.time.Duration.Companion.seconds private const val ADDRESS_RESOLVE_TIMEOUT_IN_SECONDS = 10 class JoinRoomByAddressPresenter @AssistedInject constructor( - @Assisted private val navigator: CreateRoomNavigator, + @Assisted private val navigator: StartChatNavigator, private val client: MatrixClient, private val roomAliasHelper: RoomAliasHelper, ) : Presenter { @AssistedFactory interface Factory { - fun create(navigator: CreateRoomNavigator): JoinRoomByAddressPresenter + fun create(navigator: StartChatNavigator): JoinRoomByAddressPresenter } @Composable diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressState.kt similarity index 92% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressState.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressState.kt index 11791181e1..84b01ac263 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressState.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressState.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt similarity index 95% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt index 6281a8e8e3..847ca78837 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressStateProvider.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.matrix.api.core.RoomId diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt similarity index 97% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressView.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt index c256f5140c..2d34dcc1cf 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinRoomByAddressView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -29,7 +29,7 @@ import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import io.element.android.features.createroom.impl.R +import io.element.android.features.startchat.impl.R import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatEvents.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatEvents.kt new file mode 100644 index 0000000000..6ea72d8b05 --- /dev/null +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatEvents.kt @@ -0,0 +1,15 @@ +/* + * 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. + */ + +package io.element.android.features.startchat.impl.root + +import io.element.android.libraries.matrix.api.user.MatrixUser + +sealed interface StartChatEvents { + data class StartDM(val matrixUser: MatrixUser) : StartChatEvents + data object CancelStartDM : StartChatEvents +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt similarity index 87% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt index f76a5d5c61..29a13d2fa4 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootNode.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt @@ -1,11 +1,11 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import android.app.Activity import androidx.activity.compose.LocalActivity @@ -20,21 +20,21 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.createroom.CreateRoomNavigator +import io.element.android.features.startchat.StartChatNavigator import io.element.android.libraries.deeplink.usecase.InviteFriendsUseCase import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import io.element.android.services.analytics.api.AnalyticsService @ContributesNode(SessionScope::class) -class CreateRoomRootNode @AssistedInject constructor( +class StartChatNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: CreateRoomRootPresenter, + private val presenter: StartChatPresenter, private val analyticsService: AnalyticsService, private val inviteFriendsUseCase: InviteFriendsUseCase, ) : Node(buildContext, plugins = plugins) { - private val navigator = plugins().first() + private val navigator = plugins().first() init { lifecycle.subscribe( diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenter.kt similarity index 73% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenter.kt index ea8be45e6b..9f7bea5c68 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenter.kt @@ -1,11 +1,11 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -14,11 +14,11 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import io.element.android.features.createroom.api.StartDMAction -import io.element.android.features.createroom.impl.userlist.SelectionMode -import io.element.android.features.createroom.impl.userlist.UserListDataStore -import io.element.android.features.createroom.impl.userlist.UserListPresenter -import io.element.android.features.createroom.impl.userlist.UserListPresenterArgs +import io.element.android.features.startchat.api.StartDMAction +import io.element.android.features.startchat.impl.userlist.SelectionMode +import io.element.android.features.startchat.impl.userlist.UserListDataStore +import io.element.android.features.startchat.impl.userlist.UserListPresenter +import io.element.android.features.startchat.impl.userlist.UserListPresenterArgs import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.meta.BuildMeta @@ -29,14 +29,14 @@ import io.element.android.libraries.usersearch.api.UserRepository import kotlinx.coroutines.launch import javax.inject.Inject -class CreateRoomRootPresenter @Inject constructor( +class StartChatPresenter @Inject constructor( presenterFactory: UserListPresenter.Factory, userRepository: UserRepository, userListDataStore: UserListDataStore, private val startDMAction: StartDMAction, private val buildMeta: BuildMeta, private val featureFlagService: FeatureFlagService, -) : Presenter { +) : Presenter { private val presenter = presenterFactory.create( UserListPresenterArgs( selectionMode = SelectionMode.Single, @@ -46,7 +46,7 @@ class CreateRoomRootPresenter @Inject constructor( ) @Composable - override fun present(): CreateRoomRootState { + override fun present(): StartChatState { val userListState = presenter.present() val localCoroutineScope = rememberCoroutineScope() @@ -56,20 +56,20 @@ class CreateRoomRootPresenter @Inject constructor( featureFlagService.isFeatureEnabledFlow(FeatureFlags.RoomDirectorySearch) }.collectAsState(initial = false) - fun handleEvents(event: CreateRoomRootEvents) { + fun handleEvents(event: StartChatEvents) { when (event) { - is CreateRoomRootEvents.StartDM -> localCoroutineScope.launch { + is StartChatEvents.StartDM -> localCoroutineScope.launch { startDMAction.execute( matrixUser = event.matrixUser, createIfDmDoesNotExist = startDmActionState.value is AsyncAction.Confirming, actionState = startDmActionState, ) } - CreateRoomRootEvents.CancelStartDM -> startDmActionState.value = AsyncAction.Uninitialized + StartChatEvents.CancelStartDM -> startDmActionState.value = AsyncAction.Uninitialized } } - return CreateRoomRootState( + return StartChatState( applicationName = buildMeta.applicationName, userListState = userListState, startDmAction = startDmActionState.value, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatState.kt similarity index 63% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootState.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatState.kt index 7a6d651db3..724d6e5e88 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootState.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatState.kt @@ -1,20 +1,20 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root -import io.element.android.features.createroom.impl.userlist.UserListState +import io.element.android.features.startchat.impl.userlist.UserListState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId -data class CreateRoomRootState( +data class StartChatState( val applicationName: String, val userListState: UserListState, val startDmAction: AsyncAction, val isRoomDirectorySearchEnabled: Boolean, - val eventSink: (CreateRoomRootEvents) -> Unit, + val eventSink: (StartChatEvents) -> Unit, ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt similarity index 82% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootStateProvider.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt index 9f2d59e3b6..1173425aa1 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootStateProvider.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt @@ -1,17 +1,17 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.features.createroom.impl.userlist.aRecentDirectRoomList -import io.element.android.features.createroom.impl.userlist.aUserListState +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.impl.userlist.UserListState +import io.element.android.features.startchat.impl.userlist.aRecentDirectRoomList +import io.element.android.features.startchat.impl.userlist.aUserListState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.core.RoomId @@ -19,8 +19,8 @@ import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.usersearch.api.UserSearchResult import kotlinx.collections.immutable.persistentListOf -open class CreateRoomRootStateProvider : PreviewParameterProvider { - override val values: Sequence +open class CreateRoomRootStateProvider : PreviewParameterProvider { + override val values: Sequence get() = sequenceOf( aCreateRoomRootState(), aCreateRoomRootState( @@ -64,8 +64,8 @@ fun aCreateRoomRootState( userListState: UserListState = aUserListState(), startDmAction: AsyncAction = AsyncAction.Uninitialized, isRoomDirectorySearchEnabled: Boolean = false, - eventSink: (CreateRoomRootEvents) -> Unit = {}, -) = CreateRoomRootState( + eventSink: (StartChatEvents) -> Unit = {}, +) = StartChatState( applicationName = applicationName, userListState = userListState, startDmAction = startDmAction, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt similarity index 90% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt index 248d331985..340e6a9134 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt @@ -1,11 +1,11 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.annotation.DrawableRes import androidx.compose.foundation.clickable @@ -27,9 +27,9 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.impl.R -import io.element.android.features.createroom.impl.components.UserListView +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.impl.R +import io.element.android.features.startchat.impl.components.UserListView import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults import io.element.android.libraries.designsystem.components.button.BackButton @@ -49,7 +49,7 @@ import kotlinx.collections.immutable.persistentListOf @Composable fun CreateRoomRootView( - state: CreateRoomRootState, + state: StartChatState, onCloseClick: () -> Unit, onNewRoomClick: () -> Unit, onOpenDM: (RoomId) -> Unit, @@ -80,7 +80,7 @@ fun CreateRoomRootView( recentDirectRooms = persistentListOf(), ), onSelectUser = { - state.eventSink(CreateRoomRootEvents.StartDM(it)) + state.eventSink(StartChatEvents.StartDM(it)) }, onDeselectUser = { }, ) @@ -109,20 +109,20 @@ fun CreateRoomRootView( errorMessage = { stringResource(R.string.screen_start_chat_error_starting_chat) }, onRetry = { state.userListState.selectedUsers.firstOrNull() - ?.let { state.eventSink(CreateRoomRootEvents.StartDM(it)) } + ?.let { state.eventSink(StartChatEvents.StartDM(it)) } // Cancel start DM if there is no more selected user (should not happen) - ?: state.eventSink(CreateRoomRootEvents.CancelStartDM) + ?: state.eventSink(StartChatEvents.CancelStartDM) }, - onErrorDismiss = { state.eventSink(CreateRoomRootEvents.CancelStartDM) }, + onErrorDismiss = { state.eventSink(StartChatEvents.CancelStartDM) }, confirmationDialog = { data -> if (data is ConfirmingStartDmWithMatrixUser) { CreateDmConfirmationBottomSheet( matrixUser = data.matrixUser, onSendInvite = { - state.eventSink(CreateRoomRootEvents.StartDM(data.matrixUser)) + state.eventSink(StartChatEvents.StartDM(data.matrixUser)) }, onDismiss = { - state.eventSink(CreateRoomRootEvents.CancelStartDM) + state.eventSink(StartChatEvents.CancelStartDM) }, ) } @@ -148,7 +148,7 @@ private fun CreateRoomRootViewTopBar( @Composable private fun CreateRoomActionButtonsList( - state: CreateRoomRootState, + state: StartChatState, onNewRoomClick: () -> Unit, onInvitePeopleClick: () -> Unit, onJoinByAddressClick: () -> Unit, @@ -239,7 +239,7 @@ private fun CreateRoomActionButton( @PreviewsDayNight @Composable -internal fun CreateRoomRootViewPreview(@PreviewParameter(CreateRoomRootStateProvider::class) state: CreateRoomRootState) = +internal fun CreateRoomRootViewPreview(@PreviewParameter(CreateRoomRootStateProvider::class) state: StartChatState) = ElementPreview { CreateRoomRootView( state = state, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenter.kt similarity index 98% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenter.kt index 32d5767cc6..c964b18441 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenter.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListDataStore.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListDataStore.kt similarity index 93% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListDataStore.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListDataStore.kt index a500e3a05f..64048d7e86 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListDataStore.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListDataStore.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.coroutines.flow.MutableStateFlow diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListEvents.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListEvents.kt similarity index 90% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListEvents.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListEvents.kt index 45b40597da..794b2c18af 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListEvents.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListEvents.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.matrix.api.user.MatrixUser diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenter.kt similarity index 90% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenter.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenter.kt index 38f45d202f..a07b39a1e7 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenter.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenter.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.usersearch.api.UserRepository diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenterArgs.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenterArgs.kt similarity index 84% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenterArgs.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenterArgs.kt index 85cc58e995..d7e6a727f8 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListPresenterArgs.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListPresenterArgs.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist data class UserListPresenterArgs( val selectionMode: SelectionMode, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListState.kt similarity index 94% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListState.kt index bed3ac7f63..2186bcb57a 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListState.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListState.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.room.recent.RecentDirectRoom diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListStateProvider.kt similarity index 98% rename from features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt rename to features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListStateProvider.kt index 3b5918abc5..65b4efdadb 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/userlist/UserListStateProvider.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/userlist/UserListStateProvider.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.designsystem.theme.components.SearchBarResultState diff --git a/features/startchat/impl/src/main/res/values-be/translations.xml b/features/startchat/impl/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..8acb990b02 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-be/translations.xml @@ -0,0 +1,19 @@ + + + "Новы пакой" + "Запрасіць карыстальнікаў" + "Пры стварэнні пакоя адбылася памылка" + "Толькі запрошаныя людзі могуць атрымаць доступ да гэтага пакоя. Усе паведамленні абаронены end-to-end шыфраваннем." + "Прыватны пакой" + "Любы можа знайсці гэты пакой. +Вы можаце змяніць гэта ў любы час у наладах пакоя." + "Публічны пакой" + "Хто заўгодна" + "Доступ у пакой" + "Папрасіце далучыцца" + "Назва пакоя" + "Стварыце пакой" + "Тэма (неабавязкова)" + "Каталог пакояў" + "Пры спробе пачаць чат адбылася памылка" + diff --git a/features/startchat/impl/src/main/res/values-bg/translations.xml b/features/startchat/impl/src/main/res/values-bg/translations.xml new file mode 100644 index 0000000000..fa6dae371c --- /dev/null +++ b/features/startchat/impl/src/main/res/values-bg/translations.xml @@ -0,0 +1,23 @@ + + + "Нова стая" + "Поканване на хора" + "Възникна грешка при създаването на стаята" + "Само поканени хора имат достъп до тази стая. Всички съобщения са шифровани от край до край." + "Частна стая" + "Всеки може да намери тази стая. +Можете да промените това по всяко време в настройките на стаята." + "Общодостъпна стая" + "Всеки може да се присъедини към тази стая" + "Всеки" + "За да бъде тази стая видима в директорията на общодостъпните стаи, ще ви е необходим адрес на стаята." + "Име на стаята" + "Видимост на стаята" + "Създаване на стая" + "Тема за разговор (незадължително)" + "Присъединяване към стая по адрес" + "Не е валиден адрес" + "Въведете…" + "Стаята не е намерена" + "напр. #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-cs/translations.xml b/features/startchat/impl/src/main/res/values-cs/translations.xml new file mode 100644 index 0000000000..53592e0db0 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-cs/translations.xml @@ -0,0 +1,30 @@ + + + "Nová místnost" + "Pozvat přátele" + "Při vytváření místnosti došlo k chybě" + "Do této místnosti mají přístup pouze pozvaní lidé. Všechny zprávy jsou koncově šifrovány." + "Soukromá místnost" + "Tuto místnost může najít kdokoli. +To můžete kdykoli změnit v nastavení místnosti." + "Veřejná místnost" + "Do této místnosti může vstoupit kdokoli" + "Kdokoliv" + "Přístup do místnosti" + "Kdokoli může požádat o vstup do místnosti, ale správce nebo moderátor bude muset žádost přijmout" + "Požádat o připojení" + "Aby byla tato místnost viditelná v adresáři veřejných místností, budete potřebovat adresu místnosti." + "Adresa místnosti" + "Název místnosti" + "Viditelnost místnosti" + "Vytvořit místnost" + "Téma (nepovinné)" + "Adresář místností" + "Při pokusu o zahájení chatu došlo k chybě" + "Vstoupit do místnosti pomocí adresy" + "Neplatná adresa" + "Zadejte…" + "Odpovídající místnost nalezena" + "Místnost nebyla nalezena" + "např. #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-cy/translations.xml b/features/startchat/impl/src/main/res/values-cy/translations.xml new file mode 100644 index 0000000000..a3a9e30e35 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-cy/translations.xml @@ -0,0 +1,30 @@ + + + "Ystafell newydd" + "Gwahodd pobl" + "Bu gwall wrth greu\'r ystafell" + "Dim ond pobl wahoddwyd all gael mynediad i\'r ystafell hon. Mae pob neges wedi\'i hamgryptio o\'r dechrau i\'r diwedd." + "Ystafell breifat" + "Gall unrhyw un ddod o hyd i\'r ystafell hon. +Gallwch newid hyn unrhyw bryd yng ngosodiadau ystafell." + "Ystafell gyhoeddus" + "Gall unrhyw un ymuno â\'r ystafell hon" + "Unrhyw un" + "Mynediad i\'r Ystafell" + "Gall unrhyw un ofyn am gael ymuno â\'r ystafell ond bydd rhaid i weinyddwr neu gymedrolwr dderbyn y cais" + "Gofyn i gael ymuno" + "Er mwyn i\'r ystafell hon fod yn weladwy yn y cyfeiriadur ystafelloedd cyhoeddus, bydd angen cyfeiriad ystafell arnoch." + "Cyfeiriad yr ystafell" + "Enw\'r ystafell" + "Gwelededd yr ystafell" + "Creu ystafell" + "Pwnc (dewisol)" + "Cyfeiriadur ystafelloedd" + "Digwyddodd gwall wrth geisio cychwyn sgwrs" + "Ymuno â\'r ystafell yn ôl cyfeiriad" + "Ddim yn gyfeiriad dilys" + "Ewch i mewn…" + "Cafwyd hyd i ystafell gyfatebol" + "Heb ganfod yr ystafell" + "e.e. #enw-ystafell:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-da/translations.xml b/features/startchat/impl/src/main/res/values-da/translations.xml new file mode 100644 index 0000000000..c9c182b474 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-da/translations.xml @@ -0,0 +1,30 @@ + + + "Nyt rum" + "Invitér folk" + "Der opstod en fejl ved oprettelsen af rummet" + "Kun inviterede personer kan få adgang til dette rum. Alle meddelelser er ende-til-ende krypteret." + "Privat rum" + "Alle kan finde dette rum. +Du kan ændre dette når som helst i rummets indstillinger." + "Offentligt rum" + "Alle kan deltage i dette rum" + "Enhver" + "Adgang til rummet" + "Alle kan bede om at deltage i rummet, men en administrator eller en moderator skal acceptere anmodningen" + "Spørg om at deltage" + "Hvis dette rum skal være synligt i det offentlige register, skal du bruge en rum-adresse." + "Rummets adresse" + "Navn på rum" + "Rummets synlighed" + "Opret et rum" + "Emne (valgfrit)" + "Register over rum" + "Der opstod en fejl under forsøget på at starte en samtale" + "Tilslut dig rummet med adressen" + "Ikke en gyldig adresse" + "Indtast…" + "Matchende rum fundet" + "Rum ikke fundet" + "f.eks. #rummets-navn:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-de/translations.xml b/features/startchat/impl/src/main/res/values-de/translations.xml new file mode 100644 index 0000000000..90438aa38c --- /dev/null +++ b/features/startchat/impl/src/main/res/values-de/translations.xml @@ -0,0 +1,30 @@ + + + "Neuer Raum" + "Nutzer einladen" + "Beim Erstellen des Chats ist ein Fehler aufgetreten" + "Nur eingeladene Personen haben Zutritt zu diesem Chatroom. Alle Nachrichten sind Ende-zu-Ende verschlüsselt." + "Privater Chatroom" + "Alle können diesen Chatroom finden. +Sie können dies aber jederzeit in den Chatroomeinstellungen ändern." + "Öffentlicher Raum" + "Jeder darf diesen Raum betreten" + "Jeder" + "Chatroomzugang" + "Jeder kann den Zutritt zum Raum beantragen, aber ein Moderator muss die Anfrage akzeptieren." + "Beitritt beantragen" + "Damit dieser Chatroom im öffentlichen Chatroomverzeichnis sichtbar ist, benötigen Sie eine Chatroomadresse." + "Chatroomadresse" + "Raumname" + " Sichtbarkeit des Chatrooms" + "Raum erstellen" + "Thema (optional)" + "Raum-Verzeichnis" + "Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten" + "Raum per Adresse betreten" + "Keine gültige Adresse" + "Eintreten…" + "Passender Raum gefunden" + "Raum nicht gefunden" + "z. B. #room -name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-el/translations.xml b/features/startchat/impl/src/main/res/values-el/translations.xml new file mode 100644 index 0000000000..c036b43a05 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-el/translations.xml @@ -0,0 +1,30 @@ + + + "Νέα αίθουσα" + "Πρόσκληση ατόμων" + "Προέκυψε σφάλμα κατά τη δημιουργία της αίθουσας" + "Μόνο τα άτομα που έχουν προσκληθεί μπορούν να έχουν πρόσβαση σε αυτή την αίθουσα. Όλα τα μηνύματα είναι κρυπτογραφημένα από άκρο σε άκρο." + "Ιδιωτική αίθουσα" + "Ο καθένας μπορεί να βρει αυτή την αίθουσα. +Αυτό μπορείτε να το αλλάξετε ανά πάσα στιγμή στις ρυθμίσεις της αίθουσας." + "Δημόσια αίθουσα" + "Οποιοσδήποτε μπορεί να συμμετάσχει σε αυτή την αίθουσα" + "Οποιοσδήποτε" + "Πρόσβαση στην Αίθουσα" + "Οποιοσδήποτε μπορεί να ζητήσει να συμμετάσχει στην αίθουσα, αλλά ένας διαχειριστής ή ένας συντονιστής θα πρέπει να αποδεχτεί το αίτημα" + "Αίτημα συμμετοχής" + "Για να είναι ορατή αυτή η αίθουσα στον δημόσιο κατάλογο αιθουσών, θα χρειαστείτε μια διεύθυνση αίθουσας." + "Διεύθυνση αίθουσας" + "Όνομα αίθουσας" + "Ορατότητα αίθουσας" + "Δημιουργία αίθουσας" + "Θέμα (προαιρετικό)" + "Κατάλογος αιθουσών" + "Παρουσιάστηκε σφάλμα κατά την προσπάθεια έναρξης μιας συνομιλίας" + "Συμμετοχή σε αίθουσα μέσω διεύθυνσης" + "Μη έγκυρη διεύθυνση" + "Εισάγετε…" + "Βρέθηκε η αντίστοιχη αίθουσα" + "Η αίθουσα δεν βρέθηκε" + "π.χ. #όνομα-αίθουσας:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-es/translations.xml b/features/startchat/impl/src/main/res/values-es/translations.xml new file mode 100644 index 0000000000..c11f08fc14 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-es/translations.xml @@ -0,0 +1,30 @@ + + + "Nueva sala" + "Invitar personas" + "Se ha producido un error al crear la sala" + "Solo las personas invitadas pueden acceder a esta sala. Todos los mensajes están cifrados de extremo a extremo." + "Sala privada" + "Cualquiera puede encontrar esta sala. +Puedes cambiar esto en cualquier momento en los ajustes de la sala." + "Sala pública" + "Cualquiera puede unirse a esta sala" + "Cualquiera" + "Acceso a la sala" + "Cualquiera puede solicitar unirse a la sala, pero un administrador o un moderador tendrá que aceptar la solicitud" + "Solicitud para unirse" + "Para que esta sala sea visible en el directorio de salas públicas, necesitarás una dirección de sala." + "Dirección de la sala" + "Nombre de la sala" + "Visibilidad de la sala" + "Crear una sala" + "Tema (opcional)" + "Directorio de salas" + "Se ha producido un error al intentar iniciar un chat" + "Unirse a una sala por su dirección" + "Dirección no válida" + "Introducir…" + "Sala encontrada" + "No se encontró la sala" + "p. ej., #nombre-de-la-sala:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-et/translations.xml b/features/startchat/impl/src/main/res/values-et/translations.xml new file mode 100644 index 0000000000..57a26106b3 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-et/translations.xml @@ -0,0 +1,30 @@ + + + "Uus jututuba" + "Kutsu osalejaid" + "Jututoa loomisel tekkis viga" + "Ligipääs siia jututuppa on vaid kutse alusel. Kõik sõnumid siin jututoas on läbivalt krüptitud." + "Privaatne jututuba" + "Kõik saavad seda jututuba leida. +Sa võid seda jututoa seadistustest alati muuta." + "Avalik jututuba" + "Kõik võivad selle jututoaga liituda" + "Kõik" + "Ligipääs jututoale" + "Kõik võivad paluda selle jututoaga liitumist, kuid peakasutaja või moderaator peavad selle kinnitama" + "Küsi võimalust liitumiseks" + "Selleks, et see jututuba oleks nähtav jututubade avalikus kataloogis, sa vajad jututoa aadressi." + "Jututoa aadress" + "Jututoa nimi" + "Jututoa nähtavus" + "Loo jututuba" + "Teema (kui soovid lisada)" + "Jututubade kataloog" + "Vestluse alustamisel tekkis viga" + "Liitu jututoaga aadressi alusel" + "See pole kehtiv aadress" + "Sisene…" + "Leidsime vastava jututoa" + "Jututuba ei leidu" + "nt. #jututoa-nimi:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-eu/translations.xml b/features/startchat/impl/src/main/res/values-eu/translations.xml new file mode 100644 index 0000000000..43f67e429c --- /dev/null +++ b/features/startchat/impl/src/main/res/values-eu/translations.xml @@ -0,0 +1,23 @@ + + + "Gela berria" + "Gonbidatu jendea" + "Errorea gertatu da gela sortzean" + "Gonbidatutako jendea soilik sar daiteke gelara. Mezu guztiak daude ertzetik ertzera zifratuta." + "Gela pribatua" + "Edonork aurki dezake gela hau. +Gelaren ezarpenetan aldatu dezakezu hobespena." + "Gela publikoa" + "Edonor sar daiteke gela honetara" + "Edonork" + "Gelarako sarbidea" + "Gelaren helbidea" + "Gelaren izena" + "Gelaren ikusgarritasuna" + "Sortu gela" + "Mintzagaia (aukerakoa)" + "Gelen direktorioa" + "Errorea gertatu da txata hasten saiatzean" + "Sartu…" + "Ez da gela aurkitu" + diff --git a/features/startchat/impl/src/main/res/values-fa/translations.xml b/features/startchat/impl/src/main/res/values-fa/translations.xml new file mode 100644 index 0000000000..03bc5c3f58 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-fa/translations.xml @@ -0,0 +1,28 @@ + + + "اتاق جدید" + "دعوت افراد" + "هنگام ایجاد اتاق خطایی رخ داد" + "تنها افراد دعوت شده می‌توانند به این اتاق دسترسی داشته باشند. همهٔ پیام‌ها رمزنگاری سرتاسری شده‌اند." + "اتاق خصوصی" + "هرکسی می‌تواند اتاق را بیابد. +می‌توانید بعداً در تظیمات اتاق عوضش کنید." + "اتاق عمومی" + "هرکسی می‌تواند به این اتاق بپیوندد" + "هرکسی" + "دسترسی اتاق" + "درخواست دعوت" + "نشانی اتاق" + "نام اتاق" + "نمایانی اتاق" + "ایجاد اتاق" + "موضوع (اختیاری)" + "فهرست اتاق‌ها" + "هنگام تلاش برای شروع چت خطایی روی داد" + "پیوستن به اتاق با نشانی" + "نشانی معتبری نیست" + "ورود…" + "اتاق مطابق پیدا شد" + "اتاق پیدا نشد" + "نمونه: ‪#room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-fi/translations.xml b/features/startchat/impl/src/main/res/values-fi/translations.xml new file mode 100644 index 0000000000..cdb6d04d59 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-fi/translations.xml @@ -0,0 +1,30 @@ + + + "Uusi huone" + "Kutsu ihmisiä" + "Huoneen luomisessa tapahtui virhe" + "Vain kutsutut henkilöt pääsevät tähän huoneeseen. Kaikki viestit ovat päästä päähän salattuja." + "Yksityinen huone" + "Kuka tahansa voi löytää tämän huoneen. +Voit muuttaa tämän milloin tahansa huoneen asetuksista." + "Julkinen huone" + "Kuka tahansa voi liittyä tähän huoneeseen" + "Kuka tahansa" + "Huoneeseen Pääsy" + "Kuka tahansa voi pyytää saada liittyä huoneeseen, mutta ylläpitäjän tai valvojan on hyväksyttävä pyyntö" + "Pyydä liittymistä" + "Jotta tämä huone näkyisi julkisessa huonehakemistossa, tarvitset huoneen osoitteen." + "Huoneen osoite" + "Huoneen nimi" + "Huoneen näkyvyys" + "Luo huone" + "Aihe (valinnainen)" + "Huoneluettelo" + "Keskustelun aloituksessa tapahtui virhe" + "Liity huoneeseen osoitteella" + "Osoite ei ole kelvollinen" + "Syötä…" + "Täsmäävä huone löytyi" + "Huonetta ei löytynyt" + "esim. #huoneen-nimi:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-fr/translations.xml b/features/startchat/impl/src/main/res/values-fr/translations.xml new file mode 100644 index 0000000000..3f9e01dc85 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-fr/translations.xml @@ -0,0 +1,30 @@ + + + "Nouveau salon" + "Inviter des amis" + "Une erreur s’est produite lors de la création du salon" + "Seules les personnes invitées peuvent accéder à ce salon. Tous les messages sont chiffrés de bout en bout." + "Salon privé" + "N’importe qui peut trouver ce salon. +Vous pouvez modifier cela à tout moment dans les paramètres du salon." + "Salon public" + "Tout le monde peut rejoindre ce salon" + "Tout le monde" + "Accès au salon" + "Tout le monde peut demander à rejoindre le salon, mais un administrateur ou un modérateur devra accepter la demande" + "Demander à rejoindre" + "Pour que ce salon soit visible dans le répertoire des salons publics, vous aurez besoin d’une adresse de salon." + "Adresse du salon" + "Nom du salon" + "Visibilité du salon" + "Créer un salon" + "Sujet (facultatif)" + "Annuaire des salons" + "Une erreur s’est produite lors de la tentative de création de la discussion" + "Saisir une adresse de salon" + "Ce n’est pas une adresse valide" + "Saisir…" + "Ce salon existe" + "Salon non trouvé" + "ex: #nom-du-salon:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-hu/translations.xml b/features/startchat/impl/src/main/res/values-hu/translations.xml new file mode 100644 index 0000000000..1e4a721279 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-hu/translations.xml @@ -0,0 +1,30 @@ + + + "Új szoba" + "Ismerősök meghívása" + "Hiba történt a szoba létrehozásakor" + "Csak a meghívottak léphetnek be ebbe a szobába. Az összes üzenet végpontok közti titkosítással van védve." + "Privát szoba" + "Bárki megtalálhatja ezt a szobát. +Ezt bármikor módosíthatja a szobabeállításokban." + "Nyilvános szoba" + "Bárki csatlakozhat ehhez a szobához" + "Bárki" + "Szobahozzáférés" + "Bárki kérheti, hogy csatlakozzon a szobához, de egy adminisztrátornak vagy moderátornak el kell fogadnia a kérést" + "Csatlakozás kérése" + "Ahhoz, hogy ez a szoba látható legyen a nyilvános szobák címtárában, meg kell adnia a szoba címét." + "A szoba címe" + "Szoba neve" + "Szoba láthatósága" + "Szoba létrehozása" + "Téma (nem kötelező)" + "Szobakatalógus" + "Hiba történt a csevegés indításakor" + "Csatlakozás a szobához cím szerint" + "Nem érvényes cím" + "Írja be…" + "Megfelelő szoba található" + "Szoba nem található" + "pl. #szoba-neve:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-in/translations.xml b/features/startchat/impl/src/main/res/values-in/translations.xml new file mode 100644 index 0000000000..65f135e617 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-in/translations.xml @@ -0,0 +1,30 @@ + + + "Ruangan baru" + "Undang orang-orang" + "Terjadi kesalahan saat membuat ruangan" + "Hanya orang-orang yang diundang dapat mengakses ruangan ini. Semua pesan terenkripsi secara ujung ke ujung." + "Ruangan pribadi" + "Siapa pun dapat mencari ruangan ini. +Anda dapat mengubah ini kapan pun dalam pengaturan ruangan." + "Ruangan publik" + "Siapa pun dapat bergabung dengan ruangan ini" + "Siapa pun" + "Akses Ruangan" + "Siapa pun dapat meminta untuk bergabung dengan ruangan tetapi administrator atau moderator harus menerima permintaan tersebut" + "Minta untuk bergabung" + "Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan." + "Alamat ruangan" + "Nama ruangan" + "Keterlihatan ruangan" + "Buat ruangan" + "Topik (opsional)" + "Direktori ruangan" + "Terjadi kesalahan saat mencoba memulai obrolan" + "Bergabung dalam ruangan berdasarkan alamat" + "Bukan alamat yang valid" + "Masuk…" + "Ruangan yang cocok ditemukan" + "Ruangan tidak ditemukan" + "mis. #nama-ruangan:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-it/translations.xml b/features/startchat/impl/src/main/res/values-it/translations.xml new file mode 100644 index 0000000000..701ebc967f --- /dev/null +++ b/features/startchat/impl/src/main/res/values-it/translations.xml @@ -0,0 +1,30 @@ + + + "Nuova stanza" + "Invita persone" + "Si è verificato un errore durante la creazione della stanza" + "Solo le persone invitate possono accedere a questa stanza. Tutti i messaggi sono cifrati end-to-end." + "Stanza privata" + "Chiunque può trovare questa stanza. +Puoi modificarlo in qualsiasi momento nelle impostazioni della stanza." + "Stanza pubblica" + "Chiunque può entrare in questa stanza" + "Chiunque" + "Accesso alla stanza" + "Chiunque può chiedere di entrare nella stanza, ma un amministratore o un moderatore dovrà accettare la richiesta" + "Chiedi di entrare" + "Affinché questa stanza sia visibile nell\'elenco delle stanze pubbliche, è necessario un indirizzo della stanza." + "Indirizzo della stanza" + "Nome stanza" + "Visibilità della stanza" + "Crea una stanza" + "Argomento (facoltativo)" + "Elenco delle stanze" + "Si è verificato un errore durante il tentativo di avviare una chat" + "Accedi alla stanza tramite indirizzo" + "Indirizzo non valido" + "Inserisci…" + "Stanza trovata" + "Stanza non trovata" + "ad esempio #room -name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-ka/translations.xml b/features/startchat/impl/src/main/res/values-ka/translations.xml new file mode 100644 index 0000000000..bb4a430320 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-ka/translations.xml @@ -0,0 +1,15 @@ + + + "ახალი ოთახი" + "ხალხის მოწვევა" + "ოთახის შექმნისას შეცდომა მოხდა" + "ამ ოთახში შეტყობინებები დაშიფრულია. შემდგომ დაშიფვრის გამორთვა შეუძლებელია." + "კერძო ოთახი" + "ყველას ამ ოთახის მოძებნა შეუძლია. +თქვენ ნებისმიერ დროს შეგიძლიათ ამის შეცვლა ოთახის პარამეტრებში." + "ოთახის სახელი" + "ოთახის შექმნა" + "თემა (სურვილისამებრ)" + "ოთახის კატალოგი" + "ჩატის დაწყების მცდელობისას შეცდომა მოხდა" + diff --git a/features/startchat/impl/src/main/res/values-lt/translations.xml b/features/startchat/impl/src/main/res/values-lt/translations.xml new file mode 100644 index 0000000000..2f7a4438ea --- /dev/null +++ b/features/startchat/impl/src/main/res/values-lt/translations.xml @@ -0,0 +1,14 @@ + + + "Naujas kambarys" + "Pakviesti žmonių" + "Kuriant kambarį įvyko klaida" + "Į šį kambarį gali patekti tik pakviesti žmonės. Visi pranešimai yra užšifruoti nuo pradžios iki galo." + "Privatus kambarys" + "Bet kas gali rasti šį kambarį. +Tai galite bet kada pakeisti kambario nustatymuose." + "Kambario pavadinimas" + "Kurti kambarį" + "Tema (nebūtina)" + "Bandant pradėti pokalbį įvyko klaida" + diff --git a/features/startchat/impl/src/main/res/values-nb/translations.xml b/features/startchat/impl/src/main/res/values-nb/translations.xml new file mode 100644 index 0000000000..9266993fd4 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-nb/translations.xml @@ -0,0 +1,30 @@ + + + "Nytt rom" + "Inviter folk" + "Det oppsto en feil under opprettelsen av rommet" + "Bare inviterte personer har tilgang til dette rommet. Alle meldinger er ende-til-ende-kryptert." + "Privat rom" + "Alle kan finne dette rommet. +Du kan endre dette når som helst i rominnstillingene." + "Offentlig rom" + "Alle kan bli med i dette rommet" + "Alle" + "Tilgang til rom" + "Alle kan be om å få bli med i rommet, men en administrator eller moderator må godta forespørselen" + "Be om å bli med" + "For at dette rommet skal være synlig i den offentlige romkatalogen, trenger du en romadresse." + "Romadresse" + "Romnavn" + "Romsynlighet" + "Opprett et rom" + "Emne (valgfritt)" + "Romkatalog" + "Det oppstod en feil når du prøvde å starte en chat" + "Bli med i rommet med adresse" + "Ikke en gyldig adresse" + "Gå inn…" + "Matchende rom funnet" + "Rom ikke funnet" + "f.eks. #rom-navn:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-nl/translations.xml b/features/startchat/impl/src/main/res/values-nl/translations.xml new file mode 100644 index 0000000000..29d070a263 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-nl/translations.xml @@ -0,0 +1,21 @@ + + + "Nieuwe kamer" + "Mensen uitnodigen" + "Er is een fout opgetreden bij het aanmaken van de kamer" + "Alleen uitgenodigde personen hebben toegang tot deze kamer. Alle berichten zijn end-to-end versleuteld." + "Privé kamer" + "Iedereen kan deze kamer vinden. +Je kunt dit op elk gewenst moment wijzigen in de kamerinstellingen." + "Openbare kamer" + "Iedereen kan toetreden tot deze kamer" + "Iedereen" + "Toegang tot de kamer" + "Iedereen kan vragen om toe te treden tot de kamer, maar een beheerder of moderator moet het verzoek accepteren" + "Vraag om toe te treden" + "Naam van de kamer" + "Creëer een kamer" + "Onderwerp (optioneel)" + "Kamergids" + "Er is een fout opgetreden bij het starten van een chat" + diff --git a/features/startchat/impl/src/main/res/values-pl/translations.xml b/features/startchat/impl/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..3ed917b7bb --- /dev/null +++ b/features/startchat/impl/src/main/res/values-pl/translations.xml @@ -0,0 +1,30 @@ + + + "Nowy pokój" + "Zaproś znajomych" + "Wystąpił błąd w trakcie tworzenia pokoju" + "Tylko zaproszone osoby mogą dołączyć do tego pokoju. Wszystkie wiadomości są szyfrowane end-to-end." + "Pokój prywatny" + "Każdy może znaleźć ten pokój. +Możesz to zmienić w ustawieniach pokoju." + "Pokój publiczny" + "Każdy może dołączyć do tego pokoju" + "Wszyscy" + "Dostęp do pokoju" + "Każdy może poprosić o dołączenie do pokoju, ale administrator lub moderator będzie musiał zatwierdzić prośbę" + "Poproś o dołączenie" + "Aby ten pokój był widoczny w katalogu pomieszczeń publicznych, będziesz potrzebował adres pokoju." + "Adres pokoju" + "Nazwa pokoju" + "Widoczność pomieszczenia" + "Utwórz pokój" + "Temat (opcjonalnie)" + "Katalog pokoi" + "Wystąpił błąd podczas próby rozpoczęcia czatu" + "Dołącz do pokoju za pomocą adresu" + "Nieprawidłowy adres" + "Wprowadź…" + "Znaleziono pasujący pokój" + "Nie znaleziono pokoju" + "np. #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml b/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml new file mode 100644 index 0000000000..52c9f569af --- /dev/null +++ b/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml @@ -0,0 +1,30 @@ + + + "Nova sala" + "Convidar pessoas" + "Ocorreu um erro ao criar a sala" + "Apenas as pessoas convidadas podem aceder a esta sala. Todas as mensagens são criptografadas de ponta a ponta." + "Sala privada" + "Qualquer um pode encontrar esta sala. +Você pode mudar isso a qualquer momento nas configurações da sala." + "Sala pública" + "Qualquer pessoa pode entrar nesta sala" + "Qualquer pessoa" + "Acesso à sala" + "Qualquer pessoa pode pedir para entrar na sala, mas um administrador ou moderador terá de aceitar a solicitação" + "Pedir para entrar" + "Para que esta sala fique visível no diretório público de salas, você precisará de um endereço de sala." + "Endereço da sala" + "Nome da sala" + "Visibilidade da sala" + "Criar uma sala" + "Tópico (opcional)" + "Diretório de salas" + "Ocorreu um erro ao tentar iniciar um chat" + "Entrar na sala pelo endereço" + "Não é um endereço válido" + "Entrar…" + "Foi encontrada uma sala correspondente" + "Sala não encontrada" + "Por exemplo, #nome-da-sala:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-pt/translations.xml b/features/startchat/impl/src/main/res/values-pt/translations.xml new file mode 100644 index 0000000000..5e5f5fc9c3 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-pt/translations.xml @@ -0,0 +1,30 @@ + + + "Nova sala" + "Convidar pessoas" + "Ocorreu um erro ao criar a sala" + "Apenas as pessoas convidadas podem aceder a esta sala. Todas as mensagens são cifradas ponta-a-ponta." + "Sala privada" + "Qualquer um pode encontrar esta sala. +Pode alterar esta opção nas definições da sala." + "Sala pública" + "Qualquer pessoa pode entrar nesta sala" + "Qualquer pessoa" + "Acesso à sala" + "Qualquer pessoa pode pedir para entrar na sala, mas um administrador ou um moderador terá de aceitar o pedido" + "Pedir para participar" + "Para que esta sala seja visível no diretório público de salas, precisas de um endereço de sala." + "Endereço da sala" + "Nome da sala" + "Visibilidade da sala" + "Criar uma sala" + "Descrição (opcional)" + "Diretório de salas" + "Ocorreu um erro ao tentar iniciar uma conversa" + "Entrar na sala pelo endereço" + "Não é um endereço válido" + "Entrar…" + "Sala correspondente encontrado" + "Sala não encontrada" + "por exemplo, #sala:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-ro/translations.xml b/features/startchat/impl/src/main/res/values-ro/translations.xml new file mode 100644 index 0000000000..8d9e74b530 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-ro/translations.xml @@ -0,0 +1,22 @@ + + + "Cameră nouă" + "Invitați prieteni" + "A apărut o eroare la crearea camerei" + "Doar persoanele invitate pot accesa această cameră. Toate mesajele sunt criptate end-to-end." + "Cameră privată" + "Oricine poate găsi această cameră. +Puteți modifica acest lucru oricând în setări." + "Cameră publică" + "Oricine se poate alătura acestei camere" + "Oricine" + "Acces la cameră" + "Oricine poate cere să se alăture camerei, dar un administrator sau un moderator va trebui să accepte solicitarea" + "Cereți să vă alăturați" + "Pentru ca această cameră să fie vizibilă în directorul de camere publice, veți avea nevoie de o adresă de cameră." + "Numele camerei" + "Creați o cameră" + "Subiect (opțional)" + "Director de camere" + "A apărut o eroare la încercarea începerii conversației" + diff --git a/features/startchat/impl/src/main/res/values-ru/translations.xml b/features/startchat/impl/src/main/res/values-ru/translations.xml new file mode 100644 index 0000000000..6344491248 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-ru/translations.xml @@ -0,0 +1,30 @@ + + + "Создать новую комнату" + "Пригласить в комнату" + "Произошла ошибка при создании комнаты" + "Доступ в эту комнату имеют только приглашенные пользователи. Все сообщения защищены сквозным шифрованием." + "Частная комната" + "Любой желающий может найти эту комнату. +Вы можете изменить это в любое время в настройках комнаты." + "Общедоступная комната" + "Любой желающий может присоединиться к этой комнате" + "Любой" + "Доступ в комнату" + "Любой желающий может подать заявку на присоединение к комнате, но администратор или модератор должен будет принять запрос." + "Попросить присоединиться" + "Чтобы эта комната была видна в каталоге общедоступных, вам необходим ее адрес" + "Адрес комнаты" + "Название комнаты" + "Видимость комнаты" + "Создать комнату" + "Тема (необязательно)" + "Каталог комнат" + "Произошла ошибка при запуске чата" + "Присоединиться к комнате по адресу" + "Недействительный адрес" + "Ввести…" + "Соответствующая комната найдена" + "Комната не найдена" + "прим. #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-sk/translations.xml b/features/startchat/impl/src/main/res/values-sk/translations.xml new file mode 100644 index 0000000000..eaf6c2f19c --- /dev/null +++ b/features/startchat/impl/src/main/res/values-sk/translations.xml @@ -0,0 +1,30 @@ + + + "Nová miestnosť" + "Pozvať ľudí" + "Pri vytváraní miestnosti došlo k chybe" + "Do tejto miestnosti majú prístup iba pozvaní ľudia. Všetky správy sú end-to-end šifrované." + "Súkromná miestnosť" + "Túto miestnosť môže nájsť ktokoľvek. +Môžete to kedykoľvek zmeniť v nastaveniach miestnosti." + "Verejná miestnosť" + "Do tejto miestnosti sa môže pripojiť ktokoľvek" + "Ktokoľvek" + "Prístup do miestnosti" + "Ktokoľvek môže požiadať o pripojenie sa k miestnosti, ale administrátor alebo moderátor bude musieť žiadosť schváliť" + "Požiadať o pripojenie" + "Aby bola táto miestnosť viditeľná v adresári verejných miestností, budete potrebovať adresu miestnosti." + "Adresa miestnosti" + "Názov miestnosti" + "Viditeľnosť miestnosti" + "Vytvoriť miestnosť" + "Téma (voliteľné)" + "Adresár miestností" + "Pri pokuse o spustenie konverzácie sa vyskytla chyba" + "Pripojte sa do miestnosti podľa adresy" + "Neplatná adresa" + "Zadajte…" + "Nájdená zodpovedajúca miestnosť" + "Miestnosť sa nenašla" + "napr. #nazov-miestnosti:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-sv/translations.xml b/features/startchat/impl/src/main/res/values-sv/translations.xml new file mode 100644 index 0000000000..316c9cc32e --- /dev/null +++ b/features/startchat/impl/src/main/res/values-sv/translations.xml @@ -0,0 +1,30 @@ + + + "Nytt rum" + "Bjud in personer" + "Ett fel uppstod när rummet skapades" + "Endast inbjudna personer har tillgång till detta rum. Alla meddelanden är totalsträckskrypterade." + "Privat rum" + "Vem som helst kan hitta det här rummet. +Du kan ändra detta när som helst i rumsinställningarna." + "Offentligt rum" + "Vem som helst kan gå med i det här rummet" + "Vem som helst" + "Rumsåtkomst" + "Vem som helst kan be om att gå med i rummet men en administratör eller en moderator måste acceptera begäran" + "Be om att gå med" + "För att detta rum ska vara synligt i den allmänna rumskatalogen behöver du en rumsadress." + "Rumsadress" + "Rumsnamn" + "Rumssynlighet" + "Skapa ett rum" + "Ämne (valfritt)" + "Rumskatalog" + "Ett fel uppstod när du försökte starta en chatt" + "Gå med i rum med adress" + "Inte en giltig adress" + "Ange …" + "Matchande rum hittades" + "Rummet hittades inte" + "t.ex. #rumsnamn:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-tr/translations.xml b/features/startchat/impl/src/main/res/values-tr/translations.xml new file mode 100644 index 0000000000..c8e3136517 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-tr/translations.xml @@ -0,0 +1,24 @@ + + + "Yeni oda" + "İnsanları davet et" + "Oda oluşturulurken bir hata oluştu" + "Bu odaya yalnızca davet edilen kişiler erişebilir. Tüm mesajlar uçtan uca şifrelenir." + "Özel oda" + "Bu odayı herkes bulabilir. +Bunu istediğiniz zaman oda ayarlarından değiştirebilirsiniz." + "Herkese açık oda" + "Bu odaya herkes katılabilir" + "Herkes" + "Oda Erişimi" + "Herkes odaya katılmayı isteyebilir ancak bir yönetici veya moderatörün isteği kabul etmesi gerekecektir" + "Katılmak için sor" + "Bu odanın genel oda dizininde görünür olması için bir oda adresine ihtiyacınız olacaktır." + "Oda adresi" + "Oda adı" + "Oda görünürlüğü" + "Bir oda oluştur" + "Konu (isteğe bağlı)" + "Oda dizini" + "Sohbet başlatmaya çalışırken bir hata oluştu" + diff --git a/features/startchat/impl/src/main/res/values-uk/translations.xml b/features/startchat/impl/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..a43172fb8b --- /dev/null +++ b/features/startchat/impl/src/main/res/values-uk/translations.xml @@ -0,0 +1,30 @@ + + + "Нова кімната" + "Запросити людей" + "Під час створення кімнати сталася помилка" + "Лише запрошені люди мають доступ до цієї кімнати. Усі повідомлення захищені наскрізним шифруванням." + "Приватна кімната (тільки за запрошенням)" + "Будь-хто може знайти цю кімнату. +Ви можете змінити це в будь-який час у налаштуваннях кімнати." + "Загальнодоступна кімната" + "Будь-хто може приєднатися до цієї кімнати" + "Кожний" + "Доступ до кімнати" + "Будь-хто може попросити приєднатися до кімнати, але адміністратор або модератор повинен буде прийняти запит" + "Запросити приєднатися" + "Щоб цю кімнату було видно в каталозі загальнодоступних кімнат, вам знадобиться її адреса." + "Адреса кімнати" + "Назва кімнати" + "Видимість кімнати" + "Створити кімнату" + "Тема (необов\'язково)" + "Каталог кімнат" + "Під час спроби почати бесіду сталася помилка" + "Приєднатися до кімнати за адресою" + "Недійсна адреса" + "Введіть…" + "Знайдено відповідну кімнату" + "Кімната не знайдена" + "наприклад, #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-ur/translations.xml b/features/startchat/impl/src/main/res/values-ur/translations.xml new file mode 100644 index 0000000000..6fe476462e --- /dev/null +++ b/features/startchat/impl/src/main/res/values-ur/translations.xml @@ -0,0 +1,16 @@ + + + "نیا کمرہ" + "لوگوں کو مدعو کریں" + "کمرہ تخلیق کرتے ہوئے ایک نقص واقع ہوا" + "صرف مدعو لوگ ہی اس کمرے تک رسائی حاصل کر سکتے ہیں۔ تمام پیغامات آخر تا آخر مرموز کردہ ہیں۔" + "نجی کمرہ" + "کوئی بھی یہ کمرہ ڈھونڈ سکتا ہے۔ +آپ اسے کمرے کی ترتیبات میں کسی بھی وقت تبدیل کرسکتے ہیں۔" + "عوامی کمرہ" + "کمرے کا نام" + "ایک کمرہ بنائیں" + "موضوع (اختیاری)" + "کمرے کا راہنامچہ" + "گفتگو شروع کرنے کی کوشش کرتے وقت ایک خرابی واقع ہوگئی" + diff --git a/features/startchat/impl/src/main/res/values-uz/translations.xml b/features/startchat/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..e3bc9de528 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,13 @@ + + + "Yangi xona" + "Odamlarni taklif qiling" + "Xonani yaratishda xatolik yuz berdi" + "Bu xonadagi xabarlar shifrlangan. Keyinchalik shifrlashni o‘chirib bo‘lmaydi." + "Shaxsiy xona (faqat taklif)" + "Xabarlar shifrlanmagan va har kim ularni o\'qiy oladi. Keyinchalik shifrlashni yoqishingiz mumkin." + "Xona nomi" + "Xonani yaratish" + "Mavzu (ixtiyoriy)" + "Suhbatni boshlashda xatolik yuz berdi" + diff --git a/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml b/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml new file mode 100644 index 0000000000..0d67c883c7 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml @@ -0,0 +1,30 @@ + + + "建立聊天室" + "邀請夥伴" + "建立聊天室時發生錯誤" + "僅被邀請的人才能存取此聊天室。所有訊息均會端到端加密。" + "私密聊天室" + "任何人都可以找到此聊天室。 +您隨時都可以在聊天室設定中變更此設定。" + "公開的聊天室" + "任何人都可以加入此聊天室" + "任何人" + "聊天室存取權" + "任何人都可以要求加入聊天室,但管理員或版主必須接受該請求" + "要求加入" + "為了讓此聊天室在公開聊天室目錄中可見,您需要聊天室地址。" + "聊天室地址" + "聊天室名稱" + "聊天室能見度" + "建立聊天室" + "主題(非必填)" + "聊天室目錄" + "嘗試開始聊天時發生錯誤" + "按地址加入聊天室" + "不是有效的位址" + "輸入……" + "找到相符的聊天室" + "找不到聊天室" + "例如 #room-name:matrix.org" + diff --git a/features/startchat/impl/src/main/res/values-zh/translations.xml b/features/startchat/impl/src/main/res/values-zh/translations.xml new file mode 100644 index 0000000000..24d7df7f35 --- /dev/null +++ b/features/startchat/impl/src/main/res/values-zh/translations.xml @@ -0,0 +1,24 @@ + + + "新聊天室" + "邀请朋友" + "创建聊天室时出错" + "只有受邀用户才能访问此聊天室。所有消息均经过端到端加密。" + "私有聊天室" + "任何人都能找到此聊天室。 +你可以随时在聊天室设置中更改。" + "公共聊天室" + "任何人都可以加入此房间" + "任何人" + "房间访问权限" + "任何人都可以请求加入房间,但必须由管理员或审核人接受" + "请求加入" + "要使该房间在公开房间目录中可见,您需要一个房间地址。" + "房间地址" + "聊天室名称" + "房间可见性" + "创建聊天室" + "主题(可选)" + "聊天室目录" + "在开始聊天时发生了错误" + diff --git a/features/startchat/impl/src/main/res/values/localazy.xml b/features/startchat/impl/src/main/res/values/localazy.xml new file mode 100644 index 0000000000..d011a1d87b --- /dev/null +++ b/features/startchat/impl/src/main/res/values/localazy.xml @@ -0,0 +1,30 @@ + + + "New room" + "Invite people" + "An error occurred when creating the room" + "Only people invited can access this room. All messages are end-to-end encrypted." + "Private room" + "Anyone can find this room. +You can change this anytime in room settings." + "Public room" + "Anyone can join this room" + "Anyone" + "Room Access" + "Anyone can ask to join the room but an administrator or a moderator will have to accept the request" + "Ask to join" + "In order for this room to be visible in the public room directory, you will need a room address." + "Room address" + "Room name" + "Room visibility" + "Create a room" + "Topic (optional)" + "Room directory" + "An error occurred when trying to start a chat" + "Join room by address" + "Not a valid address" + "Enter…" + "Matching room found" + "Room not found" + "e.g. #room-name:matrix.org" + diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/DefaultStartDMActionTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/DefaultStartDMActionTest.kt similarity index 97% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/DefaultStartDMActionTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/DefaultStartDMActionTest.kt index ef6b3b9517..fa6e140c3a 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/DefaultStartDMActionTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/DefaultStartDMActionTest.kt @@ -5,12 +5,12 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl +package io.element.android.features.startchat.impl import androidx.compose.runtime.mutableStateOf import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/FakeCreateRoomNavigator.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt similarity index 86% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/FakeCreateRoomNavigator.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt index 28dcdd409d..2cc0f08ea9 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/FakeCreateRoomNavigator.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt @@ -5,18 +5,18 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl +package io.element.android.features.startchat.impl -import io.element.android.features.createroom.CreateRoomNavigator +import io.element.android.features.invitepeople.StartChatNavigator import io.element.android.libraries.matrix.api.core.RoomIdOrAlias -class FakeCreateRoomNavigator( +class FakeStartChatNavigator( private val openRoomLambda: (roomIdOrAlias: RoomIdOrAlias, serverNames: List) -> Unit = { _, _ -> }, private val createNewRoomLambda: () -> Unit = {}, private val showJoinRoomByAddressLambda: () -> Unit = {}, private val dismissJoinRoomByAddressLambda: () -> Unit = {}, private val openRoomDirectoryLambda: () -> Unit = {}, -) : CreateRoomNavigator { +) : StartChatNavigator { override fun onOpenRoom(roomIdOrAlias: RoomIdOrAlias, serverNames: List) { openRoomLambda(roomIdOrAlias, serverNames) } diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenterTest.kt similarity index 79% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenterTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenterTest.kt index acb381dadc..d5742b2a26 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeoplePresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenterTest.kt @@ -1,19 +1,19 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.addpeople +package io.element.android.features.startchat.impl.addpeople 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.createroom.impl.CreateRoomDataStore -import io.element.android.features.createroom.impl.userlist.FakeUserListPresenterFactory -import io.element.android.features.createroom.impl.userlist.UserListDataStore +import io.element.android.features.invitepeople.impl.CreateRoomDataStore +import io.element.android.features.startchat.impl.userlist.FakeUserListPresenterFactory +import io.element.android.features.invitepeople.impl.userlist.UserListDataStore import io.element.android.libraries.matrix.test.room.alias.FakeRoomAliasHelper import io.element.android.libraries.usersearch.test.FakeUserRepository import io.element.android.tests.testutils.WarmUpRule diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleViewTest.kt similarity index 89% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleViewTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleViewTest.kt index c18abf0daa..9d8af8d61d 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleViewTest.kt @@ -5,15 +5,15 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.addpeople +package io.element.android.features.startchat.impl.addpeople import androidx.activity.ComponentActivity import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.features.createroom.impl.userlist.UserListEvents -import io.element.android.features.createroom.impl.userlist.UserListState -import io.element.android.features.createroom.impl.userlist.aUserListState +import io.element.android.features.invitepeople.impl.userlist.UserListEvents +import io.element.android.features.invitepeople.impl.userlist.UserListState +import io.element.android.features.invitepeople.impl.userlist.aUserListState import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder @@ -83,7 +83,7 @@ private fun AndroidComposeTestRule.setAddPe AddPeopleView( state = state, onBackClick = onBackClick, - onNextClick = onNextClick, + onSkipClick = onNextClick, ) } } diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureBaseRoomPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureBaseRoomPresenterTest.kt similarity index 98% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureBaseRoomPresenterTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureBaseRoomPresenterTest.kt index 8c8ba7ca58..8eab477f1a 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureBaseRoomPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureBaseRoomPresenterTest.kt @@ -5,15 +5,15 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.configureroom +package io.element.android.features.startchat.impl.configureroom import android.net.Uri import app.cash.turbine.TurbineTestContext import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.createroom.impl.CreateRoomConfig -import io.element.android.features.createroom.impl.CreateRoomDataStore -import io.element.android.features.createroom.impl.userlist.UserListDataStore +import io.element.android.features.invitepeople.impl.CreateRoomConfig +import io.element.android.features.invitepeople.impl.CreateRoomDataStore +import io.element.android.features.invitepeople.impl.userlist.UserListDataStore import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt similarity index 93% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt index 10cca20fa3..e477c07f60 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt @@ -5,11 +5,11 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import com.google.common.truth.Truth.assertThat -import io.element.android.features.createroom.CreateRoomNavigator -import io.element.android.features.createroom.impl.FakeCreateRoomNavigator +import io.element.android.features.invitepeople.StartChatNavigator +import io.element.android.features.startchat.impl.FakeStartChatNavigator import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomIdOrAlias import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper @@ -61,7 +61,7 @@ class JoinBaseRoomByAddressPresenterTest { fun `present - room found`() = runTest { val openRoomLambda = lambdaRecorder, Unit> { _, _ -> } val dismissJoinRoomByAddressLambda = lambdaRecorder { } - val navigator = FakeCreateRoomNavigator( + val navigator = FakeStartChatNavigator( openRoomLambda = openRoomLambda, dismissJoinRoomByAddressLambda = dismissJoinRoomByAddressLambda ) @@ -114,7 +114,7 @@ class JoinBaseRoomByAddressPresenterTest { @Test fun `present - dismiss`() = runTest { val dismissJoinRoomByAddressLambda = lambdaRecorder { } - val navigator = FakeCreateRoomNavigator( + val navigator = FakeStartChatNavigator( dismissJoinRoomByAddressLambda = dismissJoinRoomByAddressLambda ) val presenter = createJoinRoomByAddressPresenter(navigator = navigator) @@ -127,7 +127,7 @@ class JoinBaseRoomByAddressPresenterTest { } private fun createJoinRoomByAddressPresenter( - navigator: CreateRoomNavigator = FakeCreateRoomNavigator(), + navigator: StartChatNavigator = FakeStartChatNavigator(), matrixClient: MatrixClient = FakeMatrixClient(), roomAliasHelper: RoomAliasHelper = FakeRoomAliasHelper(), ): JoinRoomByAddressPresenter { diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt similarity index 94% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt index b2e75c9f5a..195ca55081 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.joinbyaddress +package io.element.android.features.startchat.impl.joinbyaddress import androidx.activity.ComponentActivity import androidx.compose.ui.test.junit4.AndroidComposeTestRule @@ -13,7 +13,7 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performTextInput import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.features.createroom.impl.R +import io.element.android.features.invitepeople.impl.R import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootPresenterTest.kt similarity index 87% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootPresenterTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootPresenterTest.kt index d2d9959e2a..9c2d2ac1ef 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootPresenterTest.kt @@ -1,23 +1,23 @@ /* - * 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. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.compose.runtime.MutableState 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.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.api.StartDMAction -import io.element.android.features.createroom.impl.userlist.FakeUserListPresenter -import io.element.android.features.createroom.impl.userlist.FakeUserListPresenterFactory -import io.element.android.features.createroom.impl.userlist.UserListDataStore -import io.element.android.features.createroom.test.FakeStartDMAction +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.StartDMAction +import io.element.android.features.startchat.impl.userlist.FakeUserListPresenter +import io.element.android.features.startchat.impl.userlist.FakeUserListPresenterFactory +import io.element.android.features.invitepeople.impl.userlist.UserListDataStore +import io.element.android.features.invitepeople.test.FakeStartDMAction import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService @@ -58,7 +58,7 @@ class CreateBaseRoomRootPresenterTest { assertThat(initialState.userListState.isSearchActive).isFalse() assertThat(initialState.userListState.isMultiSelectionEnabled).isFalse() val matrixUser = MatrixUser(UserId("@name:domain")) - initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + initialState.eventSink(StartChatEvents.StartDM(matrixUser)) awaitItem().also { state -> assertThat(state.startDmAction).isEqualTo(startDMFailureResult) executeResult.assertions().isCalledOnce().with( @@ -66,7 +66,7 @@ class CreateBaseRoomRootPresenterTest { value(false), any(), ) - state.eventSink(CreateRoomRootEvents.CancelStartDM) + state.eventSink(StartChatEvents.CancelStartDM) } awaitItem().also { state -> assertThat(state.startDmAction.isUninitialized()).isTrue() @@ -92,7 +92,7 @@ class CreateBaseRoomRootPresenterTest { assertThat(initialState.userListState.isSearchActive).isFalse() assertThat(initialState.userListState.isMultiSelectionEnabled).isFalse() val matrixUser = MatrixUser(UserId("@name:domain")) - initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + initialState.eventSink(StartChatEvents.StartDM(matrixUser)) awaitItem().also { state -> assertThat(state.startDmAction).isEqualTo(startDMSuccessResult) executeResult.assertions().isCalledOnce().with( @@ -118,7 +118,7 @@ class CreateBaseRoomRootPresenterTest { }.test { val initialState = awaitItem() assertThat(initialState.startDmAction).isInstanceOf(AsyncAction.Uninitialized::class.java) - initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + initialState.eventSink(StartChatEvents.StartDM(matrixUser)) val confirmingState = awaitItem() assertThat(confirmingState.startDmAction).isEqualTo(startDMConfirmationResult) executeResult.assertions().isCalledOnce().with( @@ -127,7 +127,7 @@ class CreateBaseRoomRootPresenterTest { any(), ) // Cancelling should not create the DM - confirmingState.eventSink(CreateRoomRootEvents.CancelStartDM) + confirmingState.eventSink(StartChatEvents.CancelStartDM) val finalState = awaitItem() assertThat(finalState.startDmAction.isUninitialized()).isTrue() executeResult.assertions().isCalledExactly(1) @@ -148,7 +148,7 @@ class CreateBaseRoomRootPresenterTest { }.test { val initialState = awaitItem() assertThat(initialState.startDmAction).isInstanceOf(AsyncAction.Uninitialized::class.java) - initialState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + initialState.eventSink(StartChatEvents.StartDM(matrixUser)) val confirmingState = awaitItem() assertThat(confirmingState.startDmAction).isEqualTo(startDMConfirmationResult) executeResult.assertions().isCalledOnce().with( @@ -157,7 +157,7 @@ class CreateBaseRoomRootPresenterTest { any(), ) // Start DM again should invoke the action with createIfDmDoesNotExist = true - confirmingState.eventSink(CreateRoomRootEvents.StartDM(matrixUser)) + confirmingState.eventSink(StartChatEvents.StartDM(matrixUser)) executeResult.assertions().isCalledExactly(2).withSequence( listOf(value(matrixUser), value(false), any()), listOf(value(matrixUser), value(true), any()), @@ -181,13 +181,13 @@ class CreateBaseRoomRootPresenterTest { private fun createCreateRoomRootPresenter( startDMAction: StartDMAction = FakeStartDMAction(), isRoomDirectorySearchEnabled: Boolean = false, - ): CreateRoomRootPresenter { + ): StartChatPresenter { val featureFlagService = FakeFeatureFlagService( initialState = mapOf( FeatureFlags.RoomDirectorySearch.key to isRoomDirectorySearchEnabled, ), ) - return CreateRoomRootPresenter( + return StartChatPresenter( presenterFactory = FakeUserListPresenterFactory(FakeUserListPresenter()), userRepository = FakeUserRepository(), userListDataStore = UserListDataStore(), diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootViewTest.kt similarity index 85% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootViewTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootViewTest.kt index 9104b2dfb2..81f764dd59 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateBaseRoomRootViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootViewTest.kt @@ -1,11 +1,11 @@ /* - * Copyright 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. */ -package io.element.android.features.createroom.impl.root +package io.element.android.features.startchat.impl.root import androidx.activity.ComponentActivity import androidx.compose.ui.test.junit4.AndroidComposeTestRule @@ -13,9 +13,9 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.features.createroom.impl.R -import io.element.android.features.createroom.impl.userlist.aRecentDirectRoomList -import io.element.android.features.createroom.impl.userlist.aUserListState +import io.element.android.features.invitepeople.impl.R +import io.element.android.features.invitepeople.impl.userlist.aRecentDirectRoomList +import io.element.android.features.invitepeople.impl.userlist.aUserListState import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.ui.strings.CommonStrings @@ -31,6 +31,7 @@ import org.junit.Test import org.junit.rules.TestRule import org.junit.runner.RunWith import org.robolectric.annotation.Config +import kotlin.collections.get @RunWith(AndroidJUnit4::class) class CreateBaseRoomRootViewTest { @@ -39,7 +40,7 @@ class CreateBaseRoomRootViewTest { @Test fun `clicking on back invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { rule.setCreateRoomRootView( aCreateRoomRootState( @@ -53,7 +54,7 @@ class CreateBaseRoomRootViewTest { @Test fun `clicking on New room invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { rule.setCreateRoomRootView( aCreateRoomRootState( @@ -68,7 +69,7 @@ class CreateBaseRoomRootViewTest { @Config(qualifiers = "h1024dp") @Test fun `clicking on Invite people invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { rule.setCreateRoomRootView( aCreateRoomRootState( @@ -87,7 +88,7 @@ class CreateBaseRoomRootViewTest { fun `clicking on a user suggestion invokes the expected callback`() { val recentDirectRoomList = aRecentDirectRoomList() val firstRoom = recentDirectRoomList[0] - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnceWithParam(firstRoom.roomId) { rule.setCreateRoomRootView( aCreateRoomRootState( @@ -105,7 +106,7 @@ class CreateBaseRoomRootViewTest { @Config(qualifiers = "h1024dp") @Test fun `clicking on Join room by address invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { rule.setCreateRoomRootView( aCreateRoomRootState( @@ -119,7 +120,7 @@ class CreateBaseRoomRootViewTest { @Test fun `clicking on room directory invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) + val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { rule.setCreateRoomRootView( aCreateRoomRootState( @@ -134,7 +135,7 @@ class CreateBaseRoomRootViewTest { } private fun AndroidComposeTestRule.setCreateRoomRootView( - state: CreateRoomRootState, + state: StartChatState, onCloseClick: () -> Unit = EnsureNeverCalled(), onNewRoomClick: () -> Unit = EnsureNeverCalled(), onOpenDM: (RoomId) -> Unit = EnsureNeverCalledWithParam(), diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenterTest.kt similarity index 99% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenterTest.kt index ac793a247f..50bbc425c2 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/DefaultUserListPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/DefaultUserListPresenterTest.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenter.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenter.kt similarity index 89% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenter.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenter.kt index a0768ffda8..84c4fd9d67 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenter.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenter.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import androidx.compose.runtime.Composable diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenterFactory.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenterFactory.kt similarity index 91% rename from features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenterFactory.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenterFactory.kt index 123a013670..8e80626e86 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/userlist/FakeUserListPresenterFactory.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/userlist/FakeUserListPresenterFactory.kt @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.impl.userlist +package io.element.android.features.startchat.impl.userlist import io.element.android.libraries.usersearch.api.UserRepository diff --git a/features/createroom/test/build.gradle.kts b/features/startchat/test/build.gradle.kts similarity index 83% rename from features/createroom/test/build.gradle.kts rename to features/startchat/test/build.gradle.kts index b7df0caab6..96b05a80fa 100644 --- a/features/createroom/test/build.gradle.kts +++ b/features/startchat/test/build.gradle.kts @@ -10,7 +10,7 @@ plugins { } android { - namespace = "io.element.android.features.createroom.test" + namespace = "io.element.android.features.invitepeople.test" } dependencies { @@ -19,5 +19,5 @@ dependencies { implementation(projects.libraries.matrix.test) implementation(projects.libraries.architecture) implementation(projects.tests.testutils) - api(projects.features.createroom.api) + api(projects.features.startchat.api) } diff --git a/features/createroom/test/src/main/kotlin/io/element/android/features/createroom/test/FakeStartDMAction.kt b/features/startchat/test/src/main/kotlin/io/element/android/features/invitepeople/test/FakeStartDMAction.kt similarity index 88% rename from features/createroom/test/src/main/kotlin/io/element/android/features/createroom/test/FakeStartDMAction.kt rename to features/startchat/test/src/main/kotlin/io/element/android/features/invitepeople/test/FakeStartDMAction.kt index 90e2ecf1c1..d7ab63d0e3 100644 --- a/features/createroom/test/src/main/kotlin/io/element/android/features/createroom/test/FakeStartDMAction.kt +++ b/features/startchat/test/src/main/kotlin/io/element/android/features/invitepeople/test/FakeStartDMAction.kt @@ -5,10 +5,10 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.createroom.test +package io.element.android.features.invitepeople.test import androidx.compose.runtime.MutableState -import io.element.android.features.createroom.api.StartDMAction +import io.element.android.features.startchat.api.StartDMAction import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.user.MatrixUser diff --git a/features/userprofile/impl/build.gradle.kts b/features/userprofile/impl/build.gradle.kts index 4242efcb98..7bcebae565 100644 --- a/features/userprofile/impl/build.gradle.kts +++ b/features/userprofile/impl/build.gradle.kts @@ -38,7 +38,7 @@ dependencies { api(projects.features.userprofile.api) api(projects.features.userprofile.shared) implementation(libs.coil.compose) - implementation(projects.features.createroom.api) + implementation(projects.features.startchat.api) implementation(projects.services.analytics.api) testImplementation(libs.test.junit) @@ -49,7 +49,7 @@ dependencies { testImplementation(libs.test.mockk) testImplementation(libs.test.robolectric) testImplementation(projects.libraries.matrix.test) - testImplementation(projects.features.createroom.test) + testImplementation(projects.features.startchat.test) testImplementation(projects.features.enterprise.test) testImplementation(projects.tests.testutils) testImplementation(libs.androidx.compose.ui.test.junit) diff --git a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt index 4de79b8375..6f696d9cdf 100644 --- a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt +++ b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt @@ -20,7 +20,7 @@ import androidx.compose.runtime.setValue import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import io.element.android.features.createroom.api.StartDMAction +import io.element.android.features.startchat.api.StartDMAction import io.element.android.features.enterprise.api.SessionEnterpriseService import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState 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 2ce7f99c2c..e86c66bc4f 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 @@ -13,9 +13,9 @@ import app.cash.molecule.moleculeFlow import app.cash.turbine.ReceiveTurbine import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser -import io.element.android.features.createroom.api.StartDMAction -import io.element.android.features.createroom.test.FakeStartDMAction +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.StartDMAction +import io.element.android.features.invitepeople.test.FakeStartDMAction import io.element.android.features.enterprise.test.FakeSessionEnterpriseService import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState diff --git a/features/userprofile/shared/build.gradle.kts b/features/userprofile/shared/build.gradle.kts index 0b14ce63f2..53e8e9dee2 100644 --- a/features/userprofile/shared/build.gradle.kts +++ b/features/userprofile/shared/build.gradle.kts @@ -39,7 +39,7 @@ dependencies { api(projects.features.userprofile.api) api(projects.services.apperror.api) implementation(libs.coil.compose) - implementation(projects.features.createroom.api) + implementation(projects.features.startchat.api) implementation(projects.services.analytics.api) testImplementation(libs.test.junit) diff --git a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileStateProvider.kt b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileStateProvider.kt index 7a5cc53239..25cb8a5df6 100644 --- a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileStateProvider.kt +++ b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileStateProvider.kt @@ -8,7 +8,7 @@ package io.element.android.features.userprofile.shared import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileVerificationState diff --git a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileView.kt b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileView.kt index a43478e466..f39cbfaf73 100644 --- a/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileView.kt +++ b/features/userprofile/shared/src/main/kotlin/io/element/android/features/userprofile/shared/UserProfileView.kt @@ -21,7 +21,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.tokens.generated.CompoundIcons -import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser +import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileVerificationState diff --git a/tools/localazy/config.json b/tools/localazy/config.json index 1f0d291d0b..923113cd39 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -65,6 +65,16 @@ "screen_room_directory_search_title*" ] }, + { + "name" : ":features:startchat:impl", + "includeRegex" : [ + "screen_create_room_.*", + "screen\\.create_room\\..*", + "screen_start_chat_.*", + "screen\\.start_chat\\..*", + "screen_room_directory_search_title*" + ] + }, { "name" : ":features:verifysession:impl", "includeRegex" : [ From 50073389c48c36025fe1f4358b6ce1e9f6971fba Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 8 Aug 2025 17:20:32 +0200 Subject: [PATCH 02/30] refactor (start chat) : create invite people module and start branching them --- features/createroom/impl/build.gradle.kts | 3 +- .../createroom/impl/CreateRoomFlowNode.kt | 28 ++- .../impl/DefaultCreateRoomEntryPoint.kt | 3 + .../impl/addpeople/AddPeopleNode.kt | 37 ++- .../impl/configureroom/ConfigureRoomNode.kt | 15 +- features/invitepeople/api/build.gradle.kts | 2 +- .../invitepeople/api/InvitePeopleEvents.kt | 12 + .../invitepeople/api/InvitePeoplePresenter.kt | 12 +- .../invitepeople/api/InvitePeopleRenderer.kt | 5 +- .../invitepeople/api/InvitePeopleState.kt | 4 +- features/invitepeople/impl/build.gradle.kts | 15 +- .../impl/DefaultInvitePeopleEvents.kt | 17 ++ .../impl/DefaultInvitePeoplePresenter.kt | 168 +++++++++++++ .../impl/DefaultInvitePeopleRenderer.kt | 33 +++ .../impl/DefaultInvitePeopleState.kt | 24 ++ .../impl/DefaultInvitePeopleStateProvider.kt | 89 +++++++ .../invitepeople/impl/InvitableUser.kt | 18 ++ .../invitepeople/impl/InvitePeopleView.kt | 227 ++++++++++++++++++ features/startchat/impl/build.gradle.kts | 1 + .../startchat/impl/StartChatFlowNode.kt | 4 +- .../matrix/api/room/FilterRoomMembers.kt | 32 +++ 21 files changed, 717 insertions(+), 32 deletions(-) create mode 100644 features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt create mode 100644 features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt create mode 100644 features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt create mode 100644 features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt create mode 100644 features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt create mode 100644 features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt create mode 100644 features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitableUser.kt create mode 100644 features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt create mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/FilterRoomMembers.kt diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index dfc503dfbf..d047fb7bc4 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -23,7 +23,7 @@ android { } } -setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP) +setupAnvil() dependencies { implementation(projects.libraries.core) @@ -41,6 +41,7 @@ dependencies { implementation(projects.services.analytics.api) implementation(libs.coil.compose) implementation(projects.libraries.featureflag.api) + implementation(projects.features.invitepeople.api) api(projects.features.createroom.api) testImplementation(libs.test.junit) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt index f1628e754b..7d0d556e18 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt @@ -8,25 +8,32 @@ package io.element.android.features.createroom.impl import android.os.Parcelable +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.createroom.impl.addpeople.AddPeopleNode import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode +import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId +import kotlinx.coroutines.runBlocking import kotlinx.parcelize.Parcelize @ContributesNode(SessionScope::class) class CreateRoomFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, + private val client: MatrixClient, ) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.ConfigureRoom, @@ -35,13 +42,30 @@ class CreateRoomFlowNode @AssistedInject constructor( buildContext = buildContext, plugins = plugins ) { + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { - NavTarget.ConfigureRoom -> createNode(buildContext) - is NavTarget.AddPeople -> createNode(buildContext) + NavTarget.ConfigureRoom -> { + val callback = object : ConfigureRoomNode.Callback { + override fun onCreateRoomSuccess(roomId: RoomId) { + backstack.push(NavTarget.AddPeople(roomId)) + } + } + createNode(buildContext, plugins = listOf(callback)) + } + is NavTarget.AddPeople -> { + val joinedRoom = runBlocking { client.getJoinedRoom(navTarget.roomId) } ?: error("Room not found") + val inputs = AddPeopleNode.Inputs(joinedRoom) + createNode(buildContext, plugins = listOf(inputs)) + } } } + @Composable + override fun View(modifier: Modifier) { + BackstackView() + } + sealed interface NavTarget : Parcelable { @Parcelize data object ConfigureRoom : NavTarget diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt index 33854be08e..95f80cdfcf 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt @@ -9,10 +9,13 @@ package io.element.android.features.createroom.impl import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node +import com.squareup.anvil.annotations.ContributesBinding import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.SessionScope import javax.inject.Inject +@ContributesBinding(SessionScope::class) class DefaultCreateRoomEntryPoint @Inject constructor(): CreateRoomEntryPoint { override fun createNode(parentNode: Node, buildContext: BuildContext): Node { return parentNode.createNode(buildContext) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt index df215c005e..914c316e1c 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt @@ -7,11 +7,40 @@ package io.element.android.features.createroom.impl.addpeople +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.squareup.anvil.annotations.ContributesBinding +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.invitepeople.api.InvitePeoplePresenter +import io.element.android.features.invitepeople.api.InvitePeopleRenderer +import io.element.android.libraries.architecture.NodeInputs +import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.room.JoinedRoom -class AddPeopleNode( - buildContext: BuildContext, - plugins: List, -) : Node(buildContext, plugins = plugins) +@ContributesNode(SessionScope::class) +class AddPeopleNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val invitePeoplePresenterFactory: InvitePeoplePresenter.Factory, + private val invitePeopleRenderer: InvitePeopleRenderer, +) : Node(buildContext, plugins = plugins) { + + data class Inputs( + val joinedRoom: JoinedRoom + ): NodeInputs + + private val joinedRoom = inputs().joinedRoom + private val invitePeoplePresenter = invitePeoplePresenterFactory.create(joinedRoom) + + @Composable + override fun View(modifier: Modifier) { + val state = invitePeoplePresenter.present() + invitePeopleRenderer.Render(state, Modifier) + } +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt index fcc85afcb7..e566a4d970 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt @@ -13,11 +13,14 @@ import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode +import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.services.analytics.api.AnalyticsService @ContributesNode(SessionScope::class) @@ -28,6 +31,10 @@ class ConfigureRoomNode @AssistedInject constructor( private val analyticsService: AnalyticsService, ) : Node(buildContext, plugins = plugins) { + interface Callback: Plugin { + fun onCreateRoomSuccess(roomId: RoomId) + } + init { lifecycle.subscribe( onResume = { @@ -36,6 +43,10 @@ class ConfigureRoomNode @AssistedInject constructor( ) } + private fun onCreateRoomSuccess(roomId: RoomId){ + plugins().forEach { it.onCreateRoomSuccess(roomId) } + } + @Composable override fun View(modifier: Modifier) { val state = presenter.present() @@ -43,9 +54,7 @@ class ConfigureRoomNode @AssistedInject constructor( state = state, modifier = modifier, onBackClick = this::navigateUp, - onCreateRoomSuccess = { - - }, + onCreateRoomSuccess = ::onCreateRoomSuccess, ) } } diff --git a/features/invitepeople/api/build.gradle.kts b/features/invitepeople/api/build.gradle.kts index 85ce7164b9..3cbd83724a 100644 --- a/features/invitepeople/api/build.gradle.kts +++ b/features/invitepeople/api/build.gradle.kts @@ -5,7 +5,7 @@ * Please see LICENSE files in the repository root for full details. */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") } android { diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt new file mode 100644 index 0000000000..60f9512651 --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt @@ -0,0 +1,12 @@ +/* + * 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. + */ + +package io.element.android.features.invitepeople.api + +interface InvitePeopleEvents { + data object SendInvites : InvitePeopleEvents +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt index d41b4db093..72175beaef 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt @@ -7,9 +7,13 @@ package io.element.android.features.invitepeople.api -import androidx.compose.runtime.Composable +import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.matrix.api.room.JoinedRoom + +interface InvitePeoplePresenter : Presenter { + + interface Factory { + fun create(room: JoinedRoom): InvitePeoplePresenter + } -interface InvitePeoplePresenter { - @Composable - fun present(): InvitePeopleState } diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt index 70523653ed..30144a11d1 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt @@ -12,5 +12,8 @@ import androidx.compose.ui.Modifier interface InvitePeopleRenderer { @Composable - fun Render(state: InvitePeopleState, modifier: Modifier) + fun Render( + state: InvitePeopleState, + modifier: Modifier, + ) } diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt index 059c360df6..fb76dc0c1a 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt @@ -7,4 +7,6 @@ package io.element.android.features.invitepeople.api -interface InvitePeopleState +interface InvitePeopleState { + val eventSink: (InvitePeopleEvents) -> Unit +} diff --git a/features/invitepeople/impl/build.gradle.kts b/features/invitepeople/impl/build.gradle.kts index 42c96fee18..80f91f2eff 100644 --- a/features/invitepeople/impl/build.gradle.kts +++ b/features/invitepeople/impl/build.gradle.kts @@ -1,4 +1,3 @@ -import extension.ComponentMergingStrategy import extension.setupAnvil /* @@ -23,7 +22,7 @@ android { } } -setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP) +setupAnvil() dependencies { implementation(projects.libraries.core) @@ -33,14 +32,8 @@ dependencies { implementation(projects.libraries.designsystem) implementation(projects.libraries.uiStrings) implementation(projects.libraries.androidutils) - implementation(projects.libraries.deeplink) - implementation(projects.libraries.mediapickers.api) - implementation(projects.libraries.mediaupload.api) - implementation(projects.libraries.permissions.api) implementation(projects.libraries.usersearch.impl) - implementation(projects.services.analytics.api) implementation(libs.coil.compose) - implementation(projects.libraries.featureflag.api) api(projects.features.invitepeople.api) testImplementation(libs.test.junit) @@ -50,14 +43,8 @@ dependencies { testImplementation(libs.test.truth) testImplementation(libs.test.turbine) testImplementation(libs.test.robolectric) - testImplementation(projects.services.analytics.test) testImplementation(projects.libraries.matrix.test) - testImplementation(projects.libraries.mediapickers.test) - testImplementation(projects.libraries.mediaupload.test) - testImplementation(projects.libraries.permissions.test) testImplementation(projects.libraries.usersearch.test) - testImplementation(projects.features.startchat.test) - testImplementation(projects.libraries.featureflag.test) testImplementation(projects.tests.testutils) testImplementation(libs.androidx.compose.ui.test.junit) testReleaseImplementation(libs.androidx.compose.ui.test.manifest) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt new file mode 100644 index 0000000000..3c41b53188 --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt @@ -0,0 +1,17 @@ +/* + * 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.features.invitepeople.impl + +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.libraries.matrix.api.user.MatrixUser + +sealed interface DefaultInvitePeopleEvents: InvitePeopleEvents { + data class ToggleUser(val user: MatrixUser) : DefaultInvitePeopleEvents + data class UpdateSearchQuery(val query: String) : DefaultInvitePeopleEvents + data class OnSearchActiveChanged(val active: Boolean) : DefaultInvitePeopleEvents +} diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt new file mode 100644 index 0000000000..7eb7af377a --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt @@ -0,0 +1,168 @@ +/* + * 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.features.invitepeople.impl + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import com.squareup.anvil.annotations.ContributesBinding +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.features.invitepeople.api.InvitePeoplePresenter +import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.architecture.runCatchingUpdatingState +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +import io.element.android.libraries.di.SessionScope +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.api.room.filterMembers +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.usersearch.api.UserRepository +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.withContext + +class DefaultInvitePeoplePresenter @AssistedInject constructor( + @Assisted private val room: JoinedRoom, + private val userRepository: UserRepository, + private val coroutineDispatchers: CoroutineDispatchers, +) : InvitePeoplePresenter { + + @AssistedFactory + @ContributesBinding(SessionScope::class) + interface Factory : InvitePeoplePresenter.Factory { + override fun create(room: JoinedRoom): DefaultInvitePeoplePresenter + } + + @Composable + override fun present(): InvitePeopleState { + val roomMembers = remember { mutableStateOf>>(AsyncData.Loading()) } + val selectedUsers = remember { mutableStateOf>(persistentListOf()) } + val searchResults = remember { mutableStateOf>>(SearchBarResultState.Initial()) } + var searchQuery by rememberSaveable { mutableStateOf("") } + var searchActive by rememberSaveable { mutableStateOf(false) } + val showSearchLoader = rememberSaveable { mutableStateOf(false) } + + LaunchedEffect(Unit) { + fetchMembers(roomMembers) + } + LaunchedEffect(searchQuery, roomMembers) { + performSearch( + searchResults = searchResults, + roomMembers = roomMembers, + selectedUsers = selectedUsers, + showSearchLoader = showSearchLoader, + searchQuery = searchQuery + ) + } + + return DefaultInvitePeopleState( + canInvite = selectedUsers.value.isNotEmpty(), + selectedUsers = selectedUsers.value, + searchQuery = searchQuery, + isSearchActive = searchActive, + searchResults = searchResults.value, + showSearchLoader = showSearchLoader.value, + eventSink = { + when (it) { + is DefaultInvitePeopleEvents.OnSearchActiveChanged -> { + searchActive = it.active + searchQuery = "" + } + + is DefaultInvitePeopleEvents.UpdateSearchQuery -> { + searchQuery = it.query + } + + is DefaultInvitePeopleEvents.ToggleUser -> { + selectedUsers.toggleUser(it.user) + searchResults.toggleUser(it.user) + } + is InvitePeopleEvents.SendInvites -> { + } + } + } + ) + } + + @JvmName("toggleUserInSelectedUsers") + private fun MutableState>.toggleUser(user: MatrixUser) { + value = if (value.contains(user)) { + value.filterNot { it.userId == user.userId } + } else { + value + user + }.toImmutableList() + } + + @JvmName("toggleUserInSearchResults") + private fun MutableState>>.toggleUser(user: MatrixUser) { + val existingResults = value + if (existingResults is SearchBarResultState.Results) { + value = SearchBarResultState.Results( + existingResults.results.map { iu -> + if (iu.matrixUser == user) { + iu.copy(isSelected = !iu.isSelected) + } else { + iu + } + }.toImmutableList() + ) + } + } + + private suspend fun performSearch( + searchResults: MutableState>>, + roomMembers: MutableState>>, + selectedUsers: MutableState>, + showSearchLoader: MutableState, + searchQuery: String, + ) = withContext(coroutineDispatchers.io) { + searchResults.value = SearchBarResultState.Initial() + showSearchLoader.value = false + val joinedMembers = roomMembers.value.dataOrNull().orEmpty() + + userRepository.search(searchQuery).onEach { state -> + showSearchLoader.value = state.isSearching + searchResults.value = when { + state.results.isEmpty() && state.isSearching -> SearchBarResultState.Initial() + state.results.isEmpty() && !state.isSearching -> SearchBarResultState.NoResultsFound() + else -> SearchBarResultState.Results(state.results.map { result -> + val existingMembership = joinedMembers.firstOrNull { j -> j.userId == result.matrixUser.userId }?.membership + val isJoined = existingMembership == RoomMembershipState.JOIN + val isInvited = existingMembership == RoomMembershipState.INVITE + InvitableUser( + matrixUser = result.matrixUser, + isSelected = selectedUsers.value.contains(result.matrixUser) || isJoined || isInvited, + isAlreadyJoined = isJoined, + isAlreadyInvited = isInvited, + isUnresolved = result.isUnresolved, + ) + }.toImmutableList()) + } + }.launchIn(this) + } + + private suspend fun fetchMembers(roomMembers: MutableState>>) { + suspend { + room.filterMembers("", coroutineDispatchers.io).toImmutableList() + }.runCatchingUpdatingState(roomMembers) + } +} diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt new file mode 100644 index 0000000000..371b2fa84b --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package io.element.android.features.invitepeople.impl + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.invitepeople.api.InvitePeopleRenderer +import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.libraries.di.SessionScope +import javax.inject.Inject + +@ContributesBinding(SessionScope::class) +class DefaultInvitePeopleRenderer @Inject constructor() : InvitePeopleRenderer { + @Composable + override fun Render(state: InvitePeopleState, modifier: Modifier) { + if (state is DefaultInvitePeopleState) { + InvitePeopleView( + state = state, + onBackClick = {}, + onSubmitClick = {}, + modifier = modifier + ) + } else { + error("Unsupported state type: ${state::javaClass}") + } + } +} diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt new file mode 100644 index 0000000000..d8104b748c --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt @@ -0,0 +1,24 @@ +/* + * 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. + */ + +package io.element.android.features.invitepeople.impl + +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +import io.element.android.libraries.matrix.api.user.MatrixUser +import kotlinx.collections.immutable.ImmutableList + +data class DefaultInvitePeopleState( + val canInvite: Boolean, + val searchQuery: String, + val showSearchLoader: Boolean, + val searchResults: SearchBarResultState>, + val selectedUsers: ImmutableList, + val isSearchActive: Boolean, + override val eventSink: (InvitePeopleEvents) -> Unit +): InvitePeopleState diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt new file mode 100644 index 0000000000..38ef157df2 --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt @@ -0,0 +1,89 @@ +/* + * 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.features.invitepeople.impl + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.ui.components.aMatrixUser +import io.element.android.libraries.matrix.ui.components.aMatrixUserList +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList + +internal class DefaultInvitePeopleStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aDefaultInvitePeopleState(), + aDefaultInvitePeopleState(canInvite = true, selectedUsers = aMatrixUserList().toImmutableList()), + aDefaultInvitePeopleState(isSearchActive = true, searchQuery = "some query"), + aDefaultInvitePeopleState(isSearchActive = true, searchQuery = "some query", selectedUsers = aMatrixUserList().toImmutableList()), + aDefaultInvitePeopleState(isSearchActive = true, searchQuery = "some query", searchResults = SearchBarResultState.NoResultsFound()), + aDefaultInvitePeopleState( + isSearchActive = true, + canInvite = true, + searchQuery = "some query", + selectedUsers = persistentListOf( + aMatrixUser("@carol:server.org", "Carol") + ), + searchResults = SearchBarResultState.Results( + persistentListOf( + InvitableUser(aMatrixUser("@alice:server.org")), + InvitableUser(aMatrixUser("@bob:server.org", "Bob")), + InvitableUser(aMatrixUser("@carol:server.org", "Carol"), isSelected = true), + InvitableUser(aMatrixUser("@eve:server.org", "Eve"), isSelected = true, isAlreadyJoined = true), + InvitableUser(aMatrixUser("@justin:server.org", "Justin"), isSelected = true, isAlreadyInvited = true), + ) + ) + ), + aDefaultInvitePeopleState( + isSearchActive = true, + canInvite = true, + searchQuery = "@alice:server.org", + selectedUsers = persistentListOf( + aMatrixUser("@carol:server.org", "Carol") + ), + searchResults = SearchBarResultState.Results( + persistentListOf( + InvitableUser(aMatrixUser("@alice:server.org"), isUnresolved = true), + InvitableUser(aMatrixUser("@bob:server.org", "Bob")), + ) + ) + ), + aDefaultInvitePeopleState( + isSearchActive = true, + canInvite = true, + searchQuery = "@alice:server.org", + searchResults = SearchBarResultState.Results( + persistentListOf( + InvitableUser(aMatrixUser("@alice:server.org"), isUnresolved = true), + ) + ), + showSearchLoader = true, + ), + ) +} + +private fun aDefaultInvitePeopleState( + canInvite: Boolean = false, + searchQuery: String = "", + searchResults: SearchBarResultState> = SearchBarResultState.Initial(), + selectedUsers: ImmutableList = persistentListOf(), + isSearchActive: Boolean = false, + showSearchLoader: Boolean = false, +): DefaultInvitePeopleState { + return DefaultInvitePeopleState( + canInvite = canInvite, + searchQuery = searchQuery, + searchResults = searchResults, + selectedUsers = selectedUsers, + isSearchActive = isSearchActive, + showSearchLoader = showSearchLoader, + eventSink = {}, + ) +} diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitableUser.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitableUser.kt new file mode 100644 index 0000000000..b2b9943e64 --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitableUser.kt @@ -0,0 +1,18 @@ +/* + * 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. + */ + +package io.element.android.features.invitepeople.impl + +import io.element.android.libraries.matrix.api.user.MatrixUser + +data class InvitableUser( + val matrixUser: MatrixUser, + val isSelected: Boolean = false, + val isAlreadyJoined: Boolean = false, + val isAlreadyInvited: Boolean = false, + val isUnresolved: Boolean = false, +) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt new file mode 100644 index 0000000000..b87f92526a --- /dev/null +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -0,0 +1,227 @@ +/* + * 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.features.invitepeople.impl + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.designsystem.components.async.AsyncLoading +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.designsystem.components.button.BackButton +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.HorizontalDivider +import io.element.android.libraries.designsystem.theme.components.Scaffold +import io.element.android.libraries.designsystem.theme.components.SearchBar +import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +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.user.MatrixUser +import io.element.android.libraries.matrix.ui.components.CheckableUserRow +import io.element.android.libraries.matrix.ui.components.CheckableUserRowData +import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList +import io.element.android.libraries.matrix.ui.model.getAvatarData +import io.element.android.libraries.matrix.ui.model.getBestName +import io.element.android.libraries.ui.strings.CommonStrings +import kotlinx.collections.immutable.ImmutableList + +@Composable +fun InvitePeopleView( + state: DefaultInvitePeopleState, + onBackClick: () -> Unit, + onSubmitClick: (List) -> Unit, + modifier: Modifier = Modifier, +) { + Scaffold( + modifier = modifier, + topBar = { + RoomInviteMembersTopBar( + onBackClick = { + if (state.isSearchActive) { + state.eventSink(DefaultInvitePeopleEvents.OnSearchActiveChanged(false)) + } else { + onBackClick() + } + }, + onSubmitClick = { onSubmitClick(state.selectedUsers) }, + canSend = state.canInvite, + ) + } + ) { padding -> + Column( + modifier = Modifier + .fillMaxWidth() + .padding(padding) + .consumeWindowInsets(padding), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + RoomInviteMembersSearchBar( + modifier = Modifier.fillMaxWidth(), + query = state.searchQuery, + showLoader = state.showSearchLoader, + selectedUsers = state.selectedUsers, + state = state.searchResults, + active = state.isSearchActive, + onActiveChange = { + state.eventSink( + DefaultInvitePeopleEvents.OnSearchActiveChanged( + it + ) + ) + }, + onTextChange = { state.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery(it)) }, + onToggleUser = { state.eventSink(DefaultInvitePeopleEvents.ToggleUser(it)) }, + ) + + if (!state.isSearchActive) { + SelectedUsersRowList( + modifier = Modifier.fillMaxWidth(), + selectedUsers = state.selectedUsers, + autoScroll = true, + onUserRemove = { state.eventSink(DefaultInvitePeopleEvents.ToggleUser(it)) }, + contentPadding = PaddingValues(16.dp), + ) + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun RoomInviteMembersTopBar( + canSend: Boolean, + onBackClick: () -> Unit, + onSubmitClick: () -> Unit, +) { + TopAppBar( + titleStr = "Invite people", + navigationIcon = { BackButton(onClick = onBackClick) }, + actions = { + TextButton( + text = stringResource(CommonStrings.action_invite), + onClick = onSubmitClick, + enabled = canSend, + ) + } + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun RoomInviteMembersSearchBar( + query: String, + state: SearchBarResultState>, + showLoader: Boolean, + selectedUsers: ImmutableList, + active: Boolean, + onActiveChange: (Boolean) -> Unit, + onTextChange: (String) -> Unit, + onToggleUser: (MatrixUser) -> Unit, + modifier: Modifier = Modifier, + placeHolderTitle: String = stringResource(CommonStrings.common_search_for_someone), +) { + SearchBar( + query = query, + onQueryChange = onTextChange, + active = active, + onActiveChange = onActiveChange, + modifier = modifier, + placeHolderTitle = placeHolderTitle, + contentPrefix = { + if (selectedUsers.isNotEmpty()) { + SelectedUsersRowList( + modifier = Modifier.fillMaxWidth(), + selectedUsers = selectedUsers, + autoScroll = true, + onUserRemove = onToggleUser, + contentPadding = PaddingValues(16.dp), + ) + } + }, + showBackButton = false, + resultState = state, + contentSuffix = { + if (showLoader) { + AsyncLoading() + } + }, + resultHandler = { results -> + Text( + text = stringResource(id = CommonStrings.common_search_results), + style = ElementTheme.typography.fontBodyLgMedium, + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, top = 12.dp, end = 16.dp, bottom = 8.dp) + ) + + LazyColumn { + itemsIndexed(results) { index, invitableUser -> + val notInvitedOrJoined = + !(invitableUser.isAlreadyInvited || invitableUser.isAlreadyJoined) + val isUnresolved = invitableUser.isUnresolved && notInvitedOrJoined + val enabled = isUnresolved || notInvitedOrJoined + val data = if (isUnresolved) { + CheckableUserRowData.Unresolved( + avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), + id = invitableUser.matrixUser.userId.value, + ) + } else { + CheckableUserRowData.Resolved( + avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), + name = invitableUser.matrixUser.getBestName(), + subtext = when { + // If they're already invited or joined we show that information + invitableUser.isAlreadyJoined -> "Already a member" + invitableUser.isAlreadyInvited -> "Already invited" + // Otherwise show the ID, unless that's already used for their name + invitableUser.matrixUser.displayName.isNullOrEmpty() + .not() -> invitableUser.matrixUser.userId.value + else -> null + } + ) + } + CheckableUserRow( + checked = invitableUser.isSelected, + enabled = enabled, + data = data, + onCheckedChange = { onToggleUser(invitableUser.matrixUser) }, + modifier = Modifier.fillMaxWidth() + ) + + if (index < results.lastIndex) { + HorizontalDivider() + } + } + } + }, + ) +} + +@PreviewsDayNight +@Composable +internal fun RoomInviteMembersViewPreview(@PreviewParameter(DefaultInvitePeopleStateProvider::class) state: DefaultInvitePeopleState) = + ElementPreview { + InvitePeopleView( + state = state, + onBackClick = {}, + onSubmitClick = {}, + ) + } diff --git a/features/startchat/impl/build.gradle.kts b/features/startchat/impl/build.gradle.kts index b53f3d8c89..270c329a02 100644 --- a/features/startchat/impl/build.gradle.kts +++ b/features/startchat/impl/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { implementation(projects.services.analytics.api) implementation(libs.coil.compose) implementation(projects.libraries.featureflag.api) + implementation(projects.features.createroom.api) api(projects.features.startchat.api) testImplementation(libs.test.junit) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt index c635023df3..1f4ae758d4 100644 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt @@ -21,6 +21,7 @@ import com.bumble.appyx.navmodel.backstack.BackStack import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.features.startchat.DefaultStartChatNavigator import io.element.android.features.startchat.api.StartChatEntryPoint import io.element.android.features.startchat.impl.joinbyaddress.JoinRoomByAddressNode @@ -36,6 +37,7 @@ import kotlinx.parcelize.Parcelize class StartChatFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, + private val createRoomEntryPoint: CreateRoomEntryPoint, ) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Root, @@ -72,7 +74,7 @@ class StartChatFlowNode @AssistedInject constructor( createNode(buildContext = buildContext, plugins = listOf(navigator)) } NavTarget.NewRoom -> { - createNode(buildContext = buildContext, plugins = listOf(navigator)) + createRoomEntryPoint.createNode(parentNode = this, buildContext = buildContext) } NavTarget.JoinByAddress -> { createNode(buildContext = buildContext, plugins = listOf(navigator)) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/FilterRoomMembers.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/FilterRoomMembers.kt new file mode 100644 index 0000000000..a1c4f0bf01 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/FilterRoomMembers.kt @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package io.element.android.libraries.matrix.api.room + +import io.element.android.libraries.core.bool.orFalse +import kotlinx.coroutines.withContext +import kotlin.coroutines.CoroutineContext + +/** + * Method to filter members by userId or displayName. + * It does filter through the already known members, it doesn't perform additional requests. + */ +suspend fun BaseRoom.filterMembers(query: String, coroutineContext: CoroutineContext): List = withContext(coroutineContext) { + val roomMembersState = membersStateFlow.value + val activeRoomMembers = roomMembersState.roomMembers() + ?.filter { it.membership.isActive() } + .orEmpty() + val filteredMembers = if (query.isBlank()) { + activeRoomMembers + } else { + activeRoomMembers.filter { member -> + member.userId.value.contains(query, ignoreCase = true) || + member.displayName?.contains(query, ignoreCase = true).orFalse() + } + } + filteredMembers +} From 98343e05316cf124a8fc976fb52bc54d41988fa7 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 8 Aug 2025 17:42:06 +0200 Subject: [PATCH 03/30] refactor (start chat) : remove useless code --- .../ConfigureRoomPresenterTest.kt} | 47 +-- .../startchat/impl/CreateRoomConfig.kt | 22 -- .../startchat/impl/CreateRoomDataStore.kt | 134 ------- .../startchat/impl/CreateRoomFlowNode.kt | 83 ----- .../startchat/impl/addpeople/AddPeopleNode.kt | 45 --- .../impl/addpeople/AddPeoplePresenter.kt | 37 -- .../AddPeopleUserListStateProvider.kt | 46 --- .../startchat/impl/addpeople/AddPeopleView.kt | 94 ----- .../impl/configureroom/ConfigureRoomEvents.kt | 23 -- .../impl/configureroom/ConfigureRoomNode.kt | 55 --- .../configureroom/ConfigureRoomPresenter.kt | 209 ----------- .../ConfigureRoomPresenterArgs.kt | 14 - .../impl/configureroom/ConfigureRoomState.kt | 30 -- .../ConfigureRoomStateProvider.kt | 102 ------ .../impl/configureroom/ConfigureRoomView.kt | 339 ------------------ .../impl/configureroom/RoomAccess.kt | 22 -- .../impl/configureroom/RoomAccessItem.kt | 25 -- .../impl/configureroom/RoomAddress.kt | 13 - .../impl/configureroom/RoomVisibilityItem.kt | 30 -- .../impl/configureroom/RoomVisibilityState.kt | 26 -- .../startchat/impl/di/CreateRoomComponent.kt | 28 -- .../startchat/impl/di/CreateRoomScope.kt | 10 - .../impl/addpeople/AddPeoplePresenterTest.kt | 50 --- .../impl/addpeople/AddPeopleViewTest.kt | 89 ----- 24 files changed, 17 insertions(+), 1556 deletions(-) rename features/{startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureBaseRoomPresenterTest.kt => createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt} (91%) delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomConfig.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomDataStore.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomFlowNode.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleNode.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenter.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleUserListStateProvider.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleView.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomEvents.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomNode.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenter.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterArgs.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomState.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomStateProvider.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomView.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccess.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccessItem.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAddress.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityItem.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityState.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomComponent.kt delete mode 100644 features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomScope.kt delete mode 100644 features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenterTest.kt delete mode 100644 features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleViewTest.kt diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureBaseRoomPresenterTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt similarity index 91% rename from features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureBaseRoomPresenterTest.kt rename to features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt index 8eab477f1a..9e11603642 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureBaseRoomPresenterTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt @@ -11,9 +11,15 @@ import android.net.Uri import app.cash.turbine.TurbineTestContext import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.invitepeople.impl.CreateRoomConfig -import io.element.android.features.invitepeople.impl.CreateRoomDataStore -import io.element.android.features.invitepeople.impl.userlist.UserListDataStore +import io.element.android.features.createroom.impl.configureroom.ConfigureRoomEvents +import io.element.android.features.createroom.impl.configureroom.ConfigureRoomPresenter +import io.element.android.features.createroom.impl.configureroom.ConfigureRoomState +import io.element.android.features.createroom.impl.configureroom.CreateRoomConfig +import io.element.android.features.createroom.impl.configureroom.CreateRoomConfigStore +import io.element.android.features.createroom.impl.configureroom.RoomAccess +import io.element.android.features.createroom.impl.configureroom.RoomAddress +import io.element.android.features.createroom.impl.configureroom.RoomVisibilityItem +import io.element.android.features.createroom.impl.configureroom.RoomVisibilityState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService @@ -28,7 +34,6 @@ 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.FakeMatrixClient import io.element.android.libraries.matrix.test.room.alias.FakeRoomAliasHelper -import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity import io.element.android.libraries.mediapickers.api.PickerProvider @@ -48,8 +53,6 @@ import io.mockk.every import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.unmockkAll -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest @@ -67,7 +70,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 ConfigureBaseRoomPresenterTest { +class ConfigureRoomPresenterTest { @get:Rule val warmUpRule = WarmUpRule() @@ -124,12 +127,11 @@ class ConfigureBaseRoomPresenterTest { @Test fun `present - state is updated when fields are changed`() = runTest { - val userListDataStore = UserListDataStore() val pickerProvider = FakePickerProvider() val permissionsPresenter = FakePermissionsPresenter() val roomAliasHelper = FakeRoomAliasHelper() val presenter = createConfigureRoomPresenter( - createRoomDataStore = CreateRoomDataStore(userListDataStore, roomAliasHelper), + dataStore = CreateRoomConfigStore(roomAliasHelper), pickerProvider = pickerProvider, permissionsPresenter = permissionsPresenter, ) @@ -138,19 +140,10 @@ class ConfigureBaseRoomPresenterTest { var expectedConfig = CreateRoomConfig() assertThat(initialState.config).isEqualTo(expectedConfig) - // Select User - val selectedUser1 = aMatrixUser() - val selectedUser2 = aMatrixUser("@id_of_bob:server.org", "Bob") - userListDataStore.selectUser(selectedUser1) - skipItems(1) - userListDataStore.selectUser(selectedUser2) - var newState = awaitItem() - expectedConfig = expectedConfig.copy(invites = persistentListOf(selectedUser1, selectedUser2)) - assertThat(newState.config).isEqualTo(expectedConfig) // Room name initialState.eventSink(ConfigureRoomEvents.RoomNameChanged(A_ROOM_NAME)) - newState = awaitItem() + var newState = awaitItem() expectedConfig = expectedConfig.copy(roomName = A_ROOM_NAME) assertThat(newState.config).isEqualTo(expectedConfig) @@ -206,12 +199,6 @@ class ConfigureBaseRoomPresenterTest { ) ) assertThat(newState.config).isEqualTo(expectedConfig) - - // Remove user - newState.eventSink(ConfigureRoomEvents.RemoveUserFromSelection(selectedUser1)) - newState = awaitItem() - expectedConfig = expectedConfig.copy(invites = expectedConfig.invites.minus(selectedUser1).toImmutableList()) - assertThat(newState.config).isEqualTo(expectedConfig) } } @@ -263,16 +250,16 @@ class ConfigureBaseRoomPresenterTest { val matrixClient = createMatrixClient() val analyticsService = FakeAnalyticsService() val mediaPreProcessor = FakeMediaPreProcessor() - val createRoomDataStore = CreateRoomDataStore(UserListDataStore(), FakeRoomAliasHelper()) + val dataStore = CreateRoomConfigStore( FakeRoomAliasHelper()) val presenter = createConfigureRoomPresenter( - createRoomDataStore = createRoomDataStore, + dataStore = dataStore, mediaPreProcessor = mediaPreProcessor, matrixClient = matrixClient, analyticsService = analyticsService ) presenter.test { val initialState = initialState() - createRoomDataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY)) + dataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY)) skipItems(1) mediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(mockk(), mockk(), mockk()))) matrixClient.givenUploadMediaResult(Result.failure(AN_EXCEPTION)) @@ -405,7 +392,7 @@ class ConfigureBaseRoomPresenterTest { private fun createConfigureRoomPresenter( roomAliasHelper: RoomAliasHelper = FakeRoomAliasHelper(), - createRoomDataStore: CreateRoomDataStore = CreateRoomDataStore(UserListDataStore(), roomAliasHelper), + dataStore: CreateRoomConfigStore = CreateRoomConfigStore(roomAliasHelper), matrixClient: MatrixClient = createMatrixClient(), pickerProvider: PickerProvider = FakePickerProvider(), mediaPreProcessor: MediaPreProcessor = FakeMediaPreProcessor(), @@ -414,7 +401,7 @@ class ConfigureBaseRoomPresenterTest { isKnockFeatureEnabled: Boolean = true, mediaOptimizationConfigProvider: FakeMediaOptimizationConfigProvider = FakeMediaOptimizationConfigProvider(), ) = ConfigureRoomPresenter( - dataStore = createRoomDataStore, + dataStore = dataStore, matrixClient = matrixClient, mediaPickerProvider = pickerProvider, mediaPreProcessor = mediaPreProcessor, diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomConfig.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomConfig.kt deleted file mode 100644 index 2cbd961dad..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomConfig.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl - -import android.net.Uri -import io.element.android.features.startchat.impl.configureroom.RoomVisibilityState -import io.element.android.libraries.matrix.api.user.MatrixUser -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf - -data class CreateRoomConfig( - val roomName: String? = null, - val topic: String? = null, - val avatarUri: Uri? = null, - val invites: ImmutableList = persistentListOf(), - val roomVisibility: RoomVisibilityState = RoomVisibilityState.Private, -) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomDataStore.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomDataStore.kt deleted file mode 100644 index ff0746c1b3..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomDataStore.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl - -import android.net.Uri -import io.element.android.features.startchat.impl.configureroom.RoomAccess -import io.element.android.features.startchat.impl.configureroom.RoomAccessItem -import io.element.android.features.startchat.impl.configureroom.RoomAddress -import io.element.android.features.startchat.impl.configureroom.RoomVisibilityItem -import io.element.android.features.startchat.impl.configureroom.RoomVisibilityState -import io.element.android.features.startchat.impl.di.CreateRoomScope -import io.element.android.features.startchat.impl.userlist.UserListDataStore -import io.element.android.libraries.androidutils.file.safeDelete -import io.element.android.libraries.di.SingleIn -import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper -import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.getAndUpdate -import java.io.File -import javax.inject.Inject - -@SingleIn(CreateRoomScope::class) -class CreateRoomDataStore @Inject constructor( - val selectedUserListDataStore: UserListDataStore, - private val roomAliasHelper: RoomAliasHelper, -) { - private val createRoomConfigFlow: MutableStateFlow = MutableStateFlow(CreateRoomConfig()) - private var cachedAvatarUri: Uri? = null - set(value) { - field?.path?.let { File(it) }?.safeDelete() - field = value - } - - val createRoomConfigWithInvites: Flow = combine( - selectedUserListDataStore.selectedUsers, - createRoomConfigFlow, - ) { selectedUsers, config -> - config.copy(invites = selectedUsers.toImmutableList()) - } - - fun setRoomName(roomName: String) { - createRoomConfigFlow.getAndUpdate { config -> - val newVisibility = when (config.roomVisibility) { - is RoomVisibilityState.Public -> { - val roomAddress = config.roomVisibility.roomAddress - if (roomAddress is RoomAddress.AutoFilled || roomName.isEmpty()) { - val roomAliasName = roomAliasHelper.roomAliasNameFromRoomDisplayName(roomName) - config.roomVisibility.copy( - roomAddress = RoomAddress.AutoFilled(roomAliasName), - ) - } else { - config.roomVisibility - } - } - else -> config.roomVisibility - } - config.copy( - roomName = roomName.takeIf { it.isNotEmpty() }, - roomVisibility = newVisibility, - ) - } - } - - fun setTopic(topic: String) { - createRoomConfigFlow.getAndUpdate { config -> - config.copy(topic = topic.takeIf { it.isNotEmpty() }) - } - } - - fun setAvatarUri(uri: Uri?, cached: Boolean = false) { - cachedAvatarUri = uri.takeIf { cached } - createRoomConfigFlow.getAndUpdate { config -> - config.copy(avatarUri = uri) - } - } - - fun setRoomVisibility(visibility: RoomVisibilityItem) { - createRoomConfigFlow.getAndUpdate { config -> - config.copy( - roomVisibility = when (visibility) { - RoomVisibilityItem.Private -> RoomVisibilityState.Private - RoomVisibilityItem.Public -> { - val roomAliasName = roomAliasHelper.roomAliasNameFromRoomDisplayName(config.roomName.orEmpty()) - RoomVisibilityState.Public( - roomAddress = RoomAddress.AutoFilled(roomAliasName), - roomAccess = RoomAccess.Anyone, - ) - } - } - ) - } - } - - fun setRoomAddress(address: String) { - createRoomConfigFlow.getAndUpdate { config -> - config.copy( - roomVisibility = when (config.roomVisibility) { - is RoomVisibilityState.Public -> { - val sanitizedAddress = address.lowercase() - config.roomVisibility.copy(roomAddress = RoomAddress.Edited(sanitizedAddress)) - } - else -> config.roomVisibility - } - ) - } - } - - fun setRoomAccess(access: RoomAccessItem) { - createRoomConfigFlow.getAndUpdate { config -> - config.copy( - roomVisibility = when (config.roomVisibility) { - is RoomVisibilityState.Public -> { - when (access) { - RoomAccessItem.Anyone -> config.roomVisibility.copy(roomAccess = RoomAccess.Anyone) - RoomAccessItem.AskToJoin -> config.roomVisibility.copy(roomAccess = RoomAccess.Knocking) - } - } - else -> config.roomVisibility - } - ) - } - } - - fun clearCachedData() { - cachedAvatarUri = null - } -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomFlowNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomFlowNode.kt deleted file mode 100644 index 1124314250..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/CreateRoomFlowNode.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl - -import android.os.Parcelable -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.plugin.Plugin -import com.bumble.appyx.core.plugin.plugins -import com.bumble.appyx.navmodel.backstack.BackStack -import com.bumble.appyx.navmodel.backstack.operation.push -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject -import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.startchat.StartChatNavigator -import io.element.android.features.startchat.impl.addpeople.AddPeopleNode -import io.element.android.features.startchat.impl.configureroom.ConfigureRoomNode -import io.element.android.features.startchat.impl.di.CreateRoomComponent -import io.element.android.libraries.architecture.BackstackView -import io.element.android.libraries.architecture.BaseFlowNode -import io.element.android.libraries.architecture.bindings -import io.element.android.libraries.architecture.createNode -import io.element.android.libraries.di.DaggerComponentOwner -import io.element.android.libraries.di.SessionScope -import kotlinx.parcelize.Parcelize - -@ContributesNode(SessionScope::class) -class CreateRoomFlowNode @AssistedInject constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, -) : DaggerComponentOwner, - BaseFlowNode( - backstack = BackStack( - initialElement = NavTarget.ConfigureRoom, - savedStateMap = buildContext.savedStateMap, - ), - buildContext = buildContext, - plugins = plugins - ) { - private val component by lazy { - parent!!.bindings().createRoomComponentBuilder().build() - } - private val navigator = plugins().first() - - override val daggerComponent: Any - get() = component - - sealed interface NavTarget : Parcelable { - @Parcelize - data object AddPeople : NavTarget - - @Parcelize - data object ConfigureRoom : NavTarget - } - - override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { - return when (navTarget) { - NavTarget.AddPeople -> { - val callback = object : AddPeopleNode.Callback { - override fun onContinue() { - backstack.push(NavTarget.ConfigureRoom) - } - } - createNode(buildContext = buildContext, plugins = listOf(callback)) - } - NavTarget.ConfigureRoom -> { - createNode(buildContext = buildContext, plugins = listOf(navigator)) - } - } - } - - @Composable - override fun View(modifier: Modifier) { - BackstackView() - } -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleNode.kt deleted file mode 100644 index 441ba8cc76..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleNode.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.addpeople - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.plugin.Plugin -import com.bumble.appyx.core.plugin.plugins -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject -import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.startchat.impl.di.CreateRoomScope - -@ContributesNode(CreateRoomScope::class) -class AddPeopleNode @AssistedInject constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, - private val presenter: AddPeoplePresenter, -) : Node(buildContext, plugins = plugins) { - interface Callback : Plugin { - fun onContinue() - } - - private fun onContinue() { - plugins().forEach { it.onContinue() } - } - - @Composable - override fun View(modifier: Modifier) { - val state = presenter.present() - AddPeopleView( - state = state, - modifier = modifier, - onBackClick = this::navigateUp, - onSkipClick = this::onContinue, - ) - } -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenter.kt deleted file mode 100644 index aacd80fca3..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenter.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.addpeople - -import androidx.compose.runtime.Composable -import io.element.android.features.startchat.impl.CreateRoomDataStore -import io.element.android.features.startchat.impl.userlist.SelectionMode -import io.element.android.features.startchat.impl.userlist.UserListPresenter -import io.element.android.features.startchat.impl.userlist.UserListPresenterArgs -import io.element.android.features.startchat.impl.userlist.UserListState -import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.usersearch.api.UserRepository -import javax.inject.Inject - -class AddPeoplePresenter @Inject constructor( - userListPresenterFactory: UserListPresenter.Factory, - userRepository: UserRepository, - dataStore: CreateRoomDataStore, -) : Presenter { - private val userListPresenter = userListPresenterFactory.create( - UserListPresenterArgs( - selectionMode = SelectionMode.Multiple, - ), - userRepository, - dataStore.selectedUserListDataStore, - ) - - @Composable - override fun present(): UserListState { - return userListPresenter.present() - } -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleUserListStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleUserListStateProvider.kt deleted file mode 100644 index 57b3a93d57..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleUserListStateProvider.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.addpeople - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.startchat.impl.userlist.SelectionMode -import io.element.android.features.startchat.impl.userlist.UserListState -import io.element.android.features.startchat.impl.userlist.aRecentDirectRoomList -import io.element.android.features.startchat.impl.userlist.aUserListState -import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -import io.element.android.libraries.matrix.ui.components.aMatrixUserList -import io.element.android.libraries.usersearch.api.UserSearchResult -import kotlinx.collections.immutable.toImmutableList - -open class AddPeopleUserListStateProvider : PreviewParameterProvider { - override val values: Sequence - get() = sequenceOf( - aUserListState(), - aUserListState( - searchResults = SearchBarResultState.Results(aMatrixUserList().toImmutableList()), - selectedUsers = aMatrixUserList().toImmutableList(), - isSearchActive = false, - selectionMode = SelectionMode.Multiple, - ), - aUserListState( - searchResults = SearchBarResultState.Results( - aMatrixUserList() - .mapIndexed { index, matrixUser -> - UserSearchResult(matrixUser, index % 2 == 0) - } - .toImmutableList() - ), - selectedUsers = aMatrixUserList().toImmutableList(), - isSearchActive = true, - selectionMode = SelectionMode.Multiple, - ), - aUserListState( - recentDirectRooms = aRecentDirectRoomList(), - ), - ) -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleView.kt deleted file mode 100644 index ac457955d5..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleView.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.addpeople - -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.PreviewParameter -import io.element.android.features.startchat.impl.R -import io.element.android.features.startchat.impl.components.UserListView -import io.element.android.features.startchat.impl.userlist.UserListEvents -import io.element.android.features.startchat.impl.userlist.UserListState -import io.element.android.libraries.designsystem.components.button.BackButton -import io.element.android.libraries.designsystem.preview.ElementPreview -import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.designsystem.theme.components.Scaffold -import io.element.android.libraries.designsystem.theme.components.TextButton -import io.element.android.libraries.designsystem.theme.components.TopAppBar -import io.element.android.libraries.ui.strings.CommonStrings - -@Composable -fun AddPeopleView( - state: UserListState, - onBackClick: () -> Unit, - onSkipClick: () -> Unit, - modifier: Modifier = Modifier, -) { - Scaffold( - modifier = modifier, - topBar = { - AddPeopleViewTopBar( - hasSelectedUsers = state.selectedUsers.isNotEmpty(), - onBackClick = { - if (state.isSearchActive) { - state.eventSink(UserListEvents.OnSearchActiveChanged(false)) - } else { - onBackClick() - } - }, - onNextClick = onSkipClick, - ) - } - ) { padding -> - UserListView( - modifier = Modifier - .fillMaxSize() - .padding(padding) - .consumeWindowInsets(padding), - state = state, - showBackButton = false, - onSelectUser = {}, - onDeselectUser = {}, - ) - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun AddPeopleViewTopBar( - hasSelectedUsers: Boolean, - onBackClick: () -> Unit, - onNextClick: () -> Unit, -) { - TopAppBar( - titleStr = stringResource(id = R.string.screen_create_room_add_people_title), - navigationIcon = { BackButton(onClick = onBackClick) }, - actions = { - val textActionResId = if (hasSelectedUsers) CommonStrings.action_next else CommonStrings.action_skip - TextButton( - text = stringResource(id = textActionResId), - onClick = onNextClick, - ) - } - ) -} - -@PreviewsDayNight -@Composable -internal fun AddPeopleViewPreview(@PreviewParameter(AddPeopleUserListStateProvider::class) state: UserListState) = ElementPreview { - AddPeopleView( - state = state, - onBackClick = {}, - onSkipClick = {}, - ) -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomEvents.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomEvents.kt deleted file mode 100644 index 13ce502559..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomEvents.kt +++ /dev/null @@ -1,23 +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.features.startchat.impl.configureroom - -import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.matrix.ui.media.AvatarAction - -sealed interface ConfigureRoomEvents { - data class RoomNameChanged(val name: String) : ConfigureRoomEvents - data class TopicChanged(val topic: String) : ConfigureRoomEvents - data class RoomVisibilityChanged(val visibilityItem: RoomVisibilityItem) : ConfigureRoomEvents - data class RoomAccessChanged(val roomAccess: RoomAccessItem) : ConfigureRoomEvents - data class RoomAddressChanged(val roomAddress: String) : ConfigureRoomEvents - data class RemoveUserFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents - data object CreateRoom : ConfigureRoomEvents - data class HandleAvatarAction(val action: AvatarAction) : ConfigureRoomEvents - data object CancelCreateRoom : ConfigureRoomEvents -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomNode.kt deleted file mode 100644 index 3251fbff8d..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomNode.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.configureroom - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.bumble.appyx.core.lifecycle.subscribe -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.plugin.Plugin -import com.bumble.appyx.core.plugin.plugins -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject -import im.vector.app.features.analytics.plan.MobileScreen -import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.startchat.StartChatNavigator -import io.element.android.features.startchat.impl.di.CreateRoomScope -import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias -import io.element.android.services.analytics.api.AnalyticsService - -@ContributesNode(CreateRoomScope::class) -class ConfigureRoomNode @AssistedInject constructor( - @Assisted buildContext: BuildContext, - @Assisted plugins: List, - private val presenter: ConfigureRoomPresenter, - private val analyticsService: AnalyticsService, -) : Node(buildContext, plugins = plugins) { - private val navigator = plugins().first() - - init { - lifecycle.subscribe( - onResume = { - analyticsService.screen(MobileScreen(screenName = MobileScreen.ScreenName.CreateRoom)) - } - ) - } - - @Composable - override fun View(modifier: Modifier) { - val state = presenter.present() - ConfigureRoomView( - state = state, - modifier = modifier, - onBackClick = this::navigateUp, - onCreateRoomSuccess = { - navigator.onOpenRoom(roomIdOrAlias = it.toRoomIdOrAlias(), serverNames = emptyList()) - }, - ) - } -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenter.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenter.kt deleted file mode 100644 index a715bf568d..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenter.kt +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.configureroom - -import android.net.Uri -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import im.vector.app.features.analytics.plan.CreatedRoom -import io.element.android.features.startchat.impl.CreateRoomConfig -import io.element.android.features.startchat.impl.CreateRoomDataStore -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.featureflag.api.FeatureFlagService -import io.element.android.libraries.featureflag.api.FeatureFlags -import io.element.android.libraries.matrix.api.MatrixClient -import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters -import io.element.android.libraries.matrix.api.createroom.RoomPreset -import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper -import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility -import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility -import io.element.android.libraries.matrix.ui.media.AvatarAction -import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity -import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidityEffect -import io.element.android.libraries.mediapickers.api.PickerProvider -import io.element.android.libraries.mediaupload.api.MediaPreProcessor -import io.element.android.libraries.permissions.api.PermissionsEvents -import io.element.android.libraries.permissions.api.PermissionsPresenter -import io.element.android.services.analytics.api.AnalyticsService -import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch -import timber.log.Timber -import javax.inject.Inject -import kotlin.jvm.optionals.getOrDefault - -class ConfigureRoomPresenter @Inject constructor( - private val dataStore: CreateRoomDataStore, - private val matrixClient: MatrixClient, - private val mediaPickerProvider: PickerProvider, - private val mediaPreProcessor: MediaPreProcessor, - private val analyticsService: AnalyticsService, - permissionsPresenterFactory: PermissionsPresenter.Factory, - private val featureFlagService: FeatureFlagService, - private val roomAliasHelper: RoomAliasHelper, -) : Presenter { - private val cameraPermissionPresenter: PermissionsPresenter = permissionsPresenterFactory.create(android.Manifest.permission.CAMERA) - private var pendingPermissionRequest = false - - @Composable - override fun present(): ConfigureRoomState { - val cameraPermissionState = cameraPermissionPresenter.present() - val createRoomConfig by dataStore.createRoomConfigWithInvites.collectAsState(CreateRoomConfig()) - val homeserverName = remember { matrixClient.userIdServerName() } - val isKnockFeatureEnabled by remember { - featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock) - }.collectAsState(initial = false) - val roomAddressValidity = remember { - mutableStateOf(RoomAddressValidity.Unknown) - } - - val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker( - onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri, cached = true) }, - ) - val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker( - onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri) } - ) - - val avatarActions by remember(createRoomConfig.avatarUri) { - derivedStateOf { - listOfNotNull( - AvatarAction.TakePhoto, - AvatarAction.ChoosePhoto, - AvatarAction.Remove.takeIf { createRoomConfig.avatarUri != null }, - ).toImmutableList() - } - } - - LaunchedEffect(cameraPermissionState.permissionGranted) { - if (cameraPermissionState.permissionGranted && pendingPermissionRequest) { - pendingPermissionRequest = false - cameraPhotoPicker.launch() - } - } - - RoomAddressValidityEffect( - client = matrixClient, - roomAliasHelper = roomAliasHelper, - newRoomAddress = createRoomConfig.roomVisibility.roomAddress().getOrDefault(""), - knownRoomAddress = null, - ) { newRoomAddressValidity -> - roomAddressValidity.value = newRoomAddressValidity - } - - val localCoroutineScope = rememberCoroutineScope() - val createRoomAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) } - - fun createRoom(config: CreateRoomConfig) { - createRoomAction.value = AsyncAction.Uninitialized - localCoroutineScope.createRoom(config, createRoomAction) - } - - fun handleEvents(event: ConfigureRoomEvents) { - when (event) { - is ConfigureRoomEvents.RoomNameChanged -> dataStore.setRoomName(event.name) - is ConfigureRoomEvents.TopicChanged -> dataStore.setTopic(event.topic) - is ConfigureRoomEvents.RoomVisibilityChanged -> dataStore.setRoomVisibility(event.visibilityItem) - is ConfigureRoomEvents.RemoveUserFromSelection -> dataStore.selectedUserListDataStore.removeUserFromSelection(event.matrixUser) - is ConfigureRoomEvents.RoomAccessChanged -> dataStore.setRoomAccess(event.roomAccess) - is ConfigureRoomEvents.RoomAddressChanged -> dataStore.setRoomAddress(event.roomAddress) - is ConfigureRoomEvents.CreateRoom -> createRoom(createRoomConfig) - is ConfigureRoomEvents.HandleAvatarAction -> { - when (event.action) { - AvatarAction.ChoosePhoto -> galleryImagePicker.launch() - AvatarAction.TakePhoto -> if (cameraPermissionState.permissionGranted) { - cameraPhotoPicker.launch() - } else { - pendingPermissionRequest = true - cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions) - } - AvatarAction.Remove -> dataStore.setAvatarUri(uri = null) - } - } - - ConfigureRoomEvents.CancelCreateRoom -> createRoomAction.value = AsyncAction.Uninitialized - } - } - - return ConfigureRoomState( - isKnockFeatureEnabled = isKnockFeatureEnabled, - config = createRoomConfig, - avatarActions = avatarActions, - createRoomAction = createRoomAction.value, - cameraPermissionState = cameraPermissionState, - homeserverName = homeserverName, - roomAddressValidity = roomAddressValidity.value, - eventSink = ::handleEvents, - ) - } - - private fun CoroutineScope.createRoom( - config: CreateRoomConfig, - createRoomAction: MutableState> - ) = launch { - suspend { - val avatarUrl = config.avatarUri?.let { uploadAvatar(it) } - val params = if (config.roomVisibility is RoomVisibilityState.Public) { - CreateRoomParameters( - name = config.roomName, - topic = config.topic, - isEncrypted = false, - isDirect = false, - visibility = RoomVisibility.Public, - joinRuleOverride = config.roomVisibility.roomAccess.toJoinRule(), - preset = RoomPreset.PUBLIC_CHAT, - invite = config.invites.map { it.userId }, - avatar = avatarUrl, - roomAliasName = config.roomVisibility.roomAddress() - ) - } else { - CreateRoomParameters( - name = config.roomName, - topic = config.topic, - isEncrypted = config.roomVisibility is RoomVisibilityState.Private, - isDirect = false, - visibility = RoomVisibility.Private, - historyVisibilityOverride = RoomHistoryVisibility.Invited, - preset = RoomPreset.PRIVATE_CHAT, - invite = config.invites.map { it.userId }, - avatar = avatarUrl, - ) - } - matrixClient.createRoom(params) - .onFailure { failure -> - Timber.e(failure, "Failed to create room") - } - .onSuccess { - dataStore.clearCachedData() - analyticsService.capture(CreatedRoom(isDM = false)) - } - .getOrThrow() - }.runCatchingUpdatingState(createRoomAction) - } - - private suspend fun uploadAvatar(avatarUri: Uri): String { - val preprocessed = mediaPreProcessor.process( - uri = avatarUri, - mimeType = MimeTypes.Jpeg, - deleteOriginal = false, - compressIfPossible = false, - ).getOrThrow() - val byteArray = preprocessed.file.readBytes() - return matrixClient.uploadMedia(MimeTypes.Jpeg, byteArray, null).getOrThrow() - } -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterArgs.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterArgs.kt deleted file mode 100644 index 2ee98b2a35..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterArgs.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.configureroom - -import io.element.android.libraries.matrix.api.user.MatrixUser - -data class ConfigureRoomPresenterArgs( - val selectedUsers: List, -) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomState.kt deleted file mode 100644 index e94066caed..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomState.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.configureroom - -import io.element.android.features.startchat.impl.CreateRoomConfig -import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.ui.media.AvatarAction -import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity -import io.element.android.libraries.permissions.api.PermissionsState -import kotlinx.collections.immutable.ImmutableList - -data class ConfigureRoomState( - val isKnockFeatureEnabled: Boolean, - val config: CreateRoomConfig, - val avatarActions: ImmutableList, - val createRoomAction: AsyncAction, - val cameraPermissionState: PermissionsState, - val roomAddressValidity: RoomAddressValidity, - val homeserverName: String, - val eventSink: (ConfigureRoomEvents) -> Unit -) { - val isValid: Boolean = config.roomName?.isNotEmpty() == true && - (config.roomVisibility is RoomVisibilityState.Private || roomAddressValidity == RoomAddressValidity.Valid) -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomStateProvider.kt deleted file mode 100644 index 09d801440b..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomStateProvider.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.configureroom - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.startchat.impl.CreateRoomConfig -import io.element.android.libraries.architecture.AsyncAction -import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.ui.components.aMatrixUserList -import io.element.android.libraries.matrix.ui.media.AvatarAction -import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity -import io.element.android.libraries.permissions.api.PermissionsState -import io.element.android.libraries.permissions.api.aPermissionsState -import kotlinx.collections.immutable.toImmutableList - -open class ConfigureRoomStateProvider : PreviewParameterProvider { - override val values: Sequence - get() = sequenceOf( - aConfigureRoomState(), - aConfigureRoomState( - isKnockFeatureEnabled = false, - config = CreateRoomConfig( - roomName = "Room 101", - topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", - invites = aMatrixUserList().toImmutableList(), - roomVisibility = RoomVisibilityState.Public( - roomAddress = RoomAddress.AutoFilled("Room-101"), - roomAccess = RoomAccess.Knocking, - ), - ), - ), - aConfigureRoomState( - config = CreateRoomConfig( - roomName = "Room 101", - topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", - invites = aMatrixUserList().toImmutableList(), - roomVisibility = RoomVisibilityState.Public( - roomAddress = RoomAddress.AutoFilled("Room-101"), - roomAccess = RoomAccess.Knocking, - ), - ), - ), - aConfigureRoomState( - config = CreateRoomConfig( - roomName = "Room 101", - topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", - roomVisibility = RoomVisibilityState.Public( - roomAddress = RoomAddress.AutoFilled("Room-101"), - roomAccess = RoomAccess.Knocking, - ), - ), - roomAddressValidity = RoomAddressValidity.NotAvailable, - ), - aConfigureRoomState( - config = CreateRoomConfig( - roomName = "Room 101", - topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", - roomVisibility = RoomVisibilityState.Public( - roomAddress = RoomAddress.AutoFilled("Room-101"), - roomAccess = RoomAccess.Knocking, - ), - ), - roomAddressValidity = RoomAddressValidity.InvalidSymbols, - ), - aConfigureRoomState( - config = CreateRoomConfig( - roomName = "Room 101", - topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines", - roomVisibility = RoomVisibilityState.Public( - roomAddress = RoomAddress.AutoFilled("Room-101"), - roomAccess = RoomAccess.Knocking, - ), - ), - roomAddressValidity = RoomAddressValidity.Valid, - ), - ) -} - -fun aConfigureRoomState( - config: CreateRoomConfig = CreateRoomConfig(), - isKnockFeatureEnabled: Boolean = true, - avatarActions: List = emptyList(), - createRoomAction: AsyncAction = AsyncAction.Uninitialized, - cameraPermissionState: PermissionsState = aPermissionsState(showDialog = false), - homeserverName: String = "matrix.org", - roomAddressValidity: RoomAddressValidity = RoomAddressValidity.Valid, - eventSink: (ConfigureRoomEvents) -> Unit = { }, -) = ConfigureRoomState( - config = config, - isKnockFeatureEnabled = isKnockFeatureEnabled, - avatarActions = avatarActions.toImmutableList(), - createRoomAction = createRoomAction, - cameraPermissionState = cameraPermissionState, - homeserverName = homeserverName, - roomAddressValidity = roomAddressValidity, - eventSink = eventSink, -) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomView.kt deleted file mode 100644 index c056570913..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomView.kt +++ /dev/null @@ -1,339 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.configureroom - -import android.net.Uri -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.selection.selectableGroup -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.KeyboardCapitalization -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.dp -import io.element.android.compound.theme.ElementTheme -import io.element.android.features.startchat.impl.R -import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage -import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtom -import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize -import io.element.android.libraries.designsystem.components.async.AsyncActionView -import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults -import io.element.android.libraries.designsystem.components.avatar.AvatarSize -import io.element.android.libraries.designsystem.components.avatar.AvatarType -import io.element.android.libraries.designsystem.components.button.BackButton -import io.element.android.libraries.designsystem.components.list.ListItemContent -import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap -import io.element.android.libraries.designsystem.preview.ElementPreviewDark -import io.element.android.libraries.designsystem.preview.ElementPreviewLight -import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight -import io.element.android.libraries.designsystem.theme.components.ListItem -import io.element.android.libraries.designsystem.theme.components.Scaffold -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.TextField -import io.element.android.libraries.designsystem.theme.components.TopAppBar -import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet -import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList -import io.element.android.libraries.matrix.ui.components.UnsavedAvatar -import io.element.android.libraries.matrix.ui.room.address.RoomAddressField -import io.element.android.libraries.permissions.api.PermissionsView -import io.element.android.libraries.ui.strings.CommonStrings - -@Composable -fun ConfigureRoomView( - state: ConfigureRoomState, - onBackClick: () -> Unit, - onCreateRoomSuccess: (RoomId) -> Unit, - modifier: Modifier = Modifier, -) { - val focusManager = LocalFocusManager.current - val isAvatarActionsSheetVisible = remember { mutableStateOf(false) } - - fun onAvatarClick() { - focusManager.clearFocus() - isAvatarActionsSheetVisible.value = true - } - - Scaffold( - modifier = modifier.clearFocusOnTap(focusManager), - topBar = { - ConfigureRoomToolbar( - isNextActionEnabled = state.isValid, - onBackClick = onBackClick, - onNextClick = { - focusManager.clearFocus() - state.eventSink(ConfigureRoomEvents.CreateRoom) - }, - ) - } - ) { padding -> - Column( - modifier = Modifier - .padding(padding) - .imePadding() - .verticalScroll(rememberScrollState()) - .consumeWindowInsets(padding), - verticalArrangement = Arrangement.spacedBy(24.dp), - ) { - RoomNameWithAvatar( - modifier = Modifier.padding(horizontal = 16.dp), - avatarUri = state.config.avatarUri, - roomName = state.config.roomName.orEmpty(), - onAvatarClick = ::onAvatarClick, - onChangeRoomName = { state.eventSink(ConfigureRoomEvents.RoomNameChanged(it)) }, - ) - RoomTopic( - modifier = Modifier.padding(horizontal = 16.dp), - topic = state.config.topic.orEmpty(), - onTopicChange = { state.eventSink(ConfigureRoomEvents.TopicChanged(it)) }, - ) - if (state.config.invites.isNotEmpty()) { - SelectedUsersRowList( - contentPadding = PaddingValues(horizontal = 24.dp), - selectedUsers = state.config.invites, - onUserRemove = { - focusManager.clearFocus() - state.eventSink(ConfigureRoomEvents.RemoveUserFromSelection(it)) - }, - ) - } - RoomVisibilityOptions( - selected = when (state.config.roomVisibility) { - is RoomVisibilityState.Private -> RoomVisibilityItem.Private - is RoomVisibilityState.Public -> RoomVisibilityItem.Public - }, - onOptionClick = { - focusManager.clearFocus() - state.eventSink(ConfigureRoomEvents.RoomVisibilityChanged(it)) - }, - ) - if (state.config.roomVisibility is RoomVisibilityState.Public && state.isKnockFeatureEnabled) { - RoomAccessOptions( - selected = when (state.config.roomVisibility.roomAccess) { - RoomAccess.Anyone -> RoomAccessItem.Anyone - RoomAccess.Knocking -> RoomAccessItem.AskToJoin - }, - onOptionClick = { - focusManager.clearFocus() - state.eventSink(ConfigureRoomEvents.RoomAccessChanged(it)) - }, - ) - RoomAddressField( - modifier = Modifier.padding(horizontal = 16.dp), - address = state.config.roomVisibility.roomAddress.value, - homeserverName = state.homeserverName, - addressValidity = state.roomAddressValidity, - onAddressChange = { state.eventSink(ConfigureRoomEvents.RoomAddressChanged(it)) }, - label = stringResource(R.string.screen_create_room_room_address_section_title), - supportingText = stringResource(R.string.screen_create_room_room_address_section_footer), - ) - Spacer(Modifier) - } - } - } - - AvatarActionBottomSheet( - actions = state.avatarActions, - isVisible = isAvatarActionsSheetVisible.value, - onDismiss = { isAvatarActionsSheetVisible.value = false }, - onSelectAction = { state.eventSink(ConfigureRoomEvents.HandleAvatarAction(it)) } - ) - - AsyncActionView( - async = state.createRoomAction, - progressDialog = { - AsyncActionViewDefaults.ProgressDialog( - progressText = stringResource(CommonStrings.common_creating_room), - ) - }, - onSuccess = { onCreateRoomSuccess(it) }, - errorMessage = { stringResource(R.string.screen_create_room_error_creating_room) }, - onRetry = { state.eventSink(ConfigureRoomEvents.CreateRoom) }, - onErrorDismiss = { state.eventSink(ConfigureRoomEvents.CancelCreateRoom) }, - ) - - PermissionsView( - state = state.cameraPermissionState, - ) -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun ConfigureRoomToolbar( - isNextActionEnabled: Boolean, - onBackClick: () -> Unit, - onNextClick: () -> Unit, -) { - TopAppBar( - titleStr = stringResource(R.string.screen_create_room_title), - navigationIcon = { BackButton(onClick = onBackClick) }, - actions = { - TextButton( - text = stringResource(CommonStrings.action_create), - enabled = isNextActionEnabled, - onClick = onNextClick, - ) - } - ) -} - -@Composable -private fun RoomNameWithAvatar( - avatarUri: Uri?, - roomName: String, - onAvatarClick: () -> Unit, - onChangeRoomName: (String) -> Unit, - modifier: Modifier = Modifier, -) { - Row( - modifier = modifier, - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - UnsavedAvatar( - avatarUri = avatarUri, - avatarSize = AvatarSize.EditRoomDetails, - avatarType = AvatarType.Room(), - modifier = Modifier.clickable(onClick = onAvatarClick), - ) - - TextField( - label = stringResource(R.string.screen_create_room_room_name_label), - value = roomName, - placeholder = stringResource(CommonStrings.common_room_name_placeholder), - singleLine = true, - onValueChange = onChangeRoomName, - ) - } -} - -@Composable -private fun RoomTopic( - topic: String, - onTopicChange: (String) -> Unit, - modifier: Modifier = Modifier, -) { - TextField( - modifier = modifier, - label = stringResource(R.string.screen_create_room_topic_label), - value = topic, - onValueChange = onTopicChange, - maxLines = 3, - supportingText = stringResource(CommonStrings.common_topic_placeholder), - keyboardOptions = KeyboardOptions( - capitalization = KeyboardCapitalization.Sentences, - ), - ) -} - -@Composable -private fun ConfigureRoomOptions( - title: String, - modifier: Modifier = Modifier, - content: @Composable ColumnScope.() -> Unit, -) { - Column( - modifier = modifier.selectableGroup() - ) { - Text( - text = title, - style = ElementTheme.typography.fontBodyLgMedium, - color = ElementTheme.colors.textPrimary, - modifier = Modifier.padding(horizontal = 16.dp), - ) - content() - } -} - -@Composable -private fun RoomVisibilityOptions( - selected: RoomVisibilityItem, - onOptionClick: (RoomVisibilityItem) -> Unit, - modifier: Modifier = Modifier, -) { - ConfigureRoomOptions( - title = stringResource(R.string.screen_create_room_room_visibility_section_title), - modifier = modifier, - ) { - RoomVisibilityItem.entries.forEach { item -> - val isSelected = item == selected - ListItem( - leadingContent = ListItemContent.Custom { - RoundedIconAtom( - size = RoundedIconAtomSize.Big, - resourceId = item.icon, - tint = if (isSelected) ElementTheme.colors.iconPrimary else ElementTheme.colors.iconSecondary, - ) - }, - headlineContent = { Text(text = stringResource(item.title)) }, - supportingContent = { Text(text = stringResource(item.description)) }, - trailingContent = ListItemContent.RadioButton(selected = isSelected), - onClick = { onOptionClick(item) }, - ) - } - } -} - -@Composable -private fun RoomAccessOptions( - selected: RoomAccessItem, - onOptionClick: (RoomAccessItem) -> Unit, - modifier: Modifier = Modifier, -) { - ConfigureRoomOptions( - title = stringResource(R.string.screen_create_room_room_access_section_header), - modifier = modifier, - ) { - RoomAccessItem.entries.forEach { item -> - ListItem( - headlineContent = { Text(text = stringResource(item.title)) }, - supportingContent = { Text(text = stringResource(item.description)) }, - trailingContent = ListItemContent.RadioButton(selected = item == selected), - onClick = { onOptionClick(item) }, - ) - } - } -} - -@PreviewWithLargeHeight -@Composable -internal fun ConfigureRoomViewLightPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) = - ElementPreviewLight { ContentToPreview(state) } - -@PreviewWithLargeHeight -@Composable -internal fun ConfigureRoomViewDarkPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) = - ElementPreviewDark { ContentToPreview(state) } - -@ExcludeFromCoverage -@Composable -private fun ContentToPreview(state: ConfigureRoomState) { - ConfigureRoomView( - state = state, - onBackClick = {}, - onCreateRoomSuccess = {}, - ) -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccess.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccess.kt deleted file mode 100644 index bf75d9605e..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccess.kt +++ /dev/null @@ -1,22 +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.features.startchat.impl.configureroom - -import io.element.android.libraries.matrix.api.room.join.JoinRule - -enum class RoomAccess { - Anyone, - Knocking -} - -fun RoomAccess.toJoinRule(): JoinRule? { - return when (this) { - RoomAccess.Anyone -> null - RoomAccess.Knocking -> JoinRule.Knock - } -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccessItem.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccessItem.kt deleted file mode 100644 index 0a48afe849..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAccessItem.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.configureroom - -import androidx.annotation.StringRes -import io.element.android.features.startchat.impl.R - -enum class RoomAccessItem( - @StringRes val title: Int, - @StringRes val description: Int -) { - Anyone( - title = R.string.screen_create_room_room_access_section_anyone_option_title, - description = R.string.screen_create_room_room_access_section_anyone_option_description, - ), - AskToJoin( - title = R.string.screen_create_room_room_access_section_knocking_option_title, - description = R.string.screen_create_room_room_access_section_knocking_option_description, - ), -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAddress.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAddress.kt deleted file mode 100644 index 51e02d881a..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomAddress.kt +++ /dev/null @@ -1,13 +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.features.startchat.impl.configureroom - -sealed class RoomAddress(open val value: String) { - data class AutoFilled(override val value: String) : RoomAddress(value) - data class Edited(override val value: String) : RoomAddress(value) -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityItem.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityItem.kt deleted file mode 100644 index 4ca8b51601..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityItem.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.configureroom - -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import io.element.android.features.startchat.impl.R -import io.element.android.libraries.designsystem.icons.CompoundDrawables - -enum class RoomVisibilityItem( - @DrawableRes val icon: Int, - @StringRes val title: Int, - @StringRes val description: Int -) { - Private( - icon = CompoundDrawables.ic_compound_lock, - title = R.string.screen_create_room_private_option_title, - description = R.string.screen_create_room_private_option_description, - ), - Public( - icon = CompoundDrawables.ic_compound_public, - title = R.string.screen_create_room_public_option_title, - description = R.string.screen_create_room_public_option_description, - ) -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityState.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityState.kt deleted file mode 100644 index 5a9a3126f6..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/configureroom/RoomVisibilityState.kt +++ /dev/null @@ -1,26 +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.features.startchat.impl.configureroom - -import java.util.Optional - -sealed interface RoomVisibilityState { - data object Private : RoomVisibilityState - - data class Public( - val roomAddress: RoomAddress, - val roomAccess: RoomAccess, - ) : RoomVisibilityState - - fun roomAddress(): Optional { - return when (this) { - is Private -> Optional.empty() - is Public -> Optional.of(roomAddress.value) - } - } -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomComponent.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomComponent.kt deleted file mode 100644 index 6f6569bcb3..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomComponent.kt +++ /dev/null @@ -1,28 +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.features.startchat.impl.di - -import com.squareup.anvil.annotations.ContributesTo -import com.squareup.anvil.annotations.MergeSubcomponent -import io.element.android.libraries.architecture.NodeFactoriesBindings -import io.element.android.libraries.di.SessionScope -import io.element.android.libraries.di.SingleIn - -@SingleIn(CreateRoomScope::class) -@MergeSubcomponent(CreateRoomScope::class) -interface CreateRoomComponent : NodeFactoriesBindings { - @MergeSubcomponent.Builder - interface Builder { - fun build(): CreateRoomComponent - } - - @ContributesTo(SessionScope::class) - interface ParentBindings { - fun createRoomComponentBuilder(): Builder - } -} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomScope.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomScope.kt deleted file mode 100644 index a164ba50b8..0000000000 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/di/CreateRoomScope.kt +++ /dev/null @@ -1,10 +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.features.startchat.impl.di - -abstract class CreateRoomScope private constructor() diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenterTest.kt deleted file mode 100644 index d5742b2a26..0000000000 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeoplePresenterTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -package io.element.android.features.startchat.impl.addpeople - -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.invitepeople.impl.CreateRoomDataStore -import io.element.android.features.startchat.impl.userlist.FakeUserListPresenterFactory -import io.element.android.features.invitepeople.impl.userlist.UserListDataStore -import io.element.android.libraries.matrix.test.room.alias.FakeRoomAliasHelper -import io.element.android.libraries.usersearch.test.FakeUserRepository -import io.element.android.tests.testutils.WarmUpRule -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Rule -import org.junit.Test - -class AddPeoplePresenterTest { - @get:Rule - val warmUpRule = WarmUpRule() - - private lateinit var presenter: AddPeoplePresenter - - @Before - fun setup() { - presenter = AddPeoplePresenter( - FakeUserListPresenterFactory(), - FakeUserRepository(), - CreateRoomDataStore(UserListDataStore(), FakeRoomAliasHelper()) - ) - } - - @Test - fun `present - initial state`() = runTest { - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - // TODO This doesn't actually test anything... - val initialState = awaitItem() - assertThat(initialState) - } - } -} diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleViewTest.kt deleted file mode 100644 index 9d8af8d61d..0000000000 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/addpeople/AddPeopleViewTest.kt +++ /dev/null @@ -1,89 +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.features.startchat.impl.addpeople - -import androidx.activity.ComponentActivity -import androidx.compose.ui.test.junit4.AndroidComposeTestRule -import androidx.compose.ui.test.junit4.createAndroidComposeRule -import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.features.invitepeople.impl.userlist.UserListEvents -import io.element.android.features.invitepeople.impl.userlist.UserListState -import io.element.android.features.invitepeople.impl.userlist.aUserListState -import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.tests.testutils.EnsureNeverCalled -import io.element.android.tests.testutils.EventsRecorder -import io.element.android.tests.testutils.clickOn -import io.element.android.tests.testutils.ensureCalledOnce -import io.element.android.tests.testutils.pressBack -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TestRule -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class AddPeopleViewTest { - @get:Rule - val rule = createAndroidComposeRule() - - @Test - fun `clicking on back invokes the expected callback`() { - val eventsRecorder = EventsRecorder() - ensureCalledOnce { - rule.setAddPeopleView( - aUserListState( - eventSink = eventsRecorder, - ), - onBackClick = it - ) - rule.pressBack() - } - eventsRecorder.assertSingle(UserListEvents.UpdateSearchQuery("")) - } - - @Test - fun `clicking on back during search emits the expected Event`() { - val eventsRecorder = EventsRecorder() - rule.setAddPeopleView( - aUserListState( - isSearchActive = true, - eventSink = eventsRecorder, - ), - ) - rule.pressBack() - eventsRecorder.assertSingle(UserListEvents.OnSearchActiveChanged(false)) - } - - @Test - fun `clicking on skip invokes the expected callback`() { - val eventsRecorder = EventsRecorder() - ensureCalledOnce { - rule.setAddPeopleView( - aUserListState( - eventSink = eventsRecorder, - ), - onNextClick = it - ) - rule.clickOn(CommonStrings.action_skip) - } - eventsRecorder.assertSingle(UserListEvents.UpdateSearchQuery("")) - } -} - -private fun AndroidComposeTestRule.setAddPeopleView( - state: UserListState, - onBackClick: () -> Unit = EnsureNeverCalled(), - onNextClick: () -> Unit = EnsureNeverCalled(), -) { - setContent { - AddPeopleView( - state = state, - onBackClick = onBackClick, - onSkipClick = onNextClick, - ) - } -} From c41994ad13d6f2619beb105135cc7439d6f366de Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 8 Aug 2025 19:06:19 +0200 Subject: [PATCH 04/30] refactor (start chat) : use invite people module in room details screen --- .../createroom/impl/CreateRoomFlowNode.kt | 3 +- .../impl/addpeople/AddPeopleNode.kt | 11 +- .../impl/addpeople/AddPeopleView.kt | 64 +++++++ .../invitepeople/api/InvitePeopleEvents.kt | 1 + .../invitepeople/api/InvitePeopleState.kt | 2 + .../api/InvitePeopleStateProvider.kt | 25 +++ features/invitepeople/impl/build.gradle.kts | 1 + .../impl/DefaultInvitePeoplePresenter.kt | 25 +++ .../impl/DefaultInvitePeopleRenderer.kt | 2 - .../impl/DefaultInvitePeopleState.kt | 4 +- .../invitepeople/impl/InvitePeopleView.kt | 111 ++++--------- features/roomdetails/impl/build.gradle.kts | 1 + .../impl/invite/RoomInviteMembersEvents.kt | 16 -- .../impl/invite/RoomInviteMembersNode.kt | 38 +---- .../impl/invite/RoomInviteMembersPresenter.kt | 154 ----------------- .../impl/invite/RoomInviteMembersState.kt | 30 ---- .../invite/RoomInviteMembersStateProvider.kt | 89 ---------- .../impl/invite/RoomInviteMembersView.kt | 157 +++--------------- .../apperror/api/AppErrorStateService.kt | 4 + .../impl/DefaultAppErrorStateService.kt | 12 +- 20 files changed, 207 insertions(+), 543 deletions(-) create mode 100644 features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt create mode 100644 features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt delete mode 100644 features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersEvents.kt delete mode 100644 features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt delete mode 100644 features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt delete mode 100644 features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt index 7d0d556e18..c4d085b95c 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt @@ -15,6 +15,7 @@ import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.push +import com.bumble.appyx.navmodel.backstack.operation.replace import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode @@ -48,7 +49,7 @@ class CreateRoomFlowNode @AssistedInject constructor( NavTarget.ConfigureRoom -> { val callback = object : ConfigureRoomNode.Callback { override fun onCreateRoomSuccess(roomId: RoomId) { - backstack.push(NavTarget.AddPeople(roomId)) + backstack.replace(NavTarget.AddPeople(roomId)) } } createNode(buildContext, plugins = listOf(callback)) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt index 914c316e1c..cba1516168 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt @@ -12,7 +12,6 @@ import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin -import com.squareup.anvil.annotations.ContributesBinding import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode @@ -27,13 +26,13 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom class AddPeopleNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val invitePeoplePresenterFactory: InvitePeoplePresenter.Factory, + invitePeoplePresenterFactory: InvitePeoplePresenter.Factory, private val invitePeopleRenderer: InvitePeopleRenderer, ) : Node(buildContext, plugins = plugins) { data class Inputs( val joinedRoom: JoinedRoom - ): NodeInputs + ) : NodeInputs private val joinedRoom = inputs().joinedRoom private val invitePeoplePresenter = invitePeoplePresenterFactory.create(joinedRoom) @@ -41,6 +40,10 @@ class AddPeopleNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { val state = invitePeoplePresenter.present() - invitePeopleRenderer.Render(state, Modifier) + AddPeopleView( + state = state, + invitePeopleView = { invitePeopleRenderer.Render(state, Modifier) }, + onFinish = {} + ) } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt new file mode 100644 index 0000000000..ddcdc7e9b1 --- /dev/null +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt @@ -0,0 +1,64 @@ +/* + * 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. + */ + +package io.element.android.features.createroom.impl.addpeople + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage +import io.element.android.libraries.designsystem.theme.components.Button +import io.element.android.libraries.designsystem.theme.components.TextButton +import io.element.android.libraries.designsystem.theme.components.TopAppBar +import io.element.android.libraries.ui.strings.CommonStrings + +@Composable +fun AddPeopleView( + state: InvitePeopleState, + invitePeopleView: @Composable () -> Unit, + onFinish: () -> Unit, + modifier: Modifier = Modifier, +) { + HeaderFooterPage( + modifier = modifier, + contentPadding = PaddingValues(0.dp), + topBar = { + AddPeopleTopBar(onSkipClick = onFinish) + }, + footer = { + Button( + text = "Finish", + onClick = { state.eventSink(InvitePeopleEvents.SendInvites) }, + enabled = state.canInvite, + modifier = Modifier.padding(bottom = 16.dp) + ) + }, + content = invitePeopleView + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun AddPeopleTopBar( + onSkipClick: () -> Unit, +) { + TopAppBar( + titleStr = "Invite people", + actions = { + TextButton( + text = stringResource(CommonStrings.action_skip), + onClick = onSkipClick, + ) + } + ) +} diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt index 60f9512651..0ab097462b 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleEvents.kt @@ -9,4 +9,5 @@ package io.element.android.features.invitepeople.api interface InvitePeopleEvents { data object SendInvites : InvitePeopleEvents + data object CloseSearch : InvitePeopleEvents } diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt index fb76dc0c1a..db8b9ffbd2 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleState.kt @@ -8,5 +8,7 @@ package io.element.android.features.invitepeople.api interface InvitePeopleState { + val canInvite: Boolean + val isSearchActive: Boolean val eventSink: (InvitePeopleEvents) -> Unit } diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt new file mode 100644 index 0000000000..70967580ac --- /dev/null +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package io.element.android.features.invitepeople.api + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider + +class InvitePeopleStateProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + PreviewInvitePeopleState(), + PreviewInvitePeopleState(canInvite = true), + PreviewInvitePeopleState(isSearchActive = true) + ) +} + +private data class PreviewInvitePeopleState( + override val canInvite: Boolean = false, + override val isSearchActive: Boolean = false, + override val eventSink: (InvitePeopleEvents) -> Unit = {} +) : InvitePeopleState diff --git a/features/invitepeople/impl/build.gradle.kts b/features/invitepeople/impl/build.gradle.kts index 80f91f2eff..82a716897e 100644 --- a/features/invitepeople/impl/build.gradle.kts +++ b/features/invitepeople/impl/build.gradle.kts @@ -34,6 +34,7 @@ dependencies { implementation(projects.libraries.androidutils) implementation(projects.libraries.usersearch.impl) implementation(libs.coil.compose) + implementation(projects.services.apperror.api) api(projects.features.invitepeople.api) testImplementation(libs.test.junit) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt index 7eb7af377a..7f3d0893ac 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt @@ -27,23 +27,30 @@ import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.annotations.AppCoroutineScope 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.api.room.filterMembers import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.usersearch.api.UserRepository +import io.element.android.services.apperror.api.AppErrorStateService import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class DefaultInvitePeoplePresenter @AssistedInject constructor( @Assisted private val room: JoinedRoom, private val userRepository: UserRepository, private val coroutineDispatchers: CoroutineDispatchers, + @AppCoroutineScope private val coroutineScope: CoroutineScope, + private val appErrorStateService: AppErrorStateService, ) : InvitePeoplePresenter { @AssistedFactory @@ -97,12 +104,30 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( searchResults.toggleUser(it.user) } is InvitePeopleEvents.SendInvites -> { + coroutineScope.sendInvites(selectedUsers.value) + } + is InvitePeopleEvents.CloseSearch -> { + searchActive = false + searchQuery = "" } } } ) } + private fun CoroutineScope.sendInvites(selectedUsers: List) = launch { + val anyInviteFailed = selectedUsers + .map { room.inviteUserById(it.userId) } + .any { it.isFailure } + + if (anyInviteFailed) { + appErrorStateService.showError( + titleRes = CommonStrings.common_unable_to_invite_title, + bodyRes = CommonStrings.common_unable_to_invite_message, + ) + } + } + @JvmName("toggleUserInSelectedUsers") private fun MutableState>.toggleUser(user: MatrixUser) { value = if (value.contains(user)) { diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt index 371b2fa84b..8207e75fd5 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleRenderer.kt @@ -22,8 +22,6 @@ class DefaultInvitePeopleRenderer @Inject constructor() : InvitePeopleRenderer { if (state is DefaultInvitePeopleState) { InvitePeopleView( state = state, - onBackClick = {}, - onSubmitClick = {}, modifier = modifier ) } else { diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt index d8104b748c..41f49e74c0 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt @@ -14,11 +14,11 @@ import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList data class DefaultInvitePeopleState( - val canInvite: Boolean, + override val canInvite: Boolean, val searchQuery: String, val showSearchLoader: Boolean, val searchResults: SearchBarResultState>, val selectedUsers: ImmutableList, - val isSearchActive: Boolean, + override val isSearchActive: Boolean, override val eventSink: (InvitePeopleEvents) -> Unit ): InvitePeopleState diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt index b87f92526a..6c9a6845a2 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -7,10 +7,10 @@ package io.element.android.features.invitepeople.impl +import androidx.activity.OnBackPressedDispatcher import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -21,6 +21,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import com.bumble.appyx.core.plugin.BackPressHandler import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.components.async.AsyncLoading import io.element.android.libraries.designsystem.components.avatar.AvatarSize @@ -28,7 +29,6 @@ import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.HorizontalDivider -import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.SearchBar import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.designsystem.theme.components.Text @@ -46,87 +46,46 @@ import kotlinx.collections.immutable.ImmutableList @Composable fun InvitePeopleView( state: DefaultInvitePeopleState, - onBackClick: () -> Unit, - onSubmitClick: (List) -> Unit, modifier: Modifier = Modifier, ) { - Scaffold( - modifier = modifier, - topBar = { - RoomInviteMembersTopBar( - onBackClick = { - if (state.isSearchActive) { - state.eventSink(DefaultInvitePeopleEvents.OnSearchActiveChanged(false)) - } else { - onBackClick() - } - }, - onSubmitClick = { onSubmitClick(state.selectedUsers) }, - canSend = state.canInvite, - ) - } - ) { padding -> - Column( - modifier = Modifier - .fillMaxWidth() - .padding(padding) - .consumeWindowInsets(padding), - verticalArrangement = Arrangement.spacedBy(16.dp), - ) { - RoomInviteMembersSearchBar( - modifier = Modifier.fillMaxWidth(), - query = state.searchQuery, - showLoader = state.showSearchLoader, - selectedUsers = state.selectedUsers, - state = state.searchResults, - active = state.isSearchActive, - onActiveChange = { - state.eventSink( - DefaultInvitePeopleEvents.OnSearchActiveChanged( - it - ) - ) - }, - onTextChange = { state.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery(it)) }, - onToggleUser = { state.eventSink(DefaultInvitePeopleEvents.ToggleUser(it)) }, - ) - if (!state.isSearchActive) { - SelectedUsersRowList( - modifier = Modifier.fillMaxWidth(), - selectedUsers = state.selectedUsers, - autoScroll = true, - onUserRemove = { state.eventSink(DefaultInvitePeopleEvents.ToggleUser(it)) }, - contentPadding = PaddingValues(16.dp), + Column( + modifier = modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + InvitePeopleSearchBar( + modifier = Modifier.fillMaxWidth(), + query = state.searchQuery, + showLoader = state.showSearchLoader, + selectedUsers = state.selectedUsers, + state = state.searchResults, + active = state.isSearchActive, + onActiveChange = { + state.eventSink( + DefaultInvitePeopleEvents.OnSearchActiveChanged( + it + ) ) - } + }, + onTextChange = { state.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery(it)) }, + onToggleUser = { state.eventSink(DefaultInvitePeopleEvents.ToggleUser(it)) }, + ) + + if (!state.isSearchActive) { + SelectedUsersRowList( + modifier = Modifier.fillMaxWidth(), + selectedUsers = state.selectedUsers, + autoScroll = true, + onUserRemove = { state.eventSink(DefaultInvitePeopleEvents.ToggleUser(it)) }, + contentPadding = PaddingValues(16.dp), + ) } } } @OptIn(ExperimentalMaterial3Api::class) @Composable -private fun RoomInviteMembersTopBar( - canSend: Boolean, - onBackClick: () -> Unit, - onSubmitClick: () -> Unit, -) { - TopAppBar( - titleStr = "Invite people", - navigationIcon = { BackButton(onClick = onBackClick) }, - actions = { - TextButton( - text = stringResource(CommonStrings.action_invite), - onClick = onSubmitClick, - enabled = canSend, - ) - } - ) -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun RoomInviteMembersSearchBar( +private fun InvitePeopleSearchBar( query: String, state: SearchBarResultState>, showLoader: Boolean, @@ -219,9 +178,5 @@ private fun RoomInviteMembersSearchBar( @Composable internal fun RoomInviteMembersViewPreview(@PreviewParameter(DefaultInvitePeopleStateProvider::class) state: DefaultInvitePeopleState) = ElementPreview { - InvitePeopleView( - state = state, - onBackClick = {}, - onSubmitClick = {}, - ) + InvitePeopleView(state = state) } diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts index 91bb79c8b7..302ae7d8c6 100644 --- a/features/roomdetails/impl/build.gradle.kts +++ b/features/roomdetails/impl/build.gradle.kts @@ -56,6 +56,7 @@ dependencies { implementation(projects.features.reportroom.api) implementation(projects.features.roommembermoderation.api) implementation(projects.features.changeroommemberroles.api) + implementation(projects.features.invitepeople.api) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersEvents.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersEvents.kt deleted file mode 100644 index a06ae82c49..0000000000 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersEvents.kt +++ /dev/null @@ -1,16 +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.features.roomdetails.impl.invite - -import io.element.android.libraries.matrix.api.user.MatrixUser - -sealed interface RoomInviteMembersEvents { - data class ToggleUser(val user: MatrixUser) : RoomInviteMembersEvents - data class UpdateSearchQuery(val query: String) : RoomInviteMembersEvents - data class OnSearchActiveChanged(val active: Boolean) : RoomInviteMembersEvents -} 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 ebfa3dcab8..270290f05d 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 @@ -9,7 +9,6 @@ package io.element.android.features.roomdetails.impl.invite import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node @@ -18,27 +17,22 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.invitepeople.api.InvitePeoplePresenter +import io.element.android.features.invitepeople.api.InvitePeopleRenderer import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.di.RoomScope 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 -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.launch @ContributesNode(RoomScope::class) class RoomInviteMembersNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - coroutineDispatchers: CoroutineDispatchers, private val room: JoinedRoom, - private val presenter: RoomInviteMembersPresenter, - private val appErrorStateService: AppErrorStateService, private val analyticsService: AnalyticsService, + private val invitePeopleRenderer: InvitePeopleRenderer, + private val invitePeoplePresenterFactory: InvitePeoplePresenter.Factory, ) : Node(buildContext, plugins = plugins) { - private val coroutineScope = CoroutineScope(SupervisorJob() + coroutineDispatchers.io) init { lifecycle.subscribe( @@ -48,31 +42,17 @@ class RoomInviteMembersNode @AssistedInject constructor( ) } + private val invitePeoplePresenter = invitePeoplePresenterFactory.create(room) + @Composable override fun View(modifier: Modifier) { - val state = presenter.present() - val context = LocalContext.current.applicationContext - + val state = invitePeoplePresenter.present() RoomInviteMembersView( state = state, modifier = modifier, + invitePeopleView = { invitePeopleRenderer.Render(state, Modifier) }, onBackClick = { navigateUp() }, - onSubmitClick = { users -> - navigateUp() - - coroutineScope.launch { - val anyInviteFailed = users - .map { room.inviteUserById(it.userId) } - .any { it.isFailure } - - if (anyInviteFailed) { - appErrorStateService.showError( - title = context.getString(CommonStrings.common_unable_to_invite_title), - body = context.getString(CommonStrings.common_unable_to_invite_message), - ) - } - } - } + onSubmitClick = { navigateUp() } ) } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt deleted file mode 100644 index ed5d13f70b..0000000000 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenter.kt +++ /dev/null @@ -1,154 +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.features.roomdetails.impl.invite - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource -import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.architecture.runCatchingUpdatingState -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.RoomMember -import io.element.android.libraries.matrix.api.room.RoomMembershipState -import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.usersearch.api.UserRepository -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.withContext -import javax.inject.Inject - -class RoomInviteMembersPresenter @Inject constructor( - private val userRepository: UserRepository, - private val roomMemberListDataSource: RoomMemberListDataSource, - private val coroutineDispatchers: CoroutineDispatchers, -) : Presenter { - @Composable - override fun present(): RoomInviteMembersState { - val roomMembers = remember { mutableStateOf>>(AsyncData.Loading()) } - val selectedUsers = remember { mutableStateOf>(persistentListOf()) } - val searchResults = remember { mutableStateOf>>(SearchBarResultState.Initial()) } - var searchQuery by rememberSaveable { mutableStateOf("") } - var searchActive by rememberSaveable { mutableStateOf(false) } - val showSearchLoader = rememberSaveable { mutableStateOf(false) } - - LaunchedEffect(Unit) { - fetchMembers(roomMembers) - } - LaunchedEffect(searchQuery, roomMembers) { - performSearch( - searchResults = searchResults, - roomMembers = roomMembers, - selectedUsers = selectedUsers, - showSearchLoader = showSearchLoader, - searchQuery = searchQuery - ) - } - - return RoomInviteMembersState( - canInvite = selectedUsers.value.isNotEmpty(), - selectedUsers = selectedUsers.value, - searchQuery = searchQuery, - isSearchActive = searchActive, - searchResults = searchResults.value, - showSearchLoader = showSearchLoader.value, - eventSink = { - when (it) { - is RoomInviteMembersEvents.OnSearchActiveChanged -> { - searchActive = it.active - searchQuery = "" - } - - is RoomInviteMembersEvents.UpdateSearchQuery -> { - searchQuery = it.query - } - - is RoomInviteMembersEvents.ToggleUser -> { - selectedUsers.toggleUser(it.user) - searchResults.toggleUser(it.user) - } - } - } - ) - } - - @JvmName("toggleUserInSelectedUsers") - private fun MutableState>.toggleUser(user: MatrixUser) { - value = if (value.contains(user)) { - value.filterNot { it.userId == user.userId } - } else { - value + user - }.toImmutableList() - } - - @JvmName("toggleUserInSearchResults") - private fun MutableState>>.toggleUser(user: MatrixUser) { - val existingResults = value - if (existingResults is SearchBarResultState.Results) { - value = SearchBarResultState.Results( - existingResults.results.map { iu -> - if (iu.matrixUser == user) { - iu.copy(isSelected = !iu.isSelected) - } else { - iu - } - }.toImmutableList() - ) - } - } - - private suspend fun performSearch( - searchResults: MutableState>>, - roomMembers: MutableState>>, - selectedUsers: MutableState>, - showSearchLoader: MutableState, - searchQuery: String, - ) = withContext(coroutineDispatchers.io) { - searchResults.value = SearchBarResultState.Initial() - showSearchLoader.value = false - val joinedMembers = roomMembers.value.dataOrNull().orEmpty() - - userRepository.search(searchQuery).onEach { state -> - showSearchLoader.value = state.isSearching - searchResults.value = when { - state.results.isEmpty() && state.isSearching -> SearchBarResultState.Initial() - state.results.isEmpty() && !state.isSearching -> SearchBarResultState.NoResultsFound() - else -> SearchBarResultState.Results(state.results.map { result -> - val existingMembership = joinedMembers.firstOrNull { j -> j.userId == result.matrixUser.userId }?.membership - val isJoined = existingMembership == RoomMembershipState.JOIN - val isInvited = existingMembership == RoomMembershipState.INVITE - InvitableUser( - matrixUser = result.matrixUser, - isSelected = selectedUsers.value.contains(result.matrixUser) || isJoined || isInvited, - isAlreadyJoined = isJoined, - isAlreadyInvited = isInvited, - isUnresolved = result.isUnresolved, - ) - }.toImmutableList()) - } - }.launchIn(this) - } - - private suspend fun fetchMembers(roomMembers: MutableState>>) { - suspend { - withContext(coroutineDispatchers.io) { - roomMemberListDataSource.search("").toImmutableList() - } - }.runCatchingUpdatingState(roomMembers) - } -} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt deleted file mode 100644 index c7927247ef..0000000000 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersState.kt +++ /dev/null @@ -1,30 +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.features.roomdetails.impl.invite - -import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -import io.element.android.libraries.matrix.api.user.MatrixUser -import kotlinx.collections.immutable.ImmutableList - -data class RoomInviteMembersState( - val canInvite: Boolean, - val searchQuery: String, - val showSearchLoader: Boolean, - val searchResults: SearchBarResultState>, - val selectedUsers: ImmutableList, - val isSearchActive: Boolean, - val eventSink: (RoomInviteMembersEvents) -> Unit, -) - -data class InvitableUser( - val matrixUser: MatrixUser, - val isSelected: Boolean = false, - val isAlreadyJoined: Boolean = false, - val isAlreadyInvited: Boolean = false, - val isUnresolved: Boolean = false, -) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt deleted file mode 100644 index 7675880f37..0000000000 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersStateProvider.kt +++ /dev/null @@ -1,89 +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.features.roomdetails.impl.invite - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.matrix.ui.components.aMatrixUser -import io.element.android.libraries.matrix.ui.components.aMatrixUserList -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList - -internal class RoomInviteMembersStateProvider : PreviewParameterProvider { - override val values: Sequence - get() = sequenceOf( - aRoomInviteMembersState(), - aRoomInviteMembersState(canInvite = true, selectedUsers = aMatrixUserList().toImmutableList()), - aRoomInviteMembersState(isSearchActive = true, searchQuery = "some query"), - aRoomInviteMembersState(isSearchActive = true, searchQuery = "some query", selectedUsers = aMatrixUserList().toImmutableList()), - aRoomInviteMembersState(isSearchActive = true, searchQuery = "some query", searchResults = SearchBarResultState.NoResultsFound()), - aRoomInviteMembersState( - isSearchActive = true, - canInvite = true, - searchQuery = "some query", - selectedUsers = persistentListOf( - aMatrixUser("@carol:server.org", "Carol") - ), - searchResults = SearchBarResultState.Results( - persistentListOf( - InvitableUser(aMatrixUser("@alice:server.org")), - InvitableUser(aMatrixUser("@bob:server.org", "Bob")), - InvitableUser(aMatrixUser("@carol:server.org", "Carol"), isSelected = true), - InvitableUser(aMatrixUser("@eve:server.org", "Eve"), isSelected = true, isAlreadyJoined = true), - InvitableUser(aMatrixUser("@justin:server.org", "Justin"), isSelected = true, isAlreadyInvited = true), - ) - ) - ), - aRoomInviteMembersState( - isSearchActive = true, - canInvite = true, - searchQuery = "@alice:server.org", - selectedUsers = persistentListOf( - aMatrixUser("@carol:server.org", "Carol") - ), - searchResults = SearchBarResultState.Results( - persistentListOf( - InvitableUser(aMatrixUser("@alice:server.org"), isUnresolved = true), - InvitableUser(aMatrixUser("@bob:server.org", "Bob")), - ) - ) - ), - aRoomInviteMembersState( - isSearchActive = true, - canInvite = true, - searchQuery = "@alice:server.org", - searchResults = SearchBarResultState.Results( - persistentListOf( - InvitableUser(aMatrixUser("@alice:server.org"), isUnresolved = true), - ) - ), - showSearchLoader = true, - ), - ) -} - -private fun aRoomInviteMembersState( - canInvite: Boolean = false, - searchQuery: String = "", - searchResults: SearchBarResultState> = SearchBarResultState.Initial(), - selectedUsers: ImmutableList = persistentListOf(), - isSearchActive: Boolean = false, - showSearchLoader: Boolean = false, -): RoomInviteMembersState { - return RoomInviteMembersState( - canInvite = canInvite, - searchQuery = searchQuery, - searchResults = searchResults, - selectedUsers = selectedUsers, - isSearchActive = isSearchActive, - showSearchLoader = showSearchLoader, - eventSink = {}, - ) -} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt index caae6ff16d..608f9047ae 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt @@ -8,47 +8,35 @@ package io.element.android.features.roomdetails.impl.invite import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import io.element.android.compound.theme.ElementTheme +import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.features.invitepeople.api.InvitePeopleStateProvider import io.element.android.features.roomdetails.impl.R -import io.element.android.libraries.designsystem.components.async.AsyncLoading -import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Scaffold -import io.element.android.libraries.designsystem.theme.components.SearchBar -import io.element.android.libraries.designsystem.theme.components.SearchBarResultState -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.user.MatrixUser -import io.element.android.libraries.matrix.ui.components.CheckableUserRow -import io.element.android.libraries.matrix.ui.components.CheckableUserRowData -import io.element.android.libraries.matrix.ui.components.SelectedUsersRowList -import io.element.android.libraries.matrix.ui.model.getAvatarData -import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.ui.strings.CommonStrings -import kotlinx.collections.immutable.ImmutableList @Composable fun RoomInviteMembersView( - state: RoomInviteMembersState, + state: InvitePeopleState, + invitePeopleView: @Composable () -> Unit, onBackClick: () -> Unit, - onSubmitClick: (List) -> Unit, + onSubmitClick: () -> Unit, modifier: Modifier = Modifier, ) { Scaffold( @@ -57,45 +45,28 @@ fun RoomInviteMembersView( RoomInviteMembersTopBar( onBackClick = { if (state.isSearchActive) { - state.eventSink(RoomInviteMembersEvents.OnSearchActiveChanged(false)) + state.eventSink(InvitePeopleEvents.CloseSearch) } else { onBackClick() } }, - onSubmitClick = { onSubmitClick(state.selectedUsers) }, + onSubmitClick = { + state.eventSink(InvitePeopleEvents.SendInvites) + onSubmitClick() + }, canSend = state.canInvite, ) } ) { padding -> - Column( + Box( modifier = Modifier - .fillMaxWidth() - .padding(padding) - .consumeWindowInsets(padding), - verticalArrangement = Arrangement.spacedBy(16.dp), + .fillMaxWidth() + .padding(padding) + .consumeWindowInsets(padding), ) { - RoomInviteMembersSearchBar( - modifier = Modifier.fillMaxWidth(), - query = state.searchQuery, - showLoader = state.showSearchLoader, - selectedUsers = state.selectedUsers, - state = state.searchResults, - active = state.isSearchActive, - onActiveChange = { state.eventSink(RoomInviteMembersEvents.OnSearchActiveChanged(it)) }, - onTextChange = { state.eventSink(RoomInviteMembersEvents.UpdateSearchQuery(it)) }, - onToggleUser = { state.eventSink(RoomInviteMembersEvents.ToggleUser(it)) }, - ) - - if (!state.isSearchActive) { - SelectedUsersRowList( - modifier = Modifier.fillMaxWidth(), - selectedUsers = state.selectedUsers, - autoScroll = true, - onUserRemove = { state.eventSink(RoomInviteMembersEvents.ToggleUser(it)) }, - contentPadding = PaddingValues(16.dp), - ) - } + invitePeopleView() } + } } @@ -119,100 +90,12 @@ private fun RoomInviteMembersTopBar( ) } -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun RoomInviteMembersSearchBar( - query: String, - state: SearchBarResultState>, - showLoader: Boolean, - selectedUsers: ImmutableList, - active: Boolean, - onActiveChange: (Boolean) -> Unit, - onTextChange: (String) -> Unit, - onToggleUser: (MatrixUser) -> Unit, - modifier: Modifier = Modifier, - placeHolderTitle: String = stringResource(CommonStrings.common_search_for_someone), -) { - SearchBar( - query = query, - onQueryChange = onTextChange, - active = active, - onActiveChange = onActiveChange, - modifier = modifier, - placeHolderTitle = placeHolderTitle, - contentPrefix = { - if (selectedUsers.isNotEmpty()) { - SelectedUsersRowList( - modifier = Modifier.fillMaxWidth(), - selectedUsers = selectedUsers, - autoScroll = true, - onUserRemove = onToggleUser, - contentPadding = PaddingValues(16.dp), - ) - } - }, - showBackButton = false, - resultState = state, - contentSuffix = { - if (showLoader) { - AsyncLoading() - } - }, - resultHandler = { results -> - Text( - text = stringResource(id = CommonStrings.common_search_results), - style = ElementTheme.typography.fontBodyLgMedium, - modifier = Modifier - .fillMaxWidth() - .padding(start = 16.dp, top = 12.dp, end = 16.dp, bottom = 8.dp) - ) - - LazyColumn { - itemsIndexed(results) { index, invitableUser -> - val notInvitedOrJoined = !(invitableUser.isAlreadyInvited || invitableUser.isAlreadyJoined) - val isUnresolved = invitableUser.isUnresolved && notInvitedOrJoined - val enabled = isUnresolved || notInvitedOrJoined - val data = if (isUnresolved) { - CheckableUserRowData.Unresolved( - avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), - id = invitableUser.matrixUser.userId.value, - ) - } else { - CheckableUserRowData.Resolved( - avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), - name = invitableUser.matrixUser.getBestName(), - subtext = when { - // If they're already invited or joined we show that information - invitableUser.isAlreadyJoined -> stringResource(R.string.screen_room_details_already_a_member) - invitableUser.isAlreadyInvited -> stringResource(R.string.screen_room_details_already_invited) - // Otherwise show the ID, unless that's already used for their name - invitableUser.matrixUser.displayName.isNullOrEmpty().not() -> invitableUser.matrixUser.userId.value - else -> null - } - ) - } - CheckableUserRow( - checked = invitableUser.isSelected, - enabled = enabled, - data = data, - onCheckedChange = { onToggleUser(invitableUser.matrixUser) }, - modifier = Modifier.fillMaxWidth() - ) - - if (index < results.lastIndex) { - HorizontalDivider() - } - } - } - }, - ) -} - @PreviewsDayNight @Composable -internal fun RoomInviteMembersViewPreview(@PreviewParameter(RoomInviteMembersStateProvider::class) state: RoomInviteMembersState) = ElementPreview { +internal fun RoomInviteMembersViewPreview(@PreviewParameter(InvitePeopleStateProvider::class) state: InvitePeopleState) = ElementPreview { RoomInviteMembersView( state = state, + invitePeopleView = {}, onBackClick = {}, onSubmitClick = {}, ) diff --git a/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt b/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt index 45031fdf33..6921ba1958 100644 --- a/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt +++ b/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt @@ -7,10 +7,14 @@ package io.element.android.services.apperror.api +import androidx.annotation.StringRes import kotlinx.coroutines.flow.StateFlow interface AppErrorStateService { val appErrorStateFlow: StateFlow fun showError(title: String, body: String) + + fun showError(@StringRes titleRes: Int, @StringRes bodyRes: Int) + } diff --git a/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt b/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt index 7341028784..ca6e6d34cf 100644 --- a/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt +++ b/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt @@ -7,8 +7,10 @@ package io.element.android.services.apperror.impl +import android.content.Context import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.SingleIn import io.element.android.services.apperror.api.AppErrorState import io.element.android.services.apperror.api.AppErrorStateService @@ -18,7 +20,9 @@ import javax.inject.Inject @ContributesBinding(AppScope::class) @SingleIn(AppScope::class) -class DefaultAppErrorStateService @Inject constructor() : AppErrorStateService { +class DefaultAppErrorStateService @Inject constructor( + @ApplicationContext private val context: Context, +) : AppErrorStateService { private val currentAppErrorState = MutableStateFlow(AppErrorState.NoError) override val appErrorStateFlow: StateFlow = currentAppErrorState @@ -31,4 +35,10 @@ class DefaultAppErrorStateService @Inject constructor() : AppErrorStateService { }, ) } + + override fun showError(titleRes: Int, bodyRes: Int) { + val title = context.getString(titleRes) + val body = context.getString(bodyRes) + showError(title, body) + } } From 5bbfaad03bd4468218f81e22b614083c2364b76f Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 8 Aug 2025 19:23:46 +0200 Subject: [PATCH 05/30] refactor (start chat) : properly finish create room flow --- .../createroom/api/CreateRoomEntryPoint.kt | 20 ++++++++++++++-- .../createroom/impl/CreateRoomFlowNode.kt | 14 +++++++++-- .../impl/DefaultCreateRoomEntryPoint.kt | 20 +++++++++++++--- .../impl/addpeople/AddPeopleNode.kt | 11 ++++++++- .../impl/addpeople/AddPeopleView.kt | 24 +++++++++++++++++-- .../startchat/impl/StartChatFlowNode.kt | 11 ++++++++- 6 files changed, 89 insertions(+), 11 deletions(-) diff --git a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt b/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt index 6b4f02c033..ad4aa75ac5 100644 --- a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt +++ b/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt @@ -7,6 +7,22 @@ package io.element.android.features.createroom.api -import io.element.android.libraries.architecture.SimpleFeatureEntryPoint +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import io.element.android.libraries.architecture.FeatureEntryPoint +import io.element.android.libraries.matrix.api.core.RoomId -interface CreateRoomEntryPoint: SimpleFeatureEntryPoint +interface CreateRoomEntryPoint : FeatureEntryPoint { + + fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + + interface NodeBuilder { + fun callback(callback: Callback): NodeBuilder + fun build(): Node + } + + interface Callback: Plugin { + fun onRoomCreated(roomId: RoomId) + } +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt index c4d085b95c..d2f6ae7ad5 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt @@ -13,12 +13,13 @@ import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack -import com.bumble.appyx.navmodel.backstack.operation.push import com.bumble.appyx.navmodel.backstack.operation.replace import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.features.createroom.impl.addpeople.AddPeopleNode import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode import io.element.android.libraries.architecture.BackstackView @@ -44,6 +45,10 @@ class CreateRoomFlowNode @AssistedInject constructor( plugins = plugins ) { + private fun onRoomCreated(roomId: RoomId) { + plugins().forEach { it.onRoomCreated(roomId) } + } + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { NavTarget.ConfigureRoom -> { @@ -57,7 +62,12 @@ class CreateRoomFlowNode @AssistedInject constructor( is NavTarget.AddPeople -> { val joinedRoom = runBlocking { client.getJoinedRoom(navTarget.roomId) } ?: error("Room not found") val inputs = AddPeopleNode.Inputs(joinedRoom) - createNode(buildContext, plugins = listOf(inputs)) + val callback: AddPeopleNode.Callback = object : AddPeopleNode.Callback { + override fun onFinish() { + onRoomCreated(navTarget.roomId) + } + } + createNode(buildContext, plugins = listOf(inputs, callback)) } } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt index 95f80cdfcf..3281aa97f3 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt @@ -9,6 +9,7 @@ package io.element.android.features.createroom.impl import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin import com.squareup.anvil.annotations.ContributesBinding import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.libraries.architecture.createNode @@ -16,8 +17,21 @@ import io.element.android.libraries.di.SessionScope import javax.inject.Inject @ContributesBinding(SessionScope::class) -class DefaultCreateRoomEntryPoint @Inject constructor(): CreateRoomEntryPoint { - override fun createNode(parentNode: Node, buildContext: BuildContext): Node { - return parentNode.createNode(buildContext) +class DefaultCreateRoomEntryPoint @Inject constructor() : CreateRoomEntryPoint { + + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): CreateRoomEntryPoint.NodeBuilder { + + val plugins = ArrayList() + + return object : CreateRoomEntryPoint.NodeBuilder { + override fun callback(callback: CreateRoomEntryPoint.Callback): CreateRoomEntryPoint.NodeBuilder { + plugins += callback + return this + } + + override fun build(): Node { + return parentNode.createNode(buildContext, plugins) + } + } } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt index cba1516168..a5bd6e828b 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode @@ -34,6 +35,14 @@ class AddPeopleNode @AssistedInject constructor( val joinedRoom: JoinedRoom ) : NodeInputs + interface Callback : Plugin { + fun onFinish() + } + + private fun onFinish() { + plugins().forEach { it.onFinish() } + } + private val joinedRoom = inputs().joinedRoom private val invitePeoplePresenter = invitePeoplePresenterFactory.create(joinedRoom) @@ -43,7 +52,7 @@ class AddPeopleNode @AssistedInject constructor( AddPeopleView( state = state, invitePeopleView = { invitePeopleRenderer.Render(state, Modifier) }, - onFinish = {} + onFinish = ::onFinish ) } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt index ddcdc7e9b1..d918b4a227 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt @@ -8,15 +8,20 @@ package io.element.android.features.createroom.impl.addpeople import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.features.invitepeople.api.InvitePeopleEvents import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.features.invitepeople.api.InvitePeopleStateProvider import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TopAppBar @@ -38,9 +43,14 @@ fun AddPeopleView( footer = { Button( text = "Finish", - onClick = { state.eventSink(InvitePeopleEvents.SendInvites) }, + onClick = { + state.eventSink(InvitePeopleEvents.SendInvites) + onFinish() + }, enabled = state.canInvite, - modifier = Modifier.padding(bottom = 16.dp) + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 16.dp) ) }, content = invitePeopleView @@ -62,3 +72,13 @@ private fun AddPeopleTopBar( } ) } + +@PreviewsDayNight +@Composable +internal fun AddPeopleViewPreview(@PreviewParameter(InvitePeopleStateProvider::class) state: InvitePeopleState) = ElementPreview { + AddPeopleView( + state = state, + invitePeopleView = {}, + onFinish = {}, + ) +} diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt index 1f4ae758d4..a312b6fa84 100644 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/StartChatFlowNode.kt @@ -31,6 +31,8 @@ import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.OverlayView import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import kotlinx.parcelize.Parcelize @ContributesNode(SessionScope::class) @@ -74,7 +76,14 @@ class StartChatFlowNode @AssistedInject constructor( createNode(buildContext = buildContext, plugins = listOf(navigator)) } NavTarget.NewRoom -> { - createRoomEntryPoint.createNode(parentNode = this, buildContext = buildContext) + val callback = object : CreateRoomEntryPoint.Callback { + override fun onRoomCreated(roomId: RoomId) { + navigator.onOpenRoom(roomId.toRoomIdOrAlias(), emptyList()) + } + } + createRoomEntryPoint.nodeBuilder(parentNode = this, buildContext = buildContext) + .callback(callback) + .build() } NavTarget.JoinByAddress -> { createNode(buildContext = buildContext, plugins = listOf(navigator)) From 9c32dbba585b096d79e1e7fcb51650f025c69ce9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 10:49:05 +0200 Subject: [PATCH 06/30] Inject a StringProvider instead of the context, and update tests. Also remove the other StringProvider we had, it was not used anymore --- appnav/build.gradle.kts | 1 + .../android/appnav/RootPresenterTest.kt | 9 ++++-- .../designsystem/utils/StringProvider.kt | 15 ---------- .../apperror/api/AppErrorStateService.kt | 1 - services/apperror/impl/build.gradle.kts | 2 ++ .../impl/DefaultAppErrorStateService.kt | 9 +++--- .../impl/DefaultAppErrorStateServiceTest.kt | 28 +++++++++++++++---- 7 files changed, 36 insertions(+), 29 deletions(-) delete mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/StringProvider.kt diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts index e6b50eaaf6..bc0fa405a7 100644 --- a/appnav/build.gradle.kts +++ b/appnav/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { testImplementation(projects.features.rageshake.test) testImplementation(projects.services.appnavstate.test) testImplementation(projects.services.analytics.test) + testImplementation(projects.services.toolbox.test) testImplementation(libs.test.appyx.junit) testImplementation(libs.test.arch.core) } diff --git a/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt index 4c8b2a803d..2a343a1592 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt @@ -19,6 +19,7 @@ import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.apperror.api.AppErrorState import io.element.android.services.apperror.api.AppErrorStateService import io.element.android.services.apperror.impl.DefaultAppErrorStateService +import io.element.android.services.toolbox.test.strings.FakeStringProvider import io.element.android.tests.testutils.WarmUpRule import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -42,7 +43,9 @@ class RootPresenterTest { @Test fun `present - passes app error state`() = runTest { val presenter = createRootPresenter( - appErrorService = DefaultAppErrorStateService().apply { + appErrorService = DefaultAppErrorStateService( + stringProvider = FakeStringProvider(), + ).apply { showError("Bad news", "Something bad happened") } ) @@ -61,7 +64,9 @@ class RootPresenterTest { } private fun createRootPresenter( - appErrorService: AppErrorStateService = DefaultAppErrorStateService(), + appErrorService: AppErrorStateService = DefaultAppErrorStateService( + stringProvider = FakeStringProvider(), + ), ): RootPresenter { return RootPresenter( crashDetectionPresenter = { aCrashDetectionState() }, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/StringProvider.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/StringProvider.kt deleted file mode 100644 index 74c11e58c0..0000000000 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/utils/StringProvider.kt +++ /dev/null @@ -1,15 +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.designsystem.utils - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider - -open class StringProvider(val strings: List) : PreviewParameterProvider { - override val values: Sequence - get() = strings.asSequence() -} diff --git a/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt b/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt index 6921ba1958..8070673804 100644 --- a/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt +++ b/services/apperror/api/src/main/kotlin/io/element/android/services/apperror/api/AppErrorStateService.kt @@ -16,5 +16,4 @@ interface AppErrorStateService { fun showError(title: String, body: String) fun showError(@StringRes titleRes: Int, @StringRes bodyRes: Int) - } diff --git a/services/apperror/impl/build.gradle.kts b/services/apperror/impl/build.gradle.kts index a3d17a14cd..01163d240c 100644 --- a/services/apperror/impl/build.gradle.kts +++ b/services/apperror/impl/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { implementation(projects.libraries.di) implementation(projects.libraries.designsystem) implementation(projects.libraries.uiStrings) + implementation(projects.services.toolbox.api) implementation(projects.anvilannotations) implementation(libs.coroutines.core) @@ -34,4 +35,5 @@ dependencies { testImplementation(libs.coroutines.test) testImplementation(libs.test.turbine) testImplementation(libs.test.truth) + testImplementation(projects.services.toolbox.test) } diff --git a/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt b/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt index ca6e6d34cf..9f9ede50ee 100644 --- a/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt +++ b/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateService.kt @@ -7,13 +7,12 @@ package io.element.android.services.apperror.impl -import android.content.Context import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.AppScope -import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.SingleIn import io.element.android.services.apperror.api.AppErrorState import io.element.android.services.apperror.api.AppErrorStateService +import io.element.android.services.toolbox.api.strings.StringProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject @@ -21,7 +20,7 @@ import javax.inject.Inject @ContributesBinding(AppScope::class) @SingleIn(AppScope::class) class DefaultAppErrorStateService @Inject constructor( - @ApplicationContext private val context: Context, + private val stringProvider: StringProvider, ) : AppErrorStateService { private val currentAppErrorState = MutableStateFlow(AppErrorState.NoError) override val appErrorStateFlow: StateFlow = currentAppErrorState @@ -37,8 +36,8 @@ class DefaultAppErrorStateService @Inject constructor( } override fun showError(titleRes: Int, bodyRes: Int) { - val title = context.getString(titleRes) - val body = context.getString(bodyRes) + val title = stringProvider.getString(titleRes) + val body = stringProvider.getString(bodyRes) showError(title, body) } } diff --git a/services/apperror/impl/src/test/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateServiceTest.kt b/services/apperror/impl/src/test/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateServiceTest.kt index 86f918c264..6eb26c9c50 100644 --- a/services/apperror/impl/src/test/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateServiceTest.kt +++ b/services/apperror/impl/src/test/kotlin/io/element/android/services/apperror/impl/DefaultAppErrorStateServiceTest.kt @@ -10,14 +10,14 @@ package io.element.android.services.apperror.impl import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.services.apperror.api.AppErrorState +import io.element.android.services.toolbox.test.strings.FakeStringProvider import kotlinx.coroutines.test.runTest import org.junit.Test internal class DefaultAppErrorStateServiceTest { @Test fun `initial value is no error`() = runTest { - val service = DefaultAppErrorStateService() - + val service = createDefaultAppErrorStateService() service.appErrorStateFlow.test { val state = awaitItem() assertThat(state).isInstanceOf(AppErrorState.NoError::class.java) @@ -26,8 +26,7 @@ internal class DefaultAppErrorStateServiceTest { @Test fun `showError - emits value`() = runTest { - val service = DefaultAppErrorStateService() - + val service = createDefaultAppErrorStateService() service.appErrorStateFlow.test { skipItems(1) @@ -42,9 +41,22 @@ internal class DefaultAppErrorStateServiceTest { } @Test - fun `dismiss - clears value`() = runTest { - val service = DefaultAppErrorStateService() + fun `showError - emits value from ids`() = runTest { + val service = createDefaultAppErrorStateService() + service.appErrorStateFlow.test { + skipItems(1) + service.showError(1, 2) + val state = awaitItem() + assertThat(state).isInstanceOf(AppErrorState.Error::class.java) + val errorState = state as AppErrorState.Error + assertThat(errorState.title).isEqualTo("A string") + assertThat(errorState.body).isEqualTo("A string") + } + } + @Test + fun `dismiss - clears value`() = runTest { + val service = createDefaultAppErrorStateService() service.appErrorStateFlow.test { skipItems(1) @@ -58,4 +70,8 @@ internal class DefaultAppErrorStateServiceTest { assertThat(awaitItem()).isInstanceOf(AppErrorState.NoError::class.java) } } + + private fun createDefaultAppErrorStateService() = DefaultAppErrorStateService( + stringProvider = FakeStringProvider(), + ) } From 90f155219733c94cf30d812f296a12cbbda09cdd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 11:17:05 +0200 Subject: [PATCH 07/30] State data class cannot have default values. --- .../api/InvitePeopleStateProvider.kt | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt index 70967580ac..b69ad7c225 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleStateProvider.kt @@ -12,14 +12,24 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider class InvitePeopleStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - PreviewInvitePeopleState(), - PreviewInvitePeopleState(canInvite = true), - PreviewInvitePeopleState(isSearchActive = true) + aPreviewInvitePeopleState(), + aPreviewInvitePeopleState(canInvite = true), + aPreviewInvitePeopleState(isSearchActive = true) ) } private data class PreviewInvitePeopleState( - override val canInvite: Boolean = false, - override val isSearchActive: Boolean = false, - override val eventSink: (InvitePeopleEvents) -> Unit = {} + override val canInvite: Boolean, + override val isSearchActive: Boolean, + override val eventSink: (InvitePeopleEvents) -> Unit, ) : InvitePeopleState + +private fun aPreviewInvitePeopleState( + canInvite: Boolean = false, + isSearchActive: Boolean = false, + eventSink: (InvitePeopleEvents) -> Unit = {}, +) = PreviewInvitePeopleState( + canInvite = canInvite, + isSearchActive = isSearchActive, + eventSink = eventSink +) From 519d24d3f0edbc837a088a6e094e99655b0dc00e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 11:19:21 +0200 Subject: [PATCH 08/30] Rename provider to follow naming convention --- .../features/startchat/impl/root/StartChatStateProvider.kt | 2 +- .../android/features/startchat/impl/root/StartChatView.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt index 1173425aa1..6b5113cc94 100644 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatStateProvider.kt @@ -19,7 +19,7 @@ import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.usersearch.api.UserSearchResult import kotlinx.collections.immutable.persistentListOf -open class CreateRoomRootStateProvider : PreviewParameterProvider { +open class StartChatStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( aCreateRoomRootState(), diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt index 340e6a9134..53ed7782ff 100644 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt @@ -239,7 +239,7 @@ private fun CreateRoomActionButton( @PreviewsDayNight @Composable -internal fun CreateRoomRootViewPreview(@PreviewParameter(CreateRoomRootStateProvider::class) state: StartChatState) = +internal fun CreateRoomRootViewPreview(@PreviewParameter(StartChatStateProvider::class) state: StartChatState) = ElementPreview { CreateRoomRootView( state = state, From 9411b309d210dbd57464cbc4abc2ac637d7fd18d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 11:21:31 +0200 Subject: [PATCH 09/30] Rename View to follow naming convention and file name --- .../startchat/impl/root/StartChatNode.kt | 2 +- .../startchat/impl/root/StartChatView.kt | 6 +++--- ...oomRootViewTest.kt => StartChatViewTest.kt} | 18 +++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) rename features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/{CreateBaseRoomRootViewTest.kt => StartChatViewTest.kt} (94%) diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt index 29a13d2fa4..f42b7da7cc 100644 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatNode.kt @@ -46,7 +46,7 @@ class StartChatNode @AssistedInject constructor( override fun View(modifier: Modifier) { val state = presenter.present() val activity = requireNotNull(LocalActivity.current) - CreateRoomRootView( + StartChatView( state = state, modifier = modifier, onCloseClick = this::navigateUp, diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt index 53ed7782ff..ebde080f75 100644 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/root/StartChatView.kt @@ -48,7 +48,7 @@ import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.collections.immutable.persistentListOf @Composable -fun CreateRoomRootView( +fun StartChatView( state: StartChatState, onCloseClick: () -> Unit, onNewRoomClick: () -> Unit, @@ -239,9 +239,9 @@ private fun CreateRoomActionButton( @PreviewsDayNight @Composable -internal fun CreateRoomRootViewPreview(@PreviewParameter(StartChatStateProvider::class) state: StartChatState) = +internal fun StartChatViewPreview(@PreviewParameter(StartChatStateProvider::class) state: StartChatState) = ElementPreview { - CreateRoomRootView( + StartChatView( state = state, onCloseClick = {}, onNewRoomClick = {}, diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt similarity index 94% rename from features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootViewTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt index 81f764dd59..d488f251e0 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt @@ -34,7 +34,7 @@ import org.robolectric.annotation.Config import kotlin.collections.get @RunWith(AndroidJUnit4::class) -class CreateBaseRoomRootViewTest { +class StartChatViewTest { @get:Rule val rule = createAndroidComposeRule() @@ -42,7 +42,7 @@ class CreateBaseRoomRootViewTest { fun `clicking on back invokes the expected callback`() { val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( eventSink = eventsRecorder, ), @@ -56,7 +56,7 @@ class CreateBaseRoomRootViewTest { fun `clicking on New room invokes the expected callback`() { val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( eventSink = eventsRecorder, ), @@ -71,7 +71,7 @@ class CreateBaseRoomRootViewTest { fun `clicking on Invite people invokes the expected callback`() { val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( applicationName = "test", eventSink = eventsRecorder, @@ -90,7 +90,7 @@ class CreateBaseRoomRootViewTest { val firstRoom = recentDirectRoomList[0] val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnceWithParam(firstRoom.roomId) { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( userListState = aUserListState( recentDirectRooms = recentDirectRoomList @@ -108,7 +108,7 @@ class CreateBaseRoomRootViewTest { fun `clicking on Join room by address invokes the expected callback`() { val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( eventSink = eventsRecorder, ), @@ -122,7 +122,7 @@ class CreateBaseRoomRootViewTest { fun `clicking on room directory invokes the expected callback`() { val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { - rule.setCreateRoomRootView( + rule.setStartChatView( aCreateRoomRootState( eventSink = eventsRecorder, isRoomDirectorySearchEnabled = true @@ -134,7 +134,7 @@ class CreateBaseRoomRootViewTest { } } -private fun AndroidComposeTestRule.setCreateRoomRootView( +private fun AndroidComposeTestRule.setStartChatView( state: StartChatState, onCloseClick: () -> Unit = EnsureNeverCalled(), onNewRoomClick: () -> Unit = EnsureNeverCalled(), @@ -144,7 +144,7 @@ private fun AndroidComposeTestRule.setCreat onRoomDirectorySearchClick: () -> Unit = EnsureNeverCalled(), ) { setContent { - CreateRoomRootView( + StartChatView( state = state, onCloseClick = onCloseClick, onNewRoomClick = onNewRoomClick, From 4db0a98ec24e15b1e6072ab47252af5749031483 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 11:22:40 +0200 Subject: [PATCH 10/30] Rename Test to follow naming convention --- ...tPresenterTest.kt => StartChatPresenterTest.kt} | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) rename features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/{CreateBaseRoomRootPresenterTest.kt => StartChatPresenterTest.kt} (95%) diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt similarity index 95% rename from features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootPresenterTest.kt rename to features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt index 9c2d2ac1ef..d52ac8f81b 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/CreateBaseRoomRootPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt @@ -36,7 +36,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -class CreateBaseRoomRootPresenterTest { +class StartChatPresenterTest { @get:Rule val warmUpRule = WarmUpRule() @@ -47,7 +47,7 @@ class CreateBaseRoomRootPresenterTest { actionState.value = startDMFailureResult } val startDMAction = FakeStartDMAction(executeResult = executeResult) - val presenter = createCreateRoomRootPresenter(startDMAction) + val presenter = createStartChatPresenter(startDMAction) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -81,7 +81,7 @@ class CreateBaseRoomRootPresenterTest { actionState.value = startDMSuccessResult } val startDMAction = FakeStartDMAction(executeResult = executeResult) - val presenter = createCreateRoomRootPresenter(startDMAction) + val presenter = createStartChatPresenter(startDMAction) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -112,7 +112,7 @@ class CreateBaseRoomRootPresenterTest { actionState.value = startDMConfirmationResult } val startDMAction = FakeStartDMAction(executeResult = executeResult) - val presenter = createCreateRoomRootPresenter(startDMAction) + val presenter = createStartChatPresenter(startDMAction) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -142,7 +142,7 @@ class CreateBaseRoomRootPresenterTest { actionState.value = startDMConfirmationResult } val startDMAction = FakeStartDMAction(executeResult = executeResult) - val presenter = createCreateRoomRootPresenter(startDMAction) + val presenter = createStartChatPresenter(startDMAction) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -167,7 +167,7 @@ class CreateBaseRoomRootPresenterTest { @Test fun `present - room directory search`() = runTest { - val presenter = createCreateRoomRootPresenter(isRoomDirectorySearchEnabled = true) + val presenter = createStartChatPresenter(isRoomDirectorySearchEnabled = true) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -178,7 +178,7 @@ class CreateBaseRoomRootPresenterTest { } } - private fun createCreateRoomRootPresenter( + private fun createStartChatPresenter( startDMAction: StartDMAction = FakeStartDMAction(), isRoomDirectorySearchEnabled: Boolean = false, ): StartChatPresenter { From feb65aa9872bd5cb4048363e24e808baa62ce09d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 11:23:34 +0200 Subject: [PATCH 11/30] Rename Preview --- .../android/features/invitepeople/impl/InvitePeopleView.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt index 6c9a6845a2..3de67e8274 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -7,7 +7,6 @@ package io.element.android.features.invitepeople.impl -import androidx.activity.OnBackPressedDispatcher import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -21,19 +20,15 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp -import com.bumble.appyx.core.plugin.BackPressHandler import io.element.android.compound.theme.ElementTheme import io.element.android.libraries.designsystem.components.async.AsyncLoading import io.element.android.libraries.designsystem.components.avatar.AvatarSize -import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.SearchBar import io.element.android.libraries.designsystem.theme.components.SearchBarResultState 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.user.MatrixUser import io.element.android.libraries.matrix.ui.components.CheckableUserRow import io.element.android.libraries.matrix.ui.components.CheckableUserRowData @@ -176,7 +171,7 @@ private fun InvitePeopleSearchBar( @PreviewsDayNight @Composable -internal fun RoomInviteMembersViewPreview(@PreviewParameter(DefaultInvitePeopleStateProvider::class) state: DefaultInvitePeopleState) = +internal fun InvitePeopleViewPreview(@PreviewParameter(DefaultInvitePeopleStateProvider::class) state: DefaultInvitePeopleState) = ElementPreview { InvitePeopleView(state = state) } From 9ef0bf35da8cab8f88ccc5ed11c45c70f8c07e30 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 12:32:47 +0200 Subject: [PATCH 12/30] Create FakeAppErrorStateService --- services/apperror/test/build.gradle.kts | 20 +++++++++++ .../apperror/test/FakeAppErrorStateService.kt | 36 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 services/apperror/test/build.gradle.kts create mode 100644 services/apperror/test/src/main/kotlin/io/element/android/services/apperror/test/FakeAppErrorStateService.kt diff --git a/services/apperror/test/build.gradle.kts b/services/apperror/test/build.gradle.kts new file mode 100644 index 0000000000..c8ac902784 --- /dev/null +++ b/services/apperror/test/build.gradle.kts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.services.apperror.test" +} + +dependencies { + implementation(libs.coroutines.core) + implementation(projects.services.apperror.api) + implementation(projects.tests.testutils) +} diff --git a/services/apperror/test/src/main/kotlin/io/element/android/services/apperror/test/FakeAppErrorStateService.kt b/services/apperror/test/src/main/kotlin/io/element/android/services/apperror/test/FakeAppErrorStateService.kt new file mode 100644 index 0000000000..0783d08e02 --- /dev/null +++ b/services/apperror/test/src/main/kotlin/io/element/android/services/apperror/test/FakeAppErrorStateService.kt @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package io.element.android.services.apperror.test + +import io.element.android.services.apperror.api.AppErrorState +import io.element.android.services.apperror.api.AppErrorStateService +import io.element.android.tests.testutils.lambda.lambdaError +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeAppErrorStateService( + initialState: AppErrorState = AppErrorState.NoError, + private val showErrorResult: (String, String) -> Unit = { _, _ -> lambdaError() }, + private val showErrorResResult: (Int, Int) -> Unit = { _, _ -> lambdaError() } +) : AppErrorStateService { + private val mutableAppErrorStateFlow = MutableStateFlow(initialState) + override val appErrorStateFlow: StateFlow = mutableAppErrorStateFlow.asStateFlow() + + override fun showError(title: String, body: String) { + showErrorResult(title, body) + } + + override fun showError(titleRes: Int, bodyRes: Int) { + showErrorResResult(titleRes, bodyRes) + } + + fun setAppErrorState(state: AppErrorState) { + mutableAppErrorStateFlow.value = state + } +} From f6b81ae21dde248672d9b3fc000bd3aa79e3570c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 15:36:01 +0200 Subject: [PATCH 13/30] Move and fix test for DefaultInvitePeoplePresenter --- features/invitepeople/impl/build.gradle.kts | 1 + .../impl/DefaultInvitePeoplePresenterTest.kt} | 210 ++++++++++-------- 2 files changed, 118 insertions(+), 93 deletions(-) rename features/{roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt => invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt} (65%) diff --git a/features/invitepeople/impl/build.gradle.kts b/features/invitepeople/impl/build.gradle.kts index 82a716897e..bdb1c6942e 100644 --- a/features/invitepeople/impl/build.gradle.kts +++ b/features/invitepeople/impl/build.gradle.kts @@ -46,6 +46,7 @@ dependencies { testImplementation(libs.test.robolectric) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.usersearch.test) + testImplementation(projects.services.apperror.test) testImplementation(projects.tests.testutils) testImplementation(libs.androidx.compose.ui.test.junit) testReleaseImplementation(libs.androidx.compose.ui.test.manifest) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt similarity index 65% rename from features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt rename to features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt index 5aae0f5d3b..2023da9b9d 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt +++ b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt @@ -5,32 +5,32 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.roomdetails.impl.invite +package io.element.android.features.invitepeople.impl import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow +import app.cash.turbine.ReceiveTurbine import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -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.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.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.room.aRoomMemberList 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.UserRepository import io.element.android.libraries.usersearch.api.UserSearchResult import io.element.android.libraries.usersearch.api.UserSearchResultState import io.element.android.libraries.usersearch.test.FakeUserRepository +import io.element.android.services.apperror.api.AppErrorStateService +import io.element.android.services.apperror.test.FakeAppErrorStateService import io.element.android.tests.testutils.WarmUpRule -import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -39,22 +39,18 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -internal class RoomInviteMembersPresenterTest { +internal class DefaultInvitePeoplePresenterTest { @get:Rule val warmUpRule = WarmUpRule() @Test fun `present - initial state has no results and no search`() = runTest { - val presenter = RoomInviteMembersPresenter( - userRepository = FakeUserRepository(), - roomMemberListDataSource = createDataSource(FakeBaseRoom()), - coroutineDispatchers = testCoroutineDispatchers() - ) + val presenter = createDefaultInvitePeoplePresenter() moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - val initialState = awaitItem() + val initialState = awaitItemAsDefault() assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(initialState.isSearchActive).isFalse() @@ -67,11 +63,7 @@ internal class RoomInviteMembersPresenterTest { @Test fun `present - updates search active state`() = runTest { - val presenter = RoomInviteMembersPresenter( - userRepository = FakeUserRepository(), - roomMemberListDataSource = createDataSource(FakeBaseRoom()), - coroutineDispatchers = testCoroutineDispatchers() - ) + val presenter = createDefaultInvitePeoplePresenter() moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -79,7 +71,7 @@ internal class RoomInviteMembersPresenterTest { val initialState = awaitItem() skipItems(1) - initialState.eventSink(RoomInviteMembersEvents.OnSearchActiveChanged(true)) + initialState.eventSink(DefaultInvitePeopleEvents.OnSearchActiveChanged(true)) val resultState = awaitItem() assertThat(resultState.isSearchActive).isTrue() @@ -89,24 +81,24 @@ internal class RoomInviteMembersPresenterTest { @Test fun `present - performs search and handles empty result list`() = runTest { val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( + val presenter = createDefaultInvitePeoplePresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitItem() - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) assertThat(repository.providedQuery).isEqualTo("some query") repository.emitState(UserSearchResultState(results = emptyList(), isSearching = true)) - consumeItemsUntilPredicate { it.showSearchLoader }.last().also { state -> + skipItems(3) + awaitItemAsDefault().also { state -> assertThat(state.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(state.showSearchLoader).isTrue() } repository.emitState(results = emptyList(), isSearching = false) - consumeItemsUntilPredicate { !it.showSearchLoader }.last().also { state -> + awaitItemAsDefault().also { state -> assertThat(state.searchResults).isInstanceOf(SearchBarResultState.NoResultsFound::class.java) assertThat(state.showSearchLoader).isFalse() } @@ -116,9 +108,8 @@ internal class RoomInviteMembersPresenterTest { @Test fun `present - performs search and handles user results`() = runTest { val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( + val presenter = createDefaultInvitePeoplePresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) moleculeFlow(RecompositionMode.Immediate) { @@ -127,23 +118,27 @@ internal class RoomInviteMembersPresenterTest { val initialState = awaitItem() skipItems(1) - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) skipItems(1) assertThat(repository.providedQuery).isEqualTo("some query") repository.emitStateWithUsers(users = aMatrixUserList()) skipItems(1) - val resultState = awaitItem() + val resultState = awaitItemAsDefault() assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) val expectedUsers = aMatrixUserList() val users = resultState.searchResults.users() expectedUsers.forEachIndexed { index, matrixUser -> assertThat(users[index].matrixUser).isEqualTo(matrixUser) - assertThat(users[index].isAlreadyInvited).isFalse() - assertThat(users[index].isAlreadyJoined).isFalse() - assertThat(users[index].isSelected).isFalse() + // All users are joined or invited + if (users[index].isAlreadyInvited) { + assertThat(users[index].isAlreadyJoined).isFalse() + } else { + assertThat(users[index].isAlreadyJoined).isTrue() + } + assertThat(users[index].isSelected).isTrue() } } } @@ -156,22 +151,21 @@ internal class RoomInviteMembersPresenterTest { val repository = FakeUserRepository() val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) - val presenter = RoomInviteMembersPresenter( + val presenter = createDefaultInvitePeoplePresenter( userRepository = repository, - roomMemberListDataSource = createDataSource( - room = FakeBaseRoom().apply { - givenRoomMembersState( - RoomMembersState.Ready( - persistentListOf( - aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), - aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), - ) - ) - ) - }, - coroutineDispatchers = coroutineDispatchers, + roomMembersState = RoomMembersState.Ready( + persistentListOf( + aRoomMember( + userId = joinedUser.userId, + membership = RoomMembershipState.JOIN + ), + aRoomMember( + userId = invitedUser.userId, + membership = RoomMembershipState.INVITE + ), + ) ), - coroutineDispatchers = coroutineDispatchers + coroutineDispatchers = coroutineDispatchers, ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -179,14 +173,14 @@ internal class RoomInviteMembersPresenterTest { val initialState = awaitItem() skipItems(1) - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) skipItems(1) assertThat(repository.providedQuery).isEqualTo("some query") repository.emitStateWithUsers(users = aMatrixUserList()) skipItems(1) - val resultState = awaitItem() + val resultState = awaitItemAsDefault() assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) val users = resultState.searchResults.users() @@ -217,18 +211,21 @@ internal class RoomInviteMembersPresenterTest { val invitedUser = userList[1] val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( + val presenter = createDefaultInvitePeoplePresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom().apply { - givenRoomMembersState( - RoomMembersState.Ready( - persistentListOf( - aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), - aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), - ) + roomMembersState = + RoomMembersState.Ready( + persistentListOf( + aRoomMember( + userId = joinedUser.userId, + membership = RoomMembershipState.JOIN + ), + aRoomMember( + userId = invitedUser.userId, + membership = RoomMembershipState.INVITE + ), ) - ) - }), + ), coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) @@ -238,16 +235,21 @@ internal class RoomInviteMembersPresenterTest { val initialState = awaitItem() skipItems(1) - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) skipItems(1) assertThat(repository.providedQuery).isEqualTo("some query") - val unresolvedUser = UserSearchResult(aMatrixUser(id = A_USER_ID.value), isUnresolved = true) - repository.emitState(listOf(unresolvedUser) + aMatrixUserList().map { UserSearchResult(it) }) + val unresolvedUser = + UserSearchResult(aMatrixUser(id = A_USER_ID.value), isUnresolved = true) + repository.emitState(listOf(unresolvedUser) + aMatrixUserList().map { + UserSearchResult( + it + ) + }) skipItems(1) - val resultState = awaitItem() + val resultState = awaitItemAsDefault() assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) val users = resultState.searchResults.users() @@ -264,9 +266,8 @@ internal class RoomInviteMembersPresenterTest { @Test fun `present - toggle users updates selected user state`() = runTest { val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( + val presenter = createDefaultInvitePeoplePresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(), coroutineDispatchers = testCoroutineDispatchers() ) @@ -277,25 +278,27 @@ internal class RoomInviteMembersPresenterTest { skipItems(1) // When we toggle a user not in the list, they are added - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(aMatrixUser())) - assertThat(awaitItem().selectedUsers).containsExactly(aMatrixUser()) + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(aMatrixUser())) + assertThat(awaitItemAsDefault().selectedUsers).containsExactly(aMatrixUser()) // Toggling a different user also adds them - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(aMatrixUser(id = A_USER_ID_2.value))) - assertThat(awaitItem().selectedUsers).containsExactly(aMatrixUser(), aMatrixUser(id = A_USER_ID_2.value)) + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(aMatrixUser(id = A_USER_ID_2.value))) + assertThat(awaitItemAsDefault().selectedUsers).containsExactly( + aMatrixUser(), + aMatrixUser(id = A_USER_ID_2.value) + ) // Toggling the first user removes them - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(aMatrixUser())) - assertThat(awaitItem().selectedUsers).containsExactly(aMatrixUser(id = A_USER_ID_2.value)) + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(aMatrixUser())) + assertThat(awaitItemAsDefault().selectedUsers).containsExactly(aMatrixUser(id = A_USER_ID_2.value)) } } @Test fun `present - selected users appear as such in search results`() = runTest { val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( + val presenter = createDefaultInvitePeoplePresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) moleculeFlow(RecompositionMode.Immediate) { @@ -306,16 +309,16 @@ internal class RoomInviteMembersPresenterTest { val selectedUser = aMatrixUser() - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(selectedUser)) + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(selectedUser)) - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) skipItems(1) assertThat(repository.providedQuery).isEqualTo("some query") repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) skipItems(2) - val resultState = awaitItem() + val resultState = awaitItemAsDefault() assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) val users = resultState.searchResults.users() @@ -325,18 +328,17 @@ internal class RoomInviteMembersPresenterTest { assertThat(shouldBeSelectedUser).isNotNull() assertThat(shouldBeSelectedUser?.isSelected).isTrue() - // And no others are + // All the others are selected since their membership is joined or invited val allOtherUsers = users.minus(shouldBeSelectedUser!!) - assertThat(allOtherUsers.none { it.isSelected }).isTrue() + assertThat(allOtherUsers.all { it.isSelected }).isTrue() } } @Test fun `present - toggling a user updates existing search results`() = runTest { val repository = FakeUserRepository() - val presenter = RoomInviteMembersPresenter( + val presenter = createDefaultInvitePeoplePresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeBaseRoom()), coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) moleculeFlow(RecompositionMode.Immediate) { @@ -348,17 +350,25 @@ internal class RoomInviteMembersPresenterTest { val selectedUser = aMatrixUser() // Given a query is made - initialState.eventSink(RoomInviteMembersEvents.UpdateSearchQuery("some query")) + initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) skipItems(1) assertThat(repository.providedQuery).isEqualTo("some query") repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) - skipItems(2) + skipItems(1) + awaitItemAsDefault().also { state -> + // selectedUser is not selected + assertThat(state.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + val users = state.searchResults.users() + val shouldNotBeSelectedUser = users.find { it.matrixUser == selectedUser } + assertThat(shouldNotBeSelectedUser).isNotNull() + assertThat(shouldNotBeSelectedUser?.isSelected).isFalse() + } // And then a user is toggled - initialState.eventSink(RoomInviteMembersEvents.ToggleUser(selectedUser)) + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(selectedUser)) skipItems(1) - val resultState = awaitItem() + val resultState = awaitItemAsDefault() // The results are updated... assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) @@ -369,9 +379,9 @@ internal class RoomInviteMembersPresenterTest { assertThat(shouldBeSelectedUser).isNotNull() assertThat(shouldBeSelectedUser?.isSelected).isTrue() - // And no others are + // All the others are selected since their membership is joined or invited val allOtherUsers = users.minus(shouldBeSelectedUser!!) - assertThat(allOtherUsers.none { it.isSelected }).isTrue() + assertThat(allOtherUsers.all { it.isSelected }).isTrue() } } @@ -396,13 +406,27 @@ internal class RoomInviteMembersPresenterTest { emitState(state) } - private fun TestScope.createDataSource( - room: BaseRoom = aRoom().apply { - givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) - }, - coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers() - ) = RoomMemberListDataSource(room, coroutineDispatchers) - private fun SearchBarResultState>.users() = (this as? SearchBarResultState.Results>)?.results.orEmpty() } + +private suspend fun ReceiveTurbine.awaitItemAsDefault(): DefaultInvitePeopleState { + return awaitItem() as DefaultInvitePeopleState +} + +fun TestScope.createDefaultInvitePeoplePresenter( + roomMembersState: RoomMembersState = RoomMembersState.Ready(aRoomMemberList()), + userRepository: UserRepository = FakeUserRepository(), + coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(), + appErrorStateService: AppErrorStateService = FakeAppErrorStateService(), +): DefaultInvitePeoplePresenter { + return DefaultInvitePeoplePresenter( + room = FakeJoinedRoom().apply { + givenRoomMembersState(roomMembersState) + }, + userRepository = userRepository, + coroutineDispatchers = coroutineDispatchers, + coroutineScope = backgroundScope, + appErrorStateService = appErrorStateService, + ) +} From 3543e3b2310fa0271805ac19b16c4630ced0a667 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 15:37:31 +0200 Subject: [PATCH 14/30] Create fun handleEvents --- .../impl/DefaultInvitePeoplePresenter.kt | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt index 7f3d0893ac..8dfa0af91e 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt @@ -81,6 +81,31 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( ) } + fun handleEvents(event: InvitePeopleEvents) { + when (event) { + is DefaultInvitePeopleEvents.OnSearchActiveChanged -> { + searchActive = event.active + searchQuery = "" + } + + is DefaultInvitePeopleEvents.UpdateSearchQuery -> { + searchQuery = event.query + } + + is DefaultInvitePeopleEvents.ToggleUser -> { + selectedUsers.toggleUser(event.user) + searchResults.toggleUser(event.user) + } + is InvitePeopleEvents.SendInvites -> { + coroutineScope.sendInvites(selectedUsers.value) + } + is InvitePeopleEvents.CloseSearch -> { + searchActive = false + searchQuery = "" + } + } + } + return DefaultInvitePeopleState( canInvite = selectedUsers.value.isNotEmpty(), selectedUsers = selectedUsers.value, @@ -88,30 +113,7 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( isSearchActive = searchActive, searchResults = searchResults.value, showSearchLoader = showSearchLoader.value, - eventSink = { - when (it) { - is DefaultInvitePeopleEvents.OnSearchActiveChanged -> { - searchActive = it.active - searchQuery = "" - } - - is DefaultInvitePeopleEvents.UpdateSearchQuery -> { - searchQuery = it.query - } - - is DefaultInvitePeopleEvents.ToggleUser -> { - selectedUsers.toggleUser(it.user) - searchResults.toggleUser(it.user) - } - is InvitePeopleEvents.SendInvites -> { - coroutineScope.sendInvites(selectedUsers.value) - } - is InvitePeopleEvents.CloseSearch -> { - searchActive = false - searchQuery = "" - } - } - } + eventSink = ::handleEvents, ) } From e5316ccbe4d4a3460f19ce7ab2e2731b03cc00e6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 15:57:35 +0200 Subject: [PATCH 15/30] Add more tests --- .../impl/DefaultInvitePeoplePresenterTest.kt | 138 +++++++++++++----- 1 file changed, 104 insertions(+), 34 deletions(-) diff --git a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt index 2023da9b9d..49e381ebee 100644 --- a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt +++ b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt @@ -7,16 +7,16 @@ package io.element.android.features.invitepeople.impl -import app.cash.molecule.RecompositionMode -import app.cash.molecule.moleculeFlow import app.cash.turbine.ReceiveTurbine -import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import io.element.android.features.invitepeople.api.InvitePeopleEvents 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.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.AN_EXCEPTION 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.FakeJoinedRoom @@ -24,6 +24,7 @@ import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.room.aRoomMemberList import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUserList +import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.usersearch.api.UserRepository import io.element.android.libraries.usersearch.api.UserSearchResult import io.element.android.libraries.usersearch.api.UserSearchResultState @@ -31,9 +32,14 @@ import io.element.android.libraries.usersearch.test.FakeUserRepository import io.element.android.services.apperror.api.AppErrorStateService import io.element.android.services.apperror.test.FakeAppErrorStateService import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.lambda.lambdaError +import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.lambda.value +import io.element.android.tests.testutils.test import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.delay import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Rule @@ -46,10 +52,7 @@ internal class DefaultInvitePeoplePresenterTest { @Test fun `present - initial state has no results and no search`() = runTest { val presenter = createDefaultInvitePeoplePresenter() - - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItemAsDefault() assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) @@ -64,10 +67,7 @@ internal class DefaultInvitePeoplePresenterTest { @Test fun `present - updates search active state`() = runTest { val presenter = createDefaultInvitePeoplePresenter() - - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() skipItems(1) @@ -75,6 +75,14 @@ internal class DefaultInvitePeoplePresenterTest { val resultState = awaitItem() assertThat(resultState.isSearchActive).isTrue() + resultState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) + assertThat(awaitItemAsDefault().searchQuery).isEqualTo("some query") + resultState.eventSink(InvitePeopleEvents.CloseSearch) + skipItems(1) + awaitItemAsDefault().also { + assertThat(it.isSearchActive).isFalse() + assertThat(it.searchQuery).isEmpty() + } } } @@ -85,9 +93,7 @@ internal class DefaultInvitePeoplePresenterTest { userRepository = repository, coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() initialState.eventSink(DefaultInvitePeopleEvents.UpdateSearchQuery("some query")) assertThat(repository.providedQuery).isEqualTo("some query") @@ -112,9 +118,7 @@ internal class DefaultInvitePeoplePresenterTest { userRepository = repository, coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() skipItems(1) @@ -167,9 +171,7 @@ internal class DefaultInvitePeoplePresenterTest { ), coroutineDispatchers = coroutineDispatchers, ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() skipItems(1) @@ -229,9 +231,7 @@ internal class DefaultInvitePeoplePresenterTest { coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() skipItems(1) @@ -270,10 +270,7 @@ internal class DefaultInvitePeoplePresenterTest { userRepository = repository, coroutineDispatchers = testCoroutineDispatchers() ) - - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() skipItems(1) @@ -301,9 +298,7 @@ internal class DefaultInvitePeoplePresenterTest { userRepository = repository, coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() skipItems(1) @@ -341,9 +336,7 @@ internal class DefaultInvitePeoplePresenterTest { userRepository = repository, coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() skipItems(1) @@ -385,6 +378,80 @@ internal class DefaultInvitePeoplePresenterTest { } } + @Test + fun `present - toggling a user and send invite success`() = runTest { + val repository = FakeUserRepository() + val inviteUserResult = lambdaRecorder> { userId: UserId -> + Result.success(Unit) + } + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + inviteUserResult = inviteUserResult, + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) + ) + presenter.test { + val initialState = awaitItem() + skipItems(1) + val selectedUser = aMatrixUser() + repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) + skipItems(1) + // And then a user is toggled + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(selectedUser)) + skipItems(1) + val resultState = awaitItemAsDefault() + // The results are updated... + assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + // Send invites + initialState.eventSink(InvitePeopleEvents.SendInvites) + delay(1_000) + inviteUserResult.assertions().isCalledOnce().with( + value(selectedUser.userId) + ) + } + } + + @Test + fun `present - toggling a user and send invite error`() = runTest { + val repository = FakeUserRepository() + val inviteUserResult = lambdaRecorder> { _: UserId -> + Result.failure(AN_EXCEPTION) + } + val showErrorResResult = lambdaRecorder { _, _ -> } + val presenter = createDefaultInvitePeoplePresenter( + userRepository = repository, + inviteUserResult = inviteUserResult, + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true), + appErrorStateService = FakeAppErrorStateService( + showErrorResResult = showErrorResResult, + ) + ) + presenter.test { + val initialState = awaitItem() + skipItems(1) + val selectedUser = aMatrixUser() + repository.emitStateWithUsers(users = aMatrixUserList() + selectedUser) + skipItems(1) + // And then a user is toggled + initialState.eventSink(DefaultInvitePeopleEvents.ToggleUser(selectedUser)) + skipItems(1) + val resultState = awaitItemAsDefault() + // The results are updated... + assertThat(resultState.searchResults).isInstanceOf(SearchBarResultState.Results::class.java) + // Send invites + initialState.eventSink(InvitePeopleEvents.SendInvites) + delay(1_000) + inviteUserResult.assertions().isCalledOnce().with( + value(selectedUser.userId) + ) + showErrorResResult.assertions() + .isCalledOnce() + .with( + value(CommonStrings.common_unable_to_invite_title), + value(CommonStrings.common_unable_to_invite_message) + ) + } + } + private suspend fun FakeUserRepository.emitStateWithUsers( users: List, isSearching: Boolean = false @@ -416,12 +483,15 @@ private suspend fun ReceiveTurbine.awaitItemAsDefault(): DefaultInvitePeo fun TestScope.createDefaultInvitePeoplePresenter( roomMembersState: RoomMembersState = RoomMembersState.Ready(aRoomMemberList()), + inviteUserResult: (UserId) -> Result = { lambdaError() }, userRepository: UserRepository = FakeUserRepository(), coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(), appErrorStateService: AppErrorStateService = FakeAppErrorStateService(), ): DefaultInvitePeoplePresenter { return DefaultInvitePeoplePresenter( - room = FakeJoinedRoom().apply { + room = FakeJoinedRoom( + inviteUserResult = inviteUserResult, + ).apply { givenRoomMembersState(roomMembersState) }, userRepository = userRepository, From 6a050569f513614e99eafc0679fa9045f86ca1f1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 16:23:48 +0200 Subject: [PATCH 16/30] Fix tests --- .../features/startchat/impl/FakeStartChatNavigator.kt | 2 +- .../joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt | 2 +- .../impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt | 2 +- .../features/startchat/impl/root/StartChatPresenterTest.kt | 2 +- .../features/startchat/impl/root/StartChatViewTest.kt | 7 +++---- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt index 2cc0f08ea9..9de00e0a4c 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/FakeStartChatNavigator.kt @@ -7,7 +7,7 @@ package io.element.android.features.startchat.impl -import io.element.android.features.invitepeople.StartChatNavigator +import io.element.android.features.startchat.StartChatNavigator import io.element.android.libraries.matrix.api.core.RoomIdOrAlias class FakeStartChatNavigator( diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt index e477c07f60..bd40b92d57 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressPresenterTest.kt @@ -8,7 +8,7 @@ package io.element.android.features.startchat.impl.joinbyaddress import com.google.common.truth.Truth.assertThat -import io.element.android.features.invitepeople.StartChatNavigator +import io.element.android.features.startchat.StartChatNavigator import io.element.android.features.startchat.impl.FakeStartChatNavigator import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomIdOrAlias diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt index 195ca55081..4de9bd1470 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinBaseRoomByAddressViewTest.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performTextInput import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.features.invitepeople.impl.R +import io.element.android.features.startchat.impl.R import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt index d52ac8f81b..cce5c1839e 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt @@ -16,8 +16,8 @@ import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser import io.element.android.features.startchat.api.StartDMAction import io.element.android.features.startchat.impl.userlist.FakeUserListPresenter import io.element.android.features.startchat.impl.userlist.FakeUserListPresenterFactory -import io.element.android.features.invitepeople.impl.userlist.UserListDataStore import io.element.android.features.invitepeople.test.FakeStartDMAction +import io.element.android.features.startchat.impl.userlist.UserListDataStore import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt index d488f251e0..dc213446a0 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatViewTest.kt @@ -13,9 +13,9 @@ import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.element.android.features.invitepeople.impl.R -import io.element.android.features.invitepeople.impl.userlist.aRecentDirectRoomList -import io.element.android.features.invitepeople.impl.userlist.aUserListState +import io.element.android.features.startchat.impl.R +import io.element.android.features.startchat.impl.userlist.aRecentDirectRoomList +import io.element.android.features.startchat.impl.userlist.aUserListState import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.ui.model.getBestName import io.element.android.libraries.ui.strings.CommonStrings @@ -31,7 +31,6 @@ import org.junit.Test import org.junit.rules.TestRule import org.junit.runner.RunWith import org.robolectric.annotation.Config -import kotlin.collections.get @RunWith(AndroidJUnit4::class) class StartChatViewTest { From f3425c33884bbf62187d34959e63928a36b3bf54 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 16:42:01 +0200 Subject: [PATCH 17/30] Cleanup codebase --- .../createroom/api/CreateRoomEntryPoint.kt | 3 +-- features/createroom/impl/build.gradle.kts | 1 - .../createroom/impl/CreateRoomFlowNode.kt | 1 - .../impl/DefaultCreateRoomEntryPoint.kt | 2 -- .../createroom/impl/addpeople/AddPeopleNode.kt | 8 ++++---- .../createroom/impl/addpeople/AddPeopleView.kt | 2 +- .../impl/configureroom/ConfigureRoomEvents.kt | 1 - .../impl/configureroom/ConfigureRoomNode.kt | 6 ++---- .../configureroom/CreateRoomConfigStore.kt | 1 - .../ConfigureRoomPresenterTest.kt | 4 +--- .../invitepeople/api/InvitePeoplePresenter.kt | 2 -- .../impl/DefaultInvitePeopleEvents.kt | 2 +- .../impl/DefaultInvitePeoplePresenter.kt | 1 - .../impl/DefaultInvitePeopleState.kt | 2 +- .../invitepeople/impl/InvitePeopleView.kt | 1 - .../impl/invite/RoomInviteMembersNode.kt | 13 ++++++------- .../impl/invite/RoomInviteMembersView.kt | 18 +++++++----------- .../impl/root/StartChatPresenterTest.kt | 2 +- .../impl/root/UserProfilePresenter.kt | 2 +- .../impl/UserProfilePresenterTest.kt | 4 ++-- 20 files changed, 28 insertions(+), 48 deletions(-) diff --git a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt b/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt index ad4aa75ac5..5fc71f2a3b 100644 --- a/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt +++ b/features/createroom/api/src/main/kotlin/io/element/android/features/createroom/api/CreateRoomEntryPoint.kt @@ -14,7 +14,6 @@ import io.element.android.libraries.architecture.FeatureEntryPoint import io.element.android.libraries.matrix.api.core.RoomId interface CreateRoomEntryPoint : FeatureEntryPoint { - fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder interface NodeBuilder { @@ -22,7 +21,7 @@ interface CreateRoomEntryPoint : FeatureEntryPoint { fun build(): Node } - interface Callback: Plugin { + interface Callback : Plugin { fun onRoomCreated(roomId: RoomId) } } diff --git a/features/createroom/impl/build.gradle.kts b/features/createroom/impl/build.gradle.kts index d047fb7bc4..99e8fc653f 100644 --- a/features/createroom/impl/build.gradle.kts +++ b/features/createroom/impl/build.gradle.kts @@ -1,4 +1,3 @@ -import extension.ComponentMergingStrategy import extension.setupAnvil /* diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt index d2f6ae7ad5..761072b0e9 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt @@ -44,7 +44,6 @@ class CreateRoomFlowNode @AssistedInject constructor( buildContext = buildContext, plugins = plugins ) { - private fun onRoomCreated(roomId: RoomId) { plugins().forEach { it.onRoomCreated(roomId) } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt index 3281aa97f3..b9dfb20960 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/DefaultCreateRoomEntryPoint.kt @@ -18,9 +18,7 @@ import javax.inject.Inject @ContributesBinding(SessionScope::class) class DefaultCreateRoomEntryPoint @Inject constructor() : CreateRoomEntryPoint { - override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): CreateRoomEntryPoint.NodeBuilder { - val plugins = ArrayList() return object : CreateRoomEntryPoint.NodeBuilder { diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt index a5bd6e828b..1e7475be0d 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt @@ -30,7 +30,6 @@ class AddPeopleNode @AssistedInject constructor( invitePeoplePresenterFactory: InvitePeoplePresenter.Factory, private val invitePeopleRenderer: InvitePeopleRenderer, ) : Node(buildContext, plugins = plugins) { - data class Inputs( val joinedRoom: JoinedRoom ) : NodeInputs @@ -51,8 +50,9 @@ class AddPeopleNode @AssistedInject constructor( val state = invitePeoplePresenter.present() AddPeopleView( state = state, - invitePeopleView = { invitePeopleRenderer.Render(state, Modifier) }, - onFinish = ::onFinish - ) + onFinish = ::onFinish, + ) { + invitePeopleRenderer.Render(state, Modifier) + } } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt index d918b4a227..0a25ec9934 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt @@ -30,9 +30,9 @@ import io.element.android.libraries.ui.strings.CommonStrings @Composable fun AddPeopleView( state: InvitePeopleState, - invitePeopleView: @Composable () -> Unit, onFinish: () -> Unit, modifier: Modifier = Modifier, + invitePeopleView: @Composable () -> Unit, ) { HeaderFooterPage( modifier = modifier, diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt index ae23149fee..cd5470bc24 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomEvents.kt @@ -7,7 +7,6 @@ package io.element.android.features.createroom.impl.configureroom -import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.ui.media.AvatarAction sealed interface ConfigureRoomEvents { diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt index e566a4d970..6927c51366 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomNode.kt @@ -18,7 +18,6 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode -import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.services.analytics.api.AnalyticsService @@ -30,8 +29,7 @@ class ConfigureRoomNode @AssistedInject constructor( private val presenter: ConfigureRoomPresenter, private val analyticsService: AnalyticsService, ) : Node(buildContext, plugins = plugins) { - - interface Callback: Plugin { + interface Callback : Plugin { fun onCreateRoomSuccess(roomId: RoomId) } @@ -43,7 +41,7 @@ class ConfigureRoomNode @AssistedInject constructor( ) } - private fun onCreateRoomSuccess(roomId: RoomId){ + private fun onCreateRoomSuccess(roomId: RoomId) { plugins().forEach { it.onCreateRoomSuccess(roomId) } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfigStore.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfigStore.kt index ef5b632306..bee9b686d6 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfigStore.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/CreateRoomConfigStore.kt @@ -12,7 +12,6 @@ import io.element.android.libraries.androidutils.file.safeDelete import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.getAndUpdate import java.io.File import javax.inject.Inject diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt index 9e11603642..635a2b330e 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/startchat/impl/configureroom/ConfigureRoomPresenterTest.kt @@ -139,8 +139,6 @@ class ConfigureRoomPresenterTest { val initialState = initialState() var expectedConfig = CreateRoomConfig() assertThat(initialState.config).isEqualTo(expectedConfig) - - // Room name initialState.eventSink(ConfigureRoomEvents.RoomNameChanged(A_ROOM_NAME)) var newState = awaitItem() @@ -250,7 +248,7 @@ class ConfigureRoomPresenterTest { val matrixClient = createMatrixClient() val analyticsService = FakeAnalyticsService() val mediaPreProcessor = FakeMediaPreProcessor() - val dataStore = CreateRoomConfigStore( FakeRoomAliasHelper()) + val dataStore = CreateRoomConfigStore(FakeRoomAliasHelper()) val presenter = createConfigureRoomPresenter( dataStore = dataStore, mediaPreProcessor = mediaPreProcessor, diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt index 72175beaef..4e5c82f684 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt @@ -11,9 +11,7 @@ import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.room.JoinedRoom interface InvitePeoplePresenter : Presenter { - interface Factory { fun create(room: JoinedRoom): InvitePeoplePresenter } - } diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt index 3c41b53188..984eefbc77 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleEvents.kt @@ -10,7 +10,7 @@ package io.element.android.features.invitepeople.impl import io.element.android.features.invitepeople.api.InvitePeopleEvents import io.element.android.libraries.matrix.api.user.MatrixUser -sealed interface DefaultInvitePeopleEvents: InvitePeopleEvents { +sealed interface DefaultInvitePeopleEvents : InvitePeopleEvents { data class ToggleUser(val user: MatrixUser) : DefaultInvitePeopleEvents data class UpdateSearchQuery(val query: String) : DefaultInvitePeopleEvents data class OnSearchActiveChanged(val active: Boolean) : DefaultInvitePeopleEvents diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt index 8dfa0af91e..fb99e36e84 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt @@ -52,7 +52,6 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( @AppCoroutineScope private val coroutineScope: CoroutineScope, private val appErrorStateService: AppErrorStateService, ) : InvitePeoplePresenter { - @AssistedFactory @ContributesBinding(SessionScope::class) interface Factory : InvitePeoplePresenter.Factory { diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt index 41f49e74c0..5e6ff0cd31 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt @@ -21,4 +21,4 @@ data class DefaultInvitePeopleState( val selectedUsers: ImmutableList, override val isSearchActive: Boolean, override val eventSink: (InvitePeopleEvents) -> Unit -): InvitePeopleState +) : InvitePeopleState diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt index 3de67e8274..7d0fc9aac8 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -43,7 +43,6 @@ fun InvitePeopleView( state: DefaultInvitePeopleState, modifier: Modifier = Modifier, ) { - Column( modifier = modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(16.dp), 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 270290f05d..b3b3a839a4 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 @@ -19,7 +19,6 @@ import im.vector.app.features.analytics.plan.MobileScreen import io.element.android.anvilannotations.ContributesNode import io.element.android.features.invitepeople.api.InvitePeoplePresenter import io.element.android.features.invitepeople.api.InvitePeopleRenderer -import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.services.analytics.api.AnalyticsService @@ -28,12 +27,11 @@ import io.element.android.services.analytics.api.AnalyticsService class RoomInviteMembersNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val room: JoinedRoom, private val analyticsService: AnalyticsService, private val invitePeopleRenderer: InvitePeopleRenderer, - private val invitePeoplePresenterFactory: InvitePeoplePresenter.Factory, + room: JoinedRoom, + invitePeoplePresenterFactory: InvitePeoplePresenter.Factory, ) : Node(buildContext, plugins = plugins) { - init { lifecycle.subscribe( onResume = { @@ -50,9 +48,10 @@ class RoomInviteMembersNode @AssistedInject constructor( RoomInviteMembersView( state = state, modifier = modifier, - invitePeopleView = { invitePeopleRenderer.Render(state, Modifier) }, onBackClick = { navigateUp() }, - onSubmitClick = { navigateUp() } - ) + onDone = { navigateUp() } + ) { + invitePeopleRenderer.Render(state, Modifier) + } } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt index 608f9047ae..8bec90707f 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersView.kt @@ -7,9 +7,7 @@ package io.element.android.features.roomdetails.impl.invite -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -18,7 +16,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.dp import io.element.android.features.invitepeople.api.InvitePeopleEvents import io.element.android.features.invitepeople.api.InvitePeopleState import io.element.android.features.invitepeople.api.InvitePeopleStateProvider @@ -34,10 +31,10 @@ import io.element.android.libraries.ui.strings.CommonStrings @Composable fun RoomInviteMembersView( state: InvitePeopleState, - invitePeopleView: @Composable () -> Unit, onBackClick: () -> Unit, - onSubmitClick: () -> Unit, + onDone: () -> Unit, modifier: Modifier = Modifier, + invitePeopleView: @Composable () -> Unit, ) { Scaffold( modifier = modifier, @@ -52,7 +49,7 @@ fun RoomInviteMembersView( }, onSubmitClick = { state.eventSink(InvitePeopleEvents.SendInvites) - onSubmitClick() + onDone() }, canSend = state.canInvite, ) @@ -60,13 +57,12 @@ fun RoomInviteMembersView( ) { padding -> Box( modifier = Modifier - .fillMaxWidth() - .padding(padding) - .consumeWindowInsets(padding), + .fillMaxWidth() + .padding(padding) + .consumeWindowInsets(padding), ) { invitePeopleView() } - } } @@ -97,6 +93,6 @@ internal fun RoomInviteMembersViewPreview(@PreviewParameter(InvitePeopleStatePro state = state, invitePeopleView = {}, onBackClick = {}, - onSubmitClick = {}, + onDone = {}, ) } diff --git a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt index cce5c1839e..59a8838c6b 100644 --- a/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt +++ b/features/startchat/impl/src/test/kotlin/io/element/android/features/startchat/impl/root/StartChatPresenterTest.kt @@ -12,11 +12,11 @@ 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.invitepeople.test.FakeStartDMAction import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser import io.element.android.features.startchat.api.StartDMAction import io.element.android.features.startchat.impl.userlist.FakeUserListPresenter import io.element.android.features.startchat.impl.userlist.FakeUserListPresenterFactory -import io.element.android.features.invitepeople.test.FakeStartDMAction import io.element.android.features.startchat.impl.userlist.UserListDataStore import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.featureflag.api.FeatureFlags diff --git a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt index 6f696d9cdf..b7fae6082b 100644 --- a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt +++ b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt @@ -20,8 +20,8 @@ import androidx.compose.runtime.setValue import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import io.element.android.features.startchat.api.StartDMAction import io.element.android.features.enterprise.api.SessionEnterpriseService +import io.element.android.features.startchat.api.StartDMAction import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileState.ConfirmationDialog 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 e86c66bc4f..dd937b067a 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 @@ -13,10 +13,10 @@ import app.cash.molecule.moleculeFlow import app.cash.turbine.ReceiveTurbine import app.cash.turbine.test import com.google.common.truth.Truth.assertThat +import io.element.android.features.enterprise.test.FakeSessionEnterpriseService +import io.element.android.features.invitepeople.test.FakeStartDMAction import io.element.android.features.startchat.api.ConfirmingStartDmWithMatrixUser import io.element.android.features.startchat.api.StartDMAction -import io.element.android.features.invitepeople.test.FakeStartDMAction -import io.element.android.features.enterprise.test.FakeSessionEnterpriseService import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileVerificationState From 8b85b01c07e5ee712ec477cab61fd0e1bda75c91 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 16:59:12 +0200 Subject: [PATCH 18/30] Add string to Localazy --- .../android/features/createroom/impl/addpeople/AddPeopleView.kt | 2 +- features/home/impl/src/main/res/values/localazy.xml | 1 + libraries/ui-strings/src/main/res/values/localazy.xml | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt index 0a25ec9934..1b3776d507 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt @@ -42,7 +42,7 @@ fun AddPeopleView( }, footer = { Button( - text = "Finish", + text = stringResource(CommonStrings.action_finish), onClick = { state.eventSink(InvitePeopleEvents.SendInvites) onFinish() diff --git a/features/home/impl/src/main/res/values/localazy.xml b/features/home/impl/src/main/res/values/localazy.xml index 4918260281..e6e09b5e47 100644 --- a/features/home/impl/src/main/res/values/localazy.xml +++ b/features/home/impl/src/main/res/values/localazy.xml @@ -33,6 +33,7 @@ For now, you can deselect filters in order to see your other chats" "Invites" "You don\'t have any pending invites." "Low Priority" + "You don’t have any low priority chats yet" "You can deselect filters in order to see your other chats" "You don’t have chats for this selection" "People" diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index ec29d79f19..242e7b67fa 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -88,6 +88,7 @@ "Enable" "End poll" "Enter PIN" + "Finish" "Forgot password?" "Forward" "Go back" @@ -301,6 +302,7 @@ Reason: %1$s." "Signing out" "Something went wrong" "We encountered an issue. Please try again." + "Space" "%1$d Space" "%1$d Spaces" From e1cc402e4bd1804725d846400bc342444108edb1 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 13 Aug 2025 15:13:24 +0000 Subject: [PATCH 19/30] Update screenshots --- ...tures.createroom.impl.addpeople_AddPeopleView_Day_0_en.png | 4 ++-- ...tures.createroom.impl.addpeople_AddPeopleView_Day_1_en.png | 4 ++-- ...tures.createroom.impl.addpeople_AddPeopleView_Day_2_en.png | 4 ++-- ...tures.createroom.impl.addpeople_AddPeopleView_Day_3_en.png | 3 --- ...res.createroom.impl.addpeople_AddPeopleView_Night_0_en.png | 4 ++-- ...res.createroom.impl.addpeople_AddPeopleView_Night_1_en.png | 4 ++-- ...res.createroom.impl.addpeople_AddPeopleView_Night_2_en.png | 4 ++-- ...res.createroom.impl.addpeople_AddPeopleView_Night_3_en.png | 3 --- ...eateroom.impl.configureroom_ConfigureRoomViewDark_1_en.png | 4 ++-- ...eateroom.impl.configureroom_ConfigureRoomViewDark_2_en.png | 4 ++-- ...ateroom.impl.configureroom_ConfigureRoomViewLight_1_en.png | 4 ++-- ...ateroom.impl.configureroom_ConfigureRoomViewLight_2_en.png | 4 ++-- .../features.invitepeople.impl_InvitePeopleView_Day_0_en.png | 3 +++ .../features.invitepeople.impl_InvitePeopleView_Day_1_en.png | 3 +++ .../features.invitepeople.impl_InvitePeopleView_Day_2_en.png | 3 +++ .../features.invitepeople.impl_InvitePeopleView_Day_3_en.png | 3 +++ .../features.invitepeople.impl_InvitePeopleView_Day_4_en.png | 3 +++ .../features.invitepeople.impl_InvitePeopleView_Day_5_en.png | 3 +++ .../features.invitepeople.impl_InvitePeopleView_Day_6_en.png | 3 +++ .../features.invitepeople.impl_InvitePeopleView_Day_7_en.png | 3 +++ ...features.invitepeople.impl_InvitePeopleView_Night_0_en.png | 3 +++ ...features.invitepeople.impl_InvitePeopleView_Night_1_en.png | 3 +++ ...features.invitepeople.impl_InvitePeopleView_Night_2_en.png | 3 +++ ...features.invitepeople.impl_InvitePeopleView_Night_3_en.png | 3 +++ ...features.invitepeople.impl_InvitePeopleView_Night_4_en.png | 3 +++ ...features.invitepeople.impl_InvitePeopleView_Night_5_en.png | 3 +++ ...features.invitepeople.impl_InvitePeopleView_Night_6_en.png | 3 +++ ...features.invitepeople.impl_InvitePeopleView_Night_7_en.png | 3 +++ ...roomdetails.impl.invite_RoomInviteMembersView_Day_0_en.png | 4 ++-- ...roomdetails.impl.invite_RoomInviteMembersView_Day_1_en.png | 4 ++-- ...roomdetails.impl.invite_RoomInviteMembersView_Day_2_en.png | 4 ++-- ...roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png | 3 --- ...roomdetails.impl.invite_RoomInviteMembersView_Day_4_en.png | 3 --- ...roomdetails.impl.invite_RoomInviteMembersView_Day_5_en.png | 3 --- ...roomdetails.impl.invite_RoomInviteMembersView_Day_6_en.png | 3 --- ...roomdetails.impl.invite_RoomInviteMembersView_Day_7_en.png | 3 --- ...omdetails.impl.invite_RoomInviteMembersView_Night_0_en.png | 4 ++-- ...omdetails.impl.invite_RoomInviteMembersView_Night_1_en.png | 4 ++-- ...omdetails.impl.invite_RoomInviteMembersView_Night_2_en.png | 4 ++-- ...omdetails.impl.invite_RoomInviteMembersView_Night_3_en.png | 3 --- ...omdetails.impl.invite_RoomInviteMembersView_Night_4_en.png | 3 --- ...omdetails.impl.invite_RoomInviteMembersView_Night_5_en.png | 3 --- ...omdetails.impl.invite_RoomInviteMembersView_Night_6_en.png | 3 --- ...omdetails.impl.invite_RoomInviteMembersView_Night_7_en.png | 3 --- ...chat.impl.components_SearchMultipleUsersResultItem_en.png} | 0 ...artchat.impl.components_SearchSingleUserResultItem_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_0_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_1_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_2_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_3_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_4_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_5_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_6_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_7_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_8_en.png} | 0 ...tures.startchat.impl.components_UserListView_Day_9_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_0_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_1_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_2_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_3_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_4_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_5_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_6_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_7_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_8_en.png} | 0 ...res.startchat.impl.components_UserListView_Night_9_en.png} | 0 ...hat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png} | 0 ...hat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png} | 0 ...hat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png} | 0 ...hat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png} | 0 ...hat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png} | 0 ...hat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png} | 0 ...t.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png} | 0 ...t.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png} | 0 ...t.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png} | 0 ...t.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png} | 0 ...t.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png} | 0 ...t.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png} | 0 ...> features.startchat.impl.root_StartChatView_Day_0_en.png} | 0 ...> features.startchat.impl.root_StartChatView_Day_1_en.png} | 0 ...> features.startchat.impl.root_StartChatView_Day_2_en.png} | 0 ...> features.startchat.impl.root_StartChatView_Day_3_en.png} | 0 ...> features.startchat.impl.root_StartChatView_Day_4_en.png} | 0 ...> features.startchat.impl.root_StartChatView_Day_5_en.png} | 0 ...features.startchat.impl.root_StartChatView_Night_0_en.png} | 0 ...features.startchat.impl.root_StartChatView_Night_1_en.png} | 0 ...features.startchat.impl.root_StartChatView_Night_2_en.png} | 0 ...features.startchat.impl.root_StartChatView_Night_3_en.png} | 0 ...features.startchat.impl.root_StartChatView_Night_4_en.png} | 0 ...features.startchat.impl.root_StartChatView_Night_5_en.png} | 0 90 files changed, 80 insertions(+), 68 deletions(-) delete mode 100644 tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_2_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_3_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_4_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_5_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_6_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_7_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_2_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_3_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_4_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_5_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_6_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_7_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en.png rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_SearchMultipleUsersResultItem_en.png => features.startchat.impl.components_SearchMultipleUsersResultItem_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_SearchSingleUserResultItem_en.png => features.startchat.impl.components_SearchSingleUserResultItem_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_0_en.png => features.startchat.impl.components_UserListView_Day_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_1_en.png => features.startchat.impl.components_UserListView_Day_1_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_2_en.png => features.startchat.impl.components_UserListView_Day_2_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_3_en.png => features.startchat.impl.components_UserListView_Day_3_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_4_en.png => features.startchat.impl.components_UserListView_Day_4_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_5_en.png => features.startchat.impl.components_UserListView_Day_5_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_6_en.png => features.startchat.impl.components_UserListView_Day_6_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_7_en.png => features.startchat.impl.components_UserListView_Day_7_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_8_en.png => features.startchat.impl.components_UserListView_Day_8_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Day_9_en.png => features.startchat.impl.components_UserListView_Day_9_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_0_en.png => features.startchat.impl.components_UserListView_Night_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_1_en.png => features.startchat.impl.components_UserListView_Night_1_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_2_en.png => features.startchat.impl.components_UserListView_Night_2_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_3_en.png => features.startchat.impl.components_UserListView_Night_3_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_4_en.png => features.startchat.impl.components_UserListView_Night_4_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_5_en.png => features.startchat.impl.components_UserListView_Night_5_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_6_en.png => features.startchat.impl.components_UserListView_Night_6_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_7_en.png => features.startchat.impl.components_UserListView_Night_7_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_8_en.png => features.startchat.impl.components_UserListView_Night_8_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.components_UserListView_Night_9_en.png => features.startchat.impl.components_UserListView_Night_9_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png => features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Day_0_en.png => features.startchat.impl.root_StartChatView_Day_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Day_1_en.png => features.startchat.impl.root_StartChatView_Day_1_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Day_2_en.png => features.startchat.impl.root_StartChatView_Day_2_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Day_3_en.png => features.startchat.impl.root_StartChatView_Day_3_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Day_4_en.png => features.startchat.impl.root_StartChatView_Day_4_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Day_5_en.png => features.startchat.impl.root_StartChatView_Day_5_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Night_0_en.png => features.startchat.impl.root_StartChatView_Night_0_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Night_1_en.png => features.startchat.impl.root_StartChatView_Night_1_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Night_2_en.png => features.startchat.impl.root_StartChatView_Night_2_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Night_3_en.png => features.startchat.impl.root_StartChatView_Night_3_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Night_4_en.png => features.startchat.impl.root_StartChatView_Night_4_en.png} (100%) rename tests/uitests/src/test/snapshots/images/{features.createroom.impl.root_CreateRoomRootView_Night_5_en.png => features.startchat.impl.root_StartChatView_Night_5_en.png} (100%) diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_0_en.png index 1360f07fe2..338eb8d3f6 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7f6f2d2302e958ec4c85a5856839f5ed430ff9bf1048a8427b8b589cbc3f8ce -size 13665 +oid sha256:7415b3286707130c0218a8d1e82a9d9c61c8eec8df346653dd67626d0dd7709c +size 10038 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_1_en.png index f5ba7efcf3..a17b156fbf 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f315821d7f65b36f1237ffc4a7fc4e8d6ca1f00cc5452322495f057a9244dd20 -size 24704 +oid sha256:efe665c1419f9674e74b04dd066adf042cd421fd3e18a8cbc1f2ed80a0977e07 +size 10340 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_2_en.png index 873b524941..338eb8d3f6 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a04777e27af3dc8068f97e64c6312af53f416353b8b886f89368e83458d48b0 -size 77516 +oid sha256:7415b3286707130c0218a8d1e82a9d9c61c8eec8df346653dd67626d0dd7709c +size 10038 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png deleted file mode 100644 index 0c7800bb11..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Day_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:72216dbc7378b0745abc76a364258254cd7b7af56e47083799fb85e9f9d181f7 -size 41977 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_0_en.png index 8207f06398..5bd1590652 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b235755e1122103b52cb68a2ddef230ecfe3d61cac802d1fd633cf3bc37dbb0 -size 12880 +oid sha256:39c67413ca997982b0fcd32831ccedee1d7a0763619784b8758b194df6c7ff81 +size 9639 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_1_en.png index 479aaeb6c6..5cfffac707 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b46150ff515da137e4b2a57c7f0739b700c984f08c5ac01b9804638e53b661d7 -size 24865 +oid sha256:d8b6fae4f9fa5be0bbad9855ce80b53206748970d1ea1f9473eaa476afa39bcc +size 9936 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_2_en.png index f9fc27e0c0..5bd1590652 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04c62992c4744efc672861adbd0635a25616f060b66824ac0ad9c9ca89922462 -size 77954 +oid sha256:39c67413ca997982b0fcd32831ccedee1d7a0763619784b8758b194df6c7ff81 +size 9639 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png deleted file mode 100644 index 52779bf8fd..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.addpeople_AddPeopleView_Night_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:be7cfa925e024d94d72b17408fe3487007b6daee2c4dc728960f56af1351f644 -size 42100 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png index 6ba325fefe..933f4d0185 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c797770fae796712a4db1d9d4084ebef2211548a33c49178d015658ebc502a6 -size 42823 +oid sha256:e7a0b233fa704f80e06b4e5ed3b787722545e30b0adf3729b1618785169c8511 +size 35832 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png index 7e0c631982..867eb9e084 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewDark_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45b66b5de32c34fde5ab5997e4ee7bc7fce64c9846220a6cb98acb462b3f79d8 -size 59051 +oid sha256:dc153a3db10441cb166f2cf1d767f59bd77f4b45ff3f6a2dce02324f265626b1 +size 56368 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png index c2c2dd1d1d..0d444e8f35 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b846ef4e88898937c13d1a8e4a25d0ac1a5673e2906cca4369453fbd45b8dfa -size 43458 +oid sha256:686dd48e4b76b6f5bc06c8b2751b981a5a53dfba9821a138d2c64a9a9aacdd3c +size 36979 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png index 372d0db1bf..661406ac93 100644 --- a/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.createroom.impl.configureroom_ConfigureRoomViewLight_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcd04f11078a2b5727a65b758b8425dddc49b28a11ef0cb61f35ad7f11ab90c9 -size 60231 +oid sha256:6c24eec8e26ba06ddb216e3d5335a139f947d9ff576dc8737af0bb713e0d68a1 +size 58216 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png new file mode 100644 index 0000000000..7b42297c4a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85bd01b35953493c35625e4d458a8b8f1557ebddec5ee3164c3f4b40f8cdf814 +size 9202 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png new file mode 100644 index 0000000000..22f04c3a07 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c6677df67d825bf0bda07723c4c0e505e7b1340d6686567234a513f4447c772c +size 20684 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_2_en.png new file mode 100644 index 0000000000..bff2174041 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a40987c3fb50529128eee026fa9b21495bacac58bdf20a01a39fb24ea462f4c +size 6676 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_3_en.png new file mode 100644 index 0000000000..5399d37415 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84b3f9bbf73e600f1e860a42c26cc4a9f5be45acae551a90a2e19084dcf5d157 +size 18031 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_4_en.png new file mode 100644 index 0000000000..09335740e8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ee1be1b069192b7e155139af4e3dba97fc21373d3e49d31be41f6263b733800 +size 8626 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_5_en.png new file mode 100644 index 0000000000..353f884e3e --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f050b90caaf47a772c72d805955b657de1f7fe544e8a45952b4f9592e54ee5d6 +size 38336 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_6_en.png new file mode 100644 index 0000000000..76b5bab350 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5996283d500a3b9eb525584865ba868dda5d688c8f757399e5b907c6aa1ea70e +size 33128 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_7_en.png new file mode 100644 index 0000000000..1be07da870 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f301d1266f98ec60c8abdb508884d44d3eb5b607654e0158b693779e5a8b6ca6 +size 25626 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png new file mode 100644 index 0000000000..6236f3c1e9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db18a58eb2d2f6e374079e3766ea84ef29beb7cc52d4f93281752826dd6c9d49 +size 8545 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png new file mode 100644 index 0000000000..c192408655 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc4d907e2ab98ae5e00d2b8acc4faa87aefc4137677301875ca7cd152a83a35f +size 20927 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_2_en.png new file mode 100644 index 0000000000..d4004dd81d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d2fae553f7775986fe0c50adcbb581eabe7ebf2f82d39e1fef3d6ecc4e3c288 +size 6511 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_3_en.png new file mode 100644 index 0000000000..68ddb5c685 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee5daee317f00723321e2b4aa0f8be015cacb9ab22e36ba74238a8063766aab5 +size 18713 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_4_en.png new file mode 100644 index 0000000000..0553656788 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_4_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fe4889333bc96358fb3121bdeb54d3d4d75eba234d318462da3985ee75cf8ed2 +size 8420 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_5_en.png new file mode 100644 index 0000000000..c3d5eebc49 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1bfd83f8bcf688f73edeeed7d085f706dc81fe7c5b608a46c55f320a0772cc14 +size 39183 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_6_en.png new file mode 100644 index 0000000000..89d64ec951 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_6_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1318a5b1a3f17f6e4e867eea5615909c9c54c13f55caeff5beb97f8251c62138 +size 33225 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_7_en.png new file mode 100644 index 0000000000..55ea3aaf4c --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_7_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ea5406893f8d4eb3ba729233fee5271c5de3d10b57cae9dd6d8cb973da04378 +size 25211 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en.png index 6102c1316d..4149be807b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb145968deaf61c3c94c5094624a1024e796698fc7b62801f852fd4db4483de6 -size 13741 +oid sha256:611314345ea0f68062800755783e790ad452adec1f1dd01fcae1eec4cc5322fc +size 8188 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en.png index 8a3e9fced6..39ff3000da 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66f4f90864984ed917ff55916b62a825ab05915de3b7e7fc9be22b4bcb7c3ef1 -size 24702 +oid sha256:86a07a08b2bd2b6672da54bec6183ccdc860740a24cf43e88d3e40c0b50138ed +size 8110 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en.png index c042e2b852..4149be807b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2df17818a5c948856cd4892f56e321b3f5f72353d0d05b0104c13115a1538c92 -size 11160 +oid sha256:611314345ea0f68062800755783e790ad452adec1f1dd01fcae1eec4cc5322fc +size 8188 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png deleted file mode 100644 index af42e49989..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c9b9ae8410f882587f286684da3d92fde0de1c5f9a42dcc4819e690c3fc997ba -size 22454 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en.png deleted file mode 100644 index 528b5ad450..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_4_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c69900f653154c27dea219139c66337783e3ed1a04d1520c18c4271430a1910b -size 13111 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en.png deleted file mode 100644 index 7db6382d79..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_5_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:022d3375146f9fc4d68b5342a725492e5e3899565518110ee0a5c25687b46764 -size 42527 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en.png deleted file mode 100644 index b9cdf531f8..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_6_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e13b174b62b089cf1275d5bbf7ca59bbcb0c8afe416d0dbc8bc92c6267b7379 -size 37547 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en.png deleted file mode 100644 index 4097a7998a..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Day_7_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5f46810124f978b267deb9b6418b740ae845bd53529cda4de688e2d09cea1010 -size 29699 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en.png index f13c0ff5ff..b27727ee2b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b385467c9bf74c9abc478d3cc2b20f73abd2da65f71a75d8f86e9e8635b86af1 -size 12919 +oid sha256:7ba9d3cb9a5a601b28ad9ff508c3179921cf26fcee86194c582092b1d7bf79d3 +size 7992 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en.png index 9832cb4eb2..3f5cacc2d0 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44264663827df1a99b190ec02edddac80d6b95a65f98a4abc4e8cf7a1141b793 -size 24841 +oid sha256:6cb292850354b8b6ba5ca36334d1664dccd617e7a6b9b55ecf3ac7d1b9729d90 +size 7872 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en.png index c9c0170659..b27727ee2b 100644 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77a5df48748a583eb76d1fd9ddfc334f16d8b327f31edde679a548ada59f4488 -size 10772 +oid sha256:7ba9d3cb9a5a601b28ad9ff508c3179921cf26fcee86194c582092b1d7bf79d3 +size 7992 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png deleted file mode 100644 index e49a38e82e..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:40eb69cf8c757555304edccca2e1b57d378e0cf9f4a8c42b275287d0f44a7f18 -size 22877 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en.png deleted file mode 100644 index 8c0a4c43a0..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_4_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2c54621eb62e69ea15b707a75a1a579836730ab321c67e16535a56da0b972ed3 -size 12689 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en.png deleted file mode 100644 index 3645708432..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_5_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:25eb2a710631f8297160e6a8e51102f454db559d7c56b8b14a33e2bbfb5a4173 -size 43159 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en.png deleted file mode 100644 index 136e28cb23..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_6_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b5d429e01ef00018de091809af63edc12827362fe82498bca5c85b85a0e6fd6a -size 37451 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en.png deleted file mode 100644 index ad4dd4a0a0..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl.invite_RoomInviteMembersView_Night_7_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4e1e57cfdee3e3f45024b9b9bafa5ea9eade19ab4b9ff48f2acd76245d5cc026 -size 29011 diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_SearchMultipleUsersResultItem_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchMultipleUsersResultItem_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_SearchMultipleUsersResultItem_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchMultipleUsersResultItem_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_SearchSingleUserResultItem_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchSingleUserResultItem_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_SearchSingleUserResultItem_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_SearchSingleUserResultItem_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_6_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_6_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_6_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_7_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_7_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_7_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_8_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_8_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_8_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_9_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Day_9_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Day_9_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_6_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_6_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_6_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_7_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_7_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_7_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_8_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_8_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_8_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_9_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.components_UserListView_Night_9_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.components_UserListView_Night_9_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Day_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.joinbyaddress_JoinRoomByAddressView_Night_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Day_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Day_5_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_0_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_0_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_1_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_1_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_1_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_2_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_2_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_2_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_3_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_3_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_4_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_4_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_4_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_5_en.png similarity index 100% rename from tests/uitests/src/test/snapshots/images/features.createroom.impl.root_CreateRoomRootView_Night_5_en.png rename to tests/uitests/src/test/snapshots/images/features.startchat.impl.root_StartChatView_Night_5_en.png From ea86be6a226839922d58932affc292233147bbd7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 17:19:38 +0200 Subject: [PATCH 20/30] Use string from Localazy --- .../features/createroom/impl/addpeople/AddPeopleView.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt index 1b3776d507..1c9a5f84d3 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleView.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import io.element.android.features.createroom.impl.R import io.element.android.features.invitepeople.api.InvitePeopleEvents import io.element.android.features.invitepeople.api.InvitePeopleState import io.element.android.features.invitepeople.api.InvitePeopleStateProvider @@ -63,7 +64,7 @@ private fun AddPeopleTopBar( onSkipClick: () -> Unit, ) { TopAppBar( - titleStr = "Invite people", + titleStr = stringResource(R.string.screen_create_room_add_people_title), actions = { TextButton( text = stringResource(CommonStrings.action_skip), From 58a3ec767b2735161f9f10fbfc11331948b7d521 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 17:41:44 +0200 Subject: [PATCH 21/30] Cleanup Localazy config and do a sync. --- .../src/main/res/values-be/translations.xml | 2 -- .../src/main/res/values-bg/translations.xml | 5 ----- .../src/main/res/values-cs/translations.xml | 8 -------- .../src/main/res/values-cy/translations.xml | 8 -------- .../src/main/res/values-da/translations.xml | 8 -------- .../src/main/res/values-de/translations.xml | 8 -------- .../src/main/res/values-el/translations.xml | 8 -------- .../src/main/res/values-es/translations.xml | 8 -------- .../src/main/res/values-et/translations.xml | 8 -------- .../src/main/res/values-eu/translations.xml | 4 ---- .../src/main/res/values-fa/translations.xml | 8 -------- .../src/main/res/values-fi/translations.xml | 8 -------- .../src/main/res/values-fr/translations.xml | 8 -------- .../src/main/res/values-hu/translations.xml | 8 -------- .../src/main/res/values-in/translations.xml | 8 -------- .../src/main/res/values-it/translations.xml | 8 -------- .../src/main/res/values-ka/translations.xml | 2 -- .../src/main/res/values-lt/translations.xml | 1 - .../src/main/res/values-nb/translations.xml | 8 -------- .../src/main/res/values-nl/translations.xml | 2 -- .../src/main/res/values-pl/translations.xml | 8 -------- .../main/res/values-pt-rBR/translations.xml | 8 -------- .../src/main/res/values-pt/translations.xml | 8 -------- .../src/main/res/values-ro/translations.xml | 2 -- .../src/main/res/values-ru/translations.xml | 8 -------- .../src/main/res/values-sk/translations.xml | 8 -------- .../src/main/res/values-sv/translations.xml | 8 -------- .../src/main/res/values-tr/translations.xml | 2 -- .../src/main/res/values-uk/translations.xml | 8 -------- .../src/main/res/values-ur/translations.xml | 2 -- .../src/main/res/values-uz/translations.xml | 1 - .../main/res/values-zh-rTW/translations.xml | 8 -------- .../src/main/res/values-zh/translations.xml | 2 -- .../impl/src/main/res/values/localazy.xml | 8 -------- .../src/main/res/values-be/translations.xml | 13 ------------- .../src/main/res/values-bg/translations.xml | 14 -------------- .../src/main/res/values-cs/translations.xml | 18 ------------------ .../src/main/res/values-cy/translations.xml | 18 ------------------ .../src/main/res/values-da/translations.xml | 18 ------------------ .../src/main/res/values-de/translations.xml | 18 ------------------ .../src/main/res/values-el/translations.xml | 18 ------------------ .../src/main/res/values-es/translations.xml | 18 ------------------ .../src/main/res/values-et/translations.xml | 18 ------------------ .../src/main/res/values-eu/translations.xml | 16 +--------------- .../src/main/res/values-fa/translations.xml | 16 ---------------- .../src/main/res/values-fi/translations.xml | 18 ------------------ .../src/main/res/values-fr/translations.xml | 18 ------------------ .../src/main/res/values-hu/translations.xml | 18 ------------------ .../src/main/res/values-in/translations.xml | 18 ------------------ .../src/main/res/values-it/translations.xml | 18 ------------------ .../src/main/res/values-ka/translations.xml | 9 --------- .../src/main/res/values-lt/translations.xml | 9 --------- .../src/main/res/values-nb/translations.xml | 18 ------------------ .../src/main/res/values-nl/translations.xml | 15 --------------- .../src/main/res/values-pl/translations.xml | 18 ------------------ .../main/res/values-pt-rBR/translations.xml | 18 ------------------ .../src/main/res/values-pt/translations.xml | 18 ------------------ .../src/main/res/values-ro/translations.xml | 16 ---------------- .../src/main/res/values-ru/translations.xml | 18 ------------------ .../src/main/res/values-sk/translations.xml | 18 ------------------ .../src/main/res/values-sv/translations.xml | 18 ------------------ .../src/main/res/values-tr/translations.xml | 18 ------------------ .../src/main/res/values-uk/translations.xml | 18 ------------------ .../src/main/res/values-ur/translations.xml | 10 ---------- .../src/main/res/values-uz/translations.xml | 8 -------- .../main/res/values-zh-rTW/translations.xml | 18 ------------------ .../src/main/res/values-zh/translations.xml | 18 ------------------ .../impl/src/main/res/values/localazy.xml | 18 ------------------ tools/localazy/config.json | 10 +++------- 69 files changed, 4 insertions(+), 773 deletions(-) diff --git a/features/createroom/impl/src/main/res/values-be/translations.xml b/features/createroom/impl/src/main/res/values-be/translations.xml index 8acb990b02..f5d6a234e2 100644 --- a/features/createroom/impl/src/main/res/values-be/translations.xml +++ b/features/createroom/impl/src/main/res/values-be/translations.xml @@ -14,6 +14,4 @@ "Назва пакоя" "Стварыце пакой" "Тэма (неабавязкова)" - "Каталог пакояў" - "Пры спробе пачаць чат адбылася памылка" diff --git a/features/createroom/impl/src/main/res/values-bg/translations.xml b/features/createroom/impl/src/main/res/values-bg/translations.xml index fa6dae371c..249058b7af 100644 --- a/features/createroom/impl/src/main/res/values-bg/translations.xml +++ b/features/createroom/impl/src/main/res/values-bg/translations.xml @@ -15,9 +15,4 @@ "Видимост на стаята" "Създаване на стая" "Тема за разговор (незадължително)" - "Присъединяване към стая по адрес" - "Не е валиден адрес" - "Въведете…" - "Стаята не е намерена" - "напр. #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-cs/translations.xml b/features/createroom/impl/src/main/res/values-cs/translations.xml index 53592e0db0..e19cfbcf91 100644 --- a/features/createroom/impl/src/main/res/values-cs/translations.xml +++ b/features/createroom/impl/src/main/res/values-cs/translations.xml @@ -19,12 +19,4 @@ To můžete kdykoli změnit v nastavení místnosti." "Viditelnost místnosti" "Vytvořit místnost" "Téma (nepovinné)" - "Adresář místností" - "Při pokusu o zahájení chatu došlo k chybě" - "Vstoupit do místnosti pomocí adresy" - "Neplatná adresa" - "Zadejte…" - "Odpovídající místnost nalezena" - "Místnost nebyla nalezena" - "např. #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-cy/translations.xml b/features/createroom/impl/src/main/res/values-cy/translations.xml index a3a9e30e35..52168014bf 100644 --- a/features/createroom/impl/src/main/res/values-cy/translations.xml +++ b/features/createroom/impl/src/main/res/values-cy/translations.xml @@ -19,12 +19,4 @@ Gallwch newid hyn unrhyw bryd yng ngosodiadau ystafell." "Gwelededd yr ystafell" "Creu ystafell" "Pwnc (dewisol)" - "Cyfeiriadur ystafelloedd" - "Digwyddodd gwall wrth geisio cychwyn sgwrs" - "Ymuno â\'r ystafell yn ôl cyfeiriad" - "Ddim yn gyfeiriad dilys" - "Ewch i mewn…" - "Cafwyd hyd i ystafell gyfatebol" - "Heb ganfod yr ystafell" - "e.e. #enw-ystafell:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-da/translations.xml b/features/createroom/impl/src/main/res/values-da/translations.xml index c9c182b474..a8f66f60db 100644 --- a/features/createroom/impl/src/main/res/values-da/translations.xml +++ b/features/createroom/impl/src/main/res/values-da/translations.xml @@ -19,12 +19,4 @@ Du kan ændre dette når som helst i rummets indstillinger." "Rummets synlighed" "Opret et rum" "Emne (valgfrit)" - "Register over rum" - "Der opstod en fejl under forsøget på at starte en samtale" - "Tilslut dig rummet med adressen" - "Ikke en gyldig adresse" - "Indtast…" - "Matchende rum fundet" - "Rum ikke fundet" - "f.eks. #rummets-navn:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-de/translations.xml b/features/createroom/impl/src/main/res/values-de/translations.xml index 90438aa38c..213d10ae7a 100644 --- a/features/createroom/impl/src/main/res/values-de/translations.xml +++ b/features/createroom/impl/src/main/res/values-de/translations.xml @@ -19,12 +19,4 @@ Sie können dies aber jederzeit in den Chatroomeinstellungen ändern." " Sichtbarkeit des Chatrooms" "Raum erstellen" "Thema (optional)" - "Raum-Verzeichnis" - "Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten" - "Raum per Adresse betreten" - "Keine gültige Adresse" - "Eintreten…" - "Passender Raum gefunden" - "Raum nicht gefunden" - "z. B. #room -name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-el/translations.xml b/features/createroom/impl/src/main/res/values-el/translations.xml index c036b43a05..a3084a4e70 100644 --- a/features/createroom/impl/src/main/res/values-el/translations.xml +++ b/features/createroom/impl/src/main/res/values-el/translations.xml @@ -19,12 +19,4 @@ "Ορατότητα αίθουσας" "Δημιουργία αίθουσας" "Θέμα (προαιρετικό)" - "Κατάλογος αιθουσών" - "Παρουσιάστηκε σφάλμα κατά την προσπάθεια έναρξης μιας συνομιλίας" - "Συμμετοχή σε αίθουσα μέσω διεύθυνσης" - "Μη έγκυρη διεύθυνση" - "Εισάγετε…" - "Βρέθηκε η αντίστοιχη αίθουσα" - "Η αίθουσα δεν βρέθηκε" - "π.χ. #όνομα-αίθουσας:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-es/translations.xml b/features/createroom/impl/src/main/res/values-es/translations.xml index c11f08fc14..521f761174 100644 --- a/features/createroom/impl/src/main/res/values-es/translations.xml +++ b/features/createroom/impl/src/main/res/values-es/translations.xml @@ -19,12 +19,4 @@ Puedes cambiar esto en cualquier momento en los ajustes de la sala." "Visibilidad de la sala" "Crear una sala" "Tema (opcional)" - "Directorio de salas" - "Se ha producido un error al intentar iniciar un chat" - "Unirse a una sala por su dirección" - "Dirección no válida" - "Introducir…" - "Sala encontrada" - "No se encontró la sala" - "p. ej., #nombre-de-la-sala:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-et/translations.xml b/features/createroom/impl/src/main/res/values-et/translations.xml index 57a26106b3..6a1d9dc58a 100644 --- a/features/createroom/impl/src/main/res/values-et/translations.xml +++ b/features/createroom/impl/src/main/res/values-et/translations.xml @@ -19,12 +19,4 @@ Sa võid seda jututoa seadistustest alati muuta." "Jututoa nähtavus" "Loo jututuba" "Teema (kui soovid lisada)" - "Jututubade kataloog" - "Vestluse alustamisel tekkis viga" - "Liitu jututoaga aadressi alusel" - "See pole kehtiv aadress" - "Sisene…" - "Leidsime vastava jututoa" - "Jututuba ei leidu" - "nt. #jututoa-nimi:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-eu/translations.xml b/features/createroom/impl/src/main/res/values-eu/translations.xml index 43f67e429c..537aa495a5 100644 --- a/features/createroom/impl/src/main/res/values-eu/translations.xml +++ b/features/createroom/impl/src/main/res/values-eu/translations.xml @@ -16,8 +16,4 @@ Gelaren ezarpenetan aldatu dezakezu hobespena." "Gelaren ikusgarritasuna" "Sortu gela" "Mintzagaia (aukerakoa)" - "Gelen direktorioa" - "Errorea gertatu da txata hasten saiatzean" - "Sartu…" - "Ez da gela aurkitu" diff --git a/features/createroom/impl/src/main/res/values-fa/translations.xml b/features/createroom/impl/src/main/res/values-fa/translations.xml index 03bc5c3f58..09869c76f6 100644 --- a/features/createroom/impl/src/main/res/values-fa/translations.xml +++ b/features/createroom/impl/src/main/res/values-fa/translations.xml @@ -17,12 +17,4 @@ "نمایانی اتاق" "ایجاد اتاق" "موضوع (اختیاری)" - "فهرست اتاق‌ها" - "هنگام تلاش برای شروع چت خطایی روی داد" - "پیوستن به اتاق با نشانی" - "نشانی معتبری نیست" - "ورود…" - "اتاق مطابق پیدا شد" - "اتاق پیدا نشد" - "نمونه: ‪#room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-fi/translations.xml b/features/createroom/impl/src/main/res/values-fi/translations.xml index cdb6d04d59..31589ab997 100644 --- a/features/createroom/impl/src/main/res/values-fi/translations.xml +++ b/features/createroom/impl/src/main/res/values-fi/translations.xml @@ -19,12 +19,4 @@ Voit muuttaa tämän milloin tahansa huoneen asetuksista." "Huoneen näkyvyys" "Luo huone" "Aihe (valinnainen)" - "Huoneluettelo" - "Keskustelun aloituksessa tapahtui virhe" - "Liity huoneeseen osoitteella" - "Osoite ei ole kelvollinen" - "Syötä…" - "Täsmäävä huone löytyi" - "Huonetta ei löytynyt" - "esim. #huoneen-nimi:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-fr/translations.xml b/features/createroom/impl/src/main/res/values-fr/translations.xml index 3f9e01dc85..afbdc919ba 100644 --- a/features/createroom/impl/src/main/res/values-fr/translations.xml +++ b/features/createroom/impl/src/main/res/values-fr/translations.xml @@ -19,12 +19,4 @@ Vous pouvez modifier cela à tout moment dans les paramètres du salon.""Visibilité du salon" "Créer un salon" "Sujet (facultatif)" - "Annuaire des salons" - "Une erreur s’est produite lors de la tentative de création de la discussion" - "Saisir une adresse de salon" - "Ce n’est pas une adresse valide" - "Saisir…" - "Ce salon existe" - "Salon non trouvé" - "ex: #nom-du-salon:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-hu/translations.xml b/features/createroom/impl/src/main/res/values-hu/translations.xml index 1e4a721279..8833afcdec 100644 --- a/features/createroom/impl/src/main/res/values-hu/translations.xml +++ b/features/createroom/impl/src/main/res/values-hu/translations.xml @@ -19,12 +19,4 @@ Ezt bármikor módosíthatja a szobabeállításokban." "Szoba láthatósága" "Szoba létrehozása" "Téma (nem kötelező)" - "Szobakatalógus" - "Hiba történt a csevegés indításakor" - "Csatlakozás a szobához cím szerint" - "Nem érvényes cím" - "Írja be…" - "Megfelelő szoba található" - "Szoba nem található" - "pl. #szoba-neve:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-in/translations.xml b/features/createroom/impl/src/main/res/values-in/translations.xml index 65f135e617..219f621068 100644 --- a/features/createroom/impl/src/main/res/values-in/translations.xml +++ b/features/createroom/impl/src/main/res/values-in/translations.xml @@ -19,12 +19,4 @@ Anda dapat mengubah ini kapan pun dalam pengaturan ruangan." "Keterlihatan ruangan" "Buat ruangan" "Topik (opsional)" - "Direktori ruangan" - "Terjadi kesalahan saat mencoba memulai obrolan" - "Bergabung dalam ruangan berdasarkan alamat" - "Bukan alamat yang valid" - "Masuk…" - "Ruangan yang cocok ditemukan" - "Ruangan tidak ditemukan" - "mis. #nama-ruangan:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-it/translations.xml b/features/createroom/impl/src/main/res/values-it/translations.xml index 701ebc967f..741b88b763 100644 --- a/features/createroom/impl/src/main/res/values-it/translations.xml +++ b/features/createroom/impl/src/main/res/values-it/translations.xml @@ -19,12 +19,4 @@ Puoi modificarlo in qualsiasi momento nelle impostazioni della stanza." "Visibilità della stanza" "Crea una stanza" "Argomento (facoltativo)" - "Elenco delle stanze" - "Si è verificato un errore durante il tentativo di avviare una chat" - "Accedi alla stanza tramite indirizzo" - "Indirizzo non valido" - "Inserisci…" - "Stanza trovata" - "Stanza non trovata" - "ad esempio #room -name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-ka/translations.xml b/features/createroom/impl/src/main/res/values-ka/translations.xml index bb4a430320..20c7af40de 100644 --- a/features/createroom/impl/src/main/res/values-ka/translations.xml +++ b/features/createroom/impl/src/main/res/values-ka/translations.xml @@ -10,6 +10,4 @@ "ოთახის სახელი" "ოთახის შექმნა" "თემა (სურვილისამებრ)" - "ოთახის კატალოგი" - "ჩატის დაწყების მცდელობისას შეცდომა მოხდა" diff --git a/features/createroom/impl/src/main/res/values-lt/translations.xml b/features/createroom/impl/src/main/res/values-lt/translations.xml index 2f7a4438ea..2fb7b3eb5c 100644 --- a/features/createroom/impl/src/main/res/values-lt/translations.xml +++ b/features/createroom/impl/src/main/res/values-lt/translations.xml @@ -10,5 +10,4 @@ Tai galite bet kada pakeisti kambario nustatymuose." "Kambario pavadinimas" "Kurti kambarį" "Tema (nebūtina)" - "Bandant pradėti pokalbį įvyko klaida" diff --git a/features/createroom/impl/src/main/res/values-nb/translations.xml b/features/createroom/impl/src/main/res/values-nb/translations.xml index 9266993fd4..e6021cf5ac 100644 --- a/features/createroom/impl/src/main/res/values-nb/translations.xml +++ b/features/createroom/impl/src/main/res/values-nb/translations.xml @@ -19,12 +19,4 @@ Du kan endre dette når som helst i rominnstillingene." "Romsynlighet" "Opprett et rom" "Emne (valgfritt)" - "Romkatalog" - "Det oppstod en feil når du prøvde å starte en chat" - "Bli med i rommet med adresse" - "Ikke en gyldig adresse" - "Gå inn…" - "Matchende rom funnet" - "Rom ikke funnet" - "f.eks. #rom-navn:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-nl/translations.xml b/features/createroom/impl/src/main/res/values-nl/translations.xml index 29d070a263..5142148171 100644 --- a/features/createroom/impl/src/main/res/values-nl/translations.xml +++ b/features/createroom/impl/src/main/res/values-nl/translations.xml @@ -16,6 +16,4 @@ Je kunt dit op elk gewenst moment wijzigen in de kamerinstellingen." "Naam van de kamer" "Creëer een kamer" "Onderwerp (optioneel)" - "Kamergids" - "Er is een fout opgetreden bij het starten van een chat" diff --git a/features/createroom/impl/src/main/res/values-pl/translations.xml b/features/createroom/impl/src/main/res/values-pl/translations.xml index 3ed917b7bb..446644b622 100644 --- a/features/createroom/impl/src/main/res/values-pl/translations.xml +++ b/features/createroom/impl/src/main/res/values-pl/translations.xml @@ -19,12 +19,4 @@ Możesz to zmienić w ustawieniach pokoju." "Widoczność pomieszczenia" "Utwórz pokój" "Temat (opcjonalnie)" - "Katalog pokoi" - "Wystąpił błąd podczas próby rozpoczęcia czatu" - "Dołącz do pokoju za pomocą adresu" - "Nieprawidłowy adres" - "Wprowadź…" - "Znaleziono pasujący pokój" - "Nie znaleziono pokoju" - "np. #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-pt-rBR/translations.xml b/features/createroom/impl/src/main/res/values-pt-rBR/translations.xml index 52c9f569af..1b1e9f2d1b 100644 --- a/features/createroom/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/createroom/impl/src/main/res/values-pt-rBR/translations.xml @@ -19,12 +19,4 @@ Você pode mudar isso a qualquer momento nas configurações da sala." "Visibilidade da sala" "Criar uma sala" "Tópico (opcional)" - "Diretório de salas" - "Ocorreu um erro ao tentar iniciar um chat" - "Entrar na sala pelo endereço" - "Não é um endereço válido" - "Entrar…" - "Foi encontrada uma sala correspondente" - "Sala não encontrada" - "Por exemplo, #nome-da-sala:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-pt/translations.xml b/features/createroom/impl/src/main/res/values-pt/translations.xml index 5e5f5fc9c3..1524914bb2 100644 --- a/features/createroom/impl/src/main/res/values-pt/translations.xml +++ b/features/createroom/impl/src/main/res/values-pt/translations.xml @@ -19,12 +19,4 @@ Pode alterar esta opção nas definições da sala." "Visibilidade da sala" "Criar uma sala" "Descrição (opcional)" - "Diretório de salas" - "Ocorreu um erro ao tentar iniciar uma conversa" - "Entrar na sala pelo endereço" - "Não é um endereço válido" - "Entrar…" - "Sala correspondente encontrado" - "Sala não encontrada" - "por exemplo, #sala:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-ro/translations.xml b/features/createroom/impl/src/main/res/values-ro/translations.xml index 8d9e74b530..a5ea4fbb85 100644 --- a/features/createroom/impl/src/main/res/values-ro/translations.xml +++ b/features/createroom/impl/src/main/res/values-ro/translations.xml @@ -17,6 +17,4 @@ Puteți modifica acest lucru oricând în setări." "Numele camerei" "Creați o cameră" "Subiect (opțional)" - "Director de camere" - "A apărut o eroare la încercarea începerii conversației" diff --git a/features/createroom/impl/src/main/res/values-ru/translations.xml b/features/createroom/impl/src/main/res/values-ru/translations.xml index 6344491248..e871673114 100644 --- a/features/createroom/impl/src/main/res/values-ru/translations.xml +++ b/features/createroom/impl/src/main/res/values-ru/translations.xml @@ -19,12 +19,4 @@ "Видимость комнаты" "Создать комнату" "Тема (необязательно)" - "Каталог комнат" - "Произошла ошибка при запуске чата" - "Присоединиться к комнате по адресу" - "Недействительный адрес" - "Ввести…" - "Соответствующая комната найдена" - "Комната не найдена" - "прим. #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-sk/translations.xml b/features/createroom/impl/src/main/res/values-sk/translations.xml index eaf6c2f19c..7b6d89b2e1 100644 --- a/features/createroom/impl/src/main/res/values-sk/translations.xml +++ b/features/createroom/impl/src/main/res/values-sk/translations.xml @@ -19,12 +19,4 @@ Môžete to kedykoľvek zmeniť v nastaveniach miestnosti." "Viditeľnosť miestnosti" "Vytvoriť miestnosť" "Téma (voliteľné)" - "Adresár miestností" - "Pri pokuse o spustenie konverzácie sa vyskytla chyba" - "Pripojte sa do miestnosti podľa adresy" - "Neplatná adresa" - "Zadajte…" - "Nájdená zodpovedajúca miestnosť" - "Miestnosť sa nenašla" - "napr. #nazov-miestnosti:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-sv/translations.xml b/features/createroom/impl/src/main/res/values-sv/translations.xml index 316c9cc32e..8cd01ebd0e 100644 --- a/features/createroom/impl/src/main/res/values-sv/translations.xml +++ b/features/createroom/impl/src/main/res/values-sv/translations.xml @@ -19,12 +19,4 @@ Du kan ändra detta när som helst i rumsinställningarna." "Rumssynlighet" "Skapa ett rum" "Ämne (valfritt)" - "Rumskatalog" - "Ett fel uppstod när du försökte starta en chatt" - "Gå med i rum med adress" - "Inte en giltig adress" - "Ange …" - "Matchande rum hittades" - "Rummet hittades inte" - "t.ex. #rumsnamn:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-tr/translations.xml b/features/createroom/impl/src/main/res/values-tr/translations.xml index c8e3136517..d97139c973 100644 --- a/features/createroom/impl/src/main/res/values-tr/translations.xml +++ b/features/createroom/impl/src/main/res/values-tr/translations.xml @@ -19,6 +19,4 @@ Bunu istediğiniz zaman oda ayarlarından değiştirebilirsiniz." "Oda görünürlüğü" "Bir oda oluştur" "Konu (isteğe bağlı)" - "Oda dizini" - "Sohbet başlatmaya çalışırken bir hata oluştu" diff --git a/features/createroom/impl/src/main/res/values-uk/translations.xml b/features/createroom/impl/src/main/res/values-uk/translations.xml index a43172fb8b..047b4dd9d2 100644 --- a/features/createroom/impl/src/main/res/values-uk/translations.xml +++ b/features/createroom/impl/src/main/res/values-uk/translations.xml @@ -19,12 +19,4 @@ "Видимість кімнати" "Створити кімнату" "Тема (необов\'язково)" - "Каталог кімнат" - "Під час спроби почати бесіду сталася помилка" - "Приєднатися до кімнати за адресою" - "Недійсна адреса" - "Введіть…" - "Знайдено відповідну кімнату" - "Кімната не знайдена" - "наприклад, #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-ur/translations.xml b/features/createroom/impl/src/main/res/values-ur/translations.xml index 6fe476462e..b68992085f 100644 --- a/features/createroom/impl/src/main/res/values-ur/translations.xml +++ b/features/createroom/impl/src/main/res/values-ur/translations.xml @@ -11,6 +11,4 @@ "کمرے کا نام" "ایک کمرہ بنائیں" "موضوع (اختیاری)" - "کمرے کا راہنامچہ" - "گفتگو شروع کرنے کی کوشش کرتے وقت ایک خرابی واقع ہوگئی" diff --git a/features/createroom/impl/src/main/res/values-uz/translations.xml b/features/createroom/impl/src/main/res/values-uz/translations.xml index e3bc9de528..c33e89be28 100644 --- a/features/createroom/impl/src/main/res/values-uz/translations.xml +++ b/features/createroom/impl/src/main/res/values-uz/translations.xml @@ -9,5 +9,4 @@ "Xona nomi" "Xonani yaratish" "Mavzu (ixtiyoriy)" - "Suhbatni boshlashda xatolik yuz berdi" diff --git a/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml b/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml index 0d67c883c7..476f9cff7e 100644 --- a/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml +++ b/features/createroom/impl/src/main/res/values-zh-rTW/translations.xml @@ -19,12 +19,4 @@ "聊天室能見度" "建立聊天室" "主題(非必填)" - "聊天室目錄" - "嘗試開始聊天時發生錯誤" - "按地址加入聊天室" - "不是有效的位址" - "輸入……" - "找到相符的聊天室" - "找不到聊天室" - "例如 #room-name:matrix.org" diff --git a/features/createroom/impl/src/main/res/values-zh/translations.xml b/features/createroom/impl/src/main/res/values-zh/translations.xml index 24d7df7f35..d20e34801d 100644 --- a/features/createroom/impl/src/main/res/values-zh/translations.xml +++ b/features/createroom/impl/src/main/res/values-zh/translations.xml @@ -19,6 +19,4 @@ "房间可见性" "创建聊天室" "主题(可选)" - "聊天室目录" - "在开始聊天时发生了错误" diff --git a/features/createroom/impl/src/main/res/values/localazy.xml b/features/createroom/impl/src/main/res/values/localazy.xml index d011a1d87b..fa9a1cb276 100644 --- a/features/createroom/impl/src/main/res/values/localazy.xml +++ b/features/createroom/impl/src/main/res/values/localazy.xml @@ -19,12 +19,4 @@ You can change this anytime in room settings." "Room visibility" "Create a room" "Topic (optional)" - "Room directory" - "An error occurred when trying to start a chat" - "Join room by address" - "Not a valid address" - "Enter…" - "Matching room found" - "Room not found" - "e.g. #room-name:matrix.org" diff --git a/features/startchat/impl/src/main/res/values-be/translations.xml b/features/startchat/impl/src/main/res/values-be/translations.xml index 8acb990b02..106159a00d 100644 --- a/features/startchat/impl/src/main/res/values-be/translations.xml +++ b/features/startchat/impl/src/main/res/values-be/translations.xml @@ -1,19 +1,6 @@ "Новы пакой" - "Запрасіць карыстальнікаў" - "Пры стварэнні пакоя адбылася памылка" - "Толькі запрошаныя людзі могуць атрымаць доступ да гэтага пакоя. Усе паведамленні абаронены end-to-end шыфраваннем." - "Прыватны пакой" - "Любы можа знайсці гэты пакой. -Вы можаце змяніць гэта ў любы час у наладах пакоя." - "Публічны пакой" - "Хто заўгодна" - "Доступ у пакой" - "Папрасіце далучыцца" - "Назва пакоя" - "Стварыце пакой" - "Тэма (неабавязкова)" "Каталог пакояў" "Пры спробе пачаць чат адбылася памылка" diff --git a/features/startchat/impl/src/main/res/values-bg/translations.xml b/features/startchat/impl/src/main/res/values-bg/translations.xml index fa6dae371c..21ad117fb6 100644 --- a/features/startchat/impl/src/main/res/values-bg/translations.xml +++ b/features/startchat/impl/src/main/res/values-bg/translations.xml @@ -1,20 +1,6 @@ "Нова стая" - "Поканване на хора" - "Възникна грешка при създаването на стаята" - "Само поканени хора имат достъп до тази стая. Всички съобщения са шифровани от край до край." - "Частна стая" - "Всеки може да намери тази стая. -Можете да промените това по всяко време в настройките на стаята." - "Общодостъпна стая" - "Всеки може да се присъедини към тази стая" - "Всеки" - "За да бъде тази стая видима в директорията на общодостъпните стаи, ще ви е необходим адрес на стаята." - "Име на стаята" - "Видимост на стаята" - "Създаване на стая" - "Тема за разговор (незадължително)" "Присъединяване към стая по адрес" "Не е валиден адрес" "Въведете…" diff --git a/features/startchat/impl/src/main/res/values-cs/translations.xml b/features/startchat/impl/src/main/res/values-cs/translations.xml index 53592e0db0..b89f27fb9e 100644 --- a/features/startchat/impl/src/main/res/values-cs/translations.xml +++ b/features/startchat/impl/src/main/res/values-cs/translations.xml @@ -1,24 +1,6 @@ "Nová místnost" - "Pozvat přátele" - "Při vytváření místnosti došlo k chybě" - "Do této místnosti mají přístup pouze pozvaní lidé. Všechny zprávy jsou koncově šifrovány." - "Soukromá místnost" - "Tuto místnost může najít kdokoli. -To můžete kdykoli změnit v nastavení místnosti." - "Veřejná místnost" - "Do této místnosti může vstoupit kdokoli" - "Kdokoliv" - "Přístup do místnosti" - "Kdokoli může požádat o vstup do místnosti, ale správce nebo moderátor bude muset žádost přijmout" - "Požádat o připojení" - "Aby byla tato místnost viditelná v adresáři veřejných místností, budete potřebovat adresu místnosti." - "Adresa místnosti" - "Název místnosti" - "Viditelnost místnosti" - "Vytvořit místnost" - "Téma (nepovinné)" "Adresář místností" "Při pokusu o zahájení chatu došlo k chybě" "Vstoupit do místnosti pomocí adresy" diff --git a/features/startchat/impl/src/main/res/values-cy/translations.xml b/features/startchat/impl/src/main/res/values-cy/translations.xml index a3a9e30e35..47faa4c5c9 100644 --- a/features/startchat/impl/src/main/res/values-cy/translations.xml +++ b/features/startchat/impl/src/main/res/values-cy/translations.xml @@ -1,24 +1,6 @@ "Ystafell newydd" - "Gwahodd pobl" - "Bu gwall wrth greu\'r ystafell" - "Dim ond pobl wahoddwyd all gael mynediad i\'r ystafell hon. Mae pob neges wedi\'i hamgryptio o\'r dechrau i\'r diwedd." - "Ystafell breifat" - "Gall unrhyw un ddod o hyd i\'r ystafell hon. -Gallwch newid hyn unrhyw bryd yng ngosodiadau ystafell." - "Ystafell gyhoeddus" - "Gall unrhyw un ymuno â\'r ystafell hon" - "Unrhyw un" - "Mynediad i\'r Ystafell" - "Gall unrhyw un ofyn am gael ymuno â\'r ystafell ond bydd rhaid i weinyddwr neu gymedrolwr dderbyn y cais" - "Gofyn i gael ymuno" - "Er mwyn i\'r ystafell hon fod yn weladwy yn y cyfeiriadur ystafelloedd cyhoeddus, bydd angen cyfeiriad ystafell arnoch." - "Cyfeiriad yr ystafell" - "Enw\'r ystafell" - "Gwelededd yr ystafell" - "Creu ystafell" - "Pwnc (dewisol)" "Cyfeiriadur ystafelloedd" "Digwyddodd gwall wrth geisio cychwyn sgwrs" "Ymuno â\'r ystafell yn ôl cyfeiriad" diff --git a/features/startchat/impl/src/main/res/values-da/translations.xml b/features/startchat/impl/src/main/res/values-da/translations.xml index c9c182b474..89092045f5 100644 --- a/features/startchat/impl/src/main/res/values-da/translations.xml +++ b/features/startchat/impl/src/main/res/values-da/translations.xml @@ -1,24 +1,6 @@ "Nyt rum" - "Invitér folk" - "Der opstod en fejl ved oprettelsen af rummet" - "Kun inviterede personer kan få adgang til dette rum. Alle meddelelser er ende-til-ende krypteret." - "Privat rum" - "Alle kan finde dette rum. -Du kan ændre dette når som helst i rummets indstillinger." - "Offentligt rum" - "Alle kan deltage i dette rum" - "Enhver" - "Adgang til rummet" - "Alle kan bede om at deltage i rummet, men en administrator eller en moderator skal acceptere anmodningen" - "Spørg om at deltage" - "Hvis dette rum skal være synligt i det offentlige register, skal du bruge en rum-adresse." - "Rummets adresse" - "Navn på rum" - "Rummets synlighed" - "Opret et rum" - "Emne (valgfrit)" "Register over rum" "Der opstod en fejl under forsøget på at starte en samtale" "Tilslut dig rummet med adressen" diff --git a/features/startchat/impl/src/main/res/values-de/translations.xml b/features/startchat/impl/src/main/res/values-de/translations.xml index 90438aa38c..dff0a6fdea 100644 --- a/features/startchat/impl/src/main/res/values-de/translations.xml +++ b/features/startchat/impl/src/main/res/values-de/translations.xml @@ -1,24 +1,6 @@ "Neuer Raum" - "Nutzer einladen" - "Beim Erstellen des Chats ist ein Fehler aufgetreten" - "Nur eingeladene Personen haben Zutritt zu diesem Chatroom. Alle Nachrichten sind Ende-zu-Ende verschlüsselt." - "Privater Chatroom" - "Alle können diesen Chatroom finden. -Sie können dies aber jederzeit in den Chatroomeinstellungen ändern." - "Öffentlicher Raum" - "Jeder darf diesen Raum betreten" - "Jeder" - "Chatroomzugang" - "Jeder kann den Zutritt zum Raum beantragen, aber ein Moderator muss die Anfrage akzeptieren." - "Beitritt beantragen" - "Damit dieser Chatroom im öffentlichen Chatroomverzeichnis sichtbar ist, benötigen Sie eine Chatroomadresse." - "Chatroomadresse" - "Raumname" - " Sichtbarkeit des Chatrooms" - "Raum erstellen" - "Thema (optional)" "Raum-Verzeichnis" "Beim Versuch, einen Chat zu starten, ist ein Fehler aufgetreten" "Raum per Adresse betreten" diff --git a/features/startchat/impl/src/main/res/values-el/translations.xml b/features/startchat/impl/src/main/res/values-el/translations.xml index c036b43a05..19e6250d12 100644 --- a/features/startchat/impl/src/main/res/values-el/translations.xml +++ b/features/startchat/impl/src/main/res/values-el/translations.xml @@ -1,24 +1,6 @@ "Νέα αίθουσα" - "Πρόσκληση ατόμων" - "Προέκυψε σφάλμα κατά τη δημιουργία της αίθουσας" - "Μόνο τα άτομα που έχουν προσκληθεί μπορούν να έχουν πρόσβαση σε αυτή την αίθουσα. Όλα τα μηνύματα είναι κρυπτογραφημένα από άκρο σε άκρο." - "Ιδιωτική αίθουσα" - "Ο καθένας μπορεί να βρει αυτή την αίθουσα. -Αυτό μπορείτε να το αλλάξετε ανά πάσα στιγμή στις ρυθμίσεις της αίθουσας." - "Δημόσια αίθουσα" - "Οποιοσδήποτε μπορεί να συμμετάσχει σε αυτή την αίθουσα" - "Οποιοσδήποτε" - "Πρόσβαση στην Αίθουσα" - "Οποιοσδήποτε μπορεί να ζητήσει να συμμετάσχει στην αίθουσα, αλλά ένας διαχειριστής ή ένας συντονιστής θα πρέπει να αποδεχτεί το αίτημα" - "Αίτημα συμμετοχής" - "Για να είναι ορατή αυτή η αίθουσα στον δημόσιο κατάλογο αιθουσών, θα χρειαστείτε μια διεύθυνση αίθουσας." - "Διεύθυνση αίθουσας" - "Όνομα αίθουσας" - "Ορατότητα αίθουσας" - "Δημιουργία αίθουσας" - "Θέμα (προαιρετικό)" "Κατάλογος αιθουσών" "Παρουσιάστηκε σφάλμα κατά την προσπάθεια έναρξης μιας συνομιλίας" "Συμμετοχή σε αίθουσα μέσω διεύθυνσης" diff --git a/features/startchat/impl/src/main/res/values-es/translations.xml b/features/startchat/impl/src/main/res/values-es/translations.xml index c11f08fc14..64a9f02a17 100644 --- a/features/startchat/impl/src/main/res/values-es/translations.xml +++ b/features/startchat/impl/src/main/res/values-es/translations.xml @@ -1,24 +1,6 @@ "Nueva sala" - "Invitar personas" - "Se ha producido un error al crear la sala" - "Solo las personas invitadas pueden acceder a esta sala. Todos los mensajes están cifrados de extremo a extremo." - "Sala privada" - "Cualquiera puede encontrar esta sala. -Puedes cambiar esto en cualquier momento en los ajustes de la sala." - "Sala pública" - "Cualquiera puede unirse a esta sala" - "Cualquiera" - "Acceso a la sala" - "Cualquiera puede solicitar unirse a la sala, pero un administrador o un moderador tendrá que aceptar la solicitud" - "Solicitud para unirse" - "Para que esta sala sea visible en el directorio de salas públicas, necesitarás una dirección de sala." - "Dirección de la sala" - "Nombre de la sala" - "Visibilidad de la sala" - "Crear una sala" - "Tema (opcional)" "Directorio de salas" "Se ha producido un error al intentar iniciar un chat" "Unirse a una sala por su dirección" diff --git a/features/startchat/impl/src/main/res/values-et/translations.xml b/features/startchat/impl/src/main/res/values-et/translations.xml index 57a26106b3..65459475a8 100644 --- a/features/startchat/impl/src/main/res/values-et/translations.xml +++ b/features/startchat/impl/src/main/res/values-et/translations.xml @@ -1,24 +1,6 @@ "Uus jututuba" - "Kutsu osalejaid" - "Jututoa loomisel tekkis viga" - "Ligipääs siia jututuppa on vaid kutse alusel. Kõik sõnumid siin jututoas on läbivalt krüptitud." - "Privaatne jututuba" - "Kõik saavad seda jututuba leida. -Sa võid seda jututoa seadistustest alati muuta." - "Avalik jututuba" - "Kõik võivad selle jututoaga liituda" - "Kõik" - "Ligipääs jututoale" - "Kõik võivad paluda selle jututoaga liitumist, kuid peakasutaja või moderaator peavad selle kinnitama" - "Küsi võimalust liitumiseks" - "Selleks, et see jututuba oleks nähtav jututubade avalikus kataloogis, sa vajad jututoa aadressi." - "Jututoa aadress" - "Jututoa nimi" - "Jututoa nähtavus" - "Loo jututuba" - "Teema (kui soovid lisada)" "Jututubade kataloog" "Vestluse alustamisel tekkis viga" "Liitu jututoaga aadressi alusel" diff --git a/features/startchat/impl/src/main/res/values-eu/translations.xml b/features/startchat/impl/src/main/res/values-eu/translations.xml index 43f67e429c..403db09c9d 100644 --- a/features/startchat/impl/src/main/res/values-eu/translations.xml +++ b/features/startchat/impl/src/main/res/values-eu/translations.xml @@ -1,23 +1,9 @@ "Gela berria" - "Gonbidatu jendea" - "Errorea gertatu da gela sortzean" - "Gonbidatutako jendea soilik sar daiteke gelara. Mezu guztiak daude ertzetik ertzera zifratuta." - "Gela pribatua" - "Edonork aurki dezake gela hau. -Gelaren ezarpenetan aldatu dezakezu hobespena." - "Gela publikoa" - "Edonor sar daiteke gela honetara" - "Edonork" - "Gelarako sarbidea" - "Gelaren helbidea" - "Gelaren izena" - "Gelaren ikusgarritasuna" - "Sortu gela" - "Mintzagaia (aukerakoa)" "Gelen direktorioa" "Errorea gertatu da txata hasten saiatzean" + "Ez da baliozko helbidea" "Sartu…" "Ez da gela aurkitu" diff --git a/features/startchat/impl/src/main/res/values-fa/translations.xml b/features/startchat/impl/src/main/res/values-fa/translations.xml index 03bc5c3f58..7cb1e1baee 100644 --- a/features/startchat/impl/src/main/res/values-fa/translations.xml +++ b/features/startchat/impl/src/main/res/values-fa/translations.xml @@ -1,22 +1,6 @@ "اتاق جدید" - "دعوت افراد" - "هنگام ایجاد اتاق خطایی رخ داد" - "تنها افراد دعوت شده می‌توانند به این اتاق دسترسی داشته باشند. همهٔ پیام‌ها رمزنگاری سرتاسری شده‌اند." - "اتاق خصوصی" - "هرکسی می‌تواند اتاق را بیابد. -می‌توانید بعداً در تظیمات اتاق عوضش کنید." - "اتاق عمومی" - "هرکسی می‌تواند به این اتاق بپیوندد" - "هرکسی" - "دسترسی اتاق" - "درخواست دعوت" - "نشانی اتاق" - "نام اتاق" - "نمایانی اتاق" - "ایجاد اتاق" - "موضوع (اختیاری)" "فهرست اتاق‌ها" "هنگام تلاش برای شروع چت خطایی روی داد" "پیوستن به اتاق با نشانی" diff --git a/features/startchat/impl/src/main/res/values-fi/translations.xml b/features/startchat/impl/src/main/res/values-fi/translations.xml index cdb6d04d59..13659571c8 100644 --- a/features/startchat/impl/src/main/res/values-fi/translations.xml +++ b/features/startchat/impl/src/main/res/values-fi/translations.xml @@ -1,24 +1,6 @@ "Uusi huone" - "Kutsu ihmisiä" - "Huoneen luomisessa tapahtui virhe" - "Vain kutsutut henkilöt pääsevät tähän huoneeseen. Kaikki viestit ovat päästä päähän salattuja." - "Yksityinen huone" - "Kuka tahansa voi löytää tämän huoneen. -Voit muuttaa tämän milloin tahansa huoneen asetuksista." - "Julkinen huone" - "Kuka tahansa voi liittyä tähän huoneeseen" - "Kuka tahansa" - "Huoneeseen Pääsy" - "Kuka tahansa voi pyytää saada liittyä huoneeseen, mutta ylläpitäjän tai valvojan on hyväksyttävä pyyntö" - "Pyydä liittymistä" - "Jotta tämä huone näkyisi julkisessa huonehakemistossa, tarvitset huoneen osoitteen." - "Huoneen osoite" - "Huoneen nimi" - "Huoneen näkyvyys" - "Luo huone" - "Aihe (valinnainen)" "Huoneluettelo" "Keskustelun aloituksessa tapahtui virhe" "Liity huoneeseen osoitteella" diff --git a/features/startchat/impl/src/main/res/values-fr/translations.xml b/features/startchat/impl/src/main/res/values-fr/translations.xml index 3f9e01dc85..9aaebd018f 100644 --- a/features/startchat/impl/src/main/res/values-fr/translations.xml +++ b/features/startchat/impl/src/main/res/values-fr/translations.xml @@ -1,24 +1,6 @@ "Nouveau salon" - "Inviter des amis" - "Une erreur s’est produite lors de la création du salon" - "Seules les personnes invitées peuvent accéder à ce salon. Tous les messages sont chiffrés de bout en bout." - "Salon privé" - "N’importe qui peut trouver ce salon. -Vous pouvez modifier cela à tout moment dans les paramètres du salon." - "Salon public" - "Tout le monde peut rejoindre ce salon" - "Tout le monde" - "Accès au salon" - "Tout le monde peut demander à rejoindre le salon, mais un administrateur ou un modérateur devra accepter la demande" - "Demander à rejoindre" - "Pour que ce salon soit visible dans le répertoire des salons publics, vous aurez besoin d’une adresse de salon." - "Adresse du salon" - "Nom du salon" - "Visibilité du salon" - "Créer un salon" - "Sujet (facultatif)" "Annuaire des salons" "Une erreur s’est produite lors de la tentative de création de la discussion" "Saisir une adresse de salon" diff --git a/features/startchat/impl/src/main/res/values-hu/translations.xml b/features/startchat/impl/src/main/res/values-hu/translations.xml index 1e4a721279..014f7baaac 100644 --- a/features/startchat/impl/src/main/res/values-hu/translations.xml +++ b/features/startchat/impl/src/main/res/values-hu/translations.xml @@ -1,24 +1,6 @@ "Új szoba" - "Ismerősök meghívása" - "Hiba történt a szoba létrehozásakor" - "Csak a meghívottak léphetnek be ebbe a szobába. Az összes üzenet végpontok közti titkosítással van védve." - "Privát szoba" - "Bárki megtalálhatja ezt a szobát. -Ezt bármikor módosíthatja a szobabeállításokban." - "Nyilvános szoba" - "Bárki csatlakozhat ehhez a szobához" - "Bárki" - "Szobahozzáférés" - "Bárki kérheti, hogy csatlakozzon a szobához, de egy adminisztrátornak vagy moderátornak el kell fogadnia a kérést" - "Csatlakozás kérése" - "Ahhoz, hogy ez a szoba látható legyen a nyilvános szobák címtárában, meg kell adnia a szoba címét." - "A szoba címe" - "Szoba neve" - "Szoba láthatósága" - "Szoba létrehozása" - "Téma (nem kötelező)" "Szobakatalógus" "Hiba történt a csevegés indításakor" "Csatlakozás a szobához cím szerint" diff --git a/features/startchat/impl/src/main/res/values-in/translations.xml b/features/startchat/impl/src/main/res/values-in/translations.xml index 65f135e617..5f796bb8da 100644 --- a/features/startchat/impl/src/main/res/values-in/translations.xml +++ b/features/startchat/impl/src/main/res/values-in/translations.xml @@ -1,24 +1,6 @@ "Ruangan baru" - "Undang orang-orang" - "Terjadi kesalahan saat membuat ruangan" - "Hanya orang-orang yang diundang dapat mengakses ruangan ini. Semua pesan terenkripsi secara ujung ke ujung." - "Ruangan pribadi" - "Siapa pun dapat mencari ruangan ini. -Anda dapat mengubah ini kapan pun dalam pengaturan ruangan." - "Ruangan publik" - "Siapa pun dapat bergabung dengan ruangan ini" - "Siapa pun" - "Akses Ruangan" - "Siapa pun dapat meminta untuk bergabung dengan ruangan tetapi administrator atau moderator harus menerima permintaan tersebut" - "Minta untuk bergabung" - "Supaya ruangan ini terlihat di direktori ruangan publik, Anda memerlukan alamat ruangan." - "Alamat ruangan" - "Nama ruangan" - "Keterlihatan ruangan" - "Buat ruangan" - "Topik (opsional)" "Direktori ruangan" "Terjadi kesalahan saat mencoba memulai obrolan" "Bergabung dalam ruangan berdasarkan alamat" diff --git a/features/startchat/impl/src/main/res/values-it/translations.xml b/features/startchat/impl/src/main/res/values-it/translations.xml index 701ebc967f..94818d7ab1 100644 --- a/features/startchat/impl/src/main/res/values-it/translations.xml +++ b/features/startchat/impl/src/main/res/values-it/translations.xml @@ -1,24 +1,6 @@ "Nuova stanza" - "Invita persone" - "Si è verificato un errore durante la creazione della stanza" - "Solo le persone invitate possono accedere a questa stanza. Tutti i messaggi sono cifrati end-to-end." - "Stanza privata" - "Chiunque può trovare questa stanza. -Puoi modificarlo in qualsiasi momento nelle impostazioni della stanza." - "Stanza pubblica" - "Chiunque può entrare in questa stanza" - "Chiunque" - "Accesso alla stanza" - "Chiunque può chiedere di entrare nella stanza, ma un amministratore o un moderatore dovrà accettare la richiesta" - "Chiedi di entrare" - "Affinché questa stanza sia visibile nell\'elenco delle stanze pubbliche, è necessario un indirizzo della stanza." - "Indirizzo della stanza" - "Nome stanza" - "Visibilità della stanza" - "Crea una stanza" - "Argomento (facoltativo)" "Elenco delle stanze" "Si è verificato un errore durante il tentativo di avviare una chat" "Accedi alla stanza tramite indirizzo" diff --git a/features/startchat/impl/src/main/res/values-ka/translations.xml b/features/startchat/impl/src/main/res/values-ka/translations.xml index bb4a430320..c5ccd79305 100644 --- a/features/startchat/impl/src/main/res/values-ka/translations.xml +++ b/features/startchat/impl/src/main/res/values-ka/translations.xml @@ -1,15 +1,6 @@ "ახალი ოთახი" - "ხალხის მოწვევა" - "ოთახის შექმნისას შეცდომა მოხდა" - "ამ ოთახში შეტყობინებები დაშიფრულია. შემდგომ დაშიფვრის გამორთვა შეუძლებელია." - "კერძო ოთახი" - "ყველას ამ ოთახის მოძებნა შეუძლია. -თქვენ ნებისმიერ დროს შეგიძლიათ ამის შეცვლა ოთახის პარამეტრებში." - "ოთახის სახელი" - "ოთახის შექმნა" - "თემა (სურვილისამებრ)" "ოთახის კატალოგი" "ჩატის დაწყების მცდელობისას შეცდომა მოხდა" diff --git a/features/startchat/impl/src/main/res/values-lt/translations.xml b/features/startchat/impl/src/main/res/values-lt/translations.xml index 2f7a4438ea..699e0703f1 100644 --- a/features/startchat/impl/src/main/res/values-lt/translations.xml +++ b/features/startchat/impl/src/main/res/values-lt/translations.xml @@ -1,14 +1,5 @@ "Naujas kambarys" - "Pakviesti žmonių" - "Kuriant kambarį įvyko klaida" - "Į šį kambarį gali patekti tik pakviesti žmonės. Visi pranešimai yra užšifruoti nuo pradžios iki galo." - "Privatus kambarys" - "Bet kas gali rasti šį kambarį. -Tai galite bet kada pakeisti kambario nustatymuose." - "Kambario pavadinimas" - "Kurti kambarį" - "Tema (nebūtina)" "Bandant pradėti pokalbį įvyko klaida" diff --git a/features/startchat/impl/src/main/res/values-nb/translations.xml b/features/startchat/impl/src/main/res/values-nb/translations.xml index 9266993fd4..ffd8fe9cfc 100644 --- a/features/startchat/impl/src/main/res/values-nb/translations.xml +++ b/features/startchat/impl/src/main/res/values-nb/translations.xml @@ -1,24 +1,6 @@ "Nytt rom" - "Inviter folk" - "Det oppsto en feil under opprettelsen av rommet" - "Bare inviterte personer har tilgang til dette rommet. Alle meldinger er ende-til-ende-kryptert." - "Privat rom" - "Alle kan finne dette rommet. -Du kan endre dette når som helst i rominnstillingene." - "Offentlig rom" - "Alle kan bli med i dette rommet" - "Alle" - "Tilgang til rom" - "Alle kan be om å få bli med i rommet, men en administrator eller moderator må godta forespørselen" - "Be om å bli med" - "For at dette rommet skal være synlig i den offentlige romkatalogen, trenger du en romadresse." - "Romadresse" - "Romnavn" - "Romsynlighet" - "Opprett et rom" - "Emne (valgfritt)" "Romkatalog" "Det oppstod en feil når du prøvde å starte en chat" "Bli med i rommet med adresse" diff --git a/features/startchat/impl/src/main/res/values-nl/translations.xml b/features/startchat/impl/src/main/res/values-nl/translations.xml index 29d070a263..244ffddba3 100644 --- a/features/startchat/impl/src/main/res/values-nl/translations.xml +++ b/features/startchat/impl/src/main/res/values-nl/translations.xml @@ -1,21 +1,6 @@ "Nieuwe kamer" - "Mensen uitnodigen" - "Er is een fout opgetreden bij het aanmaken van de kamer" - "Alleen uitgenodigde personen hebben toegang tot deze kamer. Alle berichten zijn end-to-end versleuteld." - "Privé kamer" - "Iedereen kan deze kamer vinden. -Je kunt dit op elk gewenst moment wijzigen in de kamerinstellingen." - "Openbare kamer" - "Iedereen kan toetreden tot deze kamer" - "Iedereen" - "Toegang tot de kamer" - "Iedereen kan vragen om toe te treden tot de kamer, maar een beheerder of moderator moet het verzoek accepteren" - "Vraag om toe te treden" - "Naam van de kamer" - "Creëer een kamer" - "Onderwerp (optioneel)" "Kamergids" "Er is een fout opgetreden bij het starten van een chat" diff --git a/features/startchat/impl/src/main/res/values-pl/translations.xml b/features/startchat/impl/src/main/res/values-pl/translations.xml index 3ed917b7bb..fe6b4a2c8d 100644 --- a/features/startchat/impl/src/main/res/values-pl/translations.xml +++ b/features/startchat/impl/src/main/res/values-pl/translations.xml @@ -1,24 +1,6 @@ "Nowy pokój" - "Zaproś znajomych" - "Wystąpił błąd w trakcie tworzenia pokoju" - "Tylko zaproszone osoby mogą dołączyć do tego pokoju. Wszystkie wiadomości są szyfrowane end-to-end." - "Pokój prywatny" - "Każdy może znaleźć ten pokój. -Możesz to zmienić w ustawieniach pokoju." - "Pokój publiczny" - "Każdy może dołączyć do tego pokoju" - "Wszyscy" - "Dostęp do pokoju" - "Każdy może poprosić o dołączenie do pokoju, ale administrator lub moderator będzie musiał zatwierdzić prośbę" - "Poproś o dołączenie" - "Aby ten pokój był widoczny w katalogu pomieszczeń publicznych, będziesz potrzebował adres pokoju." - "Adres pokoju" - "Nazwa pokoju" - "Widoczność pomieszczenia" - "Utwórz pokój" - "Temat (opcjonalnie)" "Katalog pokoi" "Wystąpił błąd podczas próby rozpoczęcia czatu" "Dołącz do pokoju za pomocą adresu" diff --git a/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml b/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml index 52c9f569af..f17991c56b 100644 --- a/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/startchat/impl/src/main/res/values-pt-rBR/translations.xml @@ -1,24 +1,6 @@ "Nova sala" - "Convidar pessoas" - "Ocorreu um erro ao criar a sala" - "Apenas as pessoas convidadas podem aceder a esta sala. Todas as mensagens são criptografadas de ponta a ponta." - "Sala privada" - "Qualquer um pode encontrar esta sala. -Você pode mudar isso a qualquer momento nas configurações da sala." - "Sala pública" - "Qualquer pessoa pode entrar nesta sala" - "Qualquer pessoa" - "Acesso à sala" - "Qualquer pessoa pode pedir para entrar na sala, mas um administrador ou moderador terá de aceitar a solicitação" - "Pedir para entrar" - "Para que esta sala fique visível no diretório público de salas, você precisará de um endereço de sala." - "Endereço da sala" - "Nome da sala" - "Visibilidade da sala" - "Criar uma sala" - "Tópico (opcional)" "Diretório de salas" "Ocorreu um erro ao tentar iniciar um chat" "Entrar na sala pelo endereço" diff --git a/features/startchat/impl/src/main/res/values-pt/translations.xml b/features/startchat/impl/src/main/res/values-pt/translations.xml index 5e5f5fc9c3..3efcbf7640 100644 --- a/features/startchat/impl/src/main/res/values-pt/translations.xml +++ b/features/startchat/impl/src/main/res/values-pt/translations.xml @@ -1,24 +1,6 @@ "Nova sala" - "Convidar pessoas" - "Ocorreu um erro ao criar a sala" - "Apenas as pessoas convidadas podem aceder a esta sala. Todas as mensagens são cifradas ponta-a-ponta." - "Sala privada" - "Qualquer um pode encontrar esta sala. -Pode alterar esta opção nas definições da sala." - "Sala pública" - "Qualquer pessoa pode entrar nesta sala" - "Qualquer pessoa" - "Acesso à sala" - "Qualquer pessoa pode pedir para entrar na sala, mas um administrador ou um moderador terá de aceitar o pedido" - "Pedir para participar" - "Para que esta sala seja visível no diretório público de salas, precisas de um endereço de sala." - "Endereço da sala" - "Nome da sala" - "Visibilidade da sala" - "Criar uma sala" - "Descrição (opcional)" "Diretório de salas" "Ocorreu um erro ao tentar iniciar uma conversa" "Entrar na sala pelo endereço" diff --git a/features/startchat/impl/src/main/res/values-ro/translations.xml b/features/startchat/impl/src/main/res/values-ro/translations.xml index 8d9e74b530..d306d83aab 100644 --- a/features/startchat/impl/src/main/res/values-ro/translations.xml +++ b/features/startchat/impl/src/main/res/values-ro/translations.xml @@ -1,22 +1,6 @@ "Cameră nouă" - "Invitați prieteni" - "A apărut o eroare la crearea camerei" - "Doar persoanele invitate pot accesa această cameră. Toate mesajele sunt criptate end-to-end." - "Cameră privată" - "Oricine poate găsi această cameră. -Puteți modifica acest lucru oricând în setări." - "Cameră publică" - "Oricine se poate alătura acestei camere" - "Oricine" - "Acces la cameră" - "Oricine poate cere să se alăture camerei, dar un administrator sau un moderator va trebui să accepte solicitarea" - "Cereți să vă alăturați" - "Pentru ca această cameră să fie vizibilă în directorul de camere publice, veți avea nevoie de o adresă de cameră." - "Numele camerei" - "Creați o cameră" - "Subiect (opțional)" "Director de camere" "A apărut o eroare la încercarea începerii conversației" diff --git a/features/startchat/impl/src/main/res/values-ru/translations.xml b/features/startchat/impl/src/main/res/values-ru/translations.xml index 6344491248..6d676d3c76 100644 --- a/features/startchat/impl/src/main/res/values-ru/translations.xml +++ b/features/startchat/impl/src/main/res/values-ru/translations.xml @@ -1,24 +1,6 @@ "Создать новую комнату" - "Пригласить в комнату" - "Произошла ошибка при создании комнаты" - "Доступ в эту комнату имеют только приглашенные пользователи. Все сообщения защищены сквозным шифрованием." - "Частная комната" - "Любой желающий может найти эту комнату. -Вы можете изменить это в любое время в настройках комнаты." - "Общедоступная комната" - "Любой желающий может присоединиться к этой комнате" - "Любой" - "Доступ в комнату" - "Любой желающий может подать заявку на присоединение к комнате, но администратор или модератор должен будет принять запрос." - "Попросить присоединиться" - "Чтобы эта комната была видна в каталоге общедоступных, вам необходим ее адрес" - "Адрес комнаты" - "Название комнаты" - "Видимость комнаты" - "Создать комнату" - "Тема (необязательно)" "Каталог комнат" "Произошла ошибка при запуске чата" "Присоединиться к комнате по адресу" diff --git a/features/startchat/impl/src/main/res/values-sk/translations.xml b/features/startchat/impl/src/main/res/values-sk/translations.xml index eaf6c2f19c..16a1548765 100644 --- a/features/startchat/impl/src/main/res/values-sk/translations.xml +++ b/features/startchat/impl/src/main/res/values-sk/translations.xml @@ -1,24 +1,6 @@ "Nová miestnosť" - "Pozvať ľudí" - "Pri vytváraní miestnosti došlo k chybe" - "Do tejto miestnosti majú prístup iba pozvaní ľudia. Všetky správy sú end-to-end šifrované." - "Súkromná miestnosť" - "Túto miestnosť môže nájsť ktokoľvek. -Môžete to kedykoľvek zmeniť v nastaveniach miestnosti." - "Verejná miestnosť" - "Do tejto miestnosti sa môže pripojiť ktokoľvek" - "Ktokoľvek" - "Prístup do miestnosti" - "Ktokoľvek môže požiadať o pripojenie sa k miestnosti, ale administrátor alebo moderátor bude musieť žiadosť schváliť" - "Požiadať o pripojenie" - "Aby bola táto miestnosť viditeľná v adresári verejných miestností, budete potrebovať adresu miestnosti." - "Adresa miestnosti" - "Názov miestnosti" - "Viditeľnosť miestnosti" - "Vytvoriť miestnosť" - "Téma (voliteľné)" "Adresár miestností" "Pri pokuse o spustenie konverzácie sa vyskytla chyba" "Pripojte sa do miestnosti podľa adresy" diff --git a/features/startchat/impl/src/main/res/values-sv/translations.xml b/features/startchat/impl/src/main/res/values-sv/translations.xml index 316c9cc32e..21cfb470b1 100644 --- a/features/startchat/impl/src/main/res/values-sv/translations.xml +++ b/features/startchat/impl/src/main/res/values-sv/translations.xml @@ -1,24 +1,6 @@ "Nytt rum" - "Bjud in personer" - "Ett fel uppstod när rummet skapades" - "Endast inbjudna personer har tillgång till detta rum. Alla meddelanden är totalsträckskrypterade." - "Privat rum" - "Vem som helst kan hitta det här rummet. -Du kan ändra detta när som helst i rumsinställningarna." - "Offentligt rum" - "Vem som helst kan gå med i det här rummet" - "Vem som helst" - "Rumsåtkomst" - "Vem som helst kan be om att gå med i rummet men en administratör eller en moderator måste acceptera begäran" - "Be om att gå med" - "För att detta rum ska vara synligt i den allmänna rumskatalogen behöver du en rumsadress." - "Rumsadress" - "Rumsnamn" - "Rumssynlighet" - "Skapa ett rum" - "Ämne (valfritt)" "Rumskatalog" "Ett fel uppstod när du försökte starta en chatt" "Gå med i rum med adress" diff --git a/features/startchat/impl/src/main/res/values-tr/translations.xml b/features/startchat/impl/src/main/res/values-tr/translations.xml index c8e3136517..581996500d 100644 --- a/features/startchat/impl/src/main/res/values-tr/translations.xml +++ b/features/startchat/impl/src/main/res/values-tr/translations.xml @@ -1,24 +1,6 @@ "Yeni oda" - "İnsanları davet et" - "Oda oluşturulurken bir hata oluştu" - "Bu odaya yalnızca davet edilen kişiler erişebilir. Tüm mesajlar uçtan uca şifrelenir." - "Özel oda" - "Bu odayı herkes bulabilir. -Bunu istediğiniz zaman oda ayarlarından değiştirebilirsiniz." - "Herkese açık oda" - "Bu odaya herkes katılabilir" - "Herkes" - "Oda Erişimi" - "Herkes odaya katılmayı isteyebilir ancak bir yönetici veya moderatörün isteği kabul etmesi gerekecektir" - "Katılmak için sor" - "Bu odanın genel oda dizininde görünür olması için bir oda adresine ihtiyacınız olacaktır." - "Oda adresi" - "Oda adı" - "Oda görünürlüğü" - "Bir oda oluştur" - "Konu (isteğe bağlı)" "Oda dizini" "Sohbet başlatmaya çalışırken bir hata oluştu" diff --git a/features/startchat/impl/src/main/res/values-uk/translations.xml b/features/startchat/impl/src/main/res/values-uk/translations.xml index a43172fb8b..3c2b09939c 100644 --- a/features/startchat/impl/src/main/res/values-uk/translations.xml +++ b/features/startchat/impl/src/main/res/values-uk/translations.xml @@ -1,24 +1,6 @@ "Нова кімната" - "Запросити людей" - "Під час створення кімнати сталася помилка" - "Лише запрошені люди мають доступ до цієї кімнати. Усі повідомлення захищені наскрізним шифруванням." - "Приватна кімната (тільки за запрошенням)" - "Будь-хто може знайти цю кімнату. -Ви можете змінити це в будь-який час у налаштуваннях кімнати." - "Загальнодоступна кімната" - "Будь-хто може приєднатися до цієї кімнати" - "Кожний" - "Доступ до кімнати" - "Будь-хто може попросити приєднатися до кімнати, але адміністратор або модератор повинен буде прийняти запит" - "Запросити приєднатися" - "Щоб цю кімнату було видно в каталозі загальнодоступних кімнат, вам знадобиться її адреса." - "Адреса кімнати" - "Назва кімнати" - "Видимість кімнати" - "Створити кімнату" - "Тема (необов\'язково)" "Каталог кімнат" "Під час спроби почати бесіду сталася помилка" "Приєднатися до кімнати за адресою" diff --git a/features/startchat/impl/src/main/res/values-ur/translations.xml b/features/startchat/impl/src/main/res/values-ur/translations.xml index 6fe476462e..394f6aa817 100644 --- a/features/startchat/impl/src/main/res/values-ur/translations.xml +++ b/features/startchat/impl/src/main/res/values-ur/translations.xml @@ -1,16 +1,6 @@ "نیا کمرہ" - "لوگوں کو مدعو کریں" - "کمرہ تخلیق کرتے ہوئے ایک نقص واقع ہوا" - "صرف مدعو لوگ ہی اس کمرے تک رسائی حاصل کر سکتے ہیں۔ تمام پیغامات آخر تا آخر مرموز کردہ ہیں۔" - "نجی کمرہ" - "کوئی بھی یہ کمرہ ڈھونڈ سکتا ہے۔ -آپ اسے کمرے کی ترتیبات میں کسی بھی وقت تبدیل کرسکتے ہیں۔" - "عوامی کمرہ" - "کمرے کا نام" - "ایک کمرہ بنائیں" - "موضوع (اختیاری)" "کمرے کا راہنامچہ" "گفتگو شروع کرنے کی کوشش کرتے وقت ایک خرابی واقع ہوگئی" diff --git a/features/startchat/impl/src/main/res/values-uz/translations.xml b/features/startchat/impl/src/main/res/values-uz/translations.xml index e3bc9de528..6f68899a3b 100644 --- a/features/startchat/impl/src/main/res/values-uz/translations.xml +++ b/features/startchat/impl/src/main/res/values-uz/translations.xml @@ -1,13 +1,5 @@ "Yangi xona" - "Odamlarni taklif qiling" - "Xonani yaratishda xatolik yuz berdi" - "Bu xonadagi xabarlar shifrlangan. Keyinchalik shifrlashni o‘chirib bo‘lmaydi." - "Shaxsiy xona (faqat taklif)" - "Xabarlar shifrlanmagan va har kim ularni o\'qiy oladi. Keyinchalik shifrlashni yoqishingiz mumkin." - "Xona nomi" - "Xonani yaratish" - "Mavzu (ixtiyoriy)" "Suhbatni boshlashda xatolik yuz berdi" diff --git a/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml b/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml index 0d67c883c7..c6dcd50008 100644 --- a/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml +++ b/features/startchat/impl/src/main/res/values-zh-rTW/translations.xml @@ -1,24 +1,6 @@ "建立聊天室" - "邀請夥伴" - "建立聊天室時發生錯誤" - "僅被邀請的人才能存取此聊天室。所有訊息均會端到端加密。" - "私密聊天室" - "任何人都可以找到此聊天室。 -您隨時都可以在聊天室設定中變更此設定。" - "公開的聊天室" - "任何人都可以加入此聊天室" - "任何人" - "聊天室存取權" - "任何人都可以要求加入聊天室,但管理員或版主必須接受該請求" - "要求加入" - "為了讓此聊天室在公開聊天室目錄中可見,您需要聊天室地址。" - "聊天室地址" - "聊天室名稱" - "聊天室能見度" - "建立聊天室" - "主題(非必填)" "聊天室目錄" "嘗試開始聊天時發生錯誤" "按地址加入聊天室" diff --git a/features/startchat/impl/src/main/res/values-zh/translations.xml b/features/startchat/impl/src/main/res/values-zh/translations.xml index 24d7df7f35..f5f6681073 100644 --- a/features/startchat/impl/src/main/res/values-zh/translations.xml +++ b/features/startchat/impl/src/main/res/values-zh/translations.xml @@ -1,24 +1,6 @@ "新聊天室" - "邀请朋友" - "创建聊天室时出错" - "只有受邀用户才能访问此聊天室。所有消息均经过端到端加密。" - "私有聊天室" - "任何人都能找到此聊天室。 -你可以随时在聊天室设置中更改。" - "公共聊天室" - "任何人都可以加入此房间" - "任何人" - "房间访问权限" - "任何人都可以请求加入房间,但必须由管理员或审核人接受" - "请求加入" - "要使该房间在公开房间目录中可见,您需要一个房间地址。" - "房间地址" - "聊天室名称" - "房间可见性" - "创建聊天室" - "主题(可选)" "聊天室目录" "在开始聊天时发生了错误" diff --git a/features/startchat/impl/src/main/res/values/localazy.xml b/features/startchat/impl/src/main/res/values/localazy.xml index d011a1d87b..48b6449263 100644 --- a/features/startchat/impl/src/main/res/values/localazy.xml +++ b/features/startchat/impl/src/main/res/values/localazy.xml @@ -1,24 +1,6 @@ "New room" - "Invite people" - "An error occurred when creating the room" - "Only people invited can access this room. All messages are end-to-end encrypted." - "Private room" - "Anyone can find this room. -You can change this anytime in room settings." - "Public room" - "Anyone can join this room" - "Anyone" - "Room Access" - "Anyone can ask to join the room but an administrator or a moderator will have to accept the request" - "Ask to join" - "In order for this room to be visible in the public room directory, you will need a room address." - "Room address" - "Room name" - "Room visibility" - "Create a room" - "Topic (optional)" "Room directory" "An error occurred when trying to start a chat" "Join room by address" diff --git a/tools/localazy/config.json b/tools/localazy/config.json index 923113cd39..3beacd4f5a 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -59,20 +59,16 @@ "name" : ":features:createroom:impl", "includeRegex" : [ "screen_create_room_.*", - "screen\\.create_room\\..*", - "screen_start_chat_.*", - "screen\\.start_chat\\..*", - "screen_room_directory_search_title*" + "screen\\.create_room\\..*" ] }, { "name" : ":features:startchat:impl", "includeRegex" : [ - "screen_create_room_.*", - "screen\\.create_room\\..*", "screen_start_chat_.*", "screen\\.start_chat\\..*", - "screen_room_directory_search_title*" + "screen_room_directory_search_title", + "screen_create_room_action_create_room" ] }, { From 590c9fa6f5615fdc37b53855b9c2a3a7ae0fff52 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 13 Aug 2025 18:01:43 +0200 Subject: [PATCH 22/30] Update Maestro test. Invite people step is now performed after the room has been created. --- .maestro/tests/roomList/createAndDeleteRoom.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.maestro/tests/roomList/createAndDeleteRoom.yaml b/.maestro/tests/roomList/createAndDeleteRoom.yaml index e957d04bdf..a72fb80075 100644 --- a/.maestro/tests/roomList/createAndDeleteRoom.yaml +++ b/.maestro/tests/roomList/createAndDeleteRoom.yaml @@ -3,18 +3,18 @@ appId: ${MAESTRO_APP_ID} # Purpose: Test the creation and deletion of a room - tapOn: "Create a new conversation or room" - tapOn: "New room" -- tapOn: "Search for someone" -- inputText: ${MAESTRO_INVITEE1_MXID} -- tapOn: - text: ${MAESTRO_INVITEE1_MXID} - index: 1 -- tapOn: "Next" - tapOn: "e.g. your project name" - inputText: "aRoomName" - tapOn: "What is this room about?" - inputText: "aRoomTopic" - tapOn: "Create" - takeScreenshot: build/maestro/320-createAndDeleteRoom +- tapOn: "Search for someone" +- inputText: ${MAESTRO_INVITEE1_MXID} +- tapOn: + text: ${MAESTRO_INVITEE1_MXID} + index: 1 +- tapOn: "Finish" - tapOn: "aRoomName" - tapOn: "Invite" # assert there's 1 member and 1 invitee From e74fcde43e9f34658168dd0bc3be544f2eb79c5d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Aug 2025 09:10:22 +0200 Subject: [PATCH 23/30] Remove default values for InvitableUser's constructor --- .../impl/DefaultInvitePeopleStateProvider.kt | 30 ++++++++++++++----- .../invitepeople/impl/InvitableUser.kt | 8 ++--- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt index 38ef157df2..ff1dc5c4a9 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt @@ -33,11 +33,11 @@ internal class DefaultInvitePeopleStateProvider : PreviewParameterProvider Date: Thu, 14 Aug 2025 09:13:21 +0200 Subject: [PATCH 24/30] iterate on the isSelected value. Let the UI decide how to render. --- .../invitepeople/impl/DefaultInvitePeoplePresenter.kt | 2 +- .../features/invitepeople/impl/InvitePeopleView.kt | 9 ++++----- .../impl/DefaultInvitePeoplePresenterTest.kt | 10 +++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt index fb99e36e84..d74c6ad33f 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt @@ -176,7 +176,7 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( val isInvited = existingMembership == RoomMembershipState.INVITE InvitableUser( matrixUser = result.matrixUser, - isSelected = selectedUsers.value.contains(result.matrixUser) || isJoined || isInvited, + isSelected = selectedUsers.value.contains(result.matrixUser), isAlreadyJoined = isJoined, isAlreadyInvited = isInvited, isUnresolved = result.isUnresolved, diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt index 7d0fc9aac8..ca42a32f7b 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -127,10 +127,9 @@ private fun InvitePeopleSearchBar( LazyColumn { itemsIndexed(results) { index, invitableUser -> - val notInvitedOrJoined = - !(invitableUser.isAlreadyInvited || invitableUser.isAlreadyJoined) - val isUnresolved = invitableUser.isUnresolved && notInvitedOrJoined - val enabled = isUnresolved || notInvitedOrJoined + val invitedOrJoined = invitableUser.isAlreadyInvited || invitableUser.isAlreadyJoined + val isUnresolved = invitableUser.isUnresolved && !invitedOrJoined + val enabled = isUnresolved || !invitedOrJoined val data = if (isUnresolved) { CheckableUserRowData.Unresolved( avatarData = invitableUser.matrixUser.getAvatarData(AvatarSize.UserListItem), @@ -152,7 +151,7 @@ private fun InvitePeopleSearchBar( ) } CheckableUserRow( - checked = invitableUser.isSelected, + checked = invitableUser.isSelected || invitedOrJoined, enabled = enabled, data = data, onCheckedChange = { onToggleUser(invitableUser.matrixUser) }, diff --git a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt index 49e381ebee..7f7e80fd7b 100644 --- a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt +++ b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt @@ -142,7 +142,7 @@ internal class DefaultInvitePeoplePresenterTest { } else { assertThat(users[index].isAlreadyJoined).isTrue() } - assertThat(users[index].isSelected).isTrue() + assertThat(users[index].isSelected).isFalse() } } } @@ -323,9 +323,9 @@ internal class DefaultInvitePeoplePresenterTest { assertThat(shouldBeSelectedUser).isNotNull() assertThat(shouldBeSelectedUser?.isSelected).isTrue() - // All the others are selected since their membership is joined or invited + // And no others are val allOtherUsers = users.minus(shouldBeSelectedUser!!) - assertThat(allOtherUsers.all { it.isSelected }).isTrue() + assertThat(allOtherUsers.none { it.isSelected }).isTrue() } } @@ -372,9 +372,9 @@ internal class DefaultInvitePeoplePresenterTest { assertThat(shouldBeSelectedUser).isNotNull() assertThat(shouldBeSelectedUser?.isSelected).isTrue() - // All the others are selected since their membership is joined or invited + // And no others are val allOtherUsers = users.minus(shouldBeSelectedUser!!) - assertThat(allOtherUsers.all { it.isSelected }).isTrue() + assertThat(allOtherUsers.none { it.isSelected }).isTrue() } } From 0be9e4cd663e990feaf5ca593bd4fd027ae98e58 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Aug 2025 11:44:16 +0200 Subject: [PATCH 25/30] Use string from Localazy. --- .../android/features/invitepeople/impl/InvitePeopleView.kt | 4 ++-- .../impl/src/main/res/values-be/translations.xml | 5 +++++ .../impl/src/main/res/values-bg/translations.xml | 5 +++++ .../impl/src/main/res/values-cs/translations.xml | 5 +++++ .../impl/src/main/res/values-cy/translations.xml | 5 +++++ .../impl/src/main/res/values-da/translations.xml | 5 +++++ .../impl/src/main/res/values-de/translations.xml | 5 +++++ .../impl/src/main/res/values-el/translations.xml | 5 +++++ .../impl/src/main/res/values-es/translations.xml | 5 +++++ .../impl/src/main/res/values-et/translations.xml | 5 +++++ .../impl/src/main/res/values-eu/translations.xml | 5 +++++ .../impl/src/main/res/values-fa/translations.xml | 5 +++++ .../impl/src/main/res/values-fi/translations.xml | 5 +++++ .../impl/src/main/res/values-fr/translations.xml | 5 +++++ .../impl/src/main/res/values-hu/translations.xml | 5 +++++ .../impl/src/main/res/values-in/translations.xml | 5 +++++ .../impl/src/main/res/values-it/translations.xml | 5 +++++ .../impl/src/main/res/values-ka/translations.xml | 5 +++++ .../impl/src/main/res/values-lt/translations.xml | 5 +++++ .../impl/src/main/res/values-nb/translations.xml | 5 +++++ .../impl/src/main/res/values-nl/translations.xml | 5 +++++ .../impl/src/main/res/values-pl/translations.xml | 5 +++++ .../impl/src/main/res/values-pt-rBR/translations.xml | 5 +++++ .../impl/src/main/res/values-pt/translations.xml | 5 +++++ .../impl/src/main/res/values-ro/translations.xml | 5 +++++ .../impl/src/main/res/values-ru/translations.xml | 5 +++++ .../impl/src/main/res/values-sk/translations.xml | 5 +++++ .../impl/src/main/res/values-sv/translations.xml | 5 +++++ .../impl/src/main/res/values-tr/translations.xml | 5 +++++ .../impl/src/main/res/values-uk/translations.xml | 5 +++++ .../impl/src/main/res/values-ur/translations.xml | 5 +++++ .../impl/src/main/res/values-uz/translations.xml | 5 +++++ .../impl/src/main/res/values-zh-rTW/translations.xml | 5 +++++ .../impl/src/main/res/values-zh/translations.xml | 5 +++++ features/invitepeople/impl/src/main/res/values/localazy.xml | 5 +++++ .../impl/src/main/res/values-be/translations.xml | 2 -- .../impl/src/main/res/values-bg/translations.xml | 2 -- .../impl/src/main/res/values-cs/translations.xml | 2 -- .../impl/src/main/res/values-cy/translations.xml | 2 -- .../impl/src/main/res/values-da/translations.xml | 2 -- .../impl/src/main/res/values-de/translations.xml | 2 -- .../impl/src/main/res/values-el/translations.xml | 2 -- .../impl/src/main/res/values-es/translations.xml | 2 -- .../impl/src/main/res/values-et/translations.xml | 2 -- .../impl/src/main/res/values-eu/translations.xml | 2 -- .../impl/src/main/res/values-fa/translations.xml | 2 -- .../impl/src/main/res/values-fi/translations.xml | 2 -- .../impl/src/main/res/values-fr/translations.xml | 2 -- .../impl/src/main/res/values-hu/translations.xml | 2 -- .../impl/src/main/res/values-in/translations.xml | 2 -- .../impl/src/main/res/values-it/translations.xml | 2 -- .../impl/src/main/res/values-ka/translations.xml | 2 -- .../impl/src/main/res/values-lt/translations.xml | 2 -- .../impl/src/main/res/values-nb/translations.xml | 2 -- .../impl/src/main/res/values-nl/translations.xml | 2 -- .../impl/src/main/res/values-pl/translations.xml | 2 -- .../impl/src/main/res/values-pt-rBR/translations.xml | 2 -- .../impl/src/main/res/values-pt/translations.xml | 2 -- .../impl/src/main/res/values-ro/translations.xml | 2 -- .../impl/src/main/res/values-ru/translations.xml | 2 -- .../impl/src/main/res/values-sk/translations.xml | 2 -- .../impl/src/main/res/values-sv/translations.xml | 2 -- .../impl/src/main/res/values-tr/translations.xml | 2 -- .../impl/src/main/res/values-uk/translations.xml | 2 -- .../impl/src/main/res/values-ur/translations.xml | 2 -- .../impl/src/main/res/values-uz/translations.xml | 2 -- .../impl/src/main/res/values-zh-rTW/translations.xml | 2 -- .../impl/src/main/res/values-zh/translations.xml | 2 -- features/roomdetails/impl/src/main/res/values/localazy.xml | 2 -- tools/localazy/config.json | 6 ++++++ 70 files changed, 178 insertions(+), 70 deletions(-) create mode 100644 features/invitepeople/impl/src/main/res/values-be/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-bg/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-cs/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-cy/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-da/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-de/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-el/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-es/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-et/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-eu/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-fa/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-fi/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-fr/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-hu/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-in/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-it/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-ka/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-lt/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-nb/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-nl/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-pl/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-pt-rBR/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-pt/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-ro/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-ru/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-sk/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-sv/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-tr/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-uk/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-ur/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-uz/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-zh-rTW/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values-zh/translations.xml create mode 100644 features/invitepeople/impl/src/main/res/values/localazy.xml diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt index ca42a32f7b..9a1c87cf86 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -141,8 +141,8 @@ private fun InvitePeopleSearchBar( name = invitableUser.matrixUser.getBestName(), subtext = when { // If they're already invited or joined we show that information - invitableUser.isAlreadyJoined -> "Already a member" - invitableUser.isAlreadyInvited -> "Already invited" + invitableUser.isAlreadyJoined -> stringResource(R.string.screen_invite_users_already_a_member) + invitableUser.isAlreadyInvited -> stringResource(R.string.screen_invite_users_already_invited) // Otherwise show the ID, unless that's already used for their name invitableUser.matrixUser.displayName.isNullOrEmpty() .not() -> invitableUser.matrixUser.userId.value diff --git a/features/invitepeople/impl/src/main/res/values-be/translations.xml b/features/invitepeople/impl/src/main/res/values-be/translations.xml new file mode 100644 index 0000000000..7125d8b2e6 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-be/translations.xml @@ -0,0 +1,5 @@ + + + "Ужо ўдзельнік" + "Ужо запрасілі" + diff --git a/features/invitepeople/impl/src/main/res/values-bg/translations.xml b/features/invitepeople/impl/src/main/res/values-bg/translations.xml new file mode 100644 index 0000000000..f585980920 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-bg/translations.xml @@ -0,0 +1,5 @@ + + + "Вече е член" + "Вече е бил поканен" + diff --git a/features/invitepeople/impl/src/main/res/values-cs/translations.xml b/features/invitepeople/impl/src/main/res/values-cs/translations.xml new file mode 100644 index 0000000000..fa5b3aa9a9 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-cs/translations.xml @@ -0,0 +1,5 @@ + + + "Již členem" + "Již pozván(a)" + diff --git a/features/invitepeople/impl/src/main/res/values-cy/translations.xml b/features/invitepeople/impl/src/main/res/values-cy/translations.xml new file mode 100644 index 0000000000..c58df3c541 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-cy/translations.xml @@ -0,0 +1,5 @@ + + + "Eisoes yn aelod" + "Wedi gwahodd yn barod" + diff --git a/features/invitepeople/impl/src/main/res/values-da/translations.xml b/features/invitepeople/impl/src/main/res/values-da/translations.xml new file mode 100644 index 0000000000..fbb1814e9f --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-da/translations.xml @@ -0,0 +1,5 @@ + + + "Allerede medlem" + "Allerede inviteret" + diff --git a/features/invitepeople/impl/src/main/res/values-de/translations.xml b/features/invitepeople/impl/src/main/res/values-de/translations.xml new file mode 100644 index 0000000000..182d9f289a --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-de/translations.xml @@ -0,0 +1,5 @@ + + + "Bereits Mitglied" + "Bereits eingeladen" + diff --git a/features/invitepeople/impl/src/main/res/values-el/translations.xml b/features/invitepeople/impl/src/main/res/values-el/translations.xml new file mode 100644 index 0000000000..3e3c1fd5d2 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-el/translations.xml @@ -0,0 +1,5 @@ + + + "Ήδη μέλος" + "Ήδη προσκεκλημένος" + diff --git a/features/invitepeople/impl/src/main/res/values-es/translations.xml b/features/invitepeople/impl/src/main/res/values-es/translations.xml new file mode 100644 index 0000000000..e62bb211e5 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-es/translations.xml @@ -0,0 +1,5 @@ + + + "Ya eres miembro" + "Ya estás invitado" + diff --git a/features/invitepeople/impl/src/main/res/values-et/translations.xml b/features/invitepeople/impl/src/main/res/values-et/translations.xml new file mode 100644 index 0000000000..44484d23c3 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-et/translations.xml @@ -0,0 +1,5 @@ + + + "Sa juba oled jututoa liige" + "Sa juba oled kutse saanud" + diff --git a/features/invitepeople/impl/src/main/res/values-eu/translations.xml b/features/invitepeople/impl/src/main/res/values-eu/translations.xml new file mode 100644 index 0000000000..a6aedd89cd --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-eu/translations.xml @@ -0,0 +1,5 @@ + + + "Kidea da dagoeneko" + "Lehendik ere gonbidatuta" + diff --git a/features/invitepeople/impl/src/main/res/values-fa/translations.xml b/features/invitepeople/impl/src/main/res/values-fa/translations.xml new file mode 100644 index 0000000000..544f01b8c8 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-fa/translations.xml @@ -0,0 +1,5 @@ + + + "از پیش عضو است" + "از پیش دعوت شده" + diff --git a/features/invitepeople/impl/src/main/res/values-fi/translations.xml b/features/invitepeople/impl/src/main/res/values-fi/translations.xml new file mode 100644 index 0000000000..e347919719 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-fi/translations.xml @@ -0,0 +1,5 @@ + + + "On jo jäsen" + "On jo kutsuttu" + diff --git a/features/invitepeople/impl/src/main/res/values-fr/translations.xml b/features/invitepeople/impl/src/main/res/values-fr/translations.xml new file mode 100644 index 0000000000..dcc16f58cf --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-fr/translations.xml @@ -0,0 +1,5 @@ + + + "Déjà membre" + "Déjà invité(e)" + diff --git a/features/invitepeople/impl/src/main/res/values-hu/translations.xml b/features/invitepeople/impl/src/main/res/values-hu/translations.xml new file mode 100644 index 0000000000..16f35b018c --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-hu/translations.xml @@ -0,0 +1,5 @@ + + + "Már tag" + "Már meghívták" + diff --git a/features/invitepeople/impl/src/main/res/values-in/translations.xml b/features/invitepeople/impl/src/main/res/values-in/translations.xml new file mode 100644 index 0000000000..e112033a06 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-in/translations.xml @@ -0,0 +1,5 @@ + + + "Sudah menjadi anggota" + "Sudah diundang" + diff --git a/features/invitepeople/impl/src/main/res/values-it/translations.xml b/features/invitepeople/impl/src/main/res/values-it/translations.xml new file mode 100644 index 0000000000..979e42de1b --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-it/translations.xml @@ -0,0 +1,5 @@ + + + "Già membro" + "Già invitato" + diff --git a/features/invitepeople/impl/src/main/res/values-ka/translations.xml b/features/invitepeople/impl/src/main/res/values-ka/translations.xml new file mode 100644 index 0000000000..3a34c2edac --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-ka/translations.xml @@ -0,0 +1,5 @@ + + + "უკვე წევრია" + "უკვე მოწვეულია" + diff --git a/features/invitepeople/impl/src/main/res/values-lt/translations.xml b/features/invitepeople/impl/src/main/res/values-lt/translations.xml new file mode 100644 index 0000000000..59c15290a1 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-lt/translations.xml @@ -0,0 +1,5 @@ + + + "Jau narys" + "Jau pakviestas" + diff --git a/features/invitepeople/impl/src/main/res/values-nb/translations.xml b/features/invitepeople/impl/src/main/res/values-nb/translations.xml new file mode 100644 index 0000000000..617b9271d5 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-nb/translations.xml @@ -0,0 +1,5 @@ + + + "Allerede medlem" + "Allerede invitert" + diff --git a/features/invitepeople/impl/src/main/res/values-nl/translations.xml b/features/invitepeople/impl/src/main/res/values-nl/translations.xml new file mode 100644 index 0000000000..b978dcd9cc --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-nl/translations.xml @@ -0,0 +1,5 @@ + + + "Reeds lid" + "Reeds uitgenodigd" + diff --git a/features/invitepeople/impl/src/main/res/values-pl/translations.xml b/features/invitepeople/impl/src/main/res/values-pl/translations.xml new file mode 100644 index 0000000000..bfd537bb4b --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-pl/translations.xml @@ -0,0 +1,5 @@ + + + "Jest już członkiem" + "Już zaproszony" + diff --git a/features/invitepeople/impl/src/main/res/values-pt-rBR/translations.xml b/features/invitepeople/impl/src/main/res/values-pt-rBR/translations.xml new file mode 100644 index 0000000000..7ad049843b --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-pt-rBR/translations.xml @@ -0,0 +1,5 @@ + + + "Já é membro" + "Já foi convidado" + diff --git a/features/invitepeople/impl/src/main/res/values-pt/translations.xml b/features/invitepeople/impl/src/main/res/values-pt/translations.xml new file mode 100644 index 0000000000..a953d11f67 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-pt/translations.xml @@ -0,0 +1,5 @@ + + + "Já é participante" + "Já foi convidado" + diff --git a/features/invitepeople/impl/src/main/res/values-ro/translations.xml b/features/invitepeople/impl/src/main/res/values-ro/translations.xml new file mode 100644 index 0000000000..f03be4b263 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-ro/translations.xml @@ -0,0 +1,5 @@ + + + "Deja membru" + "Deja invitat" + diff --git a/features/invitepeople/impl/src/main/res/values-ru/translations.xml b/features/invitepeople/impl/src/main/res/values-ru/translations.xml new file mode 100644 index 0000000000..0ae8eb792c --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-ru/translations.xml @@ -0,0 +1,5 @@ + + + "Уже зарегистрирован" + "Уже приглашены" + diff --git a/features/invitepeople/impl/src/main/res/values-sk/translations.xml b/features/invitepeople/impl/src/main/res/values-sk/translations.xml new file mode 100644 index 0000000000..68e34b0ada --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-sk/translations.xml @@ -0,0 +1,5 @@ + + + "Už ste členom" + "Už ste pozvaní" + diff --git a/features/invitepeople/impl/src/main/res/values-sv/translations.xml b/features/invitepeople/impl/src/main/res/values-sv/translations.xml new file mode 100644 index 0000000000..fd670c9c1a --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-sv/translations.xml @@ -0,0 +1,5 @@ + + + "Redan medlem" + "Redan inbjuden" + diff --git a/features/invitepeople/impl/src/main/res/values-tr/translations.xml b/features/invitepeople/impl/src/main/res/values-tr/translations.xml new file mode 100644 index 0000000000..427a7f3f10 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-tr/translations.xml @@ -0,0 +1,5 @@ + + + "Zaten üye" + "Zaten davet edildi" + diff --git a/features/invitepeople/impl/src/main/res/values-uk/translations.xml b/features/invitepeople/impl/src/main/res/values-uk/translations.xml new file mode 100644 index 0000000000..da3ac9fe5b --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-uk/translations.xml @@ -0,0 +1,5 @@ + + + "Уже учасник" + "Уже запрошені" + diff --git a/features/invitepeople/impl/src/main/res/values-ur/translations.xml b/features/invitepeople/impl/src/main/res/values-ur/translations.xml new file mode 100644 index 0000000000..06e8cee414 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-ur/translations.xml @@ -0,0 +1,5 @@ + + + "پہلے سے ہی رکن" + "پہلے سے مدعو شدہ" + diff --git a/features/invitepeople/impl/src/main/res/values-uz/translations.xml b/features/invitepeople/impl/src/main/res/values-uz/translations.xml new file mode 100644 index 0000000000..445a62d318 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-uz/translations.xml @@ -0,0 +1,5 @@ + + + "Allaqachon a\'zo" + "Allaqachon taklif qilingan" + diff --git a/features/invitepeople/impl/src/main/res/values-zh-rTW/translations.xml b/features/invitepeople/impl/src/main/res/values-zh-rTW/translations.xml new file mode 100644 index 0000000000..c8117ec283 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-zh-rTW/translations.xml @@ -0,0 +1,5 @@ + + + "已是成員" + "已邀請" + diff --git a/features/invitepeople/impl/src/main/res/values-zh/translations.xml b/features/invitepeople/impl/src/main/res/values-zh/translations.xml new file mode 100644 index 0000000000..b1e0e953f8 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values-zh/translations.xml @@ -0,0 +1,5 @@ + + + "已经是成员" + "已邀请" + diff --git a/features/invitepeople/impl/src/main/res/values/localazy.xml b/features/invitepeople/impl/src/main/res/values/localazy.xml new file mode 100644 index 0000000000..d89ae92e75 --- /dev/null +++ b/features/invitepeople/impl/src/main/res/values/localazy.xml @@ -0,0 +1,5 @@ + + + "Already a member" + "Already invited" + diff --git a/features/roomdetails/impl/src/main/res/values-be/translations.xml b/features/roomdetails/impl/src/main/res/values-be/translations.xml index d50b3c5f6e..01c076fdb5 100644 --- a/features/roomdetails/impl/src/main/res/values-be/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-be/translations.xml @@ -33,8 +33,6 @@ "У вас ёсць незахаваныя змены." "Захаваць змены?" "Дадаць тэму" - "Ужо ўдзельнік" - "Ужо запрасілі" "Зашыфраваны" "Не зашыфраваны" "Публічны пакой" diff --git a/features/roomdetails/impl/src/main/res/values-bg/translations.xml b/features/roomdetails/impl/src/main/res/values-bg/translations.xml index 6f9c256742..fb01acb4fb 100644 --- a/features/roomdetails/impl/src/main/res/values-bg/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-bg/translations.xml @@ -22,8 +22,6 @@ "Модератори" "Членове" "Добавяне на тема" - "Вече е член" - "Вече е бил поканен" "С шифроване" "Без шифроване" "Общодостъпна стая" diff --git a/features/roomdetails/impl/src/main/res/values-cs/translations.xml b/features/roomdetails/impl/src/main/res/values-cs/translations.xml index 3bd037b1c0..d484486940 100644 --- a/features/roomdetails/impl/src/main/res/values-cs/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-cs/translations.xml @@ -35,8 +35,6 @@ "Máte neuložené změny." "Uložit změny?" "Přidat téma" - "Již členem" - "Již pozván(a)" "Šifrováno" "Není šifrováno" "Veřejná místnost" diff --git a/features/roomdetails/impl/src/main/res/values-cy/translations.xml b/features/roomdetails/impl/src/main/res/values-cy/translations.xml index ab0a8fa95d..80726aa1f8 100644 --- a/features/roomdetails/impl/src/main/res/values-cy/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-cy/translations.xml @@ -35,8 +35,6 @@ "Mae gennych newidiadau heb eu cadw." "Cadw\'r newidiadau?" "Ychwanegu pwnc" - "Eisoes yn aelod" - "Wedi gwahodd yn barod" "Wedi\'i amgryptio" "Heb ei amgryptio" "Ystafell gyhoeddus" diff --git a/features/roomdetails/impl/src/main/res/values-da/translations.xml b/features/roomdetails/impl/src/main/res/values-da/translations.xml index e989977145..a07d86be77 100644 --- a/features/roomdetails/impl/src/main/res/values-da/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-da/translations.xml @@ -39,8 +39,6 @@ "Du har ændringer, der ikke er gemt." "Gem ændringer?" "Tilføj emne" - "Allerede medlem" - "Allerede inviteret" "Krypteret" "Ikke krypteret" "Offentligt rum" diff --git a/features/roomdetails/impl/src/main/res/values-de/translations.xml b/features/roomdetails/impl/src/main/res/values-de/translations.xml index 2a2673beb1..714d36c38a 100644 --- a/features/roomdetails/impl/src/main/res/values-de/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-de/translations.xml @@ -35,8 +35,6 @@ "Sie haben ungespeicherte Änderungen." "Änderungen speichern?" "Thema hinzufügen" - "Bereits Mitglied" - "Bereits eingeladen" "Verschlüsselt" "Nicht verschlüsselt" "Öffentlicher Raum" diff --git a/features/roomdetails/impl/src/main/res/values-el/translations.xml b/features/roomdetails/impl/src/main/res/values-el/translations.xml index aed10ce24f..678dad15c9 100644 --- a/features/roomdetails/impl/src/main/res/values-el/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-el/translations.xml @@ -35,8 +35,6 @@ "Έχεις μη αποθηκευμένες αλλαγές." "Αποθήκευση αλλαγών;" "Προσθήκη θέματος" - "Ήδη μέλος" - "Ήδη προσκεκλημένος" "Κρυπτογραφημένο" "Μη κρυπτογραφημένο" "Δημόσια αίθουσα" diff --git a/features/roomdetails/impl/src/main/res/values-es/translations.xml b/features/roomdetails/impl/src/main/res/values-es/translations.xml index ffce0a6b76..96e31eb5c5 100644 --- a/features/roomdetails/impl/src/main/res/values-es/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-es/translations.xml @@ -35,8 +35,6 @@ "Tienes cambios sin guardar." "¿Guardar cambios?" "Añadir tema" - "Ya eres miembro" - "Ya estás invitado" "Cifrada" "No cifrada" "Sala pública" diff --git a/features/roomdetails/impl/src/main/res/values-et/translations.xml b/features/roomdetails/impl/src/main/res/values-et/translations.xml index efc6ee8e6d..98b0f3ee63 100644 --- a/features/roomdetails/impl/src/main/res/values-et/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-et/translations.xml @@ -39,8 +39,6 @@ "Sul on salvestamata muudatusi" "Kas salvestame muudatused?" "Lisa teema" - "Sa juba oled jututoa liige" - "Sa juba oled kutse saanud" "Krüptitud jututuba" "Krüptimata jututuba" "Avalik jututuba" diff --git a/features/roomdetails/impl/src/main/res/values-eu/translations.xml b/features/roomdetails/impl/src/main/res/values-eu/translations.xml index bd2a370942..4eb246d36f 100644 --- a/features/roomdetails/impl/src/main/res/values-eu/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-eu/translations.xml @@ -33,8 +33,6 @@ "Gorde gabeko aldaketak dituzu." "Aldaketak gorde?" "Gehitu hizketagaia" - "Kidea da dagoeneko" - "Lehendik ere gonbidatuta" "Zifratuta" "Zifratu gabe" "Gela publikoa" diff --git a/features/roomdetails/impl/src/main/res/values-fa/translations.xml b/features/roomdetails/impl/src/main/res/values-fa/translations.xml index 7941f60609..3f0c9b949e 100644 --- a/features/roomdetails/impl/src/main/res/values-fa/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fa/translations.xml @@ -34,8 +34,6 @@ "تغییراتی ذخیره نشده دارید." "ذخیرهٔ تغییرات؟" "افزودن موضوع" - "از پیش عضو است" - "از پیش دعوت شده" "رمز شده" "رمزنگاری نشده" "اتاق عمومی" diff --git a/features/roomdetails/impl/src/main/res/values-fi/translations.xml b/features/roomdetails/impl/src/main/res/values-fi/translations.xml index 5906bd5986..04c1411e50 100644 --- a/features/roomdetails/impl/src/main/res/values-fi/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fi/translations.xml @@ -39,8 +39,6 @@ "Sinulla on tallentamattomia muutoksia" "Tallenna muutokset?" "Lisää aihe" - "On jo jäsen" - "On jo kutsuttu" "Salattu" "Ei salattu" "Julkinen huone" diff --git a/features/roomdetails/impl/src/main/res/values-fr/translations.xml b/features/roomdetails/impl/src/main/res/values-fr/translations.xml index f5b876c9f7..066ce1ee0f 100644 --- a/features/roomdetails/impl/src/main/res/values-fr/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-fr/translations.xml @@ -39,8 +39,6 @@ "Vous avez des modifications non-enregistrées." "Enregistrer les changements ?" "Ajouter un sujet" - "Déjà membre" - "Déjà invité(e)" "Chiffré" "Non chiffré" "Salon public" diff --git a/features/roomdetails/impl/src/main/res/values-hu/translations.xml b/features/roomdetails/impl/src/main/res/values-hu/translations.xml index dfe25cf712..6e2484fc68 100644 --- a/features/roomdetails/impl/src/main/res/values-hu/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-hu/translations.xml @@ -39,8 +39,6 @@ "Mentetlen módosításai vannak." "Menti a módosításokat?" "Téma hozzáadása" - "Már tag" - "Már meghívták" "Titkosított" "Nem titkosított" "Nyilvános szoba" diff --git a/features/roomdetails/impl/src/main/res/values-in/translations.xml b/features/roomdetails/impl/src/main/res/values-in/translations.xml index 2143418fb0..49f44eb985 100644 --- a/features/roomdetails/impl/src/main/res/values-in/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-in/translations.xml @@ -35,8 +35,6 @@ "Anda memiliki perubahan yang belum disimpan." "Simpan perubahan?" "Tambahkan topik" - "Sudah menjadi anggota" - "Sudah diundang" "Terenkripsi" "Tidak terenkripsi" "Ruangan publik" diff --git a/features/roomdetails/impl/src/main/res/values-it/translations.xml b/features/roomdetails/impl/src/main/res/values-it/translations.xml index 54de5f5407..988a2edafd 100644 --- a/features/roomdetails/impl/src/main/res/values-it/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-it/translations.xml @@ -35,8 +35,6 @@ "Hai delle modifiche non salvate." "Salvare le modifiche?" "Aggiungi argomento" - "Già membro" - "Già invitato" "Cifrata" "Non cifrata" "Stanza pubblica" diff --git a/features/roomdetails/impl/src/main/res/values-ka/translations.xml b/features/roomdetails/impl/src/main/res/values-ka/translations.xml index 6a68985d87..1beb70d4dd 100644 --- a/features/roomdetails/impl/src/main/res/values-ka/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ka/translations.xml @@ -32,8 +32,6 @@ "თქვენ გაქვთ შეუნახავი ცვლილებები" "შენახვა?" "თემის დამატება" - "უკვე წევრია" - "უკვე მოწვეულია" "ოთახის რედაქტირება" "უცნობი შეცდომა მოხდა. ინფორმაციის შეცვლა ვერ მოხერხდა." "ოთახის განახლება შეუძლებელია" diff --git a/features/roomdetails/impl/src/main/res/values-lt/translations.xml b/features/roomdetails/impl/src/main/res/values-lt/translations.xml index 18a908b2c0..1b3b44fdf2 100644 --- a/features/roomdetails/impl/src/main/res/values-lt/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-lt/translations.xml @@ -1,8 +1,6 @@ "Pridėti temą" - "Jau narys" - "Jau pakviestas" "Redaguoti kambarį" "Įvyko nežinoma klaida ir informacijos pakeisti nepavyko." "Nepavyko atnaujinti kambario" diff --git a/features/roomdetails/impl/src/main/res/values-nb/translations.xml b/features/roomdetails/impl/src/main/res/values-nb/translations.xml index a8f5d8d123..f964f142b5 100644 --- a/features/roomdetails/impl/src/main/res/values-nb/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-nb/translations.xml @@ -35,8 +35,6 @@ "Du har endringer som ikke er lagret." "Lagre endringer?" "Legg til emne" - "Allerede medlem" - "Allerede invitert" "Kryptert" "Ikke kryptert" "Offentlig rom" diff --git a/features/roomdetails/impl/src/main/res/values-nl/translations.xml b/features/roomdetails/impl/src/main/res/values-nl/translations.xml index 2b190fc4db..9b932f60fe 100644 --- a/features/roomdetails/impl/src/main/res/values-nl/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-nl/translations.xml @@ -33,8 +33,6 @@ "Je hebt niet-opgeslagen wijzigingen" "Wijzigingen opslaan?" "Onderwerp toevoegen" - "Reeds lid" - "Reeds uitgenodigd" "Versleuteld" "Niet versleuteld" "Openbare kamer" diff --git a/features/roomdetails/impl/src/main/res/values-pl/translations.xml b/features/roomdetails/impl/src/main/res/values-pl/translations.xml index c708ac220a..b9847c6cfd 100644 --- a/features/roomdetails/impl/src/main/res/values-pl/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-pl/translations.xml @@ -39,8 +39,6 @@ "Masz niezapisane zmiany." "Zapisać zmiany?" "Dodaj temat" - "Jest już członkiem" - "Już zaproszony" "Szyfrowany" "Nieszyfrowany" "Pokój publiczny" diff --git a/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml b/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml index 5561005e9b..bfe0b44af2 100644 --- a/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-pt-rBR/translations.xml @@ -35,8 +35,6 @@ "Você tem alterações não salvas." "Salvar alterações?" "Adicionar tópico" - "Já é membro" - "Já foi convidado" "Criptografado" "Não criptografado" "Sala pública" diff --git a/features/roomdetails/impl/src/main/res/values-pt/translations.xml b/features/roomdetails/impl/src/main/res/values-pt/translations.xml index 32d1bb8fc8..cba9ab5ac1 100644 --- a/features/roomdetails/impl/src/main/res/values-pt/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-pt/translations.xml @@ -39,8 +39,6 @@ "Tens alterações por guardar." "Guardar alterações?" "Adicionar descrição" - "Já é participante" - "Já foi convidado" "Cifrada" "Não cifrada" "Sala pública" diff --git a/features/roomdetails/impl/src/main/res/values-ro/translations.xml b/features/roomdetails/impl/src/main/res/values-ro/translations.xml index 622278dc64..b901be078e 100644 --- a/features/roomdetails/impl/src/main/res/values-ro/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ro/translations.xml @@ -33,8 +33,6 @@ "Aveți modificări nesalvate." "Salvați modificările?" "Adăugare subiect" - "Deja membru" - "Deja invitat" "Criptat" "Necriptat" "Cameră publică" diff --git a/features/roomdetails/impl/src/main/res/values-ru/translations.xml b/features/roomdetails/impl/src/main/res/values-ru/translations.xml index 77d0b94eb3..e4c53ff30d 100644 --- a/features/roomdetails/impl/src/main/res/values-ru/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ru/translations.xml @@ -35,8 +35,6 @@ "У вас есть несохраненные изменения." "Сохранить изменения?" "Добавить тему" - "Уже зарегистрирован" - "Уже приглашены" "Зашифровано" "Шифрования нет" "Общедоступная комната" diff --git a/features/roomdetails/impl/src/main/res/values-sk/translations.xml b/features/roomdetails/impl/src/main/res/values-sk/translations.xml index b8e9e0c30a..530455cbf2 100644 --- a/features/roomdetails/impl/src/main/res/values-sk/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-sk/translations.xml @@ -39,8 +39,6 @@ "Máte neuložené zmeny." "Uložiť zmeny?" "Pridať tému" - "Už ste členom" - "Už ste pozvaní" "Zašifrované" "Nešifrované" "Verejná miestnosť" diff --git a/features/roomdetails/impl/src/main/res/values-sv/translations.xml b/features/roomdetails/impl/src/main/res/values-sv/translations.xml index 12cec6d6ee..a3a9d4f144 100644 --- a/features/roomdetails/impl/src/main/res/values-sv/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-sv/translations.xml @@ -35,8 +35,6 @@ "Du har osparade ändringar." "Spara ändringar?" "Lägg till ämne" - "Redan medlem" - "Redan inbjuden" "Krypterat" "Inte krypterat" "Offentligt rum" diff --git a/features/roomdetails/impl/src/main/res/values-tr/translations.xml b/features/roomdetails/impl/src/main/res/values-tr/translations.xml index 67a8845821..92caaaf5eb 100644 --- a/features/roomdetails/impl/src/main/res/values-tr/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-tr/translations.xml @@ -35,8 +35,6 @@ "Kaydedilmemiş değişiklikleriniz var." "Değişiklikleri Kaydet?" "Konu ekle" - "Zaten üye" - "Zaten davet edildi" "Şifrelenmiş" "Şifrelenmemiş" "Herkese açık oda" diff --git a/features/roomdetails/impl/src/main/res/values-uk/translations.xml b/features/roomdetails/impl/src/main/res/values-uk/translations.xml index b3cac2e00a..7ef99d8430 100644 --- a/features/roomdetails/impl/src/main/res/values-uk/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-uk/translations.xml @@ -39,8 +39,6 @@ "У вас є не збережені зміни." "Зберегти зміни?" "Додати тему" - "Уже учасник" - "Уже запрошені" "Зашифровано" "Не зашифровано" "Загальнодоступна кімната" diff --git a/features/roomdetails/impl/src/main/res/values-ur/translations.xml b/features/roomdetails/impl/src/main/res/values-ur/translations.xml index 00c90107ac..12a8d964cb 100644 --- a/features/roomdetails/impl/src/main/res/values-ur/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-ur/translations.xml @@ -33,8 +33,6 @@ "آپکے پاس غیر محفوظ تبدیلیاں ہیں" "تبدیلیاں محفوظ کریں؟" "موضوع شامل کریں" - "پہلے سے ہی رکن" - "پہلے سے مدعو شدہ" "مرموز کردہ" "رموز کردہ نہیں" "عوامی کمرہ" diff --git a/features/roomdetails/impl/src/main/res/values-uz/translations.xml b/features/roomdetails/impl/src/main/res/values-uz/translations.xml index 030e0a91bd..e3d9418b43 100644 --- a/features/roomdetails/impl/src/main/res/values-uz/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-uz/translations.xml @@ -3,8 +3,6 @@ "Bildirishnoma sozlamalarini yangilashda xatolik yuz berdi." "Har kim" "Mavzu qo\'shish" - "Allaqachon a\'zo" - "Allaqachon taklif qilingan" "Xonani tahrirlash" "Nomaʼlum xatolik yuz berdi va maʼlumotni oʻzgartirib boʻlmadi." "Xonani yangilab bo‘lmadi" diff --git a/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml b/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml index ac32c3597b..5efcc0438a 100644 --- a/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-zh-rTW/translations.xml @@ -35,8 +35,6 @@ "您有尚未儲存的變更" "是否儲存變更?" "新增主題" - "已是成員" - "已邀請" "已加密" "未加密" "公開的聊天室" diff --git a/features/roomdetails/impl/src/main/res/values-zh/translations.xml b/features/roomdetails/impl/src/main/res/values-zh/translations.xml index 367741e4ef..7d5a9e330c 100644 --- a/features/roomdetails/impl/src/main/res/values-zh/translations.xml +++ b/features/roomdetails/impl/src/main/res/values-zh/translations.xml @@ -35,8 +35,6 @@ "您有未保存的更改。" "保存更改?" "添加主题" - "已经是成员" - "已邀请" "加密的" "未加密的" "公共聊天室" diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml index d0c389ded5..5dd185ec13 100644 --- a/features/roomdetails/impl/src/main/res/values/localazy.xml +++ b/features/roomdetails/impl/src/main/res/values/localazy.xml @@ -39,8 +39,6 @@ "You have unsaved changes." "Save changes?" "Add topic" - "Already a member" - "Already invited" "Encrypted" "Not encrypted" "Public room" diff --git a/tools/localazy/config.json b/tools/localazy/config.json index 3beacd4f5a..0aac7e51af 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -207,6 +207,12 @@ "screen_room_member_details_.*" ] }, + { + "name" : ":features:invitepeople:impl", + "includeRegex" : [ + "screen\\.invite_users\\..*" + ] + }, { "name" : ":features:messages:impl", "includeRegex" : [ From ff93a82b06bd2e50cb6a5bd4c68d265f2f37e66d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Aug 2025 14:39:00 +0200 Subject: [PATCH 26/30] Provide default value for `modifier`. --- .../features/createroom/impl/addpeople/AddPeopleNode.kt | 3 ++- .../android/features/invitepeople/api/InvitePeopleRenderer.kt | 2 +- .../features/roomdetails/impl/invite/RoomInviteMembersNode.kt | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt index 1e7475be0d..69f0d7f8a4 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt @@ -51,8 +51,9 @@ class AddPeopleNode @AssistedInject constructor( AddPeopleView( state = state, onFinish = ::onFinish, + modifier = modifier, ) { - invitePeopleRenderer.Render(state, Modifier) + invitePeopleRenderer.Render(state) } } } diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt index 30144a11d1..a8a4545415 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt @@ -14,6 +14,6 @@ interface InvitePeopleRenderer { @Composable fun Render( state: InvitePeopleState, - modifier: Modifier, + modifier: Modifier = Modifier, ) } 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 b3b3a839a4..def93b7aae 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 @@ -51,7 +51,7 @@ class RoomInviteMembersNode @AssistedInject constructor( onBackClick = { navigateUp() }, onDone = { navigateUp() } ) { - invitePeopleRenderer.Render(state, Modifier) + invitePeopleRenderer.Render(state) } } } From e31f6cb0b64ec1fa8a0760219d60344b7daf92f1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Aug 2025 14:41:51 +0200 Subject: [PATCH 27/30] Use SessionCoroutineScope here. --- .../invitepeople/impl/DefaultInvitePeoplePresenter.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt index d74c6ad33f..62715dd495 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt @@ -27,7 +27,7 @@ import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.di.SessionScope -import io.element.android.libraries.di.annotations.AppCoroutineScope +import io.element.android.libraries.di.annotations.SessionCoroutineScope 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 @@ -49,7 +49,7 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( @Assisted private val room: JoinedRoom, private val userRepository: UserRepository, private val coroutineDispatchers: CoroutineDispatchers, - @AppCoroutineScope private val coroutineScope: CoroutineScope, + @SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope, private val appErrorStateService: AppErrorStateService, ) : InvitePeoplePresenter { @AssistedFactory @@ -96,7 +96,7 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( searchResults.toggleUser(event.user) } is InvitePeopleEvents.SendInvites -> { - coroutineScope.sendInvites(selectedUsers.value) + sessionCoroutineScope.sendInvites(selectedUsers.value) } is InvitePeopleEvents.CloseSearch -> { searchActive = false From 755938543938c3622251d15f76aadd06587e60d1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Aug 2025 16:05:50 +0200 Subject: [PATCH 28/30] Revert "Provide default value for `modifier`." This reverts commit ff93a82b06bd2e50cb6a5bd4c68d265f2f37e66d. --- .../features/createroom/impl/addpeople/AddPeopleNode.kt | 3 +-- .../android/features/invitepeople/api/InvitePeopleRenderer.kt | 2 +- .../features/roomdetails/impl/invite/RoomInviteMembersNode.kt | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt index 69f0d7f8a4..1e7475be0d 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt @@ -51,9 +51,8 @@ class AddPeopleNode @AssistedInject constructor( AddPeopleView( state = state, onFinish = ::onFinish, - modifier = modifier, ) { - invitePeopleRenderer.Render(state) + invitePeopleRenderer.Render(state, Modifier) } } } diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt index a8a4545415..30144a11d1 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeopleRenderer.kt @@ -14,6 +14,6 @@ interface InvitePeopleRenderer { @Composable fun Render( state: InvitePeopleState, - modifier: Modifier = Modifier, + modifier: Modifier, ) } 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 def93b7aae..b3b3a839a4 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 @@ -51,7 +51,7 @@ class RoomInviteMembersNode @AssistedInject constructor( onBackClick = { navigateUp() }, onDone = { navigateUp() } ) { - invitePeopleRenderer.Render(state) + invitePeopleRenderer.Render(state, Modifier) } } } From 16acfa28d79a078319bfe482d7a71e89a8a56efa Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Aug 2025 16:41:29 +0200 Subject: [PATCH 29/30] Avoid using `runBlocking` in Node `resolve` function. --- .../createroom/impl/CreateRoomFlowNode.kt | 6 +- .../impl/addpeople/AddPeopleNode.kt | 11 ++-- .../invitepeople/api/InvitePeoplePresenter.kt | 6 +- .../impl/DefaultInvitePeoplePresenter.kt | 41 ++++++++++--- .../impl/DefaultInvitePeopleState.kt | 2 + .../impl/DefaultInvitePeopleStateProvider.kt | 4 ++ .../invitepeople/impl/InvitePeopleView.kt | 37 +++++++++++- .../impl/DefaultInvitePeoplePresenterTest.kt | 59 ++++++++++++++++--- .../impl/invite/RoomInviteMembersNode.kt | 5 +- .../libraries/architecture/AsyncData.kt | 14 +++++ 10 files changed, 159 insertions(+), 26 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt index 761072b0e9..6c819edf5a 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt @@ -26,16 +26,13 @@ import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope -import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId -import kotlinx.coroutines.runBlocking import kotlinx.parcelize.Parcelize @ContributesNode(SessionScope::class) class CreateRoomFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val client: MatrixClient, ) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.ConfigureRoom, @@ -59,8 +56,7 @@ class CreateRoomFlowNode @AssistedInject constructor( createNode(buildContext, plugins = listOf(callback)) } is NavTarget.AddPeople -> { - val joinedRoom = runBlocking { client.getJoinedRoom(navTarget.roomId) } ?: error("Room not found") - val inputs = AddPeopleNode.Inputs(joinedRoom) + val inputs = AddPeopleNode.Inputs(navTarget.roomId) val callback: AddPeopleNode.Callback = object : AddPeopleNode.Callback { override fun onFinish() { onRoomCreated(navTarget.roomId) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt index 1e7475be0d..3fc9cd7d81 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/addpeople/AddPeopleNode.kt @@ -21,7 +21,7 @@ import io.element.android.features.invitepeople.api.InvitePeopleRenderer import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.SessionScope -import io.element.android.libraries.matrix.api.room.JoinedRoom +import io.element.android.libraries.matrix.api.core.RoomId @ContributesNode(SessionScope::class) class AddPeopleNode @AssistedInject constructor( @@ -31,7 +31,7 @@ class AddPeopleNode @AssistedInject constructor( private val invitePeopleRenderer: InvitePeopleRenderer, ) : Node(buildContext, plugins = plugins) { data class Inputs( - val joinedRoom: JoinedRoom + val roomId: RoomId, ) : NodeInputs interface Callback : Plugin { @@ -42,8 +42,11 @@ class AddPeopleNode @AssistedInject constructor( plugins().forEach { it.onFinish() } } - private val joinedRoom = inputs().joinedRoom - private val invitePeoplePresenter = invitePeoplePresenterFactory.create(joinedRoom) + private val roomId = inputs().roomId + private val invitePeoplePresenter = invitePeoplePresenterFactory.create( + joinedRoom = null, + roomId = roomId, + ) @Composable override fun View(modifier: Modifier) { diff --git a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt index 4e5c82f684..46903bfb18 100644 --- a/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt +++ b/features/invitepeople/api/src/main/kotlin/io/element/android/features/invitepeople/api/InvitePeoplePresenter.kt @@ -8,10 +8,14 @@ package io.element.android.features.invitepeople.api import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.JoinedRoom interface InvitePeoplePresenter : Presenter { interface Factory { - fun create(room: JoinedRoom): InvitePeoplePresenter + fun create( + joinedRoom: JoinedRoom?, + roomId: RoomId, + ): InvitePeoplePresenter } } diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt index 62715dd495..8961e1157f 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenter.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue @@ -23,11 +24,14 @@ import io.element.android.features.invitepeople.api.InvitePeopleEvents import io.element.android.features.invitepeople.api.InvitePeoplePresenter import io.element.android.features.invitepeople.api.InvitePeopleState import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.architecture.map import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.annotations.SessionCoroutineScope +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.JoinedRoom import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMembershipState @@ -46,16 +50,18 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class DefaultInvitePeoplePresenter @AssistedInject constructor( - @Assisted private val room: JoinedRoom, + @Assisted private val joinedRoom: JoinedRoom?, + @Assisted private val roomId: RoomId, private val userRepository: UserRepository, private val coroutineDispatchers: CoroutineDispatchers, @SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope, private val appErrorStateService: AppErrorStateService, + private val matrixClient: MatrixClient, ) : InvitePeoplePresenter { @AssistedFactory @ContributesBinding(SessionScope::class) interface Factory : InvitePeoplePresenter.Factory { - override fun create(room: JoinedRoom): DefaultInvitePeoplePresenter + override fun create(joinedRoom: JoinedRoom?, roomId: RoomId): DefaultInvitePeoplePresenter } @Composable @@ -66,9 +72,21 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( var searchQuery by rememberSaveable { mutableStateOf("") } var searchActive by rememberSaveable { mutableStateOf(false) } val showSearchLoader = rememberSaveable { mutableStateOf(false) } + val room by produceState(if (joinedRoom != null) AsyncData.Success(joinedRoom) else AsyncData.Loading()) { + if (joinedRoom == null) { + val result = matrixClient.getJoinedRoom(roomId) + value = if (result == null) { + AsyncData.Failure(Exception("Room not found")) + } else { + AsyncData.Success(result) + } + } + } - LaunchedEffect(Unit) { - fetchMembers(roomMembers) + LaunchedEffect(room.isSuccess()) { + room.dataOrNull()?.let { + fetchMembers(it, roomMembers) + } } LaunchedEffect(searchQuery, roomMembers) { performSearch( @@ -96,7 +114,9 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( searchResults.toggleUser(event.user) } is InvitePeopleEvents.SendInvites -> { - sessionCoroutineScope.sendInvites(selectedUsers.value) + room.dataOrNull()?.let { + sessionCoroutineScope.sendInvites(it, selectedUsers.value) + } } is InvitePeopleEvents.CloseSearch -> { searchActive = false @@ -106,6 +126,7 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( } return DefaultInvitePeopleState( + room = room.map { }, canInvite = selectedUsers.value.isNotEmpty(), selectedUsers = selectedUsers.value, searchQuery = searchQuery, @@ -116,7 +137,10 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( ) } - private fun CoroutineScope.sendInvites(selectedUsers: List) = launch { + private fun CoroutineScope.sendInvites( + room: JoinedRoom, + selectedUsers: List, + ) = launch { val anyInviteFailed = selectedUsers .map { room.inviteUserById(it.userId) } .any { it.isFailure } @@ -186,7 +210,10 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor( }.launchIn(this) } - private suspend fun fetchMembers(roomMembers: MutableState>>) { + private suspend fun fetchMembers( + room: JoinedRoom, + roomMembers: MutableState>> + ) { suspend { room.filterMembers("", coroutineDispatchers.io).toImmutableList() }.runCatchingUpdatingState(roomMembers) diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt index 5e6ff0cd31..77ba8aad05 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleState.kt @@ -9,11 +9,13 @@ package io.element.android.features.invitepeople.impl import io.element.android.features.invitepeople.api.InvitePeopleEvents import io.element.android.features.invitepeople.api.InvitePeopleState +import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList data class DefaultInvitePeopleState( + val room: AsyncData, override val canInvite: Boolean, val searchQuery: String, val showSearchLoader: Boolean, diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt index ff1dc5c4a9..980d32e7fb 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeopleStateProvider.kt @@ -8,6 +8,7 @@ package io.element.android.features.invitepeople.impl import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser @@ -66,6 +67,7 @@ internal class DefaultInvitePeopleStateProvider : PreviewParameterProvider = AsyncData.Success(Unit), canInvite: Boolean = false, searchQuery: String = "", searchResults: SearchBarResultState> = SearchBarResultState.Initial(), @@ -92,6 +95,7 @@ private fun aDefaultInvitePeopleState( showSearchLoader: Boolean = false, ): DefaultInvitePeopleState { return DefaultInvitePeopleState( + room = room, canInvite = canInvite, searchQuery = searchQuery, searchResults = searchResults, diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt index 9a1c87cf86..f2382fb170 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -8,19 +8,24 @@ package io.element.android.features.invitepeople.impl import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.designsystem.components.async.AsyncFailure import io.element.android.libraries.designsystem.components.async.AsyncLoading import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.preview.ElementPreview @@ -42,9 +47,39 @@ import kotlinx.collections.immutable.ImmutableList fun InvitePeopleView( state: DefaultInvitePeopleState, modifier: Modifier = Modifier, +) { + when (state.room) { + is AsyncData.Failure -> InvitePeopleViewError(state.room.error, modifier) + AsyncData.Uninitialized, + is AsyncData.Loading, + is AsyncData.Success -> InvitePeopleContentView(state, modifier) + } +} + +@Composable +private fun InvitePeopleViewError( + error: Throwable, + modifier: Modifier = Modifier, +) { + Box( + modifier = modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + AsyncFailure( + throwable = error, + onRetry = null, + modifier = Modifier.padding(horizontal = 16.dp), + ) + } +} + +@Composable +private fun InvitePeopleContentView( + state: DefaultInvitePeopleState, + modifier: Modifier = Modifier, ) { Column( - modifier = modifier.fillMaxWidth(), + modifier = modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(16.dp), ) { InvitePeopleSearchBar( diff --git a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt index 7f7e80fd7b..1e438fab8e 100644 --- a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt +++ b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt @@ -10,15 +10,21 @@ package io.element.android.features.invitepeople.impl import app.cash.turbine.ReceiveTurbine import com.google.common.truth.Truth.assertThat import io.element.android.features.invitepeople.api.InvitePeopleEvents +import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.theme.components.SearchBarResultState +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.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.user.MatrixUser import io.element.android.libraries.matrix.test.AN_EXCEPTION +import io.element.android.libraries.matrix.test.A_ROOM_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.FakeMatrixClient 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.room.aRoomMemberList @@ -54,7 +60,7 @@ internal class DefaultInvitePeoplePresenterTest { val presenter = createDefaultInvitePeoplePresenter() presenter.test { val initialState = awaitItemAsDefault() - + assertThat(initialState.room).isEqualTo(AsyncData.Success(Unit)) assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java) assertThat(initialState.isSearchActive).isFalse() assertThat(initialState.canInvite).isFalse() @@ -452,6 +458,40 @@ internal class DefaultInvitePeoplePresenterTest { } } + @Test + fun `present - when joinedRoom is not provided, it is retrieved on the MatrixClient`() = runTest { + val matrixClient = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, FakeJoinedRoom()) + } + val presenter = createDefaultInvitePeoplePresenter( + joinedRoom = null, + roomId = A_ROOM_ID, + matrixClient = matrixClient, + ) + presenter.test { + val initialState = awaitItemAsDefault() + assertThat(initialState.room.isLoading()).isTrue() + val finalState = awaitItemAsDefault() + assertThat(finalState.room).isEqualTo(AsyncData.Success(Unit)) + } + } + + @Test + fun `present - when joinedRoom is not provided, it is retrieved on the MatrixClient - error case`() = runTest { + val matrixClient = FakeMatrixClient() + val presenter = createDefaultInvitePeoplePresenter( + joinedRoom = null, + roomId = A_ROOM_ID, + matrixClient = matrixClient, + ) + presenter.test { + val initialState = awaitItemAsDefault() + assertThat(initialState.room.isLoading()).isTrue() + val finalState = awaitItemAsDefault() + assertThat(finalState.room.errorOrNull()?.message).isEqualTo("Room not found") + } + } + private suspend fun FakeUserRepository.emitStateWithUsers( users: List, isSearching: Boolean = false @@ -484,19 +524,24 @@ private suspend fun ReceiveTurbine.awaitItemAsDefault(): DefaultInvitePeo fun TestScope.createDefaultInvitePeoplePresenter( roomMembersState: RoomMembersState = RoomMembersState.Ready(aRoomMemberList()), inviteUserResult: (UserId) -> Result = { lambdaError() }, + joinedRoom: JoinedRoom? = FakeJoinedRoom( + inviteUserResult = inviteUserResult, + ).apply { + givenRoomMembersState(roomMembersState) + }, + roomId: RoomId = A_ROOM_ID, userRepository: UserRepository = FakeUserRepository(), coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(), appErrorStateService: AppErrorStateService = FakeAppErrorStateService(), + matrixClient: MatrixClient = FakeMatrixClient(), ): DefaultInvitePeoplePresenter { return DefaultInvitePeoplePresenter( - room = FakeJoinedRoom( - inviteUserResult = inviteUserResult, - ).apply { - givenRoomMembersState(roomMembersState) - }, + joinedRoom = joinedRoom, + roomId = roomId, userRepository = userRepository, coroutineDispatchers = coroutineDispatchers, - coroutineScope = backgroundScope, + sessionCoroutineScope = backgroundScope, appErrorStateService = appErrorStateService, + matrixClient = matrixClient, ) } 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 b3b3a839a4..dc269e7322 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 @@ -40,7 +40,10 @@ class RoomInviteMembersNode @AssistedInject constructor( ) } - private val invitePeoplePresenter = invitePeoplePresenterFactory.create(room) + private val invitePeoplePresenter = invitePeoplePresenterFactory.create( + joinedRoom = room, + roomId = room.roomId, + ) @Composable override fun View(modifier: Modifier) { diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncData.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncData.kt index b7f22cbe23..7085db62f3 100644 --- a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncData.kt +++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/AsyncData.kt @@ -160,3 +160,17 @@ suspend inline fun runUpdatingState( } ) } + +inline fun AsyncData.map( + transform: (T?) -> R, +): AsyncData { + return when (this) { + is AsyncData.Failure -> AsyncData.Failure( + error = error, + prevData = transform(prevData) + ) + is AsyncData.Loading -> AsyncData.Loading(transform(prevData)) + is AsyncData.Success -> AsyncData.Success(transform(data)) + AsyncData.Uninitialized -> AsyncData.Uninitialized + } +} From 72aa0be6b3ce535fbc245c4b092827c1a2e63807 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Thu, 14 Aug 2025 15:09:26 +0000 Subject: [PATCH 30/30] Update screenshots --- .../features.invitepeople.impl_InvitePeopleView_Day_0_en.png | 4 ++-- .../features.invitepeople.impl_InvitePeopleView_Day_1_en.png | 4 ++-- .../features.invitepeople.impl_InvitePeopleView_Day_8_en.png | 3 +++ ...features.invitepeople.impl_InvitePeopleView_Night_0_en.png | 4 ++-- ...features.invitepeople.impl_InvitePeopleView_Night_1_en.png | 4 ++-- ...features.invitepeople.impl_InvitePeopleView_Night_8_en.png | 3 +++ 6 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_8_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_8_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png index 7b42297c4a..31d8d6d6ee 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85bd01b35953493c35625e4d458a8b8f1557ebddec5ee3164c3f4b40f8cdf814 -size 9202 +oid sha256:aae19b03efb483fd312e5cf4b02e000af86941ce5c8e3472fe2410bc67178519 +size 9122 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png index 22f04c3a07..dec7a7732f 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c6677df67d825bf0bda07723c4c0e505e7b1340d6686567234a513f4447c772c -size 20684 +oid sha256:1fcdfe7d1492b536b3604747ede049e24f48b75977eb3858e27a837b5b4ec6da +size 20550 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_8_en.png new file mode 100644 index 0000000000..7e1dc6ec2d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Day_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:805f7e08c25821528d2748ffa2b4edeaf21d0ee2a1d833693e36e51fafe0f92b +size 6607 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png index 6236f3c1e9..d42ab638fa 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:db18a58eb2d2f6e374079e3766ea84ef29beb7cc52d4f93281752826dd6c9d49 -size 8545 +oid sha256:31143646f33a013c30bc4e1cfd6e66beb8af100521dfd9dc599a94be8e6f415c +size 8535 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png index c192408655..aca93cea12 100644 --- a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc4d907e2ab98ae5e00d2b8acc4faa87aefc4137677301875ca7cd152a83a35f -size 20927 +oid sha256:50474e918e38f3f14e57ac6c069bf414f99050083d3796e100ac683309db74c0 +size 20917 diff --git a/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_8_en.png new file mode 100644 index 0000000000..03b52521f9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.invitepeople.impl_InvitePeopleView_Night_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65fde13bab6f3561319892c242c361fbd15874251670f5db3155ef75c3ba4cdb +size 6529