Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1832263
fix: typo
ohassine Jan 16, 2026
4cc619f
chore: update release note
ohassine Jan 5, 2026
3b626e5
fix: missing DE translation
ohassine Jan 23, 2026
6dc904f
fix: incorrect translation for files tab (WPB-22523) (#4541)
ohassine Jan 22, 2026
aedceaf
Merge branch 'develop'
sbakhtiarov Jan 29, 2026
4e119fb
fix: crash when opening Drive screen
ohassine Jan 30, 2026
f6dac18
fix: cleanup
ohassine Jan 30, 2026
80e7d11
Merge branch 'main' into crash-when-opening-Drive-screen
ohassine Jan 30, 2026
b98285f
chore: avoid nullable value
ohassine Feb 3, 2026
7ef8539
feat: filter files in Shared drive
ohassine Feb 18, 2026
38589ff
feat: remove Other filter type
ohassine Feb 19, 2026
63b43ac
feat: support public link filter
ohassine Feb 20, 2026
42b058d
Merge remote-tracking branch 'origin/develop' into wire-drive-filter
ohassine Feb 20, 2026
31c21b4
chore: conflicts
ohassine Feb 20, 2026
8d14fa2
Merge remote-tracking branch 'origin/develop' into wire-drive-filter
ohassine Feb 23, 2026
547a630
chore: merge conflicts
ohassine Feb 23, 2026
2f58b77
chore: cleanup
ohassine Feb 23, 2026
9a3c5c6
chore: cleanup
ohassine Feb 25, 2026
d914ed4
fix: pausing/jumping bottomsheetmodal
ohassine Feb 26, 2026
9876eaf
fix: pausing/jumping bottomsheetmodal
ohassine Feb 26, 2026
d4c7860
chore: duplication
ohassine Feb 26, 2026
87ba1d8
feat: fetch owners from use case
ohassine Feb 26, 2026
d64f525
feat: add use case to fetch owners
ohassine Feb 26, 2026
fd7a0e7
feat: add archive and text file types
ohassine Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.wire.kalium.cells.domain.usecase.GetCellFileUseCase
import com.wire.kalium.cells.domain.usecase.GetEditorUrlUseCase
import com.wire.kalium.cells.domain.usecase.GetFoldersUseCase
import com.wire.kalium.cells.domain.usecase.GetMessageAttachmentUseCase
import com.wire.kalium.cells.domain.usecase.GetOwnersUseCase
import com.wire.kalium.cells.domain.usecase.GetPaginatedFilesFlowUseCase
import com.wire.kalium.cells.domain.usecase.GetPaginatedNodesUseCase
import com.wire.kalium.cells.domain.usecase.GetWireCellConfigurationUseCase
Expand Down Expand Up @@ -197,6 +198,10 @@ class CellsModule {
@Provides
fun provideGetAttachmentUseCase(cellsScope: CellsScope): GetMessageAttachmentUseCase = cellsScope.getMessageAttachmentUseCase

@ViewModelScoped
@Provides
fun provideGetOwnersUseCase(cellsScope: CellsScope): GetOwnersUseCase = cellsScope.getOwnersUseCase

@Provides
fun provideFileNameResolver(): FileNameResolver = FileNameResolver()

Expand Down
179 changes: 94 additions & 85 deletions app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
package com.wire.android.navigation

import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand Down Expand Up @@ -48,14 +51,15 @@ import com.ramcosta.composedestinations.scope.resultBackNavigator
import com.ramcosta.composedestinations.scope.resultRecipient
import com.ramcosta.composedestinations.spec.Direction
import com.wire.android.feature.sketch.model.DrawingCanvasNavBackArgs
import com.wire.android.navigation.transition.LocalSharedTransitionScope
import com.wire.android.ui.authentication.login.email.LoginEmailViewModel
import com.wire.android.ui.authentication.login.sso.SSOUrlConfigHolder
import com.wire.android.ui.authentication.login.sso.SSOUrlConfigHolderImpl
import com.wire.android.ui.home.conversations.ConversationScreen
import com.wire.android.ui.home.newconversation.NewConversationViewModel
import com.wire.android.ui.userprofile.teammigration.TeamMigrationViewModel

@OptIn(ExperimentalAnimationApi::class)
@OptIn(ExperimentalAnimationApi::class, ExperimentalSharedTransitionApi::class)
@Composable
fun MainNavHost(
navigator: Navigator,
Expand All @@ -64,98 +68,103 @@ fun MainNavHost(
modifier: Modifier = Modifier,
) {
val navHostEngine = rememberWireNavHostEngine(Alignment.Center)
DestinationsNavHost(
modifier = modifier,
navGraph = WireRootGraph,
defaultTransitions = WireRootGraph.defaultTransitions,
engine = navHostEngine,
start = startDestination,
navController = navigator.navController,
dependenciesContainerBuilder = {
// 👇 To make Navigator available to all destinations as a non-navigation parameter
dependency(navigator)
SharedTransitionLayout(modifier = modifier) {
CompositionLocalProvider(LocalSharedTransitionScope provides this) {
DestinationsNavHost(
modifier = modifier,
navGraph = WireRootGraph,
defaultTransitions = WireRootGraph.defaultTransitions,
engine = navHostEngine,
start = startDestination,
navController = navigator.navController,
dependenciesContainerBuilder = {
// 👇 To make Navigator available to all destinations as a non-navigation parameter
dependency(navigator)

// Always provide a default SSO holder at root scope so destinations can resolve it
// even when navigated directly without going through the expected nested graph route.
val rootEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(WireRootGraph.route)
}
val rootSSOHolder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(rootEntry.savedStateHandle)
dependency(rootSSOHolder)
// Always provide a default SSO holder at root scope so destinations can resolve it
// even when navigated directly without going through the expected nested graph route.
val rootEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(WireRootGraph.route)
}
val rootSSOHolder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(rootEntry.savedStateHandle)
dependency(rootSSOHolder)

// 👇 To make LoginTypeSelector available to all destinations as a non-navigation parameter if provided
if (loginTypeSelector != null) dependency(loginTypeSelector)
// 👇 To make LoginTypeSelector available to all destinations as a non-navigation parameter if provided
if (loginTypeSelector != null) dependency(loginTypeSelector)

// 👇 To tie NewConversationViewModel to nested NewConversationNavGraph, making it shared between all screens that belong to it
navGraph(NewConversationGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NewConversationGraph.route)
}
dependency(hiltViewModel<NewConversationViewModel>(parentEntry))
}
// 👇 To tie NewConversationViewModel to nested NewConversationNavGraph, making it shared between all screens that belong to it
navGraph(NewConversationGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NewConversationGraph.route)
}
dependency(hiltViewModel<NewConversationViewModel>(parentEntry))
}

// 👇 To reuse LoginEmailViewModel from NewLoginPasswordScreen on NewLoginVerificationCodeScreen
destination(NewLoginVerificationCodeScreenDestination) {
val loginPasswordEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NewLoginPasswordScreenDestination.route)
}
dependency(hiltViewModel<LoginEmailViewModel>(loginPasswordEntry))
}
// 👇 To reuse LoginEmailViewModel from NewLoginPasswordScreen on NewLoginVerificationCodeScreen
destination(NewLoginVerificationCodeScreenDestination) {
val loginPasswordEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NewLoginPasswordScreenDestination.route)
}
dependency(hiltViewModel<LoginEmailViewModel>(loginPasswordEntry))
}

// 👇 To tie SSOUrlConfigHolder to nested LoginNavGraph, making it shared between all screens that belong to it
navGraph(LoginGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(LoginGraph.route)
}
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(parentEntry.savedStateHandle)
dependency(holder)
}
// 👇 To tie SSOUrlConfigHolder to nested LoginNavGraph, making it shared between all screens that belong to it
navGraph(LoginGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(LoginGraph.route)
}
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(parentEntry.savedStateHandle)
dependency(holder)
}

// 👇 To tie SSOUrlConfigHolder to nested NewLoginNavGraph, making it shared between all screens that belong to it
navGraph(NewLoginGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NewLoginGraph.route)
}
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(parentEntry.savedStateHandle)
dependency(holder)
}
// 👇 To tie SSOUrlConfigHolder to nested NewLoginNavGraph, making it shared between all screens that belong to it
navGraph(NewLoginGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(NewLoginGraph.route)
}
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(parentEntry.savedStateHandle)
dependency(holder)
}

// Some flows navigate directly to screen destinations instead of the nav graph route.
// Provide the dependency at destination scope as a safe fallback.
destination(LoginScreenDestination) {
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(navBackStackEntry.savedStateHandle)
dependency(holder)
}
destination(NewLoginScreenDestination) {
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(navBackStackEntry.savedStateHandle)
dependency(holder)
}
// Some flows navigate directly to screen destinations instead of the nav graph route.
// Provide the dependency at destination scope as a safe fallback.
destination(LoginScreenDestination) {
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(navBackStackEntry.savedStateHandle)
dependency(holder)
}
destination(NewLoginScreenDestination) {
val holder: SSOUrlConfigHolder = SSOUrlConfigHolderImpl(navBackStackEntry.savedStateHandle)
dependency(holder)
}

// 👇 To tie TeamMigrationViewModel to PersonalToTeamMigrationNavGraph, making it shared between all screens that belong to it
navGraph(PersonalToTeamMigrationGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(PersonalToTeamMigrationGraph.route)
// 👇 To tie TeamMigrationViewModel to PersonalToTeamMigrationNavGraph,
// making it shared between all screens that belong to it
navGraph(PersonalToTeamMigrationGraph) {
val parentEntry = remember(navBackStackEntry) {
navController.getBackStackEntry(PersonalToTeamMigrationGraph.route)
}
dependency(hiltViewModel<TeamMigrationViewModel>(parentEntry))
}
},
manualComposableCallsBuilder = {
/**
* Keep manual composable calls for cross-module result wiring until we refactor
* those destinations to rely on generated dependencies directly.
*/
composable(ConversationScreenDestination) {
ConversationScreen(
navigator = navigator,
groupDetailsScreenResultRecipient = resultRecipient(groupConversationDetailsNavBackArgsNavType),
mediaGalleryScreenResultRecipient = resultRecipient(mediaGalleryNavBackArgsNavType),
imagePreviewScreenResultRecipient = resultRecipient(imagesPreviewNavBackArgsNavType),
drawingCanvasScreenResultRecipient = resultRecipient<DrawingCanvasScreenDestination, DrawingCanvasNavBackArgs>(
drawingCanvasNavBackArgsNavType
),
resultNavigator = resultBackNavigator(groupConversationDetailsNavBackArgsNavType),
)
}
}
dependency(hiltViewModel<TeamMigrationViewModel>(parentEntry))
}
},
manualComposableCallsBuilder = {
/**
* Keep manual composable calls for cross-module result wiring until we refactor
* those destinations to rely on generated dependencies directly.
*/
composable(ConversationScreenDestination) {
ConversationScreen(
navigator = navigator,
groupDetailsScreenResultRecipient = resultRecipient(groupConversationDetailsNavBackArgsNavType),
mediaGalleryScreenResultRecipient = resultRecipient(mediaGalleryNavBackArgsNavType),
imagePreviewScreenResultRecipient = resultRecipient(imagesPreviewNavBackArgsNavType),
drawingCanvasScreenResultRecipient = resultRecipient<DrawingCanvasScreenDestination, DrawingCanvasNavBackArgs>(
drawingCanvasNavBackArgsNavType
),
resultNavigator = resultBackNavigator(groupConversationDetailsNavBackArgsNavType),
)
}
)
}
)
}
}
2 changes: 2 additions & 0 deletions app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.layout.ContentScale
Expand Down Expand Up @@ -345,6 +346,7 @@ fun HomeContent(
searchBarHint = stringResource(searchBar.hint),
searchQueryTextState = searchBarState.searchQueryTextState,
onActiveChanged = searchBarState::searchActiveChanged,
focusRequester = remember { FocusRequester() }
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.res.stringResource
import com.wire.android.R
import com.wire.android.navigation.Navigator
Expand Down Expand Up @@ -56,6 +58,7 @@ private fun Content(
modifier: Modifier = Modifier
) {
val lazyListState = rememberLazyListState()
val focusRequester = remember { FocusRequester() }
WireScaffold(
modifier = modifier,
topBar = {
Expand All @@ -69,7 +72,8 @@ private fun Content(
isSearchActive = true,
searchBarHint = stringResource(id = R.string.label_search_public_channels),
searchQueryTextState = searchQueryTextState,
isLoading = false
isLoading = false,
focusRequester = focusRequester,
)
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import com.wire.android.R
Expand Down Expand Up @@ -140,13 +141,15 @@ fun SearchUsersAndAppsScreen(
}
},
topBarCollapsing = {
val focusRequester = remember { FocusRequester() }
SearchTopBar(
isSearchActive = searchBarState.isSearchActive,
searchBarHint = searchBarTitle,
backIconContentDescription = stringResource(id = R.string.content_description_add_participants_back_btn),
searchBarDescription = stringResource(R.string.content_description_add_participants_search_field),
searchQueryTextState = searchBarState.searchQueryTextState,
onActiveChanged = searchBarState::searchActiveChanged,
focusRequester = focusRequester,
)
},
topBarFooter = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
Expand Down Expand Up @@ -117,7 +119,8 @@ fun SearchConversationMessagesResultContent(
searchBarHint = stringResource(id = R.string.label_search_messages),
searchQueryTextState = searchQueryTextState,
onCloseSearchClicked = onCloseSearchClicked,
isLoading = state.isLoading
isLoading = state.isLoading,
focusRequester = remember { FocusRequester() },
)
}
if (isCellsConversation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
Expand Down Expand Up @@ -526,6 +527,7 @@ fun ImportMediaTopBarContent(
thickness = 1.dp,
modifier = Modifier.padding(top = dimensions().spacing12x)
)
val focusRequester = remember { FocusRequester() }
SearchTopBar(
isSearchActive = searchBarState.isSearchActive,
searchBarHint = stringResource(
Expand All @@ -534,6 +536,7 @@ fun ImportMediaTopBarContent(
),
searchQueryTextState = searchQueryTextState,
onActiveChanged = searchBarState::searchActiveChanged,
focusRequester = focusRequester,
)
}
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-hu/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,7 @@
<string name="label_conversation_media">Média</string>
<string name="label_conversation_pictures">Képek</string>
<string name="label_conversation_pictures_empty">Ebben a beszélgetésben még senki nem osztott meg képet 🥲</string>
<string name="label_conversation_files">Fájlok</string>
<string name="label_conversation_files_empty">Ebben a beszégetésben még senki nem osztott meg fájlt 🙀</string>
<!-- Search Contact-->
<string name="label_contacts">Névjegyek</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-it/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ Un messaggio eliminato non pu&#242; essere ripristinato.</string>
<string name="label_conversation_media">Multimedia</string>
<string name="label_conversation_pictures">Immagini</string>
<string name="label_conversation_pictures_empty">Nessuno ha ancora condiviso immagini in questa conversazione 🥲</string>
<string name="label_conversation_files">File</string>
<string name="label_conversation_files_empty">Nessuno ha ancora condiviso dei file in questa conversazione 🙀</string>
<!-- Search Contact-->
<string name="label_new_group">Nuovo Gruppo</string>
Expand Down
Loading