From 5c08b02b64f9d900816cab165da7e82aa66fe491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Fri, 12 Jun 2026 11:55:03 +0200 Subject: [PATCH 01/17] feat(meeting): select participants [WPB-25049] --- .../wire/android/navigation/MainNavHost.kt | 42 +++- .../SharedNewConversationViewModel.kt | 46 ---- .../ChannelAccessOnCreateScreen.kt | 4 +- .../channelhistory/ChannelHistoryScreen.kt | 8 +- .../groupOptions/GroupOptionsScreen.kt | 4 +- .../groupname/NewGroupNameScreen.kt | 4 +- .../NewGroupConversationSearchPeopleScreen.kt | 4 +- .../NewConversationSearchPeopleScreen.kt | 4 +- .../com/wire/android/di/ViewModelScoped.kt | 6 + .../android/di/metro/MetroViewModelGraph.kt | 8 + .../kotlin/com/wire/android/model/Contact.kt | 2 + .../search/SearchMetroViewModelBindings.kt | 4 +- .../search/SearchUsersAndAppsScreen.kt | 13 +- .../android/search/SearchViewModelFactory.kt | 6 +- .../android/search/SearchViewModelGraph.kt | 19 +- .../search/users/SearchUserViewModel.kt | 3 + .../search/users/SearchUserViewModelTest.kt | 95 +++++++- .../com/wire/android/model/SnackBarMessage.kt | 0 .../ui/common/textfield/WireTextField.kt | 3 + .../common/textfield/WireTextFieldLayout.kt | 30 ++- .../ui-common/src/main/res/values/strings.xml | 1 + features/meetings/build.gradle.kts | 5 +- .../meetings/navigation/MeetingNavigator.kt | 30 +++ .../ui/MeetingsMetroViewModelBindings.kt | 17 +- .../meetings/ui/MeetingsViewModelFactory.kt | 4 +- .../meetings/ui/MeetingsViewModelGraph.kt | 28 ++- .../ui/create/NewMeetingParticipantsScreen.kt | 110 +++++++++ .../meetings/ui/create/NewMeetingScreen.kt | 227 +++++++++++++++--- .../meetings/ui/create/NewMeetingViewModel.kt | 105 +++++++- .../TextListTruncationTransformation.kt | 86 +++++++ .../src/main/res/drawable/ic_expand.xml | 24 ++ .../src/main/res/values-de/strings.xml | 2 +- .../src/main/res/values-ru/strings.xml | 2 +- .../meetings/src/main/res/values/strings.xml | 14 +- kalium | 2 +- 35 files changed, 817 insertions(+), 145 deletions(-) delete mode 100644 app/src/main/kotlin/com/wire/android/ui/home/newconversation/SharedNewConversationViewModel.kt rename {app => core/ui-common}/src/main/kotlin/com/wire/android/model/SnackBarMessage.kt (100%) create mode 100644 features/meetings/src/main/java/com/wire/android/feature/meetings/navigation/MeetingNavigator.kt create mode 100644 features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingParticipantsScreen.kt create mode 100644 features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/TextListTruncationTransformation.kt create mode 100644 features/meetings/src/main/res/drawable/ic_expand.xml diff --git a/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt b/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt index a36646d21d0..88e259ca9df 100644 --- a/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt +++ b/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt @@ -30,13 +30,16 @@ import com.ramcosta.composedestinations.DestinationsNavHost import com.ramcosta.composedestinations.generated.app.destinations.ConversationScreenDestination import com.ramcosta.composedestinations.generated.app.destinations.NewLoginPasswordScreenDestination import com.ramcosta.composedestinations.generated.app.destinations.NewLoginVerificationCodeScreenDestination +import com.ramcosta.composedestinations.generated.app.destinations.OtherUserProfileScreenDestination import com.ramcosta.composedestinations.generated.app.navArgs +import com.ramcosta.composedestinations.generated.app.navgraphs.NewConversationGraph import com.ramcosta.composedestinations.generated.app.navgraphs.PersonalToTeamMigrationGraph -import com.ramcosta.composedestinations.generated.cells.destinations.SearchScreenDestination import com.ramcosta.composedestinations.generated.app.navgraphs.WireRootGraph import com.ramcosta.composedestinations.generated.app.navtype.groupConversationDetailsNavBackArgsNavType import com.ramcosta.composedestinations.generated.app.navtype.imagesPreviewNavBackArgsNavType import com.ramcosta.composedestinations.generated.app.navtype.mediaGalleryNavBackArgsNavType +import com.ramcosta.composedestinations.generated.cells.destinations.SearchScreenDestination +import com.ramcosta.composedestinations.generated.meetings.navgraphs.NewMeetingGraph import com.ramcosta.composedestinations.generated.sketch.destinations.DrawingCanvasScreenDestination import com.ramcosta.composedestinations.generated.sketch.navtype.drawingCanvasNavBackArgsNavType import com.ramcosta.composedestinations.manualcomposablecalls.composable @@ -47,11 +50,15 @@ import com.ramcosta.composedestinations.scope.resultBackNavigator import com.ramcosta.composedestinations.scope.resultRecipient import com.ramcosta.composedestinations.spec.Direction import com.wire.android.feature.cells.ui.cellViewModel +import com.wire.android.feature.meetings.navigation.MeetingNavigator +import com.wire.android.feature.meetings.ui.newMeetingViewModel import com.wire.android.feature.sketch.model.DrawingCanvasNavBackArgs import com.wire.android.navigation.transition.LocalSharedTransitionScope import com.wire.android.ui.authentication.loginEmailViewModel import com.wire.android.ui.home.conversations.ConversationScreen +import com.wire.android.ui.home.newConversationViewModel import com.wire.android.ui.home.settings.teamMigrationViewModel +import com.wire.kalium.logic.data.user.UserId @OptIn(ExperimentalAnimationApi::class, ExperimentalSharedTransitionApi::class) @Composable @@ -62,6 +69,14 @@ fun MainNavHost( modifier: Modifier = Modifier, ) { val navHostEngine = rememberWireNavHostEngine(Alignment.Center) + val meetingNavigator = remember(navigator) { + MeetingNavigator( + navigator = navigator, + navigateToProfile = { userId: UserId -> + navigator.navigate(NavigationCommand(OtherUserProfileScreenDestination(userId = userId))) + } + ) + } SharedTransitionLayout(modifier = modifier) { CompositionLocalProvider(LocalSharedTransitionScope provides this) { DestinationsNavHost( @@ -78,6 +93,17 @@ fun MainNavHost( // 👇 To make LoginTypeSelector available to all destinations as a non-navigation parameter if provided if (loginTypeSelector != null) dependency(loginTypeSelector) + // 👇 To tie NewConversationViewModel to nested NewConversationGraph, + // making it shared between all screens that belong to it + navGraph(NewConversationGraph) { + val parentEntry = remember(navBackStackEntry) { + navController.getBackStackEntry(NewConversationGraph.route) + } + dependency( + newConversationViewModel(parentEntry) + ) + } + // 👇 To reuse LoginEmailViewModel from NewLoginPasswordScreen on NewLoginVerificationCodeScreen destination(NewLoginVerificationCodeScreenDestination) { val loginPasswordEntry = remember(navBackStackEntry) { @@ -107,6 +133,20 @@ fun MainNavHost( } dependency(teamMigrationViewModel(parentEntry)) } + + // 👇 To tie NewMeetingViewModel to nested NewMeetingGraph, + // making it shared between all screens that belong to it + navGraph(NewMeetingGraph) { + val parentEntry = remember(navBackStackEntry) { + navController.getBackStackEntry(NewMeetingGraph.route) + } + dependency(newMeetingViewModel(parentEntry)) + } + + // 👇 To make MeetingNavigator available to all destinations from NewMeetingGraph as a non-navigation parameter + navGraph(NewMeetingGraph) { + dependency(meetingNavigator) + } }, manualComposableCallsBuilder = { /** diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/SharedNewConversationViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/SharedNewConversationViewModel.kt deleted file mode 100644 index cb00530d4b1..00000000000 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/SharedNewConversationViewModel.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Wire - * Copyright (C) 2026 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ -package com.wire.android.ui.home.newconversation - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import com.ramcosta.composedestinations.generated.app.navgraphs.NewConversationGraph -import com.wire.android.navigation.Navigator -import com.wire.android.ui.home.newConversationViewModel - -@Composable -fun sharedNewConversationViewModel(navigator: Navigator): NewConversationViewModel { - val navController = navigator.navController - val currentEntry = remember(navController) { - checkNotNull(navController.currentBackStackEntry) - } - val parentEntry = remember(currentEntry) { - runCatching { navController.getBackStackEntry(NewConversationGraph.route) }.getOrNull() - } - val rememberedParentEntry = remember { mutableStateOf(parentEntry) } - SideEffect { - parentEntry?.let { rememberedParentEntry.value = it } - } - return newConversationViewModel( - checkNotNull(parentEntry ?: rememberedParentEntry.value) { - "NewConversationGraph back stack entry is missing" - } - ) -} diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelaccess/ChannelAccessOnCreateScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelaccess/ChannelAccessOnCreateScreen.kt index 86cb741e965..f0405e1a770 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelaccess/ChannelAccessOnCreateScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelaccess/ChannelAccessOnCreateScreen.kt @@ -34,7 +34,7 @@ import com.wire.android.ui.common.dimensions import com.wire.android.ui.common.scaffold.WireScaffold import com.wire.android.ui.common.topappbar.NavigationIconType import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar -import com.wire.android.ui.home.newconversation.sharedNewConversationViewModel +import com.wire.android.ui.home.newconversation.NewConversationViewModel import com.wire.android.ui.theme.WireTheme import com.wire.android.ui.theme.wireColorScheme import com.wire.android.ui.theme.wireTypography @@ -44,8 +44,8 @@ import com.wire.android.util.ui.PreviewMultipleThemes @Composable fun ChannelAccessOnCreateScreen( navigator: Navigator, + newConversationViewModel: NewConversationViewModel, ) { - val newConversationViewModel = sharedNewConversationViewModel(navigator) WireScaffold( topBar = { WireCenterAlignedTopAppBar( diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelhistory/ChannelHistoryScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelhistory/ChannelHistoryScreen.kt index a31401dafad..d6feed0d9db 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelhistory/ChannelHistoryScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelhistory/ChannelHistoryScreen.kt @@ -17,19 +17,20 @@ */ package com.wire.android.ui.home.newconversation.channelhistory -import com.wire.android.navigation.annotation.app.WireNewConversationDestination import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import com.ramcosta.composedestinations.generated.app.destinations.ChannelHistoryCustomScreenDestination import com.ramcosta.composedestinations.result.NavResult import com.ramcosta.composedestinations.result.ResultRecipient import com.wire.android.R import com.wire.android.model.Clickable import com.wire.android.navigation.NavigationCommand import com.wire.android.navigation.Navigator +import com.wire.android.navigation.annotation.app.WireNewConversationDestination import com.wire.android.navigation.style.SlideNavigationAnimation import com.wire.android.ui.common.WirePromotionCard import com.wire.android.ui.common.colorsScheme @@ -38,10 +39,9 @@ import com.wire.android.ui.common.scaffold.WireScaffold import com.wire.android.ui.common.topappbar.NavigationIconType import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar import com.wire.android.ui.common.typography -import com.ramcosta.composedestinations.generated.app.destinations.ChannelHistoryCustomScreenDestination import com.wire.android.ui.home.conversations.details.options.ArrowType import com.wire.android.ui.home.conversations.details.options.GroupConversationOptionsItem -import com.wire.android.ui.home.newconversation.sharedNewConversationViewModel +import com.wire.android.ui.home.newconversation.NewConversationViewModel import com.wire.android.ui.theme.WireTheme import com.wire.android.util.ui.PreviewMultipleThemes @@ -52,9 +52,9 @@ import com.wire.android.util.ui.PreviewMultipleThemes fun ChannelHistoryScreen( navigator: Navigator, customResultRecipient: ResultRecipient, + newConversationViewModel: NewConversationViewModel, modifier: Modifier = Modifier, ) { - val newConversationViewModel = sharedNewConversationViewModel(navigator) customResultRecipient.onNavResult { result -> when (result) { is NavResult.Canceled -> {} diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupOptions/GroupOptionsScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupOptions/GroupOptionsScreen.kt index 39d3f9c8c7e..b0445b12e5f 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupOptions/GroupOptionsScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupOptions/GroupOptionsScreen.kt @@ -62,12 +62,12 @@ import com.ramcosta.composedestinations.generated.app.destinations.HomeScreenDes import com.ramcosta.composedestinations.generated.app.destinations.NewGroupConversationSearchPeopleScreenDestination import com.wire.android.ui.home.conversations.details.options.ArrowType import com.wire.android.ui.home.conversations.details.options.GroupConversationOptionsItem +import com.wire.android.ui.home.newconversation.NewConversationViewModel import com.wire.android.ui.home.newconversation.channelaccess.ChannelAccessType import com.wire.android.ui.home.newconversation.channelhistory.ChannelHistoryType import com.wire.android.ui.home.newconversation.channelhistory.name import com.wire.android.ui.home.newconversation.common.CreateGroupErrorDialog import com.wire.android.ui.home.newconversation.common.CreateGroupState -import com.wire.android.ui.home.newconversation.sharedNewConversationViewModel import com.wire.android.ui.home.settings.SwitchState import com.wire.android.ui.theme.WireTheme import com.wire.android.ui.theme.wireColorScheme @@ -83,8 +83,8 @@ import com.wire.kalium.logic.feature.featureConfig.AppsAllowedResult @Composable fun GroupOptionScreen( navigator: Navigator, + newConversationViewModel: NewConversationViewModel, ) { - val newConversationViewModel = sharedNewConversationViewModel(navigator) fun navigateToGroup(conversationId: ConversationId): Unit = navigator.navigate(NavigationCommand(ConversationScreenDestination(conversationId), BackStackMode.REMOVE_CURRENT_NESTED_GRAPH)) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupname/NewGroupNameScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupname/NewGroupNameScreen.kt index eae43669c34..b3f947a2bfe 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupname/NewGroupNameScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupname/NewGroupNameScreen.kt @@ -32,9 +32,9 @@ import com.ramcosta.composedestinations.generated.app.destinations.ConversationS import com.ramcosta.composedestinations.generated.app.destinations.GroupOptionScreenDestination import com.ramcosta.composedestinations.generated.app.destinations.HomeScreenDestination import com.ramcosta.composedestinations.generated.app.destinations.NewGroupConversationSearchPeopleScreenDestination +import com.wire.android.ui.home.newconversation.NewConversationViewModel import com.wire.android.ui.home.newconversation.common.CreateGroupErrorDialog import com.wire.android.ui.home.newconversation.common.CreateGroupState -import com.wire.android.ui.home.newconversation.sharedNewConversationViewModel import com.wire.android.ui.theme.WireTheme import com.wire.android.util.ui.PreviewMultipleThemes import com.wire.kalium.logic.data.id.ConversationId @@ -43,8 +43,8 @@ import com.wire.kalium.logic.data.id.ConversationId @Composable fun NewGroupNameScreen( navigator: Navigator, + newConversationViewModel: NewConversationViewModel, ) { - val newConversationViewModel = sharedNewConversationViewModel(navigator) fun navigateToGroup(conversationId: ConversationId): Unit = navigator.navigate(NavigationCommand(ConversationScreenDestination(conversationId), BackStackMode.REMOVE_CURRENT_NESTED_GRAPH)) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupsearch/NewGroupConversationSearchPeopleScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupsearch/NewGroupConversationSearchPeopleScreen.kt index f4354d2ca8c..3c47a0dfb9f 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupsearch/NewGroupConversationSearchPeopleScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupsearch/NewGroupConversationSearchPeopleScreen.kt @@ -32,16 +32,16 @@ import com.ramcosta.composedestinations.generated.app.destinations.OtherUserProf import com.wire.android.model.ItemActionType import com.wire.android.search.SearchUsersAndAppsScreen import com.wire.android.ui.common.topappbar.NavigationIconType +import com.wire.android.ui.home.newconversation.NewConversationViewModel import com.wire.android.ui.home.newconversation.common.ContinueButton -import com.wire.android.ui.home.newconversation.sharedNewConversationViewModel import com.wire.kalium.logic.data.id.QualifiedID @WireNewConversationDestination @Composable fun NewGroupConversationSearchPeopleScreen( navigator: Navigator, + newConversationViewModel: NewConversationViewModel, ) { - val newConversationViewModel = sharedNewConversationViewModel(navigator) val onBackClicked = remember(Unit) { { newConversationViewModel.resetState() diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/search/NewConversationSearchPeopleScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/search/NewConversationSearchPeopleScreen.kt index 13b292029a8..641f20261e8 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/search/NewConversationSearchPeopleScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/search/NewConversationSearchPeopleScreen.kt @@ -35,8 +35,8 @@ import com.ramcosta.composedestinations.generated.app.destinations.ServiceDetail import com.wire.android.model.ItemActionType import com.wire.android.search.SearchUsersAndAppsScreen import com.wire.android.ui.common.topappbar.NavigationIconType +import com.wire.android.ui.home.newconversation.NewConversationViewModel import com.wire.android.ui.home.newconversation.common.CreateRegularGroupOrChannelButtons -import com.wire.android.ui.home.newconversation.sharedNewConversationViewModel import com.wire.android.ui.userprofile.service.ServiceDetailsNavArgs import com.wire.kalium.logic.data.id.QualifiedID import com.wire.kalium.logic.data.user.BotService @@ -50,8 +50,8 @@ import com.wire.kalium.logic.feature.featureConfig.AppsAllowedResult @Composable fun NewConversationSearchPeopleScreen( navigator: Navigator, + newConversationViewModel: NewConversationViewModel, ) { - val newConversationViewModel = sharedNewConversationViewModel(navigator) val showCreateTeamDialog = remember { mutableStateOf(false) } SearchUsersAndAppsScreen( searchTitle = stringResource(id = R.string.label_new_conversation), diff --git a/core/di/src/main/kotlin/com/wire/android/di/ViewModelScoped.kt b/core/di/src/main/kotlin/com/wire/android/di/ViewModelScoped.kt index e0bc634005c..74d0ee7e152 100644 --- a/core/di/src/main/kotlin/com/wire/android/di/ViewModelScoped.kt +++ b/core/di/src/main/kotlin/com/wire/android/di/ViewModelScoped.kt @@ -171,6 +171,12 @@ interface ScopedArgs { @Stable interface PreviewProvider { val previews: List get() = emptyList() + + companion object { + fun of(vararg previews: Any) = object : PreviewProvider { + override val previews: List = previews.toList() + } + } } object EmptyPreviewProvider : PreviewProvider diff --git a/core/di/src/main/kotlin/com/wire/android/di/metro/MetroViewModelGraph.kt b/core/di/src/main/kotlin/com/wire/android/di/metro/MetroViewModelGraph.kt index ff6a3d0caee..2caf1227340 100644 --- a/core/di/src/main/kotlin/com/wire/android/di/metro/MetroViewModelGraph.kt +++ b/core/di/src/main/kotlin/com/wire/android/di/metro/MetroViewModelGraph.kt @@ -112,9 +112,13 @@ inline fun sessionKeyedMetroViewModelAs( inline fun sessionKeyedAssistedMetroViewModel( key: String? = null, previewProvider: PreviewProvider = EmptyPreviewProvider, + viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { + "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" + }, crossinline createViewModel: Factory.() -> VM, ): VM where VM : ViewModel, Factory : ManualViewModelAssistedFactory = previewProvider.findPreviewOr { assistedMetroViewModel( + viewModelStoreOwner = viewModelStoreOwner, key = sessionKeyedMetroViewModelKey( defaultKey = VM::class.qualifiedName, key = key, @@ -137,9 +141,13 @@ inline fun sessionKeyedAssistedMetroViewModel( inline fun sessionKeyedAssistedMetroViewModelAs( key: String? = null, previewProvider: PreviewProvider = EmptyPreviewProvider, + viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { + "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" + }, crossinline createViewModel: Factory.() -> VM, ): S where VM : ViewModel, VM : S, Factory : ManualViewModelAssistedFactory = previewProvider.findPreviewOr { assistedMetroViewModel( + viewModelStoreOwner = viewModelStoreOwner, key = sessionKeyedMetroViewModelKey( defaultKey = VM::class.qualifiedName, key = key, diff --git a/core/search/src/main/kotlin/com/wire/android/model/Contact.kt b/core/search/src/main/kotlin/com/wire/android/model/Contact.kt index a08d1d7573c..f2eac30ca9c 100644 --- a/core/search/src/main/kotlin/com/wire/android/model/Contact.kt +++ b/core/search/src/main/kotlin/com/wire/android/model/Contact.kt @@ -17,9 +17,11 @@ */ package com.wire.android.model +import androidx.compose.runtime.Stable import com.wire.android.ui.home.conversationslist.model.Membership import com.wire.kalium.logic.data.user.ConnectionState +@Stable data class Contact( val id: String, val domain: String, diff --git a/core/search/src/main/kotlin/com/wire/android/search/SearchMetroViewModelBindings.kt b/core/search/src/main/kotlin/com/wire/android/search/SearchMetroViewModelBindings.kt index a5311e998a8..9b29cdf54aa 100644 --- a/core/search/src/main/kotlin/com/wire/android/search/SearchMetroViewModelBindings.kt +++ b/core/search/src/main/kotlin/com/wire/android/search/SearchMetroViewModelBindings.kt @@ -35,8 +35,8 @@ object SearchMetroViewModelBindings { @ManualViewModelAssistedFactoryKey(SearchManualViewModelFactory::class) fun searchManualViewModelFactory(factory: SearchViewModelFactory): ManualViewModelAssistedFactory = object : SearchManualViewModelFactory { - override fun searchUserViewModel(conversationId: ConversationId?): SearchUserViewModel = - factory.searchUserViewModel(conversationId) + override fun searchUserViewModel(conversationId: ConversationId?, onlyConnectedContacts: Boolean): SearchUserViewModel = + factory.searchUserViewModel(conversationId, onlyConnectedContacts) override fun searchAppsViewModel(protocolInfo: Conversation.ProtocolInfo?): SearchAppsViewModel = factory.searchAppsViewModel(protocolInfo) diff --git a/core/search/src/main/kotlin/com/wire/android/search/SearchUsersAndAppsScreen.kt b/core/search/src/main/kotlin/com/wire/android/search/SearchUsersAndAppsScreen.kt index 97736889719..10ce5301906 100644 --- a/core/search/src/main/kotlin/com/wire/android/search/SearchUsersAndAppsScreen.kt +++ b/core/search/src/main/kotlin/com/wire/android/search/SearchUsersAndAppsScreen.kt @@ -72,6 +72,7 @@ import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar import com.wire.android.ui.common.topappbar.search.SearchTopBar import com.wire.android.util.ui.UIText import com.wire.kalium.logic.data.conversation.Conversation +import com.wire.kalium.logic.data.id.ConversationId import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentSetOf import kotlinx.coroutines.launch @@ -83,12 +84,12 @@ fun SearchUsersAndAppsScreen( searchTitle: String, selectedContacts: ImmutableSet, onContactChecked: (Boolean, Contact) -> Unit, - onOpenUserProfile: (Contact) -> Unit, - onAppClicked: (Contact) -> Unit, onClose: () -> Unit, navigationIconType: NavigationIconType, itemActionType: ItemActionType, modifier: Modifier = Modifier, + conversationId: ConversationId? = null, + onlyConnectedContacts: Boolean = false, shouldHideBottomActionForSearch: Boolean = false, shouldHideBottomActionForServices: Boolean = false, isAppsTabVisible: Boolean = false, @@ -96,6 +97,8 @@ fun SearchUsersAndAppsScreen( initialPage: SearchPeopleTabItem = SearchPeopleTabItem.PEOPLE, conversationProtocol: Conversation.ProtocolInfo? = null, peopleBottomActions: (@Composable (FocusRequester) -> Unit)? = null, + onOpenUserProfile: (Contact) -> Unit = {}, + onAppClicked: (Contact) -> Unit = {}, ) { val searchBarState = rememberSearchbarState() val scope = rememberCoroutineScope() @@ -211,6 +214,8 @@ fun SearchUsersAndAppsScreen( when (tabs[pageIndex]) { SearchPeopleTabItem.PEOPLE -> { SearchAllPeopleOrContactsScreen( + conversationId = conversationId, + onlyConnectedContacts = onlyConnectedContacts, searchQuery = searchBarState.searchQueryTextState.text.toString(), contactsSelected = selectedContacts, onOpenUserProfile = onOpenUserProfile, @@ -268,7 +273,9 @@ private fun SearchAllPeopleOrContactsScreen( actionType: ItemActionType, onOpenUserProfile: (Contact) -> Unit, onContactChecked: (Boolean, Contact) -> Unit, - searchUserViewModel: SearchUserViewModel = searchUserViewModel(), + conversationId: ConversationId? = null, + onlyConnectedContacts: Boolean = false, + searchUserViewModel: SearchUserViewModel = searchUserViewModel(conversationId, onlyConnectedContacts), lazyListState: LazyListState = rememberLazyListState(), firstContactFocusRequester: FocusRequester? = null, nextFocusRequester: FocusRequester? = null, diff --git a/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelFactory.kt b/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelFactory.kt index 8622337dd64..79d418ef391 100644 --- a/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelFactory.kt +++ b/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelFactory.kt @@ -52,8 +52,12 @@ class SearchViewModelFactory @Inject constructor( private val observeIsAppsAllowedForUsage: ObserveIsAppsAllowedForUsageUseCase, private val observeSelfUser: ObserveSelfUserUseCase, ) { - fun searchUserViewModel(conversationId: ConversationId? = null) = SearchUserViewModel( + fun searchUserViewModel( + conversationId: ConversationId? = null, + onlyConnectedContacts: Boolean = false, + ) = SearchUserViewModel( conversationId = conversationId, + onlyConnectedContacts = onlyConnectedContacts, searchUserUseCase = searchUsers, searchByHandleUseCase = searchByHandle, contactMapper = contactMapper, diff --git a/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelGraph.kt b/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelGraph.kt index 1284ab88919..3c270a9fa87 100644 --- a/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelGraph.kt +++ b/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelGraph.kt @@ -28,16 +28,27 @@ import com.wire.kalium.logic.data.id.ConversationId import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactory interface SearchManualViewModelFactory : ManualViewModelAssistedFactory { - fun searchUserViewModel(conversationId: ConversationId? = null): SearchUserViewModel + fun searchUserViewModel( + conversationId: ConversationId? = null, + onlyConnectedContacts: Boolean = false, + ): SearchUserViewModel + fun searchAppsViewModel(protocolInfo: Conversation.ProtocolInfo? = null): SearchAppsViewModel } @Composable -fun searchUserViewModel(conversationId: ConversationId? = null): SearchUserViewModel = +fun searchUserViewModel( + conversationId: ConversationId? = null, + onlyConnectedContacts: Boolean = false, +): SearchUserViewModel = sessionKeyedAssistedMetroViewModel( - key = conversationId?.let { "search_user_conversation_id_$it" } ?: "search_user" + key = listOfNotNull( + "search_user", + if (onlyConnectedContacts) "only_connected_contacts" else null, + if (conversationId != null) "conversation_id_${conversationId.value}" else null + ).joinToString("_") ) { - searchUserViewModel(conversationId) + searchUserViewModel(conversationId, onlyConnectedContacts) } @Composable diff --git a/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt b/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt index 03dd8f742b8..e151cb9b0f9 100644 --- a/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt +++ b/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt @@ -50,6 +50,7 @@ import kotlinx.coroutines.launch class SearchUserViewModel( private val conversationId: ConversationId?, + private val onlyConnectedContacts: Boolean, private val searchUserUseCase: SearchUsersUseCase, private val searchByHandleUseCase: SearchByHandleUseCase, private val contactMapper: ContactMapper, @@ -142,6 +143,7 @@ class SearchUserViewModel( searchByHandleUseCase( searchTerm, excludingConversation = conversationId, + excludingRemote = onlyConnectedContacts, customDomain = domain ) @@ -149,6 +151,7 @@ class SearchUserViewModel( searchUserUseCase( searchTerm, excludingMembersOfConversation = conversationId, + excludingRemote = onlyConnectedContacts, customDomain = domain ) } diff --git a/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt b/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt index 9cffec1ec6d..248d6a9a4ff 100644 --- a/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt +++ b/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt @@ -328,6 +328,90 @@ class SearchUserViewModelTest { assertEquals(persistentListOf(), viewModel.state.contactsResult) } + @Test + fun `given only connected contacts is false, when searching by handle, then do not exclude remote`() = runTest { + val query = "handle" + val (arrangement, viewModel) = Arrangement() + .withOnlyConnectedContacts(false) + .withSearchByHandleResult(SearchUserResult(connected = listOf(), notConnected = listOf())) + .withFederatedSearchParserResult(FederatedSearchParser.Result(searchTerm = query, domain = "domain")) + .withIsValidHandleResult(ValidateUserHandleResult.Valid("")) + .arrange() + + viewModel.searchQueryChanged(query) + coVerify(exactly = 1) { + arrangement.searchByHandleUseCase.invoke( + searchHandle = query, + excludingConversation = null, + excludingRemote = false, + customDomain = "domain" + ) + } + } + + @Test + fun `given only connected contacts is true, when searching by handle, then exclude remote`() = runTest { + val query = "handle" + val (arrangement, viewModel) = Arrangement() + .withOnlyConnectedContacts(true) + .withSearchByHandleResult(SearchUserResult(connected = listOf(), notConnected = listOf())) + .withFederatedSearchParserResult(FederatedSearchParser.Result(searchTerm = query, domain = "domain")) + .withIsValidHandleResult(ValidateUserHandleResult.Valid("")) + .arrange() + + viewModel.searchQueryChanged(query) + coVerify(exactly = 1) { + arrangement.searchByHandleUseCase.invoke( + searchHandle = query, + excludingConversation = null, + excludingRemote = true, + customDomain = "domain" + ) + } + } + + @Test + fun `given only connected contacts is false, when searching by name, then do not exclude remote`() = runTest { + val query = "Name" + val (arrangement, viewModel) = Arrangement() + .withOnlyConnectedContacts(false) + .withSearchResult(SearchUserResult(connected = listOf(), notConnected = listOf())) + .withFederatedSearchParserResult(FederatedSearchParser.Result(searchTerm = query, domain = "domain")) + .withIsValidHandleResult(ValidateUserHandleResult.Invalid.InvalidCharacters("ame", listOf('N'))) + .arrange() + + viewModel.searchQueryChanged(query) + coVerify(exactly = 1) { + arrangement.searchUsersUseCase.invoke( + searchQuery = query, + excludingMembersOfConversation = null, + excludingRemote = false, + customDomain = "domain" + ) + } + } + + @Test + fun `given only connected contacts is true, when searching by name, then exclude remote`() = runTest { + val query = "Name" + val (arrangement, viewModel) = Arrangement() + .withOnlyConnectedContacts(true) + .withSearchResult(SearchUserResult(connected = listOf(), notConnected = listOf())) + .withFederatedSearchParserResult(FederatedSearchParser.Result(searchTerm = query, domain = "domain")) + .withIsValidHandleResult(ValidateUserHandleResult.Invalid.InvalidCharacters("ame", listOf('N'))) + .arrange() + + viewModel.searchQueryChanged(query) + coVerify(exactly = 1) { + arrangement.searchUsersUseCase.invoke( + searchQuery = query, + excludingMembersOfConversation = null, + excludingRemote = true, + customDomain = "domain" + ) + } + } + private class Arrangement { @MockK @@ -350,6 +434,8 @@ class SearchUserViewModelTest { private var conversationId: ConversationId? = null + private var onlyConnectedContacts: Boolean = false + init { MockKAnnotations.init(this, relaxUnitFun = true) every { contactMapper.fromSearchUserResult(any()) } answers { @@ -393,8 +479,12 @@ class SearchUserViewModelTest { this.conversationId = conversationId } + fun withOnlyConnectedContacts(onlyConnectedContacts: Boolean) = apply { + this.onlyConnectedContacts = onlyConnectedContacts + } + fun withSearchResult(result: SearchUserResult) = apply { - coEvery { searchUsersUseCase(any(), any(), any()) } returns result + coEvery { searchUsersUseCase(any(), any(), any(), any()) } returns result } fun withFederatedSearchParserResult(result: FederatedSearchParser.Result) = apply { @@ -406,7 +496,7 @@ class SearchUserViewModelTest { } fun withSearchByHandleResult(result: SearchUserResult) = apply { - coEvery { searchByHandleUseCase(any(), any(), any()) } returns result + coEvery { searchByHandleUseCase(any(), any(), any(), any()) } returns result } fun withIsFederationSearchAllowedResult(isAllowed: Boolean = true) = apply { @@ -418,6 +508,7 @@ class SearchUserViewModelTest { fun arrange() = apply { searchUserViewModel = SearchUserViewModel( conversationId = conversationId, + onlyConnectedContacts = onlyConnectedContacts, searchUserUseCase = searchUsersUseCase, searchByHandleUseCase = searchByHandleUseCase, contactMapper = contactMapper, diff --git a/app/src/main/kotlin/com/wire/android/model/SnackBarMessage.kt b/core/ui-common/src/main/kotlin/com/wire/android/model/SnackBarMessage.kt similarity index 100% rename from app/src/main/kotlin/com/wire/android/model/SnackBarMessage.kt rename to core/ui-common/src/main/kotlin/com/wire/android/model/SnackBarMessage.kt diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextField.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextField.kt index 417c694be26..648da699a16 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextField.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextField.kt @@ -53,6 +53,7 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import com.wire.android.ui.common.R import com.wire.android.ui.theme.WireTheme @@ -90,6 +91,7 @@ fun WireTextField( colors: WireTextFieldColors = wireTextFieldColors(), onSelectedLineIndexChanged: (Int) -> Unit = { }, onLineBottomYCoordinateChanged: (Float) -> Unit = { }, + onInputSizeChanged: (IntSize) -> Unit = { }, onTap: (() -> Unit)? = null, testTag: String = String.EMPTY, validateKeyboardOptions: Boolean = true, @@ -132,6 +134,7 @@ fun WireTextField( textState::setTextAndPlaceCursorAtEnd ) ), + onInputSizeChanged = onInputSizeChanged, onTap = onTap, testTag = testTag, innerBasicTextField = { decorator, textFieldModifier -> diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextFieldLayout.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextFieldLayout.kt index 3071754dedb..c84cddc8b4e 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextFieldLayout.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextFieldLayout.kt @@ -38,7 +38,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.clearAndSetSemantics @@ -48,7 +50,9 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntSize import com.wire.android.ui.common.Tint +import com.wire.android.ui.common.clickable import com.wire.android.ui.common.dimensions import com.wire.android.ui.theme.wireDimensions import com.wire.android.ui.theme.wireTypography @@ -81,6 +85,7 @@ internal fun WireTextFieldLayout( inputMinHeight: Dp = MaterialTheme.wireDimensions.textFieldMinHeight, shape: Shape = RoundedCornerShape(MaterialTheme.wireDimensions.textFieldCornerSize), colors: WireTextFieldColors = wireTextFieldColors(), + onInputSizeChanged: (IntSize) -> Unit = { }, onTap: (() -> Unit)? = null, testTag: String = String.EMPTY ) { @@ -105,9 +110,14 @@ internal fun WireTextFieldLayout( style = state, placeholderTextStyle = placeholderTextStyle, placeholderAlignment = placeholderAlignment, - inputMinHeight = inputMinHeight, colors = colors, - onTap = onTap, + onInputSizeChanged = onInputSizeChanged, + modifier = Modifier + .heightIn(min = inputMinHeight) + .clip(shape) + .let { + if (onTap != null) it.clickable(onClick = onTap) else it + } ) }, textFieldModifier = Modifier @@ -148,25 +158,19 @@ internal fun WireTextFieldLayout( private fun InnerTextLayout( innerTextField: @Composable () -> Unit, shouldShowPlaceholder: Boolean, + modifier: Modifier = Modifier, leadingIcon: @Composable (() -> Unit)? = null, trailingIcon: @Composable (() -> Unit)? = null, placeholderText: String? = null, style: WireTextFieldState = WireTextFieldState.Default, placeholderTextStyle: TextStyle = MaterialTheme.wireTypography.body01, placeholderAlignment: Alignment.Horizontal = Alignment.Start, - inputMinHeight: Dp = dimensions().spacing48x, colors: WireTextFieldColors = wireTextFieldColors(), - onTap: (() -> Unit)? = null + onInputSizeChanged: (IntSize) -> Unit = { }, ) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .heightIn(min = inputMinHeight) - .then( - onTap?.let { - Modifier.clickable { onTap() } - } ?: Modifier - ) + modifier = modifier, ) { val trailingOrStateIcon: @Composable (() -> Unit)? = when { trailingIcon != null -> trailingIcon @@ -207,7 +211,9 @@ private fun InnerTextLayout( ) } Box( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .onSizeChanged(onInputSizeChanged), propagateMinConstraints = true ) { innerTextField() diff --git a/core/ui-common/src/main/res/values/strings.xml b/core/ui-common/src/main/res/values/strings.xml index 3eda786f858..c6b30d5517c 100644 --- a/core/ui-common/src/main/res/values/strings.xml +++ b/core/ui-common/src/main/res/values/strings.xml @@ -123,4 +123,5 @@ unselect Show More Show Less + Select diff --git a/features/meetings/build.gradle.kts b/features/meetings/build.gradle.kts index 958c9eafaa2..f57bb6555dc 100644 --- a/features/meetings/build.gradle.kts +++ b/features/meetings/build.gradle.kts @@ -13,8 +13,9 @@ plugins { dependencies { implementation("com.wire.kalium:kalium-common") implementation("com.wire.kalium:kalium-logic") - implementation(project(":core:di")) - implementation(project(":core:ui-common")) + implementation(projects.core.di) + implementation(projects.core.uiCommon) + implementation(projects.core.search) implementation(libs.androidx.core) implementation(libs.androidx.appcompat) implementation(libs.ktx.immutableCollections) diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/navigation/MeetingNavigator.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/navigation/MeetingNavigator.kt new file mode 100644 index 00000000000..f30b4a4ede6 --- /dev/null +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/navigation/MeetingNavigator.kt @@ -0,0 +1,30 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.feature.meetings.navigation + +import com.wire.android.navigation.WireNavigator +import com.wire.kalium.logic.data.user.UserId + +/** + * Navigator for the meetings feature. It extends [WireNavigator] and adds meeting-specific navigation functions that allows navigating to + * different screens from other modules without needing to know about the implementation details of the whole navigation system. + */ +class MeetingNavigator( + val navigator: WireNavigator, + val navigateToProfile: (userId: UserId) -> Unit +) : WireNavigator by navigator diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsMetroViewModelBindings.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsMetroViewModelBindings.kt index 22d5dbeb02b..36ae5ac23b6 100644 --- a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsMetroViewModelBindings.kt +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsMetroViewModelBindings.kt @@ -18,7 +18,8 @@ package com.wire.android.feature.meetings.ui import androidx.lifecycle.ViewModel -import com.wire.android.feature.meetings.ui.create.NewMeetingType +import androidx.lifecycle.createSavedStateHandle +import androidx.lifecycle.viewmodel.CreationExtras import com.wire.android.feature.meetings.ui.create.NewMeetingViewModelImpl import com.wire.android.feature.meetings.ui.list.MeetingListViewModelImpl import com.wire.android.feature.meetings.ui.options.MeetingOptionsMenuViewModelImpl @@ -27,6 +28,8 @@ import dev.zacsweers.metro.IntoMap import dev.zacsweers.metro.Provides import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactory import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactoryKey +import dev.zacsweers.metrox.viewmodel.ViewModelAssistedFactory +import dev.zacsweers.metrox.viewmodel.ViewModelAssistedFactoryKey import dev.zacsweers.metrox.viewmodel.ViewModelKey @BindingContainer @@ -39,9 +42,6 @@ object MeetingsMetroViewModelBindings { object : MeetingsManualViewModelFactory { override fun meetingListViewModel(type: MeetingsTabItem): MeetingListViewModelImpl = factory.meetingListViewModel(type) - - override fun newMeetingViewModel(type: NewMeetingType): NewMeetingViewModelImpl = - factory.newMeetingViewModel(type) } @Provides @@ -49,4 +49,13 @@ object MeetingsMetroViewModelBindings { @ViewModelKey(MeetingOptionsMenuViewModelImpl::class) fun meetingOptionsMenuViewModel(factory: MeetingsViewModelFactory): ViewModel = factory.meetingOptionsMenuViewModel() + + @Provides + @IntoMap + @ViewModelAssistedFactoryKey(NewMeetingViewModelImpl::class) + fun newMeetingViewModel(factory: MeetingsViewModelFactory): ViewModelAssistedFactory = + object : ViewModelAssistedFactory { + override fun create(extras: CreationExtras): ViewModel = + factory.newMeetingViewModel(extras.createSavedStateHandle()) + } } diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsViewModelFactory.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsViewModelFactory.kt index 62065767f3b..6fb88d571c3 100644 --- a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsViewModelFactory.kt +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsViewModelFactory.kt @@ -17,7 +17,7 @@ */ package com.wire.android.feature.meetings.ui -import com.wire.android.feature.meetings.ui.create.NewMeetingType +import androidx.lifecycle.SavedStateHandle import com.wire.android.feature.meetings.ui.create.NewMeetingViewModelImpl import com.wire.android.feature.meetings.ui.list.MeetingListViewModelImpl import com.wire.android.feature.meetings.ui.options.MeetingOptionsMenuViewModelImpl @@ -42,5 +42,5 @@ class MeetingsViewModelFactory @Inject constructor( internal fun meetingOptionsMenuViewModel() = MeetingOptionsMenuViewModelImpl(getMeeting = getMeeting) - internal fun newMeetingViewModel(type: NewMeetingType) = NewMeetingViewModelImpl(type) + internal fun newMeetingViewModel(savedStateHandle: SavedStateHandle) = NewMeetingViewModelImpl(savedStateHandle) } diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsViewModelGraph.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsViewModelGraph.kt index 34b05c72cb7..dbfd39147ca 100644 --- a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsViewModelGraph.kt +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/MeetingsViewModelGraph.kt @@ -20,11 +20,15 @@ package com.wire.android.feature.meetings.ui import androidx.compose.runtime.Composable -import com.wire.android.di.metro.sessionKeyedAssistedMetroViewModel -import com.wire.android.di.metro.sessionKeyedMetroViewModel +import androidx.lifecycle.ViewModelStoreOwner +import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner +import com.wire.android.di.PreviewProvider +import com.wire.android.di.metro.sessionKeyedAssistedMetroViewModelAs +import com.wire.android.di.metro.sessionKeyedMetroViewModelAs import com.wire.android.feature.meetings.ui.create.NewMeetingType import com.wire.android.feature.meetings.ui.create.NewMeetingViewModel import com.wire.android.feature.meetings.ui.create.NewMeetingViewModelImpl +import com.wire.android.feature.meetings.ui.create.NewMeetingViewModelPreview import com.wire.android.feature.meetings.ui.list.MeetingListViewModel import com.wire.android.feature.meetings.ui.list.MeetingListViewModelImpl import com.wire.android.feature.meetings.ui.options.MeetingOptionsMenuViewModel @@ -33,14 +37,13 @@ import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactory interface MeetingsManualViewModelFactory : ManualViewModelAssistedFactory { fun meetingListViewModel(type: MeetingsTabItem): MeetingListViewModelImpl - fun newMeetingViewModel(type: NewMeetingType): NewMeetingViewModelImpl } @Composable fun meetingListViewModel( type: MeetingsTabItem, ): MeetingListViewModel = - sessionKeyedAssistedMetroViewModel( + sessionKeyedAssistedMetroViewModelAs( key = "meeting_list_${type.name}", ) { meetingListViewModel(type) @@ -48,12 +51,15 @@ fun meetingListViewModel( @Composable fun meetingOptionsMenuListViewModel(): MeetingOptionsMenuViewModel = - sessionKeyedMetroViewModel() + sessionKeyedMetroViewModelAs() @Composable -fun newMeetingViewModel(type: NewMeetingType): NewMeetingViewModel = - sessionKeyedAssistedMetroViewModel( - key = "new_meeting_${type.name}", - ) { - newMeetingViewModel(type) - } +fun newMeetingViewModel( + viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { + "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" + }, +): NewMeetingViewModel = + sessionKeyedMetroViewModelAs( + viewModelStoreOwner = viewModelStoreOwner, + previewProvider = PreviewProvider.of(NewMeetingViewModelPreview(NewMeetingType.Schedule)), + ) diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingParticipantsScreen.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingParticipantsScreen.kt new file mode 100644 index 00000000000..6dd88f4ab26 --- /dev/null +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingParticipantsScreen.kt @@ -0,0 +1,110 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.feature.meetings.ui.create + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.Dp +import com.wire.android.feature.meetings.R +import com.wire.android.feature.meetings.navigation.MeetingNavigator +import com.wire.android.model.ItemActionType +import com.wire.android.navigation.annotation.features.meetings.WireNewMeetingDestination +import com.wire.android.navigation.style.PopUpNavigationAnimation +import com.wire.android.search.SearchUsersAndAppsScreen +import com.wire.android.ui.common.button.WireButtonState +import com.wire.android.ui.common.button.WirePrimaryButton +import com.wire.android.ui.common.dimensions +import com.wire.android.ui.common.topappbar.NavigationIconType +import com.wire.android.ui.theme.wireColorScheme +import com.wire.android.ui.theme.wireDimensions +import com.wire.kalium.logic.data.user.UserId +import com.wire.android.ui.common.R as commonR + +@WireNewMeetingDestination( + style = PopUpNavigationAnimation::class, +) +@Composable +fun NewMeetingParticipantsScreen( + navigator: MeetingNavigator, + newMeetingViewModel: NewMeetingViewModel, +) { + SearchUsersAndAppsScreen( + onlyConnectedContacts = true, + searchTitle = stringResource(R.string.new_meeting_participants_title), + selectedContacts = newMeetingViewModel.state.selectedContacts, + onContactChecked = newMeetingViewModel::updateSelectedContact, + onClose = { + newMeetingViewModel.resetSelectedContacts() + navigator.navigateBack() + }, + navigationIconType = NavigationIconType.Back(R.string.content_description_new_meeting_participants_back_icon), + itemActionType = ItemActionType.CHECK, + isAppsTabVisible = false, + onOpenUserProfile = { contact -> + navigator.navigateToProfile(UserId(contact.id, contact.domain)) + }, + peopleBottomActions = { focusRequester -> + SelectButton( + onClick = { + newMeetingViewModel.confirmSelectedContacts() + navigator.navigateBack() + }, + buttonModifier = Modifier.focusRequester(focusRequester), + ) + } + ) +} + +@Composable +private fun SelectButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + buttonModifier: Modifier = Modifier, + leadingIcon: @Composable (() -> Unit)? = null, + elevation: Dp = MaterialTheme.wireDimensions.bottomNavigationShadowElevation +) { + Surface( + color = MaterialTheme.wireColorScheme.background, + shadowElevation = elevation + ) { + Row( + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + modifier = modifier + .padding(horizontal = dimensions().spacing16x) + .height(dimensions().groupButtonHeight) + ) { + WirePrimaryButton( + text = stringResource(commonR.string.label_select), + leadingIcon = leadingIcon, + onClick = onClick, + state = WireButtonState.Default, + modifier = buttonModifier, + ) + } + } +} diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingScreen.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingScreen.kt index 69a6ac095f5..51bafd687b4 100644 --- a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingScreen.kt +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingScreen.kt @@ -17,38 +17,72 @@ */ package com.wire.android.feature.meetings.ui.create +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.input.InputTransformation import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.foundation.text.input.clearText import androidx.compose.foundation.text.input.rememberTextFieldState +import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.platform.LocalResources +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.rememberTextMeasurer +import com.ramcosta.composedestinations.generated.meetings.destinations.NewMeetingParticipantsScreenDestination import com.wire.android.feature.meetings.R -import com.wire.android.feature.meetings.ui.newMeetingViewModel +import com.wire.android.feature.meetings.ui.create.NewMeetingViewModel.Companion.MEETING_NAME_MAX_COUNT import com.wire.android.feature.meetings.ui.util.PreviewMultipleThemes +import com.wire.android.model.Contact +import com.wire.android.navigation.NavigationCommand import com.wire.android.navigation.WireNavigator import com.wire.android.navigation.annotation.features.meetings.WireNewMeetingDestination import com.wire.android.navigation.style.PopUpNavigationAnimation +import com.wire.android.ui.common.HandleActions +import com.wire.android.ui.common.animation.ShakeAnimation import com.wire.android.ui.common.button.WireButtonState import com.wire.android.ui.common.button.WirePrimaryButton +import com.wire.android.ui.common.colorsScheme import com.wire.android.ui.common.dimensions import com.wire.android.ui.common.scaffold.WireScaffold +import com.wire.android.ui.common.spacers.VerticalSpace import com.wire.android.ui.common.textfield.DefaultEmailDone +import com.wire.android.ui.common.textfield.DefaultText import com.wire.android.ui.common.textfield.WireTextField +import com.wire.android.ui.common.textfield.WireTextFieldState +import com.wire.android.ui.common.textfield.maxLengthWithCallback import com.wire.android.ui.common.topappbar.NavigationIconType import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar +import com.wire.android.ui.common.typography +import com.wire.android.ui.home.conversationslist.model.Membership import com.wire.android.ui.theme.WireTheme import com.wire.android.ui.theme.wireColorScheme import com.wire.android.ui.theme.wireDimensions +import com.wire.kalium.logic.data.user.ConnectionState +import kotlinx.collections.immutable.ImmutableSet +import kotlinx.collections.immutable.toPersistentSet +import com.wire.android.ui.common.R as commonR @WireNewMeetingDestination( start = true, @@ -59,24 +93,37 @@ import com.wire.android.ui.theme.wireDimensions fun NewMeetingScreen( navigator: WireNavigator, navArgs: NewMeetingNavArgs, + newMeetingViewModel: NewMeetingViewModel, ) { - val meetingListViewModel: NewMeetingViewModel = when { - LocalInspectionMode.current -> NewMeetingViewModelPreview(navArgs.type) - else -> newMeetingViewModel(navArgs.type) - } NewMeetingContent( type = navArgs.type, onBackPressed = navigator::navigateBack, - titleState = meetingListViewModel.titleTextState, + state = newMeetingViewModel.state, + titleState = newMeetingViewModel.titleTextState, + onParticipantsClicked = { + navigator.navigate(NavigationCommand(NewMeetingParticipantsScreenDestination)) + }, + onCreateClicked = { + newMeetingViewModel.createMeeting() + } ) + + HandleActions(newMeetingViewModel.actions) { action -> + when (action) { + is NewMeetingViewActions.Success -> navigator.navigateBack() + } + } } @Composable fun NewMeetingContent( + state: NewMeetingState, titleState: TextFieldState, type: NewMeetingType, - onBackPressed: () -> Unit, modifier: Modifier = Modifier, + onBackPressed: () -> Unit = {}, + onParticipantsClicked: () -> Unit = {}, + onCreateClicked: () -> Unit = {}, ) { WireScaffold( modifier = modifier, @@ -86,7 +133,7 @@ fun NewMeetingContent( title = stringResource(type.title), onNavigationPressed = onBackPressed, navigationIconType = NavigationIconType.Back( - contentDescription = R.string.contnt_description_new_meeting_back_icon + contentDescription = R.string.content_description_new_meeting_back_icon ), ) }, @@ -101,7 +148,15 @@ fun NewMeetingContent( end = dimensions().spacing16x, ) ) { - TitleInput(titleState = titleState) + TitleInput( + titleState = titleState, + titleError = state.titleError, + ) + VerticalSpace.x24() + ParticipantsInput( + participants = state.confirmedContacts, + onClick = onParticipantsClicked, + ) } }, bottomBar = { @@ -110,21 +165,21 @@ fun NewMeetingContent( color = MaterialTheme.wireColorScheme.background, modifier = Modifier.fillMaxWidth(), ) { - WirePrimaryButton( - text = stringResource(type.action), - leadingIcon = { - Icon( - painter = painterResource(type.icon), - contentDescription = null, // no separate content description as the text already describes the action - modifier = Modifier.padding(dimensions().spacing4x), - ) - }, - state = WireButtonState.Disabled, // TODO - onClick = { /*TODO*/ }, - modifier = Modifier - .fillMaxWidth() - .padding(dimensions().spacing16x), - ) + WirePrimaryButton( + text = stringResource(type.action), + leadingIcon = { + Icon( + painter = painterResource(type.icon), + contentDescription = null, // no separate content description as the text already describes the action + modifier = Modifier.padding(dimensions().spacing4x), + ) + }, + state = if (state.continueButtonEnabled) WireButtonState.Default else WireButtonState.Disabled, + onClick = onCreateClicked, + modifier = Modifier + .fillMaxWidth() + .padding(dimensions().spacing16x), + ) } } ) @@ -133,14 +188,104 @@ fun NewMeetingContent( @Composable private fun TitleInput( titleState: TextFieldState, + titleError: NewMeetingState.TitleError?, ) { + val keyboardController = LocalSoftwareKeyboardController.current + + ShakeAnimation { animate -> + WireTextField( + textState = titleState, + state = when (titleError) { + is NewMeetingState.TitleError.TitleEmptyError -> + WireTextFieldState.Error(stringResource(R.string.new_meeting_title_name_error_empty)) + is NewMeetingState.TitleError.TitleExceedsLimitError -> + WireTextFieldState.Error(stringResource(R.string.new_meeting_title_name_error_exceeded_limit)) + else -> WireTextFieldState.Default + }, + placeholderText = stringResource(R.string.new_meeting_title_input_placeholder), + labelText = stringResource(R.string.new_meeting_title_input_label).uppercase(), + semanticDescription = stringResource(R.string.new_meeting_title_input_placeholder), + keyboardOptions = KeyboardOptions.DefaultText, + onKeyboardAction = { keyboardController?.hide() }, + testTag = "titleInput", + inputTransformation = InputTransformation.maxLengthWithCallback(MEETING_NAME_MAX_COUNT, animate), + trailingIcon = { + Box( + modifier = Modifier + .width(dimensions().spacing64x) + .height(dimensions().spacing40x), + contentAlignment = Alignment.CenterEnd + ) { + AnimatedVisibility( + visible = titleState.text.isNotBlank(), + enter = fadeIn(), + exit = fadeOut() + ) { + IconButton( + modifier = Modifier.padding(start = dimensions().spacing12x), + onClick = titleState::clearText, + ) { + Icon( + painter = painterResource(id = commonR.drawable.ic_clear_search), + contentDescription = stringResource(commonR.string.content_description_clear_content) + ) + } + } + } + }, + ) + } +} + +@Composable +private fun ParticipantsInput( + participants: ImmutableSet, + onClick: () -> Unit, +) { + val resources = LocalResources.current + val textStyle = typography().body01 + val textColor = colorsScheme().onSurface + val suffixColor = colorsScheme().secondaryText + val textMeasurer = rememberTextMeasurer() + val textFieldState = rememberTextFieldState(participants.joinToString(", ") { it.name }) + var innerTextWidthPx by remember { mutableIntStateOf(0) } + val truncationTransformation = remember(innerTextWidthPx) { + TextListTruncationTransformation( + availableWidthPx = innerTextWidthPx, + textMeasurer = textMeasurer, + textStyle = textStyle, + textColor = textColor, + suffixColor = suffixColor, + provideSuffixText = { count -> + resources.getQuantityString(R.plurals.new_meeting_participants_input_more_suffix, count, count) + }, + ) + } + + LaunchedEffect(participants) { + textFieldState.setTextAndPlaceCursorAtEnd(participants.joinToString(", ") { it.name }) + } + WireTextField( - textState = titleState, - placeholderText = stringResource(R.string.new_meeting_title_input_placeholder), - labelText = stringResource(R.string.new_meeting_title_input_label).uppercase(), - semanticDescription = stringResource(R.string.new_meeting_title_input_placeholder), + textState = textFieldState, + placeholderText = stringResource(R.string.new_meeting_participants_input_placeholder), + labelText = stringResource(R.string.new_meeting_participants_input_label).uppercase(), + semanticDescription = stringResource(R.string.new_meeting_participants_input_placeholder), keyboardOptions = KeyboardOptions.DefaultEmailDone, - testTag = "titleInput", + state = WireTextFieldState.ReadOnly, + onInputSizeChanged = { innerTextWidthPx = it.width }, + outputTransformation = truncationTransformation, + onTap = onClick, + trailingIcon = { + Icon( + painter = painterResource(R.drawable.ic_expand), + contentDescription = null, + tint = colorsScheme().onSurfaceVariant, + modifier = Modifier + .padding(dimensions().spacing16x) + .size(dimensions().spacing16x) + ) + } ) } @@ -148,9 +293,9 @@ private fun TitleInput( @Composable fun PreviewNewMeetingScreen_MeetNow() = WireTheme { NewMeetingContent( - titleState = rememberTextFieldState(), + titleState = rememberTextFieldState("Meeting with 9 users"), type = NewMeetingType.MeetNow, - onBackPressed = {}, + state = NewMeetingState(confirmedContacts = buildContacts(names.size), continueButtonEnabled = true), ) } @@ -160,6 +305,22 @@ fun PreviewNewMeetingScreen_Schedule() = WireTheme { NewMeetingContent( titleState = rememberTextFieldState(), type = NewMeetingType.Schedule, - onBackPressed = {}, + state = NewMeetingState(), ) } + +private val names: List = listOf( + "Alice Smith", "Bob Johnson", "Charlie Brown", "David Wilson", "Eve Davis", "Frank Miller", "Grace Lee", "Hank Taylor", "Ivy Anderson" +) + +private fun buildContacts(count: Int) = List(count) { + Contact( + id = "id_$it", + domain = "domain", + name = names[it % names.size], + handle = names[it % names.size].lowercase().replace(" ", "."), + label = names[it % names.size].lowercase().replace(" ", "."), + membership = Membership.Standard, + connectionState = ConnectionState.ACCEPTED, + ) +}.toPersistentSet() diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingViewModel.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingViewModel.kt index 48144e10203..326d95c21ed 100644 --- a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingViewModel.kt +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/NewMeetingViewModel.kt @@ -18,21 +18,118 @@ package com.wire.android.feature.meetings.ui.create import androidx.compose.foundation.text.input.TextFieldState -import androidx.lifecycle.ViewModel +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import com.ramcosta.composedestinations.generated.meetings.navArgs +import com.wire.android.feature.meetings.ui.create.NewMeetingViewModel.Companion.MEETING_NAME_MAX_COUNT +import com.wire.android.model.Contact +import com.wire.android.ui.common.ActionsManager +import com.wire.android.ui.common.ActionsViewModel +import com.wire.android.ui.common.textfield.textAsFlow +import kotlinx.collections.immutable.ImmutableSet +import kotlinx.collections.immutable.persistentSetOf +import kotlinx.collections.immutable.toPersistentSet +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch -interface NewMeetingViewModel { +interface NewMeetingViewModel : ActionsManager { val type: NewMeetingType val titleTextState: TextFieldState + val state: NewMeetingState + + fun updateSelectedContact(selected: Boolean, contact: Contact) {} + fun confirmSelectedContacts() {} + fun resetSelectedContacts() {} + fun createMeeting() {} + + companion object { + const val MEETING_NAME_MAX_COUNT = 64 + } } class NewMeetingViewModelPreview( override val type: NewMeetingType ) : NewMeetingViewModel { override val titleTextState: TextFieldState = TextFieldState() + override val state: NewMeetingState = NewMeetingState() } class NewMeetingViewModelImpl( - override val type: NewMeetingType, -) : ViewModel(), NewMeetingViewModel { + savedStateHandle: SavedStateHandle +) : ActionsViewModel(), NewMeetingViewModel { + val navArgs: NewMeetingNavArgs = savedStateHandle.navArgs() + override val type: NewMeetingType = navArgs.type override val titleTextState: TextFieldState = TextFieldState() + override var state: NewMeetingState by mutableStateOf(NewMeetingState()) + private set + + init { + viewModelScope.launch { + titleTextState.textAsFlow().collectLatest { + if (state.titleError != null) validateTitle() + validateContinueButton() + } + } + } + + override fun updateSelectedContact(selected: Boolean, contact: Contact) { + state = state.copy( + selectedContacts = when (selected) { + true -> state.selectedContacts.plus(contact).toPersistentSet() + false -> state.selectedContacts.minus(contact).toPersistentSet() + } + ) + } + + override fun confirmSelectedContacts() { + state = state.copy(confirmedContacts = state.selectedContacts) + } + + override fun resetSelectedContacts() { + state = state.copy(selectedContacts = state.confirmedContacts) + } + + private fun validateContinueButton() { + state = state.copy(continueButtonEnabled = titleTextState.text.isNotEmpty()) + } + + private fun validateTitle(): Boolean { + state = state.copy( + titleError = when { + titleTextState.text.isEmpty() -> NewMeetingState.TitleError.TitleEmptyError + titleTextState.text.length > MEETING_NAME_MAX_COUNT -> NewMeetingState.TitleError.TitleExceedsLimitError + else -> null + } + ) + return state.titleError == null + } + + override fun createMeeting() { + if (validateTitle()) { + // TODO implement meeting creation + sendAction(NewMeetingViewActions.Success) + } + } +} + +@Stable +data class NewMeetingState( + val selectedContacts: ImmutableSet = persistentSetOf(), + val confirmedContacts: ImmutableSet = persistentSetOf(), + val continueButtonEnabled: Boolean = false, + val titleError: TitleError? = null, +) { + @Stable + sealed interface TitleError { + data object TitleEmptyError : TitleError + data object TitleExceedsLimitError : TitleError + } +} + +sealed interface NewMeetingViewActions { + data object Success : NewMeetingViewActions } diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/TextListTruncationTransformation.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/TextListTruncationTransformation.kt new file mode 100644 index 00000000000..b2cf49725f7 --- /dev/null +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/TextListTruncationTransformation.kt @@ -0,0 +1,86 @@ +/* + * Wire + * Copyright (C) 2026 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.feature.meetings.ui.create + +import androidx.compose.foundation.text.input.OutputTransformation +import androidx.compose.foundation.text.input.TextFieldBuffer +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextMeasurer +import androidx.compose.ui.text.TextStyle + +/** + * Custom [OutputTransformation] to handle dynamic truncation of a comma-separated list of items (e.g., participant names) based on + * available width. It iteratively reduces the number of visible items and appends a dynamic suffix (e.g., "and X more") until the text + * fits within the specified width. The transformation ensures that the visible items and the ellipsis are styled in main color, + * while the dynamic suffix is styled in different color. + * Example: "Alice, Bob, Charlie... +2 more" + */ +class TextListTruncationTransformation( + private val availableWidthPx: Int, + private val textMeasurer: TextMeasurer, + private val textStyle: TextStyle, + private val textColor: Color, + private val suffixColor: Color, + private val provideSuffixText: (Int) -> String, + private val separator: String = ", ", + private val ellipsis: String = "... ", +) : OutputTransformation { + @Suppress("CyclomaticComplexMethod", "NestedBlockDepth", "ReturnCount") + override fun TextFieldBuffer.transformOutput() { + if (availableWidthPx <= 0) return + + val fullText = asCharSequence().toString() + if (fullText.isEmpty()) return + + val allItems = fullText.split(separator).map { it.trim() }.filter { it.isNotEmpty() } + if (allItems.isEmpty()) return + + fun visibleNames(visibleCount: Int): String = allItems.take(visibleCount).joinToString(separator) + fun ellipsisText(visibleCount: Int): String = if (visibleCount < allItems.size) ellipsis else "" + fun suffixText(remainingCount: Int): String = if (remainingCount > 0) provideSuffixText(remainingCount) else "" + + for (i in allItems.size downTo 0) { + val text = visibleNames(i) + ellipsisText(i) + val suffix = suffixText(allItems.size - i) + if (textMeasurer.measure(text + suffix, textStyle).size.width <= availableWidthPx) { + if (i < allItems.size) { + val currentItem = allItems[i] + for (j in currentItem.length downTo 1) { + val truncatedItem = currentItem.take(j) + val separatorBeforeTruncatedItem = if (i > 0) separator else "" + val textWithTruncated = visibleNames(i) + separatorBeforeTruncatedItem + truncatedItem + ellipsisText(i + 1) + val suffixWithoutTruncated = suffixText(allItems.size - i - 1) + if (textMeasurer.measure(textWithTruncated + suffixWithoutTruncated, textStyle).size.width <= availableWidthPx) { + applyVisuals(this, textWithTruncated, suffixWithoutTruncated) + return + } + } + } + applyVisuals(this, text, suffix) + return + } + } + } + + private fun applyVisuals(buffer: TextFieldBuffer, mainTextWithEllipsis: String, suffix: String) { + buffer.replace(0, buffer.length, mainTextWithEllipsis + suffix) + buffer.addStyle(SpanStyle(color = textColor), 0, mainTextWithEllipsis.length) + buffer.addStyle(SpanStyle(color = suffixColor), mainTextWithEllipsis.length, mainTextWithEllipsis.length + suffix.length) + } +} diff --git a/features/meetings/src/main/res/drawable/ic_expand.xml b/features/meetings/src/main/res/drawable/ic_expand.xml new file mode 100644 index 00000000000..4f214f77431 --- /dev/null +++ b/features/meetings/src/main/res/drawable/ic_expand.xml @@ -0,0 +1,24 @@ + + + + diff --git a/features/meetings/src/main/res/values-de/strings.xml b/features/meetings/src/main/res/values-de/strings.xml index 79c74845520..75cbf103f98 100644 --- a/features/meetings/src/main/res/values-de/strings.xml +++ b/features/meetings/src/main/res/values-de/strings.xml @@ -49,5 +49,5 @@ Planen Titel Meeting-Titel eingeben - Neue Meetingansicht schließen + Neue Meetingansicht schließen diff --git a/features/meetings/src/main/res/values-ru/strings.xml b/features/meetings/src/main/res/values-ru/strings.xml index db3b1ff58fd..7d90af0c63a 100644 --- a/features/meetings/src/main/res/values-ru/strings.xml +++ b/features/meetings/src/main/res/values-ru/strings.xml @@ -58,5 +58,5 @@ Расписание Название Введите название встречи - Закрыть вид новой встречи + Закрыть вид новой встречи diff --git a/features/meetings/src/main/res/values/strings.xml b/features/meetings/src/main/res/values/strings.xml index dbacfd53044..5c54be3ee3b 100644 --- a/features/meetings/src/main/res/values/strings.xml +++ b/features/meetings/src/main/res/values/strings.xml @@ -51,11 +51,23 @@ "Start a meeting with team members, guests or external parties." Previous meetings will be listed here. New Meeting + Select participants Meet Now Schedule a Meetingv Start Meeting Schedule Title Enter meeting title - Close new meeting view + Participants + Select participants + Close new meeting view + Close select participants view + Please enter a meeting name + Meeting name should not exceed 64 characters + + + +%1$d more + +%1$d more + + diff --git a/kalium b/kalium index 09e868d171c..09e4c7906d8 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 09e868d171cb71f123a69afd90fd07c6c488bdf8 +Subproject commit 09e4c7906d86fb68d2c34b30f34c2087b9dbe98d From 78f9b43056352e86ddcba6a53c8f3000877704fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Fri, 12 Jun 2026 11:55:52 +0200 Subject: [PATCH 02/17] clean-up --- .../com/wire/android/ui/common/textfield/WireTextFieldLayout.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextFieldLayout.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextFieldLayout.kt index c84cddc8b4e..dd2b576f1a6 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextFieldLayout.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/textfield/WireTextFieldLayout.kt @@ -52,7 +52,6 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import com.wire.android.ui.common.Tint -import com.wire.android.ui.common.clickable import com.wire.android.ui.common.dimensions import com.wire.android.ui.theme.wireDimensions import com.wire.android.ui.theme.wireTypography From 31fdf9ff6c2a18fab5b650e902732236b9556bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Fri, 12 Jun 2026 13:02:55 +0200 Subject: [PATCH 03/17] update kalium ref --- kalium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalium b/kalium index 09e4c7906d8..7b90342a4c3 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 09e4c7906d86fb68d2c34b30f34c2087b9dbe98d +Subproject commit 7b90342a4c395ce6ee16e23e742bf5fe8e861698 From 0204c39b18135d095e5b636f5457f9c3372d39c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Fri, 12 Jun 2026 13:03:21 +0200 Subject: [PATCH 04/17] update use case names --- .../android/search/SearchViewModelFactory.kt | 12 ++++++------ .../android/search/users/SearchUserViewModel.kt | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelFactory.kt b/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelFactory.kt index 79d418ef391..64f794a83c5 100644 --- a/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelFactory.kt +++ b/core/search/src/main/kotlin/com/wire/android/search/SearchViewModelFactory.kt @@ -28,8 +28,8 @@ import com.wire.kalium.logic.feature.auth.ValidateUserHandleUseCase import com.wire.kalium.logic.feature.featureConfig.ObserveIsAppsAllowedForUsageUseCase import com.wire.kalium.logic.feature.search.FederatedSearchParser import com.wire.kalium.logic.feature.search.IsFederationSearchAllowedUseCase -import com.wire.kalium.logic.feature.search.SearchByHandleUseCase -import com.wire.kalium.logic.feature.search.SearchUsersUseCase +import com.wire.kalium.logic.feature.search.SearchUsersByHandleUseCase +import com.wire.kalium.logic.feature.search.SearchUsersByNameUseCase import com.wire.kalium.logic.feature.service.ObserveAllServicesUseCase import com.wire.kalium.logic.feature.service.SearchServicesByNameUseCase import com.wire.kalium.logic.feature.service.SyncServicesUseCase @@ -38,8 +38,8 @@ import dev.zacsweers.metro.Inject @Suppress("LongParameterList") class SearchViewModelFactory @Inject constructor( - private val searchUsers: SearchUsersUseCase, - private val searchByHandle: SearchByHandleUseCase, + private val searchUsersByName: SearchUsersByNameUseCase, + private val searchUsersByHandle: SearchUsersByHandleUseCase, private val contactMapper: ContactMapper, private val federatedSearchParser: FederatedSearchParser, private val validateUserHandle: ValidateUserHandleUseCase, @@ -58,8 +58,8 @@ class SearchViewModelFactory @Inject constructor( ) = SearchUserViewModel( conversationId = conversationId, onlyConnectedContacts = onlyConnectedContacts, - searchUserUseCase = searchUsers, - searchByHandleUseCase = searchByHandle, + searchUsersByName = searchUsersByName, + searchUsersByHandle = searchUsersByHandle, contactMapper = contactMapper, federatedSearchParser = federatedSearchParser, validateUserHandle = validateUserHandle, diff --git a/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt b/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt index e151cb9b0f9..ef8c37cdde9 100644 --- a/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt +++ b/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt @@ -32,9 +32,9 @@ import com.wire.kalium.logic.feature.auth.ValidateUserHandleResult import com.wire.kalium.logic.feature.auth.ValidateUserHandleUseCase import com.wire.kalium.logic.feature.search.FederatedSearchParser import com.wire.kalium.logic.feature.search.IsFederationSearchAllowedUseCase -import com.wire.kalium.logic.feature.search.SearchByHandleUseCase import com.wire.kalium.logic.feature.search.SearchUserResult -import com.wire.kalium.logic.feature.search.SearchUsersUseCase +import com.wire.kalium.logic.feature.search.SearchUsersByHandleUseCase +import com.wire.kalium.logic.feature.search.SearchUsersByNameUseCase import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentListOf @@ -51,8 +51,8 @@ import kotlinx.coroutines.launch class SearchUserViewModel( private val conversationId: ConversationId?, private val onlyConnectedContacts: Boolean, - private val searchUserUseCase: SearchUsersUseCase, - private val searchByHandleUseCase: SearchByHandleUseCase, + private val searchUsersByName: SearchUsersByNameUseCase, + private val searchUsersByHandle: SearchUsersByHandleUseCase, private val contactMapper: ContactMapper, private val federatedSearchParser: FederatedSearchParser, private val validateUserHandle: ValidateUserHandleUseCase, @@ -140,18 +140,18 @@ class SearchUserViewModel( } private suspend fun searchByHandle(searchTerm: String, domain: String?): SearchUserResult = - searchByHandleUseCase( + searchUsersByHandle( searchTerm, excludingConversation = conversationId, - excludingRemote = onlyConnectedContacts, + excludingNotConnected = onlyConnectedContacts, customDomain = domain ) private suspend fun searchByName(searchTerm: String, domain: String?): SearchUserResult = - searchUserUseCase( + searchUsersByName( searchTerm, excludingMembersOfConversation = conversationId, - excludingRemote = onlyConnectedContacts, + excludingNotConnected = onlyConnectedContacts, customDomain = domain ) } From 2b1bdf598a532743704fbd1a8804e6d7eb13e166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Fri, 12 Jun 2026 15:41:49 +0200 Subject: [PATCH 05/17] update use case names --- .../android/di/accountScoped/SearchModule.kt | 8 ++-- .../search/users/SearchUserViewModelTest.kt | 40 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/di/accountScoped/SearchModule.kt b/app/src/main/kotlin/com/wire/android/di/accountScoped/SearchModule.kt index 1cbda4379f1..9ca0a42d252 100644 --- a/app/src/main/kotlin/com/wire/android/di/accountScoped/SearchModule.kt +++ b/app/src/main/kotlin/com/wire/android/di/accountScoped/SearchModule.kt @@ -23,9 +23,9 @@ import com.wire.kalium.logic.CoreLogic import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.feature.search.FederatedSearchParser import com.wire.kalium.logic.feature.search.IsFederationSearchAllowedUseCase -import com.wire.kalium.logic.feature.search.SearchByHandleUseCase +import com.wire.kalium.logic.feature.search.SearchUsersByHandleUseCase import com.wire.kalium.logic.feature.search.SearchScope -import com.wire.kalium.logic.feature.search.SearchUsersUseCase +import com.wire.kalium.logic.feature.search.SearchUsersByNameUseCase import dev.zacsweers.metro.BindingContainer import dev.zacsweers.metro.Provides @@ -39,10 +39,10 @@ class SearchModule { ): SearchScope = coreLogic.getSessionScope(currentAccount).search @Provides - fun provideSearchUsersUseCase(searchScope: SearchScope): SearchUsersUseCase = searchScope.searchUsers + fun provideSearchUsersByNameUseCase(searchScope: SearchScope): SearchUsersByNameUseCase = searchScope.searchUsersByName @Provides - fun provideSearchByHandleUseCase(searchScope: SearchScope): SearchByHandleUseCase = searchScope.searchByHandle + fun provideSearchUsersByHandleUseCase(searchScope: SearchScope): SearchUsersByHandleUseCase = searchScope.searchUsersByHandle @Provides fun provideFederatedSearchParser(searchScope: SearchScope): FederatedSearchParser = searchScope.federatedSearchParser diff --git a/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt b/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt index 248d6a9a4ff..68d62c0e113 100644 --- a/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt +++ b/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt @@ -37,9 +37,9 @@ import com.wire.kalium.logic.feature.auth.ValidateUserHandleResult import com.wire.kalium.logic.feature.auth.ValidateUserHandleUseCase import com.wire.kalium.logic.feature.search.FederatedSearchParser import com.wire.kalium.logic.feature.search.IsFederationSearchAllowedUseCase -import com.wire.kalium.logic.feature.search.SearchByHandleUseCase +import com.wire.kalium.logic.feature.search.SearchUsersByHandleUseCase import com.wire.kalium.logic.feature.search.SearchUserResult -import com.wire.kalium.logic.feature.search.SearchUsersUseCase +import com.wire.kalium.logic.feature.search.SearchUsersByNameUseCase import io.mockk.MockKAnnotations import io.mockk.coEvery import io.mockk.coVerify @@ -79,7 +79,7 @@ class SearchUserViewModelTest { viewModel.searchQueryChanged(query) coVerify(exactly = 1) { - arrangement.searchUsersUseCase( + arrangement.searchUsersByNameUseCase( query, excludingMembersOfConversation = null, customDomain = "domain" @@ -117,7 +117,7 @@ class SearchUserViewModelTest { viewModel.searchQueryChanged(query) coVerify(exactly = 1) { - arrangement.searchUsersUseCase( + arrangement.searchUsersByNameUseCase( query, excludingMembersOfConversation = conversationId, customDomain = "domain" @@ -248,7 +248,7 @@ class SearchUserViewModelTest { viewModel.searchQueryChanged(query) coVerify(exactly = 1) { - arrangement.searchUsersUseCase( + arrangement.searchUsersByNameUseCase( query, excludingMembersOfConversation = null, customDomain = "domain" @@ -284,7 +284,7 @@ class SearchUserViewModelTest { viewModel.searchQueryChanged(query) coVerify(exactly = 1) { - arrangement.searchByHandleUseCase.invoke( + arrangement.searchUsersByHandleUseCase.invoke( query, excludingConversation = null, customDomain = "domain" @@ -340,10 +340,10 @@ class SearchUserViewModelTest { viewModel.searchQueryChanged(query) coVerify(exactly = 1) { - arrangement.searchByHandleUseCase.invoke( + arrangement.searchUsersByHandleUseCase.invoke( searchHandle = query, excludingConversation = null, - excludingRemote = false, + excludingNotConnected = false, customDomain = "domain" ) } @@ -361,10 +361,10 @@ class SearchUserViewModelTest { viewModel.searchQueryChanged(query) coVerify(exactly = 1) { - arrangement.searchByHandleUseCase.invoke( + arrangement.searchUsersByHandleUseCase.invoke( searchHandle = query, excludingConversation = null, - excludingRemote = true, + excludingNotConnected = true, customDomain = "domain" ) } @@ -382,10 +382,10 @@ class SearchUserViewModelTest { viewModel.searchQueryChanged(query) coVerify(exactly = 1) { - arrangement.searchUsersUseCase.invoke( + arrangement.searchUsersByNameUseCase.invoke( searchQuery = query, excludingMembersOfConversation = null, - excludingRemote = false, + excludingNotConnected = false, customDomain = "domain" ) } @@ -403,10 +403,10 @@ class SearchUserViewModelTest { viewModel.searchQueryChanged(query) coVerify(exactly = 1) { - arrangement.searchUsersUseCase.invoke( + arrangement.searchUsersByNameUseCase.invoke( searchQuery = query, excludingMembersOfConversation = null, - excludingRemote = true, + excludingNotConnected = true, customDomain = "domain" ) } @@ -415,7 +415,7 @@ class SearchUserViewModelTest { private class Arrangement { @MockK - lateinit var searchUsersUseCase: SearchUsersUseCase + lateinit var searchUsersByNameUseCase: SearchUsersByNameUseCase @MockK lateinit var contactMapper: ContactMapper @@ -427,7 +427,7 @@ class SearchUserViewModelTest { lateinit var validateUserHandle: ValidateUserHandleUseCase @MockK - lateinit var searchByHandleUseCase: SearchByHandleUseCase + lateinit var searchUsersByHandleUseCase: SearchUsersByHandleUseCase @MockK lateinit var isFederationSearchAllowedUseCase: IsFederationSearchAllowedUseCase @@ -484,7 +484,7 @@ class SearchUserViewModelTest { } fun withSearchResult(result: SearchUserResult) = apply { - coEvery { searchUsersUseCase(any(), any(), any(), any()) } returns result + coEvery { searchUsersByNameUseCase(any(), any(), any(), any()) } returns result } fun withFederatedSearchParserResult(result: FederatedSearchParser.Result) = apply { @@ -496,7 +496,7 @@ class SearchUserViewModelTest { } fun withSearchByHandleResult(result: SearchUserResult) = apply { - coEvery { searchByHandleUseCase(any(), any(), any(), any()) } returns result + coEvery { searchUsersByHandleUseCase(any(), any(), any(), any()) } returns result } fun withIsFederationSearchAllowedResult(isAllowed: Boolean = true) = apply { @@ -509,8 +509,8 @@ class SearchUserViewModelTest { searchUserViewModel = SearchUserViewModel( conversationId = conversationId, onlyConnectedContacts = onlyConnectedContacts, - searchUserUseCase = searchUsersUseCase, - searchByHandleUseCase = searchByHandleUseCase, + searchUsersByName = searchUsersByNameUseCase, + searchUsersByHandle = searchUsersByHandleUseCase, contactMapper = contactMapper, federatedSearchParser = federatedSearchParser, validateUserHandle = validateUserHandle, From aa58e501653b918967ebc7242f7a20eb2e39fc7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Fri, 12 Jun 2026 16:22:56 +0200 Subject: [PATCH 06/17] fix participants text when last one is truncated --- .../meetings/ui/create/TextListTruncationTransformation.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/TextListTruncationTransformation.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/TextListTruncationTransformation.kt index b2cf49725f7..764ae282a44 100644 --- a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/TextListTruncationTransformation.kt +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/create/TextListTruncationTransformation.kt @@ -52,11 +52,11 @@ class TextListTruncationTransformation( if (allItems.isEmpty()) return fun visibleNames(visibleCount: Int): String = allItems.take(visibleCount).joinToString(separator) - fun ellipsisText(visibleCount: Int): String = if (visibleCount < allItems.size) ellipsis else "" fun suffixText(remainingCount: Int): String = if (remainingCount > 0) provideSuffixText(remainingCount) else "" for (i in allItems.size downTo 0) { - val text = visibleNames(i) + ellipsisText(i) + val ellipsis = if (i < allItems.size) ellipsis else "" + val text = visibleNames(i) + ellipsis val suffix = suffixText(allItems.size - i) if (textMeasurer.measure(text + suffix, textStyle).size.width <= availableWidthPx) { if (i < allItems.size) { @@ -64,7 +64,8 @@ class TextListTruncationTransformation( for (j in currentItem.length downTo 1) { val truncatedItem = currentItem.take(j) val separatorBeforeTruncatedItem = if (i > 0) separator else "" - val textWithTruncated = visibleNames(i) + separatorBeforeTruncatedItem + truncatedItem + ellipsisText(i + 1) + val ellipsisAfterTruncatedItem = if (i + 1 < allItems.size || j < currentItem.length) ellipsis else "" + val textWithTruncated = visibleNames(i) + separatorBeforeTruncatedItem + truncatedItem + ellipsisAfterTruncatedItem val suffixWithoutTruncated = suffixText(allItems.size - i - 1) if (textMeasurer.measure(textWithTruncated + suffixWithoutTruncated, textStyle).size.width <= availableWidthPx) { applyVisuals(this, textWithTruncated, suffixWithoutTruncated) From 2f39f084a68c856593821ebdbc447ca8544f1349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Fri, 12 Jun 2026 16:27:11 +0200 Subject: [PATCH 07/17] update kalium ref --- kalium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalium b/kalium index 7b90342a4c3..394b90ff1ce 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 7b90342a4c395ce6ee16e23e742bf5fe8e861698 +Subproject commit 394b90ff1ce22ff8ee38bccf679616c2a13644fb From 34425f1df4135d584c7da730475feabede20324f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Fri, 12 Jun 2026 17:57:11 +0200 Subject: [PATCH 08/17] fixed some text formatting --- .../android/ui/common/button/WireItemLabel.kt | 6 ++++-- .../com/wire/android/util/DateAndTimeParsers.kt | 17 ++++------------- .../feature/meetings/ui/list/MeetingItem.kt | 2 +- .../feature/meetings/ui/list/MeetingList.kt | 3 ++- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireItemLabel.kt b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireItemLabel.kt index 9cfdfd4905d..83ede11585d 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireItemLabel.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/ui/common/button/WireItemLabel.kt @@ -36,11 +36,12 @@ import androidx.compose.ui.graphics.Shape import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.wire.android.ui.common.dimensions +import com.wire.android.ui.common.typography import com.wire.android.ui.theme.wireColorScheme -import com.wire.android.ui.theme.wireTypography @Composable fun WireItemLabel( @@ -49,6 +50,7 @@ fun WireItemLabel( contentPadding: PaddingValues = PaddingValues(horizontal = dimensions().spacing6x, vertical = dimensions().spacing2x), shape: Shape = RoundedCornerShape(dimensions().spacing6x), + textStyle: TextStyle = typography().label02, contentDescription: String = text ) = Box( modifier = modifier @@ -61,7 +63,7 @@ fun WireItemLabel( Text( modifier = Modifier.clearAndSetSemantics { }, text = text, - style = MaterialTheme.wireTypography.label02, + style = textStyle, ) } diff --git a/core/ui-common/src/main/kotlin/com/wire/android/util/DateAndTimeParsers.kt b/core/ui-common/src/main/kotlin/com/wire/android/util/DateAndTimeParsers.kt index 13da58b375b..57e8903b143 100644 --- a/core/ui-common/src/main/kotlin/com/wire/android/util/DateAndTimeParsers.kt +++ b/core/ui-common/src/main/kotlin/com/wire/android/util/DateAndTimeParsers.kt @@ -89,11 +89,6 @@ class DateAndTimeParsers private constructor() { this.timeZone = java.util.TimeZone.getDefault() } - private val longDateFormat = - java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG, Locale.getDefault()).apply { - this.timeZone = java.util.TimeZone.getDefault() - } - private val shortTimeFormat = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT, Locale.getDefault()).apply { this.timeZone = java.util.TimeZone.getDefault() @@ -118,13 +113,9 @@ class DateAndTimeParsers private constructor() { private val videoMessageTimeFormat = DateTimeFormatter.ofPattern("mm:ss", Locale.getDefault()) .withZone(ZoneId.systemDefault()) - private val linkExpirationDateFormat = DateTimeFormatter.ofPattern("EEEE, MMMM dd", Locale.getDefault()) + private val dayOfWeekMonthDayDateFormat = DateTimeFormatter.ofPattern("EEEE, MMMM dd", Locale.getDefault()) .withZone(ZoneId.systemDefault()) - private val linkExpirationTimeFormat = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT, Locale.getDefault()).apply { - this.timeZone = java.util.TimeZone.getDefault() - } - @Deprecated("Date String parsing is discouraged and will be removed soon for direct Instant/DateTime versions") fun serverDate(stringDate: String): Date? { return try { @@ -203,10 +194,10 @@ class DateAndTimeParsers private constructor() { fun videoMessageTime(timeMs: Long): String = videoMessageTimeFormat.format(java.time.Instant.ofEpochMilli(timeMs)) - fun meetingDate(instant: Instant): String = longDateFormat.format(Date.from(instant.toJavaInstant())) + fun meetingDate(instant: Instant): String = dayOfWeekMonthDayDateFormat.format(instant.toJavaInstant()) fun meetingTime(instant: Instant): String = shortTimeFormat.format(Date.from(instant.toJavaInstant())) - fun linkExpirationDate(timeMs: Long): String = linkExpirationDateFormat.format(java.time.Instant.ofEpochMilli(timeMs)) - fun linkExpirationTime(timeMs: Long): String = linkExpirationTimeFormat.format(Date.from(java.time.Instant.ofEpochMilli(timeMs))) + fun linkExpirationDate(timeMs: Long): String = dayOfWeekMonthDayDateFormat.format(java.time.Instant.ofEpochMilli(timeMs)) + fun linkExpirationTime(timeMs: Long): String = shortTimeFormat.format(Date.from(java.time.Instant.ofEpochMilli(timeMs))) } } diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/list/MeetingItem.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/list/MeetingItem.kt index 4ce2f18b4ff..98539b635f6 100644 --- a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/list/MeetingItem.kt +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/list/MeetingItem.kt @@ -200,7 +200,7 @@ private fun MeetingOngoingDurationTimeSublineText(startedTime: Instant) { @Composable private fun RepeatingIntervalInfoLabel(repeatingInterval: RepeatingInterval?) { repeatingInterval?.let { - WireItemLabel(text = stringResource(repeatingInterval.nameResId)) + WireItemLabel(text = stringResource(repeatingInterval.nameResId), textStyle = typography().label01) } } diff --git a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/list/MeetingList.kt b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/list/MeetingList.kt index 9a873e219f1..a5db8804662 100644 --- a/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/list/MeetingList.kt +++ b/features/meetings/src/main/java/com/wire/android/feature/meetings/ui/list/MeetingList.kt @@ -24,6 +24,7 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.stringResource @@ -52,7 +53,7 @@ fun MeetingList( openMeetingOptions: (meetingId: String) -> Unit = {}, ) { val meetingListViewModel: MeetingListViewModel = when { - LocalInspectionMode.current -> MeetingListViewModelPreview(type = type) + LocalInspectionMode.current -> remember(type) { MeetingListViewModelPreview(type = type) } else -> meetingListViewModel(type) } val lazyPagingItems = meetingListViewModel.meetings.collectAsLazyPagingItems() From 9436918f57500c6925bcf43945a1514447fe18f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Fri, 12 Jun 2026 18:33:54 +0200 Subject: [PATCH 09/17] stability baseline update --- core/di/stability/di-debug.stability | 10 ++-- core/search/stability/search-debug.stability | 15 ++++-- .../stability/ui-common-debug.stability | 24 ++++++--- .../stability/meetings-debug.stability | 54 ++++++++++++++++--- 4 files changed, 80 insertions(+), 23 deletions(-) diff --git a/core/di/stability/di-debug.stability b/core/di/stability/di-debug.stability index 930e8a5e5e0..644e997877d 100644 --- a/core/di/stability/di-debug.stability +++ b/core/di/stability/di-debug.stability @@ -25,21 +25,23 @@ internal fun com.wire.android.di.manualScopedViewModelFactory(create: @[Extensio - create: STABLE (function type) @Composable -public fun com.wire.android.di.metro.sessionKeyedAssistedMetroViewModel(key: kotlin.String?, previewProvider: com.wire.android.di.PreviewProvider, createViewModel: @[ExtensionFunctionType] kotlin.Function1): VM of com.wire.android.di.metro.sessionKeyedAssistedMetroViewModel - skippable: true +public fun com.wire.android.di.metro.sessionKeyedAssistedMetroViewModel(key: kotlin.String?, previewProvider: com.wire.android.di.PreviewProvider, viewModelStoreOwner: androidx.lifecycle.ViewModelStoreOwner, createViewModel: @[ExtensionFunctionType] kotlin.Function1): VM of com.wire.android.di.metro.sessionKeyedAssistedMetroViewModel + skippable: false restartable: true params: - key: STABLE (class with no mutable properties) - previewProvider: STABLE (marked @Stable or @Immutable) + - viewModelStoreOwner: RUNTIME (requires runtime check) - createViewModel: STABLE (function type) @Composable -public fun com.wire.android.di.metro.sessionKeyedAssistedMetroViewModelAs(key: kotlin.String?, previewProvider: com.wire.android.di.PreviewProvider, createViewModel: @[ExtensionFunctionType] kotlin.Function1): S of com.wire.android.di.metro.sessionKeyedAssistedMetroViewModelAs - skippable: true +public fun com.wire.android.di.metro.sessionKeyedAssistedMetroViewModelAs(key: kotlin.String?, previewProvider: com.wire.android.di.PreviewProvider, viewModelStoreOwner: androidx.lifecycle.ViewModelStoreOwner, createViewModel: @[ExtensionFunctionType] kotlin.Function1): S of com.wire.android.di.metro.sessionKeyedAssistedMetroViewModelAs + skippable: false restartable: true params: - key: STABLE (class with no mutable properties) - previewProvider: STABLE (marked @Stable or @Immutable) + - viewModelStoreOwner: RUNTIME (requires runtime check) - createViewModel: STABLE (function type) @Composable diff --git a/core/search/stability/search-debug.stability b/core/search/stability/search-debug.stability index 535b4b2e048..d722f82b059 100644 --- a/core/search/stability/search-debug.stability +++ b/core/search/stability/search-debug.stability @@ -5,7 +5,7 @@ // ./gradlew :search:stabilityDump @Composable -private fun com.wire.android.search.SearchAllPeopleOrContactsScreen(searchQuery: kotlin.String, contactsSelected: kotlinx.collections.immutable.ImmutableSet, isSearchActive: kotlin.Boolean, actionType: com.wire.android.model.ItemActionType, onOpenUserProfile: kotlin.Function1, onContactChecked: kotlin.Function2, searchUserViewModel: com.wire.android.search.users.SearchUserViewModel, lazyListState: androidx.compose.foundation.lazy.LazyListState, firstContactFocusRequester: androidx.compose.ui.focus.FocusRequester?, nextFocusRequester: androidx.compose.ui.focus.FocusRequester?): kotlin.Unit +private fun com.wire.android.search.SearchAllPeopleOrContactsScreen(searchQuery: kotlin.String, contactsSelected: kotlinx.collections.immutable.ImmutableSet, isSearchActive: kotlin.Boolean, actionType: com.wire.android.model.ItemActionType, onOpenUserProfile: kotlin.Function1, onContactChecked: kotlin.Function2, conversationId: com.wire.kalium.logic.data.id.QualifiedID?, onlyConnectedContacts: kotlin.Boolean, searchUserViewModel: com.wire.android.search.users.SearchUserViewModel, lazyListState: androidx.compose.foundation.lazy.LazyListState, firstContactFocusRequester: androidx.compose.ui.focus.FocusRequester?, nextFocusRequester: androidx.compose.ui.focus.FocusRequester?): kotlin.Unit skippable: false restartable: true params: @@ -15,25 +15,27 @@ private fun com.wire.android.search.SearchAllPeopleOrContactsScreen(searchQuery: - actionType: STABLE (class with no mutable properties) - onOpenUserProfile: STABLE (function type) - onContactChecked: STABLE (function type) + - conversationId: UNSTABLE (has mutable properties or unstable members) + - onlyConnectedContacts: STABLE (primitive type) - searchUserViewModel: UNSTABLE (has mutable properties or unstable members) - lazyListState: STABLE (marked @Stable or @Immutable) - firstContactFocusRequester: STABLE (marked @Stable or @Immutable) - nextFocusRequester: STABLE (marked @Stable or @Immutable) @Composable -public fun com.wire.android.search.SearchUsersAndAppsScreen(searchTitle: kotlin.String, selectedContacts: kotlinx.collections.immutable.ImmutableSet, onContactChecked: kotlin.Function2, onOpenUserProfile: kotlin.Function1, onAppClicked: kotlin.Function1, onClose: kotlin.Function0, navigationIconType: com.wire.android.ui.common.topappbar.NavigationIconType, itemActionType: com.wire.android.model.ItemActionType, modifier: androidx.compose.ui.Modifier, shouldHideBottomActionForSearch: kotlin.Boolean, shouldHideBottomActionForServices: kotlin.Boolean, isAppsTabVisible: kotlin.Boolean, isConversationAppsEnabled: kotlin.Boolean, initialPage: com.wire.android.search.SearchPeopleTabItem, conversationProtocol: com.wire.kalium.logic.data.conversation.Conversation.ProtocolInfo?, peopleBottomActions: @[Composable] androidx.compose.runtime.internal.ComposableFunction1?): kotlin.Unit +public fun com.wire.android.search.SearchUsersAndAppsScreen(searchTitle: kotlin.String, selectedContacts: kotlinx.collections.immutable.ImmutableSet, onContactChecked: kotlin.Function2, onClose: kotlin.Function0, navigationIconType: com.wire.android.ui.common.topappbar.NavigationIconType, itemActionType: com.wire.android.model.ItemActionType, modifier: androidx.compose.ui.Modifier, conversationId: com.wire.kalium.logic.data.id.QualifiedID?, onlyConnectedContacts: kotlin.Boolean, shouldHideBottomActionForSearch: kotlin.Boolean, shouldHideBottomActionForServices: kotlin.Boolean, isAppsTabVisible: kotlin.Boolean, isConversationAppsEnabled: kotlin.Boolean, initialPage: com.wire.android.search.SearchPeopleTabItem, conversationProtocol: com.wire.kalium.logic.data.conversation.Conversation.ProtocolInfo?, peopleBottomActions: @[Composable] androidx.compose.runtime.internal.ComposableFunction1?, onOpenUserProfile: kotlin.Function1, onAppClicked: kotlin.Function1): kotlin.Unit skippable: false restartable: true params: - searchTitle: STABLE (String is immutable) - selectedContacts: STABLE (known stable type) - onContactChecked: STABLE (function type) - - onOpenUserProfile: STABLE (function type) - - onAppClicked: STABLE (function type) - onClose: STABLE (function type) - navigationIconType: STABLE (marked @Stable or @Immutable) - itemActionType: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) + - conversationId: UNSTABLE (has mutable properties or unstable members) + - onlyConnectedContacts: STABLE (primitive type) - shouldHideBottomActionForSearch: STABLE (primitive type) - shouldHideBottomActionForServices: STABLE (primitive type) - isAppsTabVisible: STABLE (primitive type) @@ -41,6 +43,8 @@ public fun com.wire.android.search.SearchUsersAndAppsScreen(searchTitle: kotlin. - initialPage: STABLE (class with no mutable properties) - conversationProtocol: UNSTABLE (has mutable properties or unstable members) - peopleBottomActions: STABLE (composable function type) + - onOpenUserProfile: STABLE (function type) + - onAppClicked: STABLE (function type) @Composable private fun com.wire.android.search.apps.AppsList(searchQuery: kotlin.String, apps: kotlin.collections.List, onServiceClicked: kotlin.Function1, lazyListState: androidx.compose.foundation.lazy.LazyListState): kotlin.Unit @@ -112,11 +116,12 @@ public fun com.wire.android.search.searchAppsViewModel(protocolInfo: com.wire.ka - protocolInfo: UNSTABLE (has mutable properties or unstable members) @Composable -public fun com.wire.android.search.searchUserViewModel(conversationId: com.wire.kalium.logic.data.id.QualifiedID?): com.wire.android.search.users.SearchUserViewModel +public fun com.wire.android.search.searchUserViewModel(conversationId: com.wire.kalium.logic.data.id.QualifiedID?, onlyConnectedContacts: kotlin.Boolean): com.wire.android.search.users.SearchUserViewModel skippable: false restartable: true params: - conversationId: UNSTABLE (has mutable properties or unstable members) + - onlyConnectedContacts: STABLE (primitive type) @Composable public fun com.wire.android.search.users.SearchAllPeopleScreen(searchQuery: kotlin.String, contactsSearchResult: kotlinx.collections.immutable.ImmutableList, publicSearchResult: kotlinx.collections.immutable.ImmutableList, contactsSelectedSearchResult: kotlinx.collections.immutable.ImmutableList, isLoading: kotlin.Boolean, isSearchActive: kotlin.Boolean, actionType: com.wire.android.model.ItemActionType, onChecked: kotlin.Function2, onOpenUserProfile: kotlin.Function1, firstContactFocusRequester: androidx.compose.ui.focus.FocusRequester?, nextFocusRequester: androidx.compose.ui.focus.FocusRequester?, selectedContactResultsExpanded: kotlin.Boolean, onSelectedContactResultsExpansionChanged: kotlin.Function1, contactResultsExpanded: kotlin.Boolean, onContactResultsExpansionChanged: kotlin.Function1, publicResultsExpanded: kotlin.Boolean, onPublicResultsExpansionChanged: kotlin.Function1, lazyListState: androidx.compose.foundation.lazy.LazyListState): kotlin.Unit diff --git a/core/ui-common/stability/ui-common-debug.stability b/core/ui-common/stability/ui-common-debug.stability index 7d9e7a5fce8..e7524a64488 100644 --- a/core/ui-common/stability/ui-common-debug.stability +++ b/core/ui-common/stability/ui-common-debug.stability @@ -869,7 +869,7 @@ public fun com.wire.android.ui.common.button.WireButtonColors.rippleColor(state: - state: STABLE (class with no mutable properties) @Composable -public fun com.wire.android.ui.common.button.WireItemLabel(text: kotlin.String, modifier: androidx.compose.ui.Modifier, contentPadding: androidx.compose.foundation.layout.PaddingValues, shape: androidx.compose.ui.graphics.Shape, contentDescription: kotlin.String): kotlin.Unit +public fun com.wire.android.ui.common.button.WireItemLabel(text: kotlin.String, modifier: androidx.compose.ui.Modifier, contentPadding: androidx.compose.foundation.layout.PaddingValues, shape: androidx.compose.ui.graphics.Shape, textStyle: androidx.compose.ui.text.TextStyle, contentDescription: kotlin.String): kotlin.Unit skippable: true restartable: true params: @@ -877,6 +877,7 @@ public fun com.wire.android.ui.common.button.WireItemLabel(text: kotlin.String, - modifier: STABLE (marked @Stable or @Immutable) - contentPadding: STABLE (marked @Stable or @Immutable) - shape: STABLE (marked @Stable or @Immutable) + - textStyle: STABLE (marked @Stable or @Immutable) - contentDescription: STABLE (String is immutable) @Composable @@ -1339,6 +1340,15 @@ public fun com.wire.android.ui.common.image.WireImage(model: kotlin.Any?, conten - contentScale: STABLE (marked @Stable or @Immutable) - placeholder: RUNTIME (requires runtime check) +@Composable +public fun com.wire.android.ui.common.image.ZoomableImageContainer(painter: androidx.compose.ui.graphics.painter.Painter, contentDescription: kotlin.String, modifier: androidx.compose.ui.Modifier): kotlin.Unit + skippable: false + restartable: true + params: + - painter: RUNTIME (requires runtime check) + - contentDescription: STABLE (String is immutable) + - modifier: STABLE (marked @Stable or @Immutable) + @Composable public fun com.wire.android.ui.common.legalhold.dialog.common.LearnMoreAboutLegalHoldButton(modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -1774,21 +1784,21 @@ public fun com.wire.android.ui.common.textfield.InnerBasicTextFieldBuilder.Build - textFieldModifier: STABLE (marked @Stable or @Immutable) @Composable -private fun com.wire.android.ui.common.textfield.InnerTextLayout(innerTextField: @[Composable] androidx.compose.runtime.internal.ComposableFunction0, shouldShowPlaceholder: kotlin.Boolean, leadingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, trailingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, placeholderText: kotlin.String?, style: com.wire.android.ui.common.textfield.WireTextFieldState, placeholderTextStyle: androidx.compose.ui.text.TextStyle, placeholderAlignment: androidx.compose.ui.Alignment.Horizontal, inputMinHeight: androidx.compose.ui.unit.Dp, colors: com.wire.android.ui.common.textfield.WireTextFieldColors, onTap: kotlin.Function0?): kotlin.Unit +private fun com.wire.android.ui.common.textfield.InnerTextLayout(innerTextField: @[Composable] androidx.compose.runtime.internal.ComposableFunction0, shouldShowPlaceholder: kotlin.Boolean, modifier: androidx.compose.ui.Modifier, leadingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, trailingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, placeholderText: kotlin.String?, style: com.wire.android.ui.common.textfield.WireTextFieldState, placeholderTextStyle: androidx.compose.ui.text.TextStyle, placeholderAlignment: androidx.compose.ui.Alignment.Horizontal, colors: com.wire.android.ui.common.textfield.WireTextFieldColors, onInputSizeChanged: kotlin.Function1): kotlin.Unit skippable: true restartable: true params: - innerTextField: STABLE (composable function type) - shouldShowPlaceholder: STABLE (primitive type) + - modifier: STABLE (marked @Stable or @Immutable) - leadingIcon: STABLE (composable function type) - trailingIcon: STABLE (composable function type) - placeholderText: STABLE (class with no mutable properties) - style: STABLE (class with no mutable properties) - placeholderTextStyle: STABLE (marked @Stable or @Immutable) - placeholderAlignment: STABLE (marked @Stable or @Immutable) - - inputMinHeight: STABLE (marked @Stable or @Immutable) - colors: STABLE (marked @Stable or @Immutable) - - onTap: STABLE (function type) + - onInputSizeChanged: STABLE (function type) @Composable private fun com.wire.android.ui.common.textfield.VisibilityIconButton(isVisible: kotlin.Boolean, onVisibleChange: kotlin.Function1): kotlin.Unit @@ -1838,7 +1848,7 @@ public fun com.wire.android.ui.common.textfield.WirePasswordTextField(textState: - testTag: STABLE (String is immutable) @Composable -public fun com.wire.android.ui.common.textfield.WireTextField(textState: androidx.compose.foundation.text.input.TextFieldState, modifier: androidx.compose.ui.Modifier, inputModifier: androidx.compose.ui.Modifier, placeholderText: kotlin.String?, labelText: kotlin.String?, labelMandatoryIcon: kotlin.Boolean, descriptionText: kotlin.String?, semanticDescription: kotlin.String?, leadingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, trailingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, state: com.wire.android.ui.common.textfield.WireTextFieldState, autoFillType: com.wire.android.ui.common.textfield.WireAutoFillType, lineLimits: androidx.compose.foundation.text.input.TextFieldLineLimits, inputTransformation: androidx.compose.foundation.text.input.InputTransformation, outputTransformation: androidx.compose.foundation.text.input.OutputTransformation?, keyboardOptions: androidx.compose.foundation.text.KeyboardOptions, onKeyboardAction: androidx.compose.foundation.text.input.KeyboardActionHandler?, scrollState: androidx.compose.foundation.ScrollState, interactionSource: androidx.compose.foundation.interaction.MutableInteractionSource, textStyle: androidx.compose.ui.text.TextStyle, placeholderTextStyle: androidx.compose.ui.text.TextStyle, placeholderAlignment: androidx.compose.ui.Alignment.Horizontal, inputMinHeight: androidx.compose.ui.unit.Dp, shape: androidx.compose.ui.graphics.Shape, colors: com.wire.android.ui.common.textfield.WireTextFieldColors, onSelectedLineIndexChanged: kotlin.Function1, onLineBottomYCoordinateChanged: kotlin.Function1, onTap: kotlin.Function0?, testTag: kotlin.String, validateKeyboardOptions: kotlin.Boolean, enabled: kotlin.Boolean): kotlin.Unit +public fun com.wire.android.ui.common.textfield.WireTextField(textState: androidx.compose.foundation.text.input.TextFieldState, modifier: androidx.compose.ui.Modifier, inputModifier: androidx.compose.ui.Modifier, placeholderText: kotlin.String?, labelText: kotlin.String?, labelMandatoryIcon: kotlin.Boolean, descriptionText: kotlin.String?, semanticDescription: kotlin.String?, leadingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, trailingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, state: com.wire.android.ui.common.textfield.WireTextFieldState, autoFillType: com.wire.android.ui.common.textfield.WireAutoFillType, lineLimits: androidx.compose.foundation.text.input.TextFieldLineLimits, inputTransformation: androidx.compose.foundation.text.input.InputTransformation, outputTransformation: androidx.compose.foundation.text.input.OutputTransformation?, keyboardOptions: androidx.compose.foundation.text.KeyboardOptions, onKeyboardAction: androidx.compose.foundation.text.input.KeyboardActionHandler?, scrollState: androidx.compose.foundation.ScrollState, interactionSource: androidx.compose.foundation.interaction.MutableInteractionSource, textStyle: androidx.compose.ui.text.TextStyle, placeholderTextStyle: androidx.compose.ui.text.TextStyle, placeholderAlignment: androidx.compose.ui.Alignment.Horizontal, inputMinHeight: androidx.compose.ui.unit.Dp, shape: androidx.compose.ui.graphics.Shape, colors: com.wire.android.ui.common.textfield.WireTextFieldColors, onSelectedLineIndexChanged: kotlin.Function1, onLineBottomYCoordinateChanged: kotlin.Function1, onInputSizeChanged: kotlin.Function1, onTap: kotlin.Function0?, testTag: kotlin.String, validateKeyboardOptions: kotlin.Boolean, enabled: kotlin.Boolean): kotlin.Unit skippable: true restartable: true params: @@ -1869,6 +1879,7 @@ public fun com.wire.android.ui.common.textfield.WireTextField(textState: android - colors: STABLE (marked @Stable or @Immutable) - onSelectedLineIndexChanged: STABLE (function type) - onLineBottomYCoordinateChanged: STABLE (function type) + - onInputSizeChanged: STABLE (function type) - onTap: STABLE (function type) - testTag: STABLE (String is immutable) - validateKeyboardOptions: STABLE (primitive type) @@ -1940,7 +1951,7 @@ public fun com.wire.android.ui.common.textfield.WireTextFieldColors.textColor(st - state: STABLE (class with no mutable properties) @Composable -internal fun com.wire.android.ui.common.textfield.WireTextFieldLayout(shouldShowPlaceholder: kotlin.Boolean, innerBasicTextField: com.wire.android.ui.common.textfield.InnerBasicTextFieldBuilder, modifier: androidx.compose.ui.Modifier, placeholderText: kotlin.String?, labelText: kotlin.String?, labelMandatoryIcon: kotlin.Boolean, descriptionText: kotlin.String?, semanticDescription: kotlin.String?, leadingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, trailingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, state: com.wire.android.ui.common.textfield.WireTextFieldState, interactionSource: androidx.compose.foundation.interaction.MutableInteractionSource, placeholderTextStyle: androidx.compose.ui.text.TextStyle, placeholderAlignment: androidx.compose.ui.Alignment.Horizontal, inputMinHeight: androidx.compose.ui.unit.Dp, shape: androidx.compose.ui.graphics.Shape, colors: com.wire.android.ui.common.textfield.WireTextFieldColors, onTap: kotlin.Function0?, testTag: kotlin.String): kotlin.Unit +internal fun com.wire.android.ui.common.textfield.WireTextFieldLayout(shouldShowPlaceholder: kotlin.Boolean, innerBasicTextField: com.wire.android.ui.common.textfield.InnerBasicTextFieldBuilder, modifier: androidx.compose.ui.Modifier, placeholderText: kotlin.String?, labelText: kotlin.String?, labelMandatoryIcon: kotlin.Boolean, descriptionText: kotlin.String?, semanticDescription: kotlin.String?, leadingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, trailingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, state: com.wire.android.ui.common.textfield.WireTextFieldState, interactionSource: androidx.compose.foundation.interaction.MutableInteractionSource, placeholderTextStyle: androidx.compose.ui.text.TextStyle, placeholderAlignment: androidx.compose.ui.Alignment.Horizontal, inputMinHeight: androidx.compose.ui.unit.Dp, shape: androidx.compose.ui.graphics.Shape, colors: com.wire.android.ui.common.textfield.WireTextFieldColors, onInputSizeChanged: kotlin.Function1, onTap: kotlin.Function0?, testTag: kotlin.String): kotlin.Unit skippable: false restartable: true params: @@ -1961,6 +1972,7 @@ internal fun com.wire.android.ui.common.textfield.WireTextFieldLayout(shouldShow - inputMinHeight: STABLE (marked @Stable or @Immutable) - shape: STABLE (marked @Stable or @Immutable) - colors: STABLE (marked @Stable or @Immutable) + - onInputSizeChanged: STABLE (function type) - onTap: STABLE (function type) - testTag: STABLE (String is immutable) diff --git a/features/meetings/stability/meetings-debug.stability b/features/meetings/stability/meetings-debug.stability index 04444a3c10f..ecf91e9adfc 100644 --- a/features/meetings/stability/meetings-debug.stability +++ b/features/meetings/stability/meetings-debug.stability @@ -4,6 +4,12 @@ // Do not edit this file directly. To update it, run: // ./gradlew :meetings:stabilityDump +@Composable +public fun com.ramcosta.composedestinations.generated.meetings.destinations.NewMeetingParticipantsScreenDestination.Content(): kotlin.Unit + skippable: true + restartable: true + params: + @Composable public fun com.ramcosta.composedestinations.generated.meetings.destinations.NewMeetingScreenDestination.Content(): kotlin.Unit skippable: true @@ -30,29 +36,61 @@ public fun com.wire.android.feature.meetings.ui.NewMeetingBottomSheet(sheetState - onScheduleClick: STABLE (function type) @Composable -public fun com.wire.android.feature.meetings.ui.create.NewMeetingContent(titleState: androidx.compose.foundation.text.input.TextFieldState, type: com.wire.android.feature.meetings.ui.create.NewMeetingType, onBackPressed: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit +public fun com.wire.android.feature.meetings.ui.create.NewMeetingContent(state: com.wire.android.feature.meetings.ui.create.NewMeetingState, titleState: androidx.compose.foundation.text.input.TextFieldState, type: com.wire.android.feature.meetings.ui.create.NewMeetingType, modifier: androidx.compose.ui.Modifier, onBackPressed: kotlin.Function0, onParticipantsClicked: kotlin.Function0, onCreateClicked: kotlin.Function0): kotlin.Unit skippable: true restartable: true params: + - state: STABLE (marked @Stable or @Immutable) - titleState: STABLE (marked @Stable or @Immutable) - type: STABLE (class with no mutable properties) - - onBackPressed: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) + - onBackPressed: STABLE (function type) + - onParticipantsClicked: STABLE (function type) + - onCreateClicked: STABLE (function type) @Composable -public fun com.wire.android.feature.meetings.ui.create.NewMeetingScreen(navigator: com.wire.android.navigation.WireNavigator, navArgs: com.wire.android.feature.meetings.ui.create.NewMeetingNavArgs): kotlin.Unit - skippable: true +public fun com.wire.android.feature.meetings.ui.create.NewMeetingParticipantsScreen(navigator: com.wire.android.feature.meetings.navigation.MeetingNavigator, newMeetingViewModel: com.wire.android.feature.meetings.ui.create.NewMeetingViewModel): kotlin.Unit + skippable: false + restartable: true + params: + - navigator: STABLE (class with no mutable properties) + - newMeetingViewModel: RUNTIME (requires runtime check) + +@Composable +public fun com.wire.android.feature.meetings.ui.create.NewMeetingScreen(navigator: com.wire.android.navigation.WireNavigator, navArgs: com.wire.android.feature.meetings.ui.create.NewMeetingNavArgs, newMeetingViewModel: com.wire.android.feature.meetings.ui.create.NewMeetingViewModel): kotlin.Unit + skippable: false restartable: true params: - navigator: STABLE (marked @Stable or @Immutable) - navArgs: STABLE (class with no mutable properties) + - newMeetingViewModel: RUNTIME (requires runtime check) + +@Composable +private fun com.wire.android.feature.meetings.ui.create.ParticipantsInput(participants: kotlinx.collections.immutable.ImmutableSet, onClick: kotlin.Function0): kotlin.Unit + skippable: true + restartable: true + params: + - participants: STABLE (known stable type) + - onClick: STABLE (function type) @Composable -private fun com.wire.android.feature.meetings.ui.create.TitleInput(titleState: androidx.compose.foundation.text.input.TextFieldState): kotlin.Unit +private fun com.wire.android.feature.meetings.ui.create.SelectButton(onClick: kotlin.Function0, modifier: androidx.compose.ui.Modifier, buttonModifier: androidx.compose.ui.Modifier, leadingIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, elevation: androidx.compose.ui.unit.Dp): kotlin.Unit + skippable: true + restartable: true + params: + - onClick: STABLE (function type) + - modifier: STABLE (marked @Stable or @Immutable) + - buttonModifier: STABLE (marked @Stable or @Immutable) + - leadingIcon: STABLE (composable function type) + - elevation: STABLE (marked @Stable or @Immutable) + +@Composable +private fun com.wire.android.feature.meetings.ui.create.TitleInput(titleState: androidx.compose.foundation.text.input.TextFieldState, titleError: com.wire.android.feature.meetings.ui.create.NewMeetingState.TitleError?): kotlin.Unit skippable: true restartable: true params: - titleState: STABLE (marked @Stable or @Immutable) + - titleError: STABLE (marked @Stable or @Immutable) @Composable internal fun com.wire.android.feature.meetings.ui.list.CalendarIcon(tint: androidx.compose.ui.graphics.Color, modifier: androidx.compose.ui.Modifier): kotlin.Unit @@ -233,11 +271,11 @@ public fun com.wire.android.feature.meetings.ui.meetingOptionsMenuListViewModel( params: @Composable -public fun com.wire.android.feature.meetings.ui.newMeetingViewModel(type: com.wire.android.feature.meetings.ui.create.NewMeetingType): com.wire.android.feature.meetings.ui.create.NewMeetingViewModel - skippable: true +public fun com.wire.android.feature.meetings.ui.newMeetingViewModel(viewModelStoreOwner: androidx.lifecycle.ViewModelStoreOwner): com.wire.android.feature.meetings.ui.create.NewMeetingViewModel + skippable: false restartable: true params: - - type: STABLE (class with no mutable properties) + - viewModelStoreOwner: RUNTIME (requires runtime check) @Composable private fun com.wire.android.feature.meetings.ui.options.MeetingOptionsModalContent(meeting: com.wire.android.feature.meetings.model.MeetingItem, onStartMeeting: kotlin.Function0, onCreateConversation: kotlin.Function0, onCopyLink: kotlin.Function0, onEditMeeting: kotlin.Function0, onDeleteMeetingForMe: kotlin.Function0, onDeleteMeetingForEveryone: kotlin.Function0): kotlin.Unit From b8ad070fbd4325d335f59ea38ed706539e7a60cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Mon, 15 Jun 2026 09:41:49 +0200 Subject: [PATCH 10/17] stability baseline update --- .../cells/stability/cells-debug.stability | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/features/cells/stability/cells-debug.stability b/features/cells/stability/cells-debug.stability index ae8dbab1c04..569825736be 100644 --- a/features/cells/stability/cells-debug.stability +++ b/features/cells/stability/cells-debug.stability @@ -10,6 +10,12 @@ public fun com.ramcosta.composedestinations.generated.cells.destinations.AddRemo restartable: true params: +@Composable +public fun com.ramcosta.composedestinations.generated.cells.destinations.CellImageViewerScreenDestination.Content(): kotlin.Unit + skippable: true + restartable: true + params: + @Composable public fun com.ramcosta.composedestinations.generated.cells.destinations.ConversationFilesScreenDestination.Content(): kotlin.Unit skippable: true @@ -134,7 +140,7 @@ internal fun com.wire.android.feature.cells.ui.CellListItem(cell: com.wire.andro - showConversationName: STABLE (primitive type) @Composable -internal fun com.wire.android.feature.cells.ui.CellScreenContent(actionsFlow: kotlinx.coroutines.flow.Flow, pagingListItems: androidx.paging.compose.LazyPagingItems, sendIntent: kotlin.Function1, openFolder: kotlin.Function3, menuState: kotlinx.coroutines.flow.Flow, showPublicLinkScreen: kotlin.Function1, showRenameScreen: kotlin.Function1, showMoveToFolderScreen: kotlin.Function3, showAddRemoveTagsScreen: kotlin.Function1, isRefreshing: androidx.compose.runtime.State, onRefresh: kotlin.Function0, isRestoreInProgress: kotlin.Boolean, isDeleteInProgress: kotlin.Boolean, modifier: androidx.compose.ui.Modifier, isRecycleBin: kotlin.Boolean, isAllFiles: kotlin.Boolean, isSearchResult: kotlin.Boolean, isOffline: kotlin.Boolean, isPullToRefreshEnabled: kotlin.Boolean, lazyListState: androidx.compose.foundation.lazy.LazyListState, retryEditNodeError: kotlin.Function1, showVersionHistoryScreen: kotlin.Function2, fileReadyFlow: kotlinx.coroutines.flow.Flow?): kotlin.Unit +internal fun com.wire.android.feature.cells.ui.CellScreenContent(actionsFlow: kotlinx.coroutines.flow.Flow, pagingListItems: androidx.paging.compose.LazyPagingItems, sendIntent: kotlin.Function1, openFolder: kotlin.Function3, menuState: kotlinx.coroutines.flow.Flow, showPublicLinkScreen: kotlin.Function1, showRenameScreen: kotlin.Function1, showMoveToFolderScreen: kotlin.Function3, showAddRemoveTagsScreen: kotlin.Function1, isRefreshing: androidx.compose.runtime.State, onRefresh: kotlin.Function0, isRestoreInProgress: kotlin.Boolean, isDeleteInProgress: kotlin.Boolean, modifier: androidx.compose.ui.Modifier, isRecycleBin: kotlin.Boolean, isAllFiles: kotlin.Boolean, isSearchResult: kotlin.Boolean, isOffline: kotlin.Boolean, isPullToRefreshEnabled: kotlin.Boolean, lazyListState: androidx.compose.foundation.lazy.LazyListState, retryEditNodeError: kotlin.Function1, showVersionHistoryScreen: kotlin.Function2, showImageViewer: kotlin.Function1, fileReadyFlow: kotlinx.coroutines.flow.Flow?): kotlin.Unit skippable: false restartable: true params: @@ -160,6 +166,7 @@ internal fun com.wire.android.feature.cells.ui.CellScreenContent(actionsFlow: ko - lazyListState: STABLE (marked @Stable or @Immutable) - retryEditNodeError: STABLE (function type) - showVersionHistoryScreen: STABLE (function type) + - showImageViewer: STABLE (function type) - fileReadyFlow: RUNTIME (requires runtime check) @Composable @@ -291,6 +298,12 @@ public fun com.wire.android.feature.cells.ui.addRemoveTagsViewModel(): com.wire. restartable: true params: +@Composable +public fun com.wire.android.feature.cells.ui.cellImageViewerViewModel(): com.wire.android.feature.cells.ui.imageviewer.CellImageViewerViewModel + skippable: true + restartable: true + params: + @Composable public fun com.wire.android.feature.cells.ui.cellViewModel(viewModelStoreOwner: androidx.lifecycle.ViewModelStoreOwner): com.wire.android.feature.cells.ui.CellViewModel skippable: false @@ -521,6 +534,40 @@ private fun com.wire.android.feature.cells.ui.dialog.ShowRecycleBinItem(title: k - onClicked: STABLE (function type) - enabled: STABLE (primitive type) +@Composable +public fun com.wire.android.feature.cells.ui.imageviewer.CellImageViewerScreen(navigator: com.wire.android.navigation.WireNavigator, modifier: androidx.compose.ui.Modifier, viewModel: com.wire.android.feature.cells.ui.imageviewer.CellImageViewerViewModel): kotlin.Unit + skippable: true + restartable: true + params: + - navigator: STABLE (marked @Stable or @Immutable) + - modifier: STABLE (marked @Stable or @Immutable) + - viewModel: STABLE (class with no mutable properties) + +@Composable +internal fun com.wire.android.feature.cells.ui.imageviewer.CellImageViewerScreenContent(localPath: kotlin.String?, contentUrl: kotlin.String?, previewUrl: kotlin.String?, contentHash: kotlin.String?, fileName: kotlin.String?, onNavigateBack: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit + skippable: true + restartable: true + params: + - localPath: STABLE (class with no mutable properties) + - contentUrl: STABLE (class with no mutable properties) + - previewUrl: STABLE (class with no mutable properties) + - contentHash: STABLE (class with no mutable properties) + - fileName: STABLE (class with no mutable properties) + - onNavigateBack: STABLE (function type) + - modifier: STABLE (marked @Stable or @Immutable) + +@Composable +public fun com.wire.android.feature.cells.ui.imageviewer.CellZoomableImage(localPath: kotlin.String?, contentUrl: kotlin.String?, previewUrl: kotlin.String?, contentHash: kotlin.String?, contentDescription: kotlin.String, modifier: androidx.compose.ui.Modifier): kotlin.Unit + skippable: true + restartable: true + params: + - localPath: STABLE (class with no mutable properties) + - contentUrl: STABLE (class with no mutable properties) + - previewUrl: STABLE (class with no mutable properties) + - contentHash: STABLE (class with no mutable properties) + - contentDescription: STABLE (String is immutable) + - modifier: STABLE (marked @Stable or @Immutable) + @Composable public fun com.wire.android.feature.cells.ui.moveToFolderViewModel(): com.wire.android.feature.cells.ui.movetofolder.MoveToFolderViewModel skippable: true From cd91324f2fa7da51ad658593f1574ccebe54b0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Mon, 15 Jun 2026 09:42:54 +0200 Subject: [PATCH 11/17] update kalium ref --- kalium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalium b/kalium index 394b90ff1ce..5b742c31427 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 394b90ff1ce22ff8ee38bccf679616c2a13644fb +Subproject commit 5b742c31427bc713903a4416a65797329e9ac6d2 From e139d490db9f6c673ca2130e3ccbbc0377f526e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Mon, 15 Jun 2026 10:30:25 +0200 Subject: [PATCH 12/17] stability baseline update --- app/stability/app-devDebug.stability | 726 ++++----------------------- 1 file changed, 93 insertions(+), 633 deletions(-) diff --git a/app/stability/app-devDebug.stability b/app/stability/app-devDebug.stability index d8cb5e0a50e..1aec690158e 100644 --- a/app/stability/app-devDebug.stability +++ b/app/stability/app-devDebug.stability @@ -559,54 +559,6 @@ public fun com.ramcosta.composedestinations.generated.app.destinations.WhatsNewS restartable: true params: -@Composable -internal fun com.wire.android.di.defaultViewModelCreationExtras(): androidx.lifecycle.viewmodel.CreationExtras - skippable: true - restartable: true - params: - -@Composable -internal fun com.wire.android.di.manualScopedViewModelFactory(create: @[ExtensionFunctionType] kotlin.Function2): androidx.lifecycle.ViewModelProvider.Factory - skippable: true - restartable: true - params: - - create: STABLE (function type) - -@Composable -public fun com.wire.android.di.wireManualMetroViewModelScoped(arguments: R of com.wire.android.di.wireManualMetroViewModelScoped, clearDelay: kotlin.time.Duration?, create: @[ExtensionFunctionType] kotlin.Function3): S of com.wire.android.di.wireManualMetroViewModelScoped - skippable: false - restartable: true - params: - - arguments: RUNTIME (requires runtime check) - - clearDelay: STABLE (known stable type) - - create: STABLE (function type) - -@Composable -public fun com.wire.android.di.wireManualMetroViewModelScoped(arguments: R of com.wire.android.di.wireManualMetroViewModelScoped, keyInScopeResolver: kotlin.Function1<@[ParameterName(name = \, clearDelay: kotlin.time.Duration?, create: @[ExtensionFunctionType] kotlin.Function3): S of com.wire.android.di.wireManualMetroViewModelScoped - skippable: false - restartable: true - params: - - arguments: RUNTIME (requires runtime check) - - keyInScopeResolver: STABLE (function type) - - clearDelay: STABLE (known stable type) - - create: STABLE (function type) - -@Composable -public fun com.wire.android.di.wireManualMetroViewModelScoped(clearDelay: kotlin.time.Duration?, create: @[ExtensionFunctionType] kotlin.Function2): S of com.wire.android.di.wireManualMetroViewModelScoped - skippable: true - restartable: true - params: - - clearDelay: STABLE (known stable type) - - create: STABLE (function type) - -@Composable -public fun com.wire.android.di.wireManualMetroViewModelScoped(clearDelay: kotlin.time.Duration?, create: @[ExtensionFunctionType] kotlin.Function2): T of com.wire.android.di.wireManualMetroViewModelScoped - skippable: true - restartable: true - params: - - clearDelay: STABLE (known stable type) - - create: STABLE (function type) - @Composable public fun com.wire.android.navigation.AdjustDestinationStylesForTablets(): kotlin.Unit skippable: true @@ -799,6 +751,19 @@ private fun com.wire.android.ui.WireActivity.HandleScreenshotCensoring(): kotlin restartable: true params: +@Composable +private fun com.wire.android.ui.WireActivity.HandleSessionGraphEffects(currentUserId: com.wire.kalium.logic.data.id.QualifiedID?, currentBaseRoute: kotlin.String?, isAuthenticationRoute: kotlin.Boolean, isUserUiBlocked: kotlin.Boolean, isSessionTransitionInProgress: kotlin.Boolean, graphContext: com.wire.android.ui.WireActivityGraphContext?, navigator: com.wire.android.navigation.Navigator): kotlin.Unit + skippable: false + restartable: true + params: + - currentUserId: UNSTABLE (has mutable properties or unstable members) + - currentBaseRoute: STABLE (class with no mutable properties) + - isAuthenticationRoute: STABLE (primitive type) + - isUserUiBlocked: STABLE (primitive type) + - isSessionTransitionInProgress: STABLE (primitive type) + - graphContext: UNSTABLE (has mutable properties or unstable members) + - navigator: STABLE (marked @Stable or @Immutable) + @Composable private fun com.wire.android.ui.WireActivity.HandleThemeChanges(themeOption: com.wire.android.ui.theme.ThemeOption): kotlin.Unit skippable: true @@ -807,10 +772,11 @@ private fun com.wire.android.ui.WireActivity.HandleThemeChanges(themeOption: com - themeOption: STABLE (class with no mutable properties) @Composable -private fun com.wire.android.ui.WireActivity.ProvideViewModelGraph(content: @[Composable] androidx.compose.runtime.internal.ComposableFunction0): kotlin.Unit +private fun com.wire.android.ui.WireActivity.ProvideViewModelGraph(logoutAction: kotlin.Function1<@[ParameterName(name = \, content: @[Composable] androidx.compose.runtime.internal.ComposableFunction0): kotlin.Unit skippable: true restartable: true params: + - logoutAction: STABLE (function type) - content: STABLE (composable function type) @Composable @@ -821,7 +787,35 @@ private fun com.wire.android.ui.WireActivity.SetUpNavigation(navigator: com.wire - navigator: STABLE (marked @Stable or @Immutable) @Composable -private fun com.wire.android.ui.WireActivity.rememberWireActivityGraphContext(appGraph: com.wire.android.di.metro.WireApplicationGraph, authenticationViewModelGraph: com.wire.android.di.metro.AppAuthenticationViewModelGraph, currentUserId: com.wire.kalium.logic.data.id.QualifiedID?, currentBaseRoute: kotlin.String?, startDestinationBaseRoute: kotlin.String, isUserUiBlocked: kotlin.Boolean): com.wire.android.ui.WireActivityGraphContext? +private fun com.wire.android.ui.WireActivity.WireActivityMainContent(startDestination: com.ramcosta.composedestinations.spec.Direction, navigator: com.wire.android.navigation.Navigator, graphContext: com.wire.android.ui.WireActivityGraphContext?, backgroundType: com.wire.android.navigation.style.BackgroundType, context: android.content.Context): kotlin.Unit + skippable: false + restartable: true + params: + - startDestination: RUNTIME (requires runtime check) + - navigator: STABLE (marked @Stable or @Immutable) + - graphContext: UNSTABLE (has mutable properties or unstable members) + - backgroundType: STABLE (class with no mutable properties) + - context: RUNTIME (requires runtime check) + +@Composable +private fun com.wire.android.ui.WireActivity.WireActivityRoot(startDestination: com.ramcosta.composedestinations.spec.Direction): kotlin.Unit + skippable: false + restartable: true + params: + - startDestination: RUNTIME (requires runtime check) + +@Composable +private fun com.wire.android.ui.WireActivity.WireActivityThemedContent(startDestination: com.ramcosta.composedestinations.spec.Direction, appGraph: com.wire.android.di.metro.WireApplicationGraph, authenticationViewModelGraph: com.wire.android.di.metro.AppAuthenticationViewModelGraph, context: android.content.Context): kotlin.Unit + skippable: false + restartable: true + params: + - startDestination: RUNTIME (requires runtime check) + - appGraph: RUNTIME (requires runtime check) + - authenticationViewModelGraph: STABLE (class with no mutable properties) + - context: RUNTIME (requires runtime check) + +@Composable +private fun com.wire.android.ui.WireActivity.rememberWireActivityGraphContext(appGraph: com.wire.android.di.metro.WireApplicationGraph, authenticationViewModelGraph: com.wire.android.di.metro.AppAuthenticationViewModelGraph, currentUserId: com.wire.kalium.logic.data.id.QualifiedID?, currentBaseRoute: kotlin.String?, startDestinationBaseRoute: kotlin.String, isUserUiBlocked: kotlin.Boolean, isSessionTransitionInProgress: kotlin.Boolean): com.wire.android.ui.WireActivityGraphContext? skippable: false restartable: true params: @@ -831,6 +825,7 @@ private fun com.wire.android.ui.WireActivity.rememberWireActivityGraphContext(ap - currentBaseRoute: STABLE (class with no mutable properties) - startDestinationBaseRoute: STABLE (String is immutable) - isUserUiBlocked: STABLE (primitive type) + - isSessionTransitionInProgress: STABLE (primitive type) @Composable private fun com.wire.android.ui.WireActivity.wireActivityScopedViewModels(graph: com.wire.android.di.metro.AppSessionViewModelGraph): com.wire.android.ui.WireActivityScopedViewModels @@ -1722,7 +1717,7 @@ public fun com.wire.android.ui.calling.common.CallerDetails(conversationId: com. - isCbrEnabled: STABLE (primitive type) - avatarAssetId: STABLE (marked @Stable or @Immutable) - conversationTypeForCall: STABLE (class with no mutable properties) - - membership: STABLE (class with no mutable properties) + - membership: STABLE (marked @Stable or @Immutable) - groupCallerName: STABLE (class with no mutable properties) - protocolInfo: UNSTABLE (has mutable properties or unstable members) - mlsVerificationStatus: STABLE (class with no mutable properties) @@ -2610,42 +2605,7 @@ public fun com.wire.android.ui.calling.sharedCallingViewModel(conversationId: co - conversationId: STABLE (matched by stability configuration) @Composable -public fun com.wire.android.ui.common.AddContactButton(userId: com.wire.kalium.logic.data.id.QualifiedID, userName: kotlin.String, modifier: androidx.compose.ui.Modifier, viewModel: com.wire.android.ui.connection.ConnectionActionButtonViewModel): kotlin.Unit - skippable: false - restartable: true - params: - - userId: STABLE (matched by stability configuration) - - userName: STABLE (String is immutable) - - modifier: STABLE (marked @Stable or @Immutable) - - viewModel: RUNTIME (requires runtime check) - -@Composable -private fun com.wire.android.ui.common.ArrowIcon(arrowIcon: kotlin.Int, contentDescription: kotlin.Int, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - arrowIcon: STABLE (primitive type) - - contentDescription: STABLE (primitive type) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.common.ArrowLeftIcon(modifier: androidx.compose.ui.Modifier, contentDescription: kotlin.Int): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - - contentDescription: STABLE (primitive type) - -@Composable -public fun com.wire.android.ui.common.ArrowRightIcon(modifier: androidx.compose.ui.Modifier, contentDescription: kotlin.Int): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - - contentDescription: STABLE (primitive type) - -@Composable -public fun com.wire.android.ui.common.AttachmentButton(icon: kotlin.Int, labelStyle: androidx.compose.ui.text.TextStyle, modifier: androidx.compose.ui.Modifier, text: kotlin.String, onClick: kotlin.Function0): kotlin.Unit +public fun com.wire.android.ui.common.AttachmentButton(icon: kotlin.Int, labelStyle: androidx.compose.ui.text.TextStyle, modifier: androidx.compose.ui.Modifier, text: kotlin.String, enabled: kotlin.Boolean, onClick: kotlin.Function0): kotlin.Unit skippable: true restartable: true params: @@ -2653,15 +2613,9 @@ public fun com.wire.android.ui.common.AttachmentButton(icon: kotlin.Int, labelSt - labelStyle: STABLE (marked @Stable or @Immutable) - modifier: STABLE (marked @Stable or @Immutable) - text: STABLE (String is immutable) + - enabled: STABLE (primitive type) - onClick: STABLE (function type) -@Composable -public fun com.wire.android.ui.common.BlockedLabel(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - @Composable public fun com.wire.android.ui.common.ClickableText(text: androidx.compose.ui.text.AnnotatedString, onClick: kotlin.Function1, modifier: androidx.compose.ui.Modifier, color: androidx.compose.ui.graphics.Color, textDecoration: androidx.compose.ui.text.style.TextDecoration?, textAlign: androidx.compose.ui.text.style.TextAlign?, overflow: androidx.compose.ui.text.style.TextOverflow, softWrap: kotlin.Boolean, maxLines: kotlin.Int, onTextLayout: kotlin.Function1, style: androidx.compose.ui.text.TextStyle, onLongClick: kotlin.Function0?): kotlin.Unit skippable: true @@ -2699,13 +2653,6 @@ public fun com.wire.android.ui.common.CopyButton(onCopyClicked: kotlin.Function0 - contentDescription: STABLE (primitive type) - state: STABLE (class with no mutable properties) -@Composable -public fun com.wire.android.ui.common.DeletedLabel(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - @Composable private fun com.wire.android.ui.common.DropdownItem(text: kotlin.String, leadingCompose: @[Composable] androidx.compose.runtime.internal.ComposableFunction0?, isSelected: kotlin.Boolean, onClick: kotlin.Function0): kotlin.Unit skippable: true @@ -2768,14 +2715,6 @@ public fun com.wire.android.ui.common.MLSVerifiedIcon(modifier: androidx.compose - modifier: STABLE (marked @Stable or @Immutable) - contentDescriptionId: STABLE (primitive type) -@Composable -public fun com.wire.android.ui.common.MembershipQualifierLabel(membership: com.wire.android.ui.home.conversationslist.model.Membership, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - membership: STABLE (class with no mutable properties) - - modifier: STABLE (marked @Stable or @Immutable) - @Composable private fun com.wire.android.ui.common.MenuPopUp(shape: androidx.compose.foundation.shape.RoundedCornerShape, textFieldWidth: androidx.compose.ui.geometry.Size, expanded: kotlin.Boolean, borderColor: androidx.compose.ui.graphics.Color, leadingCompose: @[Composable] androidx.compose.runtime.internal.ComposableFunction1<@[ParameterName(name = \, selectedIndex: kotlin.Int, items: kotlin.collections.List, showDefaultTextIndicator: kotlin.Boolean, defaultItemIndex: kotlin.Int, selectionText: kotlin.String, arrowRotation: kotlin.Float, hidePopUp: kotlin.Function0, onChange: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit skippable: false @@ -2828,14 +2767,6 @@ public fun com.wire.android.ui.common.ProteusVerifiedIcon(modifier: androidx.com - modifier: STABLE (marked @Stable or @Immutable) - contentDescriptionId: STABLE (primitive type) -@Composable -public fun com.wire.android.ui.common.ProtocolLabel(protocolName: kotlin.String, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - protocolName: STABLE (String is immutable) - - modifier: STABLE (marked @Stable or @Immutable) - @Composable private fun com.wire.android.ui.common.SelectionField(leadingCompose: @[Composable] androidx.compose.runtime.internal.ComposableFunction1<@[ParameterName(name = \, selectedIndex: kotlin.Int, text: kotlin.String, arrowRotation: kotlin.Float, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -2859,17 +2790,6 @@ public fun com.wire.android.ui.common.SettingUpWireScreenContent(modifier: andro - message: STABLE (marked @Stable or @Immutable) - type: STABLE (class with no mutable properties) -@Composable -public fun com.wire.android.ui.common.StatusBox(statusText: kotlin.String, modifier: androidx.compose.ui.Modifier, textColor: androidx.compose.ui.graphics.Color, badgeColor: androidx.compose.ui.graphics.Color, withBorder: kotlin.Boolean): kotlin.Unit - skippable: true - restartable: true - params: - - statusText: STABLE (String is immutable) - - modifier: STABLE (marked @Stable or @Immutable) - - textColor: STABLE (marked @Stable or @Immutable) - - badgeColor: STABLE (marked @Stable or @Immutable) - - withBorder: STABLE (primitive type) - @Composable public fun com.wire.android.ui.common.TextWithLearnMore(textAnnotatedString: androidx.compose.ui.text.AnnotatedString, learnMoreLink: kotlin.String, modifier: androidx.compose.ui.Modifier, onTextLayout: kotlin.Function1): kotlin.Unit skippable: true @@ -2888,36 +2808,6 @@ public fun com.wire.android.ui.common.UnderConstructionScreen(screenName: kotlin - screenName: STABLE (String is immutable) - modifier: STABLE (marked @Stable or @Immutable) -@Composable -public fun com.wire.android.ui.common.UserBadge(membership: com.wire.android.ui.home.conversationslist.model.Membership, modifier: androidx.compose.ui.Modifier, connectionState: com.wire.kalium.logic.data.user.ConnectionState?, isDeleted: kotlin.Boolean, startPadding: androidx.compose.ui.unit.Dp, topPadding: androidx.compose.ui.unit.Dp): kotlin.Unit - skippable: true - restartable: true - params: - - membership: STABLE (class with no mutable properties) - - modifier: STABLE (marked @Stable or @Immutable) - - connectionState: STABLE (class with no mutable properties) - - isDeleted: STABLE (primitive type) - - startPadding: STABLE (marked @Stable or @Immutable) - - topPadding: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.common.VisibilityState(status: com.wire.android.ui.common.visbility.VisibilityState, content: @[Composable] androidx.compose.runtime.internal.ComposableFunction1): kotlin.Unit - skippable: false - restartable: true - params: - - status: UNSTABLE (has mutable properties or unstable members) - - content: STABLE (composable function type) - -@Composable -public fun com.wire.android.ui.common.WireCheckbox(checked: kotlin.Boolean, onCheckedChange: kotlin.Function1?, modifier: androidx.compose.ui.Modifier, enabled: kotlin.Boolean): kotlin.Unit - skippable: true - restartable: true - params: - - checked: STABLE (primitive type) - - onCheckedChange: STABLE (function type) - - modifier: STABLE (marked @Stable or @Immutable) - - enabled: STABLE (primitive type) - @Composable internal fun com.wire.android.ui.common.WireDropDown(items: kotlin.collections.List, label: kotlin.String?, modifier: androidx.compose.ui.Modifier, defaultItemIndex: kotlin.Int, selectedItemIndex: kotlin.Int, autoUpdateSelection: kotlin.Boolean, showDefaultTextIndicator: kotlin.Boolean, leadingCompose: @[Composable] androidx.compose.runtime.internal.ComposableFunction1<@[ParameterName(name = \, onChangeClickDescription: kotlin.String, placeholder: kotlin.String, onSelected: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit skippable: false @@ -2935,21 +2825,6 @@ internal fun com.wire.android.ui.common.WireDropDown(items: kotlin.collections.L - placeholder: STABLE (String is immutable) - onSelected: STABLE (function type) -@Composable -public fun com.wire.android.ui.common.WireLabelledCheckbox(label: kotlin.String, checked: kotlin.Boolean, onCheckClicked: kotlin.Function1, modifier: androidx.compose.ui.Modifier, maxLine: kotlin.Int, overflow: androidx.compose.ui.text.style.TextOverflow, horizontalArrangement: androidx.compose.foundation.layout.Arrangement.Horizontal, contentPadding: androidx.compose.foundation.layout.PaddingValues, checkboxEnabled: kotlin.Boolean): kotlin.Unit - skippable: true - restartable: true - params: - - label: STABLE (String is immutable) - - checked: STABLE (primitive type) - - onCheckClicked: STABLE (function type) - - modifier: STABLE (marked @Stable or @Immutable) - - maxLine: STABLE (primitive type) - - overflow: STABLE (known stable type) - - horizontalArrangement: STABLE (marked @Stable or @Immutable) - - contentPadding: STABLE (marked @Stable or @Immutable) - - checkboxEnabled: STABLE (primitive type) - @Composable public fun com.wire.android.ui.common.WireRadioButton(checked: kotlin.Boolean, modifier: androidx.compose.ui.Modifier, onButtonChecked: kotlin.Function0?, enabled: kotlin.Boolean): kotlin.Unit skippable: true @@ -3212,13 +3087,6 @@ private fun com.wire.android.ui.common.bottomsheet.conversation.PreviewConversat params: - initialPage: STABLE (class with no mutable properties) -@Composable -public fun com.wire.android.ui.common.connectionActionButtonViewModel(args: com.wire.android.ui.connection.ConnectionActionButtonArgs): com.wire.android.ui.connection.ConnectionActionButtonViewModel - skippable: false - restartable: true - params: - - args: UNSTABLE (has mutable properties or unstable members) - @Composable public fun com.wire.android.ui.common.conversationOptionsMenuViewModel(): com.wire.android.ui.common.bottomsheet.conversation.ConversationOptionsMenuViewModel skippable: true @@ -3371,14 +3239,6 @@ public fun com.wire.android.ui.common.dialogs.SureAboutMessagingInDegradedConver - sendAnyway: STABLE (function type) - hideDialog: STABLE (function type) -@Composable -public fun com.wire.android.ui.common.dialogs.UnblockUserDialogContent(dialogState: com.wire.android.ui.common.visbility.VisibilityState, onUnblock: kotlin.Function1): kotlin.Unit - skippable: false - restartable: true - params: - - dialogState: UNSTABLE (has mutable properties or unstable members) - - onUnblock: STABLE (function type) - @Composable public fun com.wire.android.ui.common.dialogs.UserNotFoundDialog(onActionButtonClicked: kotlin.Function0): kotlin.Unit skippable: true @@ -3539,14 +3399,6 @@ public fun com.wire.android.ui.common.imagepreview.rememberPickPictureState(onIm - onCameraPermissionPermanentlyDenied: STABLE (function type) - onGalleryPermissionPermanentlyDenied: STABLE (function type) -@Composable -public fun com.wire.android.ui.common.rememberFlow(flow: kotlinx.coroutines.flow.Flow, lifecycleOwner: androidx.lifecycle.LifecycleOwner): kotlinx.coroutines.flow.Flow - skippable: false - restartable: true - params: - - flow: RUNTIME (requires runtime check) - - lifecycleOwner: RUNTIME (requires runtime check) - @Composable public fun com.wire.android.ui.common.securityClassificationViewModel(args: com.wire.android.ui.common.banner.SecurityClassificationArgs): com.wire.android.ui.common.banner.SecurityClassificationViewModel skippable: false @@ -3554,22 +3406,6 @@ public fun com.wire.android.ui.common.securityClassificationViewModel(args: com. params: - args: UNSTABLE (has mutable properties or unstable members) -@Composable -public fun com.wire.android.ui.common.selectableBackground(isSelected: kotlin.Boolean, onClickDescription: kotlin.String, onClick: kotlin.Function0): androidx.compose.ui.Modifier - skippable: true - restartable: true - params: - - isSelected: STABLE (primitive type) - - onClickDescription: STABLE (String is immutable) - - onClick: STABLE (function type) - -@Composable -public fun com.wire.android.ui.common.snackbar.collectAndShowSnackbar(snackbarFlow: kotlinx.coroutines.flow.SharedFlow): kotlin.Unit - skippable: false - restartable: true - params: - - snackbarFlow: RUNTIME (requires runtime check) - @Composable private fun com.wire.android.ui.common.topappbar.CallsContent(calls: kotlin.collections.List, onReturnToCallClick: kotlin.Function1, onReturnToIncomingCallClick: kotlin.Function1, onReturnToOutgoingCallClick: kotlin.Function1): kotlin.Unit skippable: false @@ -3711,42 +3547,6 @@ public fun com.wire.android.ui.common.topappbar.rememberConversationFilterState( restartable: true params: -@Composable -public fun com.wire.android.ui.common.upgradetoapps.UpgradeToGetAppsBanner(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.common.visbility.rememberVisibilityState(saveable: Saveable of com.wire.android.ui.common.visbility.rememberVisibilityState?): com.wire.android.ui.common.visbility.VisibilityState - skippable: false - restartable: true - params: - - saveable: RUNTIME (requires runtime check) - -@Composable -public fun com.wire.android.ui.connection.ConnectionActionButton(userId: com.wire.kalium.logic.data.id.QualifiedID, userName: kotlin.String, fullName: kotlin.String, connectionStatus: com.wire.kalium.logic.data.user.ConnectionState, isConversationStarted: kotlin.Boolean, modifier: androidx.compose.ui.Modifier, onConnectionRequestIgnored: kotlin.Function1, onOpenConversation: kotlin.Function1, viewModel: com.wire.android.ui.connection.ConnectionActionButtonViewModel): kotlin.Unit - skippable: false - restartable: true - params: - - userId: STABLE (matched by stability configuration) - - userName: STABLE (String is immutable) - - fullName: STABLE (String is immutable) - - connectionStatus: STABLE (class with no mutable properties) - - isConversationStarted: STABLE (primitive type) - - modifier: STABLE (marked @Stable or @Immutable) - - onConnectionRequestIgnored: STABLE (function type) - - onOpenConversation: STABLE (function type) - - viewModel: RUNTIME (requires runtime check) - -@Composable -public fun com.wire.android.ui.connection.UnableStartConversationDialogContent(dialogState: com.wire.android.ui.common.visbility.VisibilityState): kotlin.Unit - skippable: false - restartable: true - params: - - dialogState: UNSTABLE (has mutable properties or unstable members) - @Composable private fun com.wire.android.ui.debug.CheckCrlRevocationButton(onClick: kotlin.Function0): kotlin.Unit skippable: true @@ -5826,12 +5626,13 @@ public fun com.wire.android.ui.home.conversations.details.updatechannelaccess.Ch - updateChannelAccessViewModel: UNSTABLE (has mutable properties or unstable members) @Composable -private fun com.wire.android.ui.home.conversations.edit.MessageOptionsModalContent(message: com.wire.android.ui.home.conversations.model.UIMessage.Regular, sheetState: com.wire.android.ui.common.bottomsheet.WireModalSheetState, onCopyClick: kotlin.Function1<@[ParameterName(name = \, onDeleteClick: kotlin.Function2<@[ParameterName(name = \, onReactionClick: kotlin.Function2<@[ParameterName(name = \, onDetailsClick: kotlin.Function2<@[ParameterName(name = \, onReplyClick: kotlin.Function1, onEditClick: kotlin.Function4<@[ParameterName(name = \, onShareAssetClick: kotlin.Function1<@[ParameterName(name = \, onDownloadAssetClick: kotlin.Function1<@[ParameterName(name = \, onOpenAssetClick: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit +private fun com.wire.android.ui.home.conversations.edit.MessageOptionsModalContent(message: com.wire.android.ui.home.conversations.model.UIMessage.Regular, sheetState: com.wire.android.ui.common.bottomsheet.WireModalSheetState, isNetworkAvailable: kotlin.Boolean, onCopyClick: kotlin.Function1<@[ParameterName(name = \, onDeleteClick: kotlin.Function2<@[ParameterName(name = \, onReactionClick: kotlin.Function2<@[ParameterName(name = \, onDetailsClick: kotlin.Function2<@[ParameterName(name = \, onReplyClick: kotlin.Function1, onEditClick: kotlin.Function4<@[ParameterName(name = \, onShareAssetClick: kotlin.Function1<@[ParameterName(name = \, onDownloadAssetClick: kotlin.Function1<@[ParameterName(name = \, onOpenAssetClick: kotlin.Function1<@[ParameterName(name = \): kotlin.Unit skippable: false restartable: true params: - message: UNSTABLE (has mutable properties or unstable members) - sheetState: UNSTABLE (has mutable properties or unstable members) + - isNetworkAvailable: STABLE (primitive type) - onCopyClick: STABLE (function type) - onDeleteClick: STABLE (function type) - onReactionClick: STABLE (function type) @@ -5843,12 +5644,13 @@ private fun com.wire.android.ui.home.conversations.edit.MessageOptionsModalConte - onOpenAssetClick: STABLE (function type) @Composable -public fun com.wire.android.ui.home.conversations.edit.MessageOptionsModalSheetLayout(conversationId: com.wire.kalium.logic.data.id.QualifiedID, sheetState: com.wire.android.ui.common.bottomsheet.WireModalSheetState, onCopyClick: kotlin.Function1<@[ParameterName(name = \, onDeleteClick: kotlin.Function2<@[ParameterName(name = \, onReactionClick: kotlin.Function2<@[ParameterName(name = \, onDetailsClick: kotlin.Function2<@[ParameterName(name = \, onReplyClick: kotlin.Function1, onEditClick: kotlin.Function4<@[ParameterName(name = \, onShareAssetClick: kotlin.Function1<@[ParameterName(name = \, onDownloadAssetClick: kotlin.Function1<@[ParameterName(name = \, onOpenAssetClick: kotlin.Function1<@[ParameterName(name = \, viewModel: com.wire.android.ui.home.conversations.edit.MessageOptionsMenuViewModel): kotlin.Unit +public fun com.wire.android.ui.home.conversations.edit.MessageOptionsModalSheetLayout(conversationId: com.wire.kalium.logic.data.id.QualifiedID, sheetState: com.wire.android.ui.common.bottomsheet.WireModalSheetState, isNetworkAvailable: kotlin.Boolean, onCopyClick: kotlin.Function1<@[ParameterName(name = \, onDeleteClick: kotlin.Function2<@[ParameterName(name = \, onReactionClick: kotlin.Function2<@[ParameterName(name = \, onDetailsClick: kotlin.Function2<@[ParameterName(name = \, onReplyClick: kotlin.Function1, onEditClick: kotlin.Function4<@[ParameterName(name = \, onShareAssetClick: kotlin.Function1<@[ParameterName(name = \, onDownloadAssetClick: kotlin.Function1<@[ParameterName(name = \, onOpenAssetClick: kotlin.Function1<@[ParameterName(name = \, viewModel: com.wire.android.ui.home.conversations.edit.MessageOptionsMenuViewModel): kotlin.Unit skippable: false restartable: true params: - conversationId: STABLE (matched by stability configuration) - sheetState: UNSTABLE (has mutable properties or unstable members) + - isNetworkAvailable: STABLE (primitive type) - onCopyClick: STABLE (function type) - onDeleteClick: STABLE (function type) - onReactionClick: STABLE (function type) @@ -6220,7 +6022,7 @@ public fun com.wire.android.ui.home.conversations.mention.MemberItemToMention(av - avatarData: STABLE (marked @Stable or @Immutable) - name: STABLE (String is immutable) - label: STABLE (String is immutable) - - membership: STABLE (class with no mutable properties) + - membership: STABLE (marked @Stable or @Immutable) - searchQuery: STABLE (String is immutable) - clickable: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) @@ -7682,162 +7484,6 @@ private fun com.wire.android.ui.home.conversations.scopedMessageViewModel(clearD - clearDelay: STABLE (known stable type) - create: STABLE (function type) -@Composable -public fun com.wire.android.ui.home.conversations.search.EmptySearchQueryScreen(modifier: androidx.compose.ui.Modifier, text: kotlin.String, learnMoreTextToLink: kotlin.Pair): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - - text: STABLE (String is immutable) - - learnMoreTextToLink: STABLE (known stable type) - -@Composable -public fun com.wire.android.ui.home.conversations.search.ExternalContactSearchResultItem(avatarData: com.wire.android.model.UserAvatarData, userId: com.wire.kalium.logic.data.id.QualifiedID, name: kotlin.String, label: kotlin.String, membership: com.wire.android.ui.home.conversationslist.model.Membership, searchQuery: kotlin.String, connectionState: com.wire.kalium.logic.data.user.ConnectionState, clickable: com.wire.android.model.Clickable, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - avatarData: STABLE (marked @Stable or @Immutable) - - userId: STABLE (matched by stability configuration) - - name: STABLE (String is immutable) - - label: STABLE (String is immutable) - - membership: STABLE (class with no mutable properties) - - searchQuery: STABLE (String is immutable) - - connectionState: STABLE (class with no mutable properties) - - clickable: STABLE (class with no mutable properties) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversations.search.HighlightName(name: kotlin.String, searchQuery: kotlin.String, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - name: STABLE (String is immutable) - - searchQuery: STABLE (String is immutable) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversations.search.HighlightSubtitle(subTitle: kotlin.String, modifier: androidx.compose.ui.Modifier, searchQuery: kotlin.String, prefix: kotlin.String): kotlin.Unit - skippable: true - restartable: true - params: - - subTitle: STABLE (String is immutable) - - modifier: STABLE (marked @Stable or @Immutable) - - searchQuery: STABLE (String is immutable) - - prefix: STABLE (String is immutable) - -@Composable -public fun com.wire.android.ui.home.conversations.search.InternalContactSearchResultItem(avatarData: com.wire.android.model.UserAvatarData, name: kotlin.String, label: kotlin.String, membership: com.wire.android.ui.home.conversationslist.model.Membership, searchQuery: kotlin.String, connectionState: com.wire.kalium.logic.data.user.ConnectionState, onCheckClickable: com.wire.android.model.Clickable, isSelected: kotlin.Boolean, clickable: com.wire.android.model.Clickable, actionType: com.wire.android.model.ItemActionType, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - avatarData: STABLE (marked @Stable or @Immutable) - - name: STABLE (String is immutable) - - label: STABLE (String is immutable) - - membership: STABLE (class with no mutable properties) - - searchQuery: STABLE (String is immutable) - - connectionState: STABLE (class with no mutable properties) - - onCheckClickable: STABLE (class with no mutable properties) - - isSelected: STABLE (primitive type) - - clickable: STABLE (class with no mutable properties) - - actionType: STABLE (class with no mutable properties) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -private fun com.wire.android.ui.home.conversations.search.SearchAllPeopleOrContactsScreen(searchQuery: kotlin.String, contactsSelected: kotlinx.collections.immutable.ImmutableSet, isSearchActive: kotlin.Boolean, actionType: com.wire.android.model.ItemActionType, onOpenUserProfile: kotlin.Function1, onContactChecked: kotlin.Function2, searchUserViewModel: com.wire.android.ui.home.conversations.search.SearchUserViewModel, lazyListState: androidx.compose.foundation.lazy.LazyListState, firstContactFocusRequester: androidx.compose.ui.focus.FocusRequester?, nextFocusRequester: androidx.compose.ui.focus.FocusRequester?): kotlin.Unit - skippable: false - restartable: true - params: - - searchQuery: STABLE (String is immutable) - - contactsSelected: STABLE (known stable type) - - isSearchActive: STABLE (primitive type) - - actionType: STABLE (class with no mutable properties) - - onOpenUserProfile: STABLE (function type) - - onContactChecked: STABLE (function type) - - searchUserViewModel: UNSTABLE (has mutable properties or unstable members) - - lazyListState: STABLE (marked @Stable or @Immutable) - - firstContactFocusRequester: STABLE (marked @Stable or @Immutable) - - nextFocusRequester: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversations.search.SearchAllPeopleScreen(searchQuery: kotlin.String, contactsSearchResult: kotlinx.collections.immutable.ImmutableList, publicSearchResult: kotlinx.collections.immutable.ImmutableList, contactsSelectedSearchResult: kotlinx.collections.immutable.ImmutableList, isLoading: kotlin.Boolean, isSearchActive: kotlin.Boolean, actionType: com.wire.android.model.ItemActionType, onChecked: kotlin.Function2, onOpenUserProfile: kotlin.Function1, firstContactFocusRequester: androidx.compose.ui.focus.FocusRequester?, nextFocusRequester: androidx.compose.ui.focus.FocusRequester?, selectedContactResultsExpanded: kotlin.Boolean, onSelectedContactResultsExpansionChanged: kotlin.Function1, contactResultsExpanded: kotlin.Boolean, onContactResultsExpansionChanged: kotlin.Function1, publicResultsExpanded: kotlin.Boolean, onPublicResultsExpansionChanged: kotlin.Function1, lazyListState: androidx.compose.foundation.lazy.LazyListState): kotlin.Unit - skippable: true - restartable: true - params: - - searchQuery: STABLE (String is immutable) - - contactsSearchResult: STABLE (known stable type) - - publicSearchResult: STABLE (known stable type) - - contactsSelectedSearchResult: STABLE (known stable type) - - isLoading: STABLE (primitive type) - - isSearchActive: STABLE (primitive type) - - actionType: STABLE (class with no mutable properties) - - onChecked: STABLE (function type) - - onOpenUserProfile: STABLE (function type) - - firstContactFocusRequester: STABLE (marked @Stable or @Immutable) - - nextFocusRequester: STABLE (marked @Stable or @Immutable) - - selectedContactResultsExpanded: STABLE (primitive type) - - onSelectedContactResultsExpansionChanged: STABLE (function type) - - contactResultsExpanded: STABLE (primitive type) - - onContactResultsExpansionChanged: STABLE (function type) - - publicResultsExpanded: STABLE (primitive type) - - onPublicResultsExpansionChanged: STABLE (function type) - - lazyListState: STABLE (marked @Stable or @Immutable) - -@Composable -private fun com.wire.android.ui.home.conversations.search.SearchResult(searchQuery: kotlin.String, contactsSearchResult: kotlinx.collections.immutable.ImmutableList, publicSearchResult: kotlinx.collections.immutable.ImmutableList, contactsSelectedSearchResult: kotlinx.collections.immutable.ImmutableList, isSearchActive: kotlin.Boolean, actionType: com.wire.android.model.ItemActionType, onChecked: kotlin.Function2, onOpenUserProfile: kotlin.Function1, selectedContactResultsExpanded: kotlin.Boolean, onSelectedContactResultsExpansionChanged: kotlin.Function1, contactResultsExpanded: kotlin.Boolean, onContactResultsExpansionChanged: kotlin.Function1, publicResultsExpanded: kotlin.Boolean, onPublicResultsExpansionChanged: kotlin.Function1, lazyListState: androidx.compose.foundation.lazy.LazyListState, firstContactFocusRequester: androidx.compose.ui.focus.FocusRequester?, nextFocusRequester: androidx.compose.ui.focus.FocusRequester?): kotlin.Unit - skippable: true - restartable: true - params: - - searchQuery: STABLE (String is immutable) - - contactsSearchResult: STABLE (known stable type) - - publicSearchResult: STABLE (known stable type) - - contactsSelectedSearchResult: STABLE (known stable type) - - isSearchActive: STABLE (primitive type) - - actionType: STABLE (class with no mutable properties) - - onChecked: STABLE (function type) - - onOpenUserProfile: STABLE (function type) - - selectedContactResultsExpanded: STABLE (primitive type) - - onSelectedContactResultsExpansionChanged: STABLE (function type) - - contactResultsExpanded: STABLE (primitive type) - - onContactResultsExpansionChanged: STABLE (function type) - - publicResultsExpanded: STABLE (primitive type) - - onPublicResultsExpansionChanged: STABLE (function type) - - lazyListState: STABLE (marked @Stable or @Immutable) - - firstContactFocusRequester: STABLE (marked @Stable or @Immutable) - - nextFocusRequester: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversations.search.SearchUsersAndAppsScreen(searchTitle: kotlin.String, selectedContacts: kotlinx.collections.immutable.ImmutableSet, onContactChecked: kotlin.Function2, onOpenUserProfile: kotlin.Function1, onAppClicked: kotlin.Function1, onClose: kotlin.Function0, screenType: com.wire.android.ui.home.conversations.search.SearchPeopleScreenType, shouldShowChannelPromotion: kotlin.Boolean, isUserAllowedToCreateChannels: kotlin.Boolean, modifier: androidx.compose.ui.Modifier, isGroupSubmitVisible: kotlin.Boolean, isAppsTabVisible: kotlin.Boolean, isConversationAppsEnabled: kotlin.Boolean, initialPage: com.wire.android.ui.home.conversations.search.SearchPeopleTabItem, conversationProtocol: com.wire.kalium.logic.data.conversation.Conversation.ProtocolInfo?, onContinue: kotlin.Function0, onCreateNewGroup: kotlin.Function0, onCreateNewChannel: kotlin.Function0): kotlin.Unit - skippable: false - restartable: true - params: - - searchTitle: STABLE (String is immutable) - - selectedContacts: STABLE (known stable type) - - onContactChecked: STABLE (function type) - - onOpenUserProfile: STABLE (function type) - - onAppClicked: STABLE (function type) - - onClose: STABLE (function type) - - screenType: STABLE (class with no mutable properties) - - shouldShowChannelPromotion: STABLE (primitive type) - - isUserAllowedToCreateChannels: STABLE (primitive type) - - modifier: STABLE (marked @Stable or @Immutable) - - isGroupSubmitVisible: STABLE (primitive type) - - isAppsTabVisible: STABLE (primitive type) - - isConversationAppsEnabled: STABLE (primitive type) - - initialPage: STABLE (class with no mutable properties) - - conversationProtocol: UNSTABLE (has mutable properties or unstable members) - - onContinue: STABLE (function type) - - onCreateNewGroup: STABLE (function type) - - onCreateNewChannel: STABLE (function type) - -@Composable -private fun com.wire.android.ui.home.conversations.search.ShowButton(isShownAll: kotlin.Boolean, onShowButtonClicked: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - isShownAll: STABLE (primitive type) - - onShowButtonClicked: STABLE (function type) - - modifier: STABLE (marked @Stable or @Immutable) - @Composable public fun com.wire.android.ui.home.conversations.search.adddembertoconversation.AddMembersSearchScreen(navigator: com.wire.android.navigation.Navigator, navArgs: com.wire.android.ui.home.conversations.search.AddMembersSearchNavArgs, addMembersToConversationViewModel: com.wire.android.ui.home.conversations.search.adddembertoconversation.AddMembersToConversationViewModel): kotlin.Unit skippable: false @@ -7847,74 +7493,6 @@ public fun com.wire.android.ui.home.conversations.search.adddembertoconversation - navArgs: UNSTABLE (has mutable properties or unstable members) - addMembersToConversationViewModel: UNSTABLE (has mutable properties or unstable members) -@Composable -private fun com.wire.android.ui.home.conversations.search.apps.AppsList(searchQuery: kotlin.String, apps: kotlin.collections.List, onServiceClicked: kotlin.Function1, lazyListState: androidx.compose.foundation.lazy.LazyListState): kotlin.Unit - skippable: false - restartable: true - params: - - searchQuery: STABLE (String is immutable) - - apps: RUNTIME (requires runtime check) - - onServiceClicked: STABLE (function type) - - lazyListState: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversations.search.apps.EmptySearchAppsContent(isSelfATeamAdmin: kotlin.Boolean, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - isSelfATeamAdmin: STABLE (primitive type) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversations.search.apps.EmptySearchDisabledByConversationContent(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -private fun com.wire.android.ui.home.conversations.search.apps.SearchAllAppsContent(searchQuery: kotlin.String, result: kotlinx.collections.immutable.ImmutableList, isLoading: kotlin.Boolean, onServiceClicked: kotlin.Function1, appsAllowedResult: com.wire.kalium.logic.feature.featureConfig.AppsAllowedResult, isSelfATeamAdmin: kotlin.Boolean, isConversationAppsEnabled: kotlin.Boolean, lazyListState: androidx.compose.foundation.lazy.LazyListState): kotlin.Unit - skippable: false - restartable: true - params: - - searchQuery: STABLE (String is immutable) - - result: STABLE (known stable type) - - isLoading: STABLE (primitive type) - - onServiceClicked: STABLE (function type) - - appsAllowedResult: UNSTABLE (has mutable properties or unstable members) - - isSelfATeamAdmin: STABLE (primitive type) - - isConversationAppsEnabled: STABLE (primitive type) - - lazyListState: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversations.search.apps.SearchAppsScreen(protocolInfo: com.wire.kalium.logic.data.conversation.Conversation.ProtocolInfo?, searchQuery: kotlin.String, onServiceClicked: kotlin.Function1, isConversationAppsEnabled: kotlin.Boolean, searchAppsViewModel: com.wire.android.ui.home.conversations.search.apps.SearchAppsViewModel, lazyListState: androidx.compose.foundation.lazy.LazyListState): kotlin.Unit - skippable: false - restartable: true - params: - - protocolInfo: UNSTABLE (has mutable properties or unstable members) - - searchQuery: STABLE (String is immutable) - - onServiceClicked: STABLE (function type) - - isConversationAppsEnabled: STABLE (primitive type) - - searchAppsViewModel: UNSTABLE (has mutable properties or unstable members) - - lazyListState: STABLE (marked @Stable or @Immutable) - -@Composable -private fun com.wire.android.ui.home.conversations.search.apps.rememberAppsContentState(isConversationAppsEnabled: kotlin.Boolean, isLoading: kotlin.Boolean, appsAllowedResult: com.wire.kalium.logic.feature.featureConfig.AppsAllowedResult, searchQuery: kotlin.String, result: kotlinx.collections.immutable.ImmutableList): androidx.compose.runtime.State - skippable: false - restartable: true - params: - - isConversationAppsEnabled: STABLE (primitive type) - - isLoading: STABLE (primitive type) - - appsAllowedResult: UNSTABLE (has mutable properties or unstable members) - - searchQuery: STABLE (String is immutable) - - result: STABLE (known stable type) - -@Composable -private fun com.wire.android.ui.home.conversations.search.isUnknownUser(): kotlin.Boolean - skippable: true - restartable: true - params: - @Composable public fun com.wire.android.ui.home.conversations.search.messages.SearchConversationMessagesButton(modifier: androidx.compose.ui.Modifier, onClick: kotlin.Function0): kotlin.Unit skippable: true @@ -7977,40 +7555,12 @@ public fun com.wire.android.ui.home.conversations.search.messages.SearchConversa - navigator: STABLE (marked @Stable or @Immutable) - searchConversationMessagesViewModel: UNSTABLE (has mutable properties or unstable members) -@Composable -public fun com.wire.android.ui.home.conversations.search.rememberSearchPeopleScreenState(coroutineScope: kotlinx.coroutines.CoroutineScope): com.wire.android.ui.home.conversations.search.SearchPeopleScreenState - skippable: false - restartable: true - params: - - coroutineScope: RUNTIME (requires runtime check) - -@Composable -public fun com.wire.android.ui.home.conversations.search.widget.SearchFailureBox(failureMessage: kotlin.Int, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - failureMessage: STABLE (primitive type) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversations.searchAppsViewModel(protocolInfo: com.wire.kalium.logic.data.conversation.Conversation.ProtocolInfo?): com.wire.android.ui.home.conversations.search.apps.SearchAppsViewModel - skippable: false - restartable: true - params: - - protocolInfo: UNSTABLE (has mutable properties or unstable members) - @Composable public fun com.wire.android.ui.home.conversations.searchConversationMessagesViewModel(): com.wire.android.ui.home.conversations.search.messages.SearchConversationMessagesViewModel skippable: true restartable: true params: -@Composable -public fun com.wire.android.ui.home.conversations.searchUserViewModel(): com.wire.android.ui.home.conversations.search.SearchUserViewModel - skippable: true - restartable: true - params: - @Composable public fun com.wire.android.ui.home.conversations.selfDeletingMessageActionViewModel(args: com.wire.android.ui.home.messagecomposer.actions.SelfDeletingMessageActionArgs): com.wire.android.ui.home.messagecomposer.actions.SelfDeletingMessageActionViewModel skippable: false @@ -8142,20 +7692,6 @@ private fun com.wire.android.ui.home.conversationslist.common.BrowsePublicChanne params: - onBrowsePublicChannels: STABLE (function type) -@Composable -public fun com.wire.android.ui.home.conversationslist.common.ConnectPendingRequestBadge(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversationslist.common.ConnectRequestBadge(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - @Composable public fun com.wire.android.ui.home.conversationslist.common.ConnectionLabel(connectionInfo: com.wire.android.ui.home.conversations.model.UILastMessageContent.Connection, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -8258,14 +7794,6 @@ public fun com.wire.android.ui.home.conversationslist.common.ConversationUserAva params: - avatarData: STABLE (marked @Stable or @Immutable) -@Composable -public fun com.wire.android.ui.home.conversationslist.common.EventBadgeFactory(eventType: com.wire.android.ui.home.conversationslist.model.BadgeEventType, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - eventType: STABLE (class with no mutable properties) - - modifier: STABLE (marked @Stable or @Immutable) - @Composable private fun com.wire.android.ui.home.conversationslist.common.GeneralConversationItem(conversation: com.wire.android.ui.home.conversationslist.model.ConversationItem, isChecked: kotlin.Boolean, isSelectable: kotlin.Boolean, onConversationItemClick: com.wire.android.model.Clickable, onJoinCallClick: kotlin.Function0, onAudioPermissionPermanentlyDenied: kotlin.Function0, showLegalHoldIndicator: kotlin.Boolean, modifier: androidx.compose.ui.Modifier, selectOnRadioGroup: kotlin.Function0, subTitle: @[Composable] androidx.compose.runtime.internal.ComposableFunction0, searchQuery: kotlin.String, playingAudio: com.wire.android.ui.home.conversationslist.model.PlayingAudioInConversation?, onPlayPauseCurrentAudio: kotlin.Function0, onStopCurrentAudio: kotlin.Function0): kotlin.Unit skippable: false @@ -8337,13 +7865,6 @@ public fun com.wire.android.ui.home.conversationslist.common.LastMultipleMessage - messages: RUNTIME (requires runtime check) - separator: STABLE (String is immutable) -@Composable -private fun com.wire.android.ui.home.conversationslist.common.MissedCallBadge(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - @Composable public fun com.wire.android.ui.home.conversationslist.common.MutedConversationBadge(modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -8351,43 +7872,6 @@ public fun com.wire.android.ui.home.conversationslist.common.MutedConversationBa params: - modifier: STABLE (marked @Stable or @Immutable) -@Composable -private fun com.wire.android.ui.home.conversationslist.common.NotificationBadgeContainer(notificationIcon: @[Composable] androidx.compose.runtime.internal.ComposableFunction0, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - notificationIcon: STABLE (composable function type) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversationslist.common.UnreadKnockBadge(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -private fun com.wire.android.ui.home.conversationslist.common.UnreadMentionBadge(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.conversationslist.common.UnreadMessageEventBadge(unreadMessageCount: kotlin.Int, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - unreadMessageCount: STABLE (primitive type) - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -private fun com.wire.android.ui.home.conversationslist.common.UnreadReplyBadge(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - @Composable public fun com.wire.android.ui.home.conversationslist.common.UserLabel(searchQuery: kotlin.String, userInfoLabel: com.wire.android.ui.home.conversationslist.common.UserInfoLabel, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -8623,11 +8107,12 @@ private fun com.wire.android.ui.home.messagecomposer.AddMentionAction(isActive: - onButtonClicked: STABLE (function type) @Composable -public fun com.wire.android.ui.home.messagecomposer.AdditionalOptionSubMenu(isFileSharingEnabled: kotlin.Boolean, optionsVisible: kotlin.Boolean, onPermissionPermanentlyDenied: kotlin.Function1<@[ParameterName(name = \, onLocationPickerClicked: kotlin.Function0, onCloseAdditionalAttachment: kotlin.Function0, onRecordAudioMessageClicked: kotlin.Function0, additionalOptionsState: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSubMenuState, onImagesPicked: kotlin.Function1, kotlin.Unit>, onAttachmentPicked: kotlin.Function1, onAudioRecorded: kotlin.Function1, tempWritableImageUri: android.net.Uri?, tempWritableVideoUri: android.net.Uri?, modifier: androidx.compose.ui.Modifier): kotlin.Unit +public fun com.wire.android.ui.home.messagecomposer.AdditionalOptionSubMenu(isFileSharingEnabled: kotlin.Boolean, areAttachmentOptionsEnabled: kotlin.Boolean, optionsVisible: kotlin.Boolean, onPermissionPermanentlyDenied: kotlin.Function1<@[ParameterName(name = \, onLocationPickerClicked: kotlin.Function0, onCloseAdditionalAttachment: kotlin.Function0, onRecordAudioMessageClicked: kotlin.Function0, additionalOptionsState: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSubMenuState, onImagesPicked: kotlin.Function1, kotlin.Unit>, onAttachmentPicked: kotlin.Function1, onAudioRecorded: kotlin.Function1, tempWritableImageUri: android.net.Uri?, tempWritableVideoUri: android.net.Uri?, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: false restartable: true params: - isFileSharingEnabled: STABLE (primitive type) + - areAttachmentOptionsEnabled: STABLE (primitive type) - optionsVisible: STABLE (primitive type) - onPermissionPermanentlyDenied: STABLE (function type) - onLocationPickerClicked: STABLE (function type) @@ -8642,7 +8127,7 @@ public fun com.wire.android.ui.home.messagecomposer.AdditionalOptionSubMenu(isFi - modifier: STABLE (marked @Stable or @Immutable) @Composable -public fun com.wire.android.ui.home.messagecomposer.AdditionalOptionsMenu(conversationId: com.wire.kalium.logic.data.id.QualifiedID, additionalOptionsState: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionMenuState, selectedOption: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSelectItem, attachmentsVisible: kotlin.Boolean, isEditing: kotlin.Boolean, isMentionActive: kotlin.Boolean, isFileSharingEnabled: kotlin.Boolean, onAdditionalOptionsMenuClicked: kotlin.Function0, onMentionButtonClicked: kotlin.Function0, onPingOptionClicked: kotlin.Function0, onRichEditingButtonClicked: kotlin.Function0, onCloseRichEditingButtonClicked: kotlin.Function0, onRichOptionButtonClicked: kotlin.Function1, onDrawingModeClicked: kotlin.Function0, modifier: androidx.compose.ui.Modifier, onOnSelfDeletingOptionClicked: kotlin.Function1?, onGifOptionClicked: kotlin.Function0?): kotlin.Unit +public fun com.wire.android.ui.home.messagecomposer.AdditionalOptionsMenu(conversationId: com.wire.kalium.logic.data.id.QualifiedID, additionalOptionsState: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionMenuState, selectedOption: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSelectItem, attachmentsVisible: kotlin.Boolean, isEditing: kotlin.Boolean, isMentionActive: kotlin.Boolean, isFileSharingEnabled: kotlin.Boolean, areAttachmentOptionsEnabled: kotlin.Boolean, onAdditionalOptionsMenuClicked: kotlin.Function0, onMentionButtonClicked: kotlin.Function0, onPingOptionClicked: kotlin.Function0, onRichEditingButtonClicked: kotlin.Function0, onCloseRichEditingButtonClicked: kotlin.Function0, onRichOptionButtonClicked: kotlin.Function1, onDrawingModeClicked: kotlin.Function0, modifier: androidx.compose.ui.Modifier, onOnSelfDeletingOptionClicked: kotlin.Function1?, onGifOptionClicked: kotlin.Function0?): kotlin.Unit skippable: true restartable: true params: @@ -8653,6 +8138,7 @@ public fun com.wire.android.ui.home.messagecomposer.AdditionalOptionsMenu(conver - isEditing: STABLE (primitive type) - isMentionActive: STABLE (primitive type) - isFileSharingEnabled: STABLE (primitive type) + - areAttachmentOptionsEnabled: STABLE (primitive type) - onAdditionalOptionsMenuClicked: STABLE (function type) - onMentionButtonClicked: STABLE (function type) - onPingOptionClicked: STABLE (function type) @@ -8665,7 +8151,7 @@ public fun com.wire.android.ui.home.messagecomposer.AdditionalOptionsMenu(conver - onGifOptionClicked: STABLE (function type) @Composable -public fun com.wire.android.ui.home.messagecomposer.AttachmentAndAdditionalOptionsMenuItems(conversationId: com.wire.kalium.logic.data.id.QualifiedID, isEditing: kotlin.Boolean, selectedOption: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSelectItem, attachmentsVisible: kotlin.Boolean, isMentionActive: kotlin.Boolean, isFileSharingEnabled: kotlin.Boolean, onMentionButtonClicked: kotlin.Function0, onSelfDeletionOptionButtonClicked: kotlin.Function1, modifier: androidx.compose.ui.Modifier, onAdditionalOptionsMenuClicked: kotlin.Function0, onPingClicked: kotlin.Function0, onGifButtonClicked: kotlin.Function0, onRichEditingButtonClicked: kotlin.Function0, onDrawingModeClicked: kotlin.Function0): kotlin.Unit +public fun com.wire.android.ui.home.messagecomposer.AttachmentAndAdditionalOptionsMenuItems(conversationId: com.wire.kalium.logic.data.id.QualifiedID, isEditing: kotlin.Boolean, selectedOption: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSelectItem, attachmentsVisible: kotlin.Boolean, isMentionActive: kotlin.Boolean, isFileSharingEnabled: kotlin.Boolean, areAttachmentOptionsEnabled: kotlin.Boolean, onMentionButtonClicked: kotlin.Function0, onSelfDeletionOptionButtonClicked: kotlin.Function1, modifier: androidx.compose.ui.Modifier, onAdditionalOptionsMenuClicked: kotlin.Function0, onPingClicked: kotlin.Function0, onGifButtonClicked: kotlin.Function0, onRichEditingButtonClicked: kotlin.Function0, onDrawingModeClicked: kotlin.Function0): kotlin.Unit skippable: true restartable: true params: @@ -8675,6 +8161,7 @@ public fun com.wire.android.ui.home.messagecomposer.AttachmentAndAdditionalOptio - attachmentsVisible: STABLE (primitive type) - isMentionActive: STABLE (primitive type) - isFileSharingEnabled: STABLE (primitive type) + - areAttachmentOptionsEnabled: STABLE (primitive type) - onMentionButtonClicked: STABLE (function type) - onSelfDeletionOptionButtonClicked: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) @@ -8685,7 +8172,7 @@ public fun com.wire.android.ui.home.messagecomposer.AttachmentAndAdditionalOptio - onDrawingModeClicked: STABLE (function type) @Composable -public fun com.wire.android.ui.home.messagecomposer.AttachmentOptionsComponent(optionsVisible: kotlin.Boolean, onImagesPicked: kotlin.Function1, kotlin.Unit>, onAttachmentPicked: kotlin.Function1, onRecordAudioMessageClicked: kotlin.Function0, tempWritableImageUri: android.net.Uri?, tempWritableVideoUri: android.net.Uri?, isFileSharingEnabled: kotlin.Boolean, onLocationPickerClicked: kotlin.Function0, onPermissionPermanentlyDenied: kotlin.Function1<@[ParameterName(name = \, modifier: androidx.compose.ui.Modifier): kotlin.Unit +public fun com.wire.android.ui.home.messagecomposer.AttachmentOptionsComponent(optionsVisible: kotlin.Boolean, onImagesPicked: kotlin.Function1, kotlin.Unit>, onAttachmentPicked: kotlin.Function1, onRecordAudioMessageClicked: kotlin.Function0, tempWritableImageUri: android.net.Uri?, tempWritableVideoUri: android.net.Uri?, isFileSharingEnabled: kotlin.Boolean, areAttachmentOptionsEnabled: kotlin.Boolean, onLocationPickerClicked: kotlin.Function0, onPermissionPermanentlyDenied: kotlin.Function1<@[ParameterName(name = \, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: false restartable: true params: @@ -8696,6 +8183,7 @@ public fun com.wire.android.ui.home.messagecomposer.AttachmentOptionsComponent(o - tempWritableImageUri: RUNTIME (requires runtime check) - tempWritableVideoUri: RUNTIME (requires runtime check) - isFileSharingEnabled: STABLE (primitive type) + - areAttachmentOptionsEnabled: STABLE (primitive type) - onLocationPickerClicked: STABLE (function type) - onPermissionPermanentlyDenied: STABLE (function type) - modifier: STABLE (marked @Stable or @Immutable) @@ -8732,13 +8220,14 @@ public fun com.wire.android.ui.home.messagecomposer.CollapseButton(isCollapsed: - modifier: STABLE (marked @Stable or @Immutable) @Composable -private fun com.wire.android.ui.home.messagecomposer.ComposingActions(conversationId: com.wire.kalium.logic.data.id.QualifiedID, selectedOption: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSelectItem, isFileSharingEnabled: kotlin.Boolean, attachmentsVisible: kotlin.Boolean, isMentionActive: kotlin.Boolean, onAdditionalOptionButtonClicked: kotlin.Function0, onRichEditingButtonClicked: kotlin.Function0, onGifButtonClicked: kotlin.Function0, onSelfDeletionOptionButtonClicked: kotlin.Function1, onPingButtonClicked: kotlin.Function0, onMentionButtonClicked: kotlin.Function0, onDrawingModeClicked: kotlin.Function0): kotlin.Unit +private fun com.wire.android.ui.home.messagecomposer.ComposingActions(conversationId: com.wire.kalium.logic.data.id.QualifiedID, selectedOption: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSelectItem, isFileSharingEnabled: kotlin.Boolean, areAttachmentOptionsEnabled: kotlin.Boolean, attachmentsVisible: kotlin.Boolean, isMentionActive: kotlin.Boolean, onAdditionalOptionButtonClicked: kotlin.Function0, onRichEditingButtonClicked: kotlin.Function0, onGifButtonClicked: kotlin.Function0, onSelfDeletionOptionButtonClicked: kotlin.Function1, onPingButtonClicked: kotlin.Function0, onMentionButtonClicked: kotlin.Function0, onDrawingModeClicked: kotlin.Function0): kotlin.Unit skippable: true restartable: true params: - conversationId: STABLE (matched by stability configuration) - selectedOption: STABLE (class with no mutable properties) - isFileSharingEnabled: STABLE (primitive type) + - areAttachmentOptionsEnabled: STABLE (primitive type) - attachmentsVisible: STABLE (primitive type) - isMentionActive: STABLE (primitive type) - onAdditionalOptionButtonClicked: STABLE (function type) @@ -8760,14 +8249,15 @@ private fun com.wire.android.ui.home.messagecomposer.DisabledInteractionMessageC - messageListContent: STABLE (composable function type) @Composable -private fun com.wire.android.ui.home.messagecomposer.DrawingModeAction(onButtonClicked: kotlin.Function0): kotlin.Unit +private fun com.wire.android.ui.home.messagecomposer.DrawingModeAction(onButtonClicked: kotlin.Function0, isEnabled: kotlin.Boolean): kotlin.Unit skippable: true restartable: true params: - onButtonClicked: STABLE (function type) + - isEnabled: STABLE (primitive type) @Composable -public fun com.wire.android.ui.home.messagecomposer.DropDownMentionsSuggestions(searchQuery: kotlin.String, currentSelectedLineIndex: kotlin.Int, cursorCoordinateY: kotlin.Float, membersToMention: kotlin.collections.List, onMentionPicked: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit +public fun com.wire.android.ui.home.messagecomposer.DropDownMentionsSuggestions(searchQuery: kotlin.String, currentSelectedLineIndex: kotlin.Int, cursorCoordinateY: kotlin.Float, membersToMention: kotlin.collections.List, onMentionPicked: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: false restartable: true params: @@ -8856,7 +8346,7 @@ private fun com.wire.android.ui.home.messagecomposer.ItalicButton(onRichTextItal - modifier: STABLE (marked @Stable or @Immutable) @Composable -public fun com.wire.android.ui.home.messagecomposer.MembersMentionList(membersToMention: kotlin.collections.List, searchQuery: kotlin.String, onMentionPicked: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit +public fun com.wire.android.ui.home.messagecomposer.MembersMentionList(membersToMention: kotlin.collections.List, searchQuery: kotlin.String, onMentionPicked: kotlin.Function1, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: false restartable: true params: @@ -8876,7 +8366,7 @@ public fun com.wire.android.ui.home.messagecomposer.MessageAttachments(attachmen - modifier: STABLE (marked @Stable or @Immutable) @Composable -public fun com.wire.android.ui.home.messagecomposer.MessageComposeActions(conversationId: com.wire.kalium.logic.data.id.QualifiedID, isEditing: kotlin.Boolean, attachmentsVisible: kotlin.Boolean, selectedOption: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSelectItem, onMentionButtonClicked: kotlin.Function0, onAdditionalOptionButtonClicked: kotlin.Function0, onPingButtonClicked: kotlin.Function0, onSelfDeletionOptionButtonClicked: kotlin.Function1, onGifButtonClicked: kotlin.Function0, onRichEditingButtonClicked: kotlin.Function0, isFileSharingEnabled: kotlin.Boolean, isMentionActive: kotlin.Boolean, onDrawingModeClicked: kotlin.Function0): kotlin.Unit +public fun com.wire.android.ui.home.messagecomposer.MessageComposeActions(conversationId: com.wire.kalium.logic.data.id.QualifiedID, isEditing: kotlin.Boolean, attachmentsVisible: kotlin.Boolean, selectedOption: com.wire.android.ui.home.messagecomposer.state.AdditionalOptionSelectItem, onMentionButtonClicked: kotlin.Function0, onAdditionalOptionButtonClicked: kotlin.Function0, onPingButtonClicked: kotlin.Function0, onSelfDeletionOptionButtonClicked: kotlin.Function1, onGifButtonClicked: kotlin.Function0, onRichEditingButtonClicked: kotlin.Function0, isFileSharingEnabled: kotlin.Boolean, areAttachmentOptionsEnabled: kotlin.Boolean, isMentionActive: kotlin.Boolean, onDrawingModeClicked: kotlin.Function0): kotlin.Unit skippable: true restartable: true params: @@ -8891,6 +8381,7 @@ public fun com.wire.android.ui.home.messagecomposer.MessageComposeActions(conver - onGifButtonClicked: STABLE (function type) - onRichEditingButtonClicked: STABLE (function type) - isFileSharingEnabled: STABLE (primitive type) + - areAttachmentOptionsEnabled: STABLE (primitive type) - isMentionActive: STABLE (primitive type) - onDrawingModeClicked: STABLE (function type) @@ -9010,11 +8501,12 @@ public fun com.wire.android.ui.home.messagecomposer.attachments.AdditionalOption - viewModel: RUNTIME (requires runtime check) @Composable -private fun com.wire.android.ui.home.messagecomposer.buildAttachmentOptionItems(isFileSharingEnabled: kotlin.Boolean, tempWritableImageUri: android.net.Uri?, tempWritableVideoUri: android.net.Uri?, onImagesPicked: kotlin.Function1, kotlin.Unit>, onFilePicked: kotlin.Function1, onRecordAudioMessageClicked: kotlin.Function0, onLocationPickerClicked: kotlin.Function0, onPermissionPermanentlyDenied: kotlin.Function1<@[ParameterName(name = \): kotlin.collections.List +private fun com.wire.android.ui.home.messagecomposer.buildAttachmentOptionItems(isFileSharingEnabled: kotlin.Boolean, areAttachmentOptionsEnabled: kotlin.Boolean, tempWritableImageUri: android.net.Uri?, tempWritableVideoUri: android.net.Uri?, onImagesPicked: kotlin.Function1, kotlin.Unit>, onFilePicked: kotlin.Function1, onRecordAudioMessageClicked: kotlin.Function0, onLocationPickerClicked: kotlin.Function0, onPermissionPermanentlyDenied: kotlin.Function1<@[ParameterName(name = \): kotlin.collections.List skippable: false restartable: true params: - isFileSharingEnabled: STABLE (primitive type) + - areAttachmentOptionsEnabled: STABLE (primitive type) - tempWritableImageUri: RUNTIME (requires runtime check) - tempWritableVideoUri: RUNTIME (requires runtime check) - onImagesPicked: STABLE (function type) @@ -9325,11 +8817,12 @@ private fun com.wire.android.ui.home.newconversation.channelaccess.AccessSection - onAccessChange: STABLE (function type) @Composable -public fun com.wire.android.ui.home.newconversation.channelaccess.ChannelAccessOnCreateScreen(navigator: com.wire.android.navigation.Navigator): kotlin.Unit - skippable: true +public fun com.wire.android.ui.home.newconversation.channelaccess.ChannelAccessOnCreateScreen(navigator: com.wire.android.navigation.Navigator, newConversationViewModel: com.wire.android.ui.home.newconversation.NewConversationViewModel): kotlin.Unit + skippable: false restartable: true params: - navigator: STABLE (marked @Stable or @Immutable) + - newConversationViewModel: UNSTABLE (has mutable properties or unstable members) @Composable public fun com.wire.android.ui.home.newconversation.channelaccess.ChannelAccessScreenContent(internalPadding: androidx.compose.foundation.layout.PaddingValues, selectedAccess: com.wire.android.ui.home.newconversation.channelaccess.ChannelAccessType, selectedPermission: com.wire.android.ui.home.newconversation.channelaccess.ChannelAddPermissionType, modifier: androidx.compose.ui.Modifier, onAccessChange: kotlin.Function1, onPermissionChange: kotlin.Function1): kotlin.Unit @@ -9389,12 +8882,13 @@ private fun com.wire.android.ui.home.newconversation.channelhistory.ChannelHisto params: @Composable -public fun com.wire.android.ui.home.newconversation.channelhistory.ChannelHistoryScreen(navigator: com.wire.android.navigation.Navigator, customResultRecipient: com.ramcosta.composedestinations.result.ResultRecipient, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true +public fun com.wire.android.ui.home.newconversation.channelhistory.ChannelHistoryScreen(navigator: com.wire.android.navigation.Navigator, customResultRecipient: com.ramcosta.composedestinations.result.ResultRecipient, newConversationViewModel: com.wire.android.ui.home.newconversation.NewConversationViewModel, modifier: androidx.compose.ui.Modifier): kotlin.Unit + skippable: false restartable: true params: - navigator: STABLE (marked @Stable or @Immutable) - customResultRecipient: STABLE (marked @Stable or @Immutable) + - newConversationViewModel: UNSTABLE (has mutable properties or unstable members) - modifier: STABLE (marked @Stable or @Immutable) @Composable @@ -9526,11 +9020,12 @@ private fun com.wire.android.ui.home.newconversation.groupOptions.EnableWireCell - onEnableWireCell: STABLE (function type) @Composable -public fun com.wire.android.ui.home.newconversation.groupOptions.GroupOptionScreen(navigator: com.wire.android.navigation.Navigator): kotlin.Unit - skippable: true +public fun com.wire.android.ui.home.newconversation.groupOptions.GroupOptionScreen(navigator: com.wire.android.navigation.Navigator, newConversationViewModel: com.wire.android.ui.home.newconversation.NewConversationViewModel): kotlin.Unit + skippable: false restartable: true params: - navigator: STABLE (marked @Stable or @Immutable) + - newConversationViewModel: UNSTABLE (has mutable properties or unstable members) @Composable private fun com.wire.android.ui.home.newconversation.groupOptions.GroupOptionScreenContent(groupOptionState: com.wire.android.ui.home.newconversation.groupOptions.GroupOptionState, createGroupState: com.wire.android.ui.home.newconversation.common.CreateGroupState, groupMetadataState: com.wire.android.ui.common.groupname.GroupMetadataState, onAccessClicked: kotlin.Function0, onHistoryClicked: kotlin.Function0, onAllowGuestChanged: kotlin.Function1, onAllowServicesChanged: kotlin.Function1, onReadReceiptChanged: kotlin.Function1, onEnableWireCellChanged: kotlin.Function1, onContinuePressed: kotlin.Function0, onAllowGuestsDialogDismissed: kotlin.Function0, onNotAllowGuestsClicked: kotlin.Function0, onAllowGuestsClicked: kotlin.Function0, onErrorDismissed: kotlin.Function0, onEditParticipantsClick: kotlin.Function0, onDiscardGroupCreationClick: kotlin.Function0, onBackPressed: kotlin.Function0, channelsHistoryOptionsEnabled: kotlin.Boolean, mlsReadReceiptsEnabled: kotlin.Boolean): kotlin.Unit @@ -9601,18 +9096,20 @@ private fun com.wire.android.ui.home.newconversation.groupOptions.ReadReceiptsOp - onReadReceiptChanged: STABLE (function type) @Composable -public fun com.wire.android.ui.home.newconversation.groupname.NewGroupNameScreen(navigator: com.wire.android.navigation.Navigator): kotlin.Unit - skippable: true +public fun com.wire.android.ui.home.newconversation.groupname.NewGroupNameScreen(navigator: com.wire.android.navigation.Navigator, newConversationViewModel: com.wire.android.ui.home.newconversation.NewConversationViewModel): kotlin.Unit + skippable: false restartable: true params: - navigator: STABLE (marked @Stable or @Immutable) + - newConversationViewModel: UNSTABLE (has mutable properties or unstable members) @Composable -public fun com.wire.android.ui.home.newconversation.groupsearch.NewGroupConversationSearchPeopleScreen(navigator: com.wire.android.navigation.Navigator): kotlin.Unit - skippable: true +public fun com.wire.android.ui.home.newconversation.groupsearch.NewGroupConversationSearchPeopleScreen(navigator: com.wire.android.navigation.Navigator, newConversationViewModel: com.wire.android.ui.home.newconversation.NewConversationViewModel): kotlin.Unit + skippable: false restartable: true params: - navigator: STABLE (marked @Stable or @Immutable) + - newConversationViewModel: UNSTABLE (has mutable properties or unstable members) @Composable public fun com.wire.android.ui.home.newconversation.search.ChannelNotAvailableDialog(onCreateTeam: kotlin.Function0, onDismiss: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit @@ -9624,18 +9121,12 @@ public fun com.wire.android.ui.home.newconversation.search.ChannelNotAvailableDi - modifier: STABLE (marked @Stable or @Immutable) @Composable -public fun com.wire.android.ui.home.newconversation.search.NewConversationSearchPeopleScreen(navigator: com.wire.android.navigation.Navigator): kotlin.Unit - skippable: true - restartable: true - params: - - navigator: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.home.newconversation.sharedNewConversationViewModel(navigator: com.wire.android.navigation.Navigator): com.wire.android.ui.home.newconversation.NewConversationViewModel - skippable: true +public fun com.wire.android.ui.home.newconversation.search.NewConversationSearchPeopleScreen(navigator: com.wire.android.navigation.Navigator, newConversationViewModel: com.wire.android.ui.home.newconversation.NewConversationViewModel): kotlin.Unit + skippable: false restartable: true params: - navigator: STABLE (marked @Stable or @Immutable) + - newConversationViewModel: UNSTABLE (has mutable properties or unstable members) @Composable public fun com.wire.android.ui.home.rememberHomeScreenState(navigator: com.wire.android.navigation.Navigator, coroutineScope: kotlinx.coroutines.CoroutineScope, navController: androidx.navigation.NavHostController, drawerState: androidx.compose.material3.DrawerState): com.wire.android.ui.home.HomeStateHolder @@ -10530,21 +10021,6 @@ public fun com.wire.android.ui.legalhold.banner.LegalHoldSubjectBanner(modifier: - modifier: STABLE (marked @Stable or @Immutable) - onClick: STABLE (function type) -@Composable -public fun com.wire.android.ui.legalhold.dialog.common.LearnMoreAboutLegalHoldButton(modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - modifier: STABLE (marked @Stable or @Immutable) - -@Composable -public fun com.wire.android.ui.legalhold.dialog.connectionfailed.LegalHoldSubjectConnectionFailedDialog(dialogDismissed: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit - skippable: true - restartable: true - params: - - dialogDismissed: STABLE (function type) - - modifier: STABLE (marked @Stable or @Immutable) - @Composable public fun com.wire.android.ui.legalhold.dialog.deactivated.LegalHoldDeactivatedDialog(dialogDismissed: kotlin.Function0, modifier: androidx.compose.ui.Modifier): kotlin.Unit skippable: true @@ -11587,7 +11063,7 @@ public fun com.wire.android.ui.userprofile.common.UserProfileInfo(userId: com.wi - fullName: STABLE (String is immutable) - userName: STABLE (String is immutable) - teamName: STABLE (class with no mutable properties) - - membership: STABLE (class with no mutable properties) + - membership: STABLE (marked @Stable or @Immutable) - onUserProfileClick: STABLE (function type) - editableState: STABLE (class with no mutable properties) - modifier: STABLE (marked @Stable or @Immutable) @@ -11616,7 +11092,7 @@ private fun com.wire.android.ui.userprofile.common.processUsername(userName: kot restartable: true params: - userName: STABLE (String is immutable) - - membership: STABLE (class with no mutable properties) + - membership: STABLE (marked @Stable or @Immutable) - expiresAt: UNSTABLE (has mutable properties or unstable members) @Composable @@ -11679,7 +11155,7 @@ public fun com.wire.android.ui.userprofile.other.OtherUserConnectionStatusInfo(c restartable: true params: - connectionStatus: STABLE (class with no mutable properties) - - membership: STABLE (class with no mutable properties) + - membership: STABLE (marked @Stable or @Immutable) - modifier: STABLE (marked @Stable or @Immutable) @Composable @@ -11849,7 +11325,7 @@ private fun com.wire.android.ui.userprofile.other.descriptionResourceForConnecti restartable: true params: - connectionStatus: STABLE (class with no mutable properties) - - membership: STABLE (class with no mutable properties) + - membership: STABLE (marked @Stable or @Immutable) @Composable public fun com.wire.android.ui.userprofile.other.rememberOtherUserProfileScreenState(): com.wire.android.ui.userprofile.other.OtherUserProfileScreenState @@ -12428,15 +11904,6 @@ public fun com.wire.android.util.permission.rememberWriteStoragePermissionFlow(o - onPermissionDenied: STABLE (function type) - onPermissionPermanentlyDenied: STABLE (function type) -@Composable -public fun com.wire.android.util.ui.LinkText(linkTextData: kotlin.collections.List, modifier: androidx.compose.ui.Modifier, textColor: androidx.compose.ui.graphics.Color): kotlin.Unit - skippable: false - restartable: true - params: - - linkTextData: RUNTIME (requires runtime check) - - modifier: STABLE (marked @Stable or @Immutable) - - textColor: STABLE (marked @Stable or @Immutable) - @Composable public fun com.wire.android.util.ui.SnackBarMessageHandler(infoMessages: kotlinx.coroutines.flow.SharedFlow, onEmitted: kotlin.Function0, onActionClicked: kotlin.Function1): kotlin.Unit skippable: false @@ -12453,10 +11920,3 @@ public fun com.wire.android.util.ui.WireScrollableThemePreview(content: @[Compos params: - content: STABLE (composable function type) -@Composable -private fun com.wire.android.util.ui.createAnnotatedString(data: kotlin.collections.List): androidx.compose.ui.text.AnnotatedString - skippable: false - restartable: true - params: - - data: RUNTIME (requires runtime check) - From 4b4fef5147acdd39a8e7a3c36f91a926bff475af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Mon, 15 Jun 2026 10:32:06 +0200 Subject: [PATCH 13/17] update kalium ref --- kalium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalium b/kalium index 5b742c31427..5f605d3fe90 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 5b742c31427bc713903a4416a65797329e9ac6d2 +Subproject commit 5f605d3fe909bc7b8fa90048ad4dcb033c3b97d9 From 16d2576348cd4e77dbedd6eb7f7adeeced94cba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Mon, 15 Jun 2026 14:44:20 +0200 Subject: [PATCH 14/17] combine both dependencies into one block --- .../kotlin/com/wire/android/navigation/MainNavHost.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt b/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt index 88e259ca9df..3537631c748 100644 --- a/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt +++ b/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt @@ -134,17 +134,13 @@ fun MainNavHost( dependency(teamMigrationViewModel(parentEntry)) } - // 👇 To tie NewMeetingViewModel to nested NewMeetingGraph, - // making it shared between all screens that belong to it + // 👇 To tie NewMeetingViewModel to nested NewMeetingGraph, making it shared between all screens that belong to it + // Also, make MeetingNavigator available to all destinations from NewMeetingGraph as a non-navigation parameter navGraph(NewMeetingGraph) { val parentEntry = remember(navBackStackEntry) { navController.getBackStackEntry(NewMeetingGraph.route) } dependency(newMeetingViewModel(parentEntry)) - } - - // 👇 To make MeetingNavigator available to all destinations from NewMeetingGraph as a non-navigation parameter - navGraph(NewMeetingGraph) { dependency(meetingNavigator) } }, From 967212c2b1d109f8f5917a1d833f57ddf7b1bedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Mon, 15 Jun 2026 15:15:18 +0200 Subject: [PATCH 15/17] fixes after resolving conflicts --- .../channelhistory/ChannelHistoryScreen.kt | 1 - .../groupOptions/GroupOptionsScreen.kt | 13 ++++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelhistory/ChannelHistoryScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelhistory/ChannelHistoryScreen.kt index 8664e4e7fcf..af3c425b1cd 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelhistory/ChannelHistoryScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/channelhistory/ChannelHistoryScreen.kt @@ -53,7 +53,6 @@ fun ChannelHistoryScreen( navigator: Navigator, newConversationViewModel: NewConversationViewModel, customResultRecipient: ResultRecipient, - newConversationViewModel: NewConversationViewModel, modifier: Modifier = Modifier, ) { customResultRecipient.onNavResult { result -> diff --git a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupOptions/GroupOptionsScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupOptions/GroupOptionsScreen.kt index 144c0320665..698af439f42 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupOptions/GroupOptionsScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/newconversation/groupOptions/GroupOptionsScreen.kt @@ -19,7 +19,6 @@ package com.wire.android.ui.home.newconversation.groupOptions -import com.wire.android.navigation.annotation.app.WireNewConversationDestination import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -36,12 +35,18 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration +import com.ramcosta.composedestinations.generated.app.destinations.ChannelAccessOnCreateScreenDestination +import com.ramcosta.composedestinations.generated.app.destinations.ChannelHistoryScreenDestination +import com.ramcosta.composedestinations.generated.app.destinations.ConversationScreenDestination +import com.ramcosta.composedestinations.generated.app.destinations.HomeScreenDestination +import com.ramcosta.composedestinations.generated.app.destinations.NewGroupConversationSearchPeopleScreenDestination import com.wire.android.BuildConfig import com.wire.android.R import com.wire.android.model.Clickable import com.wire.android.navigation.BackStackMode import com.wire.android.navigation.NavigationCommand import com.wire.android.navigation.Navigator +import com.wire.android.navigation.annotation.app.WireNewConversationDestination import com.wire.android.ui.common.TextWithLinkSuffix import com.wire.android.ui.common.WireDialog import com.wire.android.ui.common.WireDialogButtonProperties @@ -55,18 +60,12 @@ import com.wire.android.ui.common.topappbar.NavigationIconType import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar import com.wire.android.ui.common.typography import com.wire.android.ui.common.upgradetoapps.UpgradeToGetAppsBanner -import com.ramcosta.composedestinations.generated.app.destinations.ChannelAccessOnCreateScreenDestination -import com.ramcosta.composedestinations.generated.app.destinations.ChannelHistoryScreenDestination -import com.ramcosta.composedestinations.generated.app.destinations.ConversationScreenDestination -import com.ramcosta.composedestinations.generated.app.destinations.HomeScreenDestination -import com.ramcosta.composedestinations.generated.app.destinations.NewGroupConversationSearchPeopleScreenDestination import com.wire.android.ui.home.conversations.details.options.ArrowType import com.wire.android.ui.home.conversations.details.options.GroupConversationOptionsItem import com.wire.android.ui.home.newconversation.NewConversationViewModel import com.wire.android.ui.home.newconversation.channelaccess.ChannelAccessType import com.wire.android.ui.home.newconversation.channelhistory.ChannelHistoryType import com.wire.android.ui.home.newconversation.channelhistory.name -import com.wire.android.ui.home.newconversation.NewConversationViewModel import com.wire.android.ui.home.newconversation.common.CreateGroupErrorDialog import com.wire.android.ui.home.newconversation.common.CreateGroupState import com.wire.android.ui.home.settings.SwitchState From 52bc7936303a458c5ed7a48a96ed93645e234467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Mon, 15 Jun 2026 17:22:19 +0200 Subject: [PATCH 16/17] renamed parameter --- .../com/wire/android/search/users/SearchUserViewModel.kt | 4 ++-- .../wire/android/search/users/SearchUserViewModelTest.kt | 8 ++++---- kalium | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt b/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt index ef8c37cdde9..e4380f57800 100644 --- a/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt +++ b/core/search/src/main/kotlin/com/wire/android/search/users/SearchUserViewModel.kt @@ -143,7 +143,7 @@ class SearchUserViewModel( searchUsersByHandle( searchTerm, excludingConversation = conversationId, - excludingNotConnected = onlyConnectedContacts, + skipRemoteSearch = onlyConnectedContacts, customDomain = domain ) @@ -151,7 +151,7 @@ class SearchUserViewModel( searchUsersByName( searchTerm, excludingMembersOfConversation = conversationId, - excludingNotConnected = onlyConnectedContacts, + skipRemoteSearch = onlyConnectedContacts, customDomain = domain ) } diff --git a/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt b/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt index 68d62c0e113..cbab1dd2cec 100644 --- a/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt +++ b/core/search/src/test/kotlin/com/wire/android/search/users/SearchUserViewModelTest.kt @@ -343,7 +343,7 @@ class SearchUserViewModelTest { arrangement.searchUsersByHandleUseCase.invoke( searchHandle = query, excludingConversation = null, - excludingNotConnected = false, + skipRemoteSearch = false, customDomain = "domain" ) } @@ -364,7 +364,7 @@ class SearchUserViewModelTest { arrangement.searchUsersByHandleUseCase.invoke( searchHandle = query, excludingConversation = null, - excludingNotConnected = true, + skipRemoteSearch = true, customDomain = "domain" ) } @@ -385,7 +385,7 @@ class SearchUserViewModelTest { arrangement.searchUsersByNameUseCase.invoke( searchQuery = query, excludingMembersOfConversation = null, - excludingNotConnected = false, + skipRemoteSearch = false, customDomain = "domain" ) } @@ -406,7 +406,7 @@ class SearchUserViewModelTest { arrangement.searchUsersByNameUseCase.invoke( searchQuery = query, excludingMembersOfConversation = null, - excludingNotConnected = true, + skipRemoteSearch = true, customDomain = "domain" ) } diff --git a/kalium b/kalium index 5f605d3fe90..674782270de 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 5f605d3fe909bc7b8fa90048ad4dcb033c3b97d9 +Subproject commit 674782270de4f1abb89c7ebb16d7930e131c96ec From 85368e19e855fcd616682eda2f9744f84c10145d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Mon, 15 Jun 2026 18:52:35 +0200 Subject: [PATCH 17/17] update kalium ref --- kalium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalium b/kalium index 674782270de..7fed478f72d 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 674782270de4f1abb89c7ebb16d7930e131c96ec +Subproject commit 7fed478f72d9f885211a0f088ab40c96cc5670ec