From 5e89a0b221821e4be5b83d01075e794cb7239031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= <30429749+saleniuk@users.noreply.github.com> Date: Wed, 5 Jun 2024 14:43:39 +0200 Subject: [PATCH] fix: issues with sharing media [WPB-9550] (#3077) --- .../com/wire/android/ui/WireActivity.kt | 20 ++- .../ImportMediaAuthenticatedViewModel.kt | 2 +- .../android/ui/sharing/ImportMediaScreen.kt | 153 ++++++++++-------- 3 files changed, 104 insertions(+), 71 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt b/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt index 2a8574d6f82..9abb0e07972 100644 --- a/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt +++ b/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt @@ -115,6 +115,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onSubscription import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -142,6 +143,7 @@ class WireActivity : AppCompatActivity() { // This flag is used to keep the splash screen open until the first screen is drawn. private var shouldKeepSplashOpen = true + private var isNavigationCollecting = false override fun onCreate(savedInstanceState: Bundle?) { @@ -181,11 +183,15 @@ class WireActivity : AppCompatActivity() { } override fun onNewIntent(intent: Intent?) { - if (viewModel.isSharingIntent(intent)) { + super.onNewIntent(intent) + if (isNavigationCollecting) { + // when true then navigationCommands is subscribed and can handle navigation commands + handleDeepLink(intent) + } else { + // when false then navigationCommands needs to be subscribed again to be able to receive and handle navigation commands + // Activity intent is updated to handle deep link after navigationCommands is subscribed again and onComplete called again setIntent(intent) } - handleDeepLink(intent) - super.onNewIntent(intent) } private fun setComposableContent( @@ -260,7 +266,13 @@ class WireActivity : AppCompatActivity() { lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { navigationCommands - .onSubscription { onComplete() } + .onSubscription { + isNavigationCollecting = true + onComplete() + } + .onCompletion { + isNavigationCollecting = false + } .collectLatest { currentKeyboardController?.hide() currentNavController.navigateToItem(it) diff --git a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt index 1270fde5122..fc24373cc00 100644 --- a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaAuthenticatedViewModel.kt @@ -99,7 +99,7 @@ class ImportMediaAuthenticatedViewModel @Inject constructor( private val _infoMessage = MutableSharedFlow() val infoMessage = _infoMessage.asSharedFlow() - fun init() { + init { viewModelScope.launch { loadUserAvatar() observeConversationWithSearch() diff --git a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaScreen.kt b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaScreen.kt index e1fd291bad1..782b7fa7fc9 100644 --- a/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/sharing/ImportMediaScreen.kt @@ -46,7 +46,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.ramcosta.composedestinations.annotation.Destination @@ -72,6 +71,7 @@ import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar import com.wire.android.ui.common.topappbar.search.SearchBarState import com.wire.android.ui.common.topappbar.search.SearchTopBar import com.wire.android.ui.destinations.ConversationScreenDestination +import com.wire.android.ui.destinations.WelcomeScreenDestination import com.wire.android.ui.home.FeatureFlagState import com.wire.android.ui.home.conversations.AssetTooLargeDialog import com.wire.android.ui.home.conversations.ConversationNavArgs @@ -91,6 +91,7 @@ import com.wire.android.util.CustomTabsHelper import com.wire.android.util.extension.getActivity import com.wire.android.util.ui.LinkText import com.wire.android.util.ui.LinkTextData +import com.wire.android.util.ui.PreviewMultipleThemes import com.wire.kalium.logic.data.asset.AttachmentType import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.util.isPositiveNotNull @@ -107,69 +108,25 @@ import okio.Path.Companion.toPath fun ImportMediaScreen( navigator: Navigator, featureFlagNotificationViewModel: FeatureFlagNotificationViewModel = hiltViewModel(), - checkAssetRestrictionsViewModel: CheckAssetRestrictionsViewModel = hiltViewModel(), - importMediaViewModel: ImportMediaAuthenticatedViewModel = hiltViewModel(), ) { when (val fileSharingRestrictedState = featureFlagNotificationViewModel.featureFlagState.fileSharingRestrictedState) { FeatureFlagState.SharingRestrictedState.NO_USER -> { ImportMediaLoggedOutContent( fileSharingRestrictedState = fileSharingRestrictedState, - navigateBack = navigator.finish - ) - } - - FeatureFlagState.SharingRestrictedState.RESTRICTED_IN_TEAM -> { - - ImportMediaRestrictedContent( - fileSharingRestrictedState = fileSharingRestrictedState, - importMediaAuthenticatedState = importMediaViewModel.importMediaState, - navigateBack = navigator.finish + navigateBack = navigator.finish, + openWireAction = { + navigator.navigate(NavigationCommand(WelcomeScreenDestination, BackStackMode.CLEAR_WHOLE)) + } ) } + FeatureFlagState.SharingRestrictedState.RESTRICTED_IN_TEAM, FeatureFlagState.SharingRestrictedState.NONE -> { - ImportMediaRegularContent( - importMediaAuthenticatedState = importMediaViewModel.importMediaState, - onSearchQueryChanged = importMediaViewModel::onSearchQueryChanged, - onConversationClicked = importMediaViewModel::onConversationClicked, - checkRestrictionsAndSendImportedMedia = { - importMediaViewModel.importMediaState.selectedConversationItem.firstOrNull()?.let { conversationItem -> - checkAssetRestrictionsViewModel.checkRestrictions( - importedMediaList = importMediaViewModel.importMediaState.importedAssets, - onSuccess = { - navigator.navigate( - NavigationCommand( - ConversationScreenDestination( - ConversationNavArgs( - conversationId = conversationItem.conversationId, - pendingBundles = ArrayList(it) - ) - ), - BackStackMode.UPDATE_EXISTED - ), - ) - } - ) - } - }, - onNewSelfDeletionTimerPicked = importMediaViewModel::onNewSelfDeletionTimerPicked, - infoMessage = importMediaViewModel.infoMessage, - navigateBack = navigator.finish, - onRemoveAsset = importMediaViewModel::onRemove - ) - AssetTooLargeDialog( - dialogState = checkAssetRestrictionsViewModel.assetTooLargeDialogState, - hideDialog = checkAssetRestrictionsViewModel::hideDialog + ImportMediaAuthenticatedContent( + navigator = navigator, + isRestrictedInTeam = fileSharingRestrictedState == FeatureFlagState.SharingRestrictedState.RESTRICTED_IN_TEAM, ) - - val context = LocalContext.current - LaunchedEffect(importMediaViewModel.importMediaState.importedAssets) { - if (importMediaViewModel.importMediaState.importedAssets.isEmpty()) { - context.getActivity() - ?.let { importMediaViewModel.handleReceivedDataFromSharingIntent(it) } - } - } } null -> { @@ -180,9 +137,65 @@ fun ImportMediaScreen( BackHandler { navigator.finish() } } +@Composable +private fun ImportMediaAuthenticatedContent( + navigator: Navigator, + isRestrictedInTeam: Boolean, + checkAssetRestrictionsViewModel: CheckAssetRestrictionsViewModel = hiltViewModel(), + importMediaViewModel: ImportMediaAuthenticatedViewModel = hiltViewModel(), +) { + if (isRestrictedInTeam) { + ImportMediaRestrictedContent( + importMediaAuthenticatedState = importMediaViewModel.importMediaState, + navigateBack = navigator.finish + ) + } else { + ImportMediaRegularContent( + importMediaAuthenticatedState = importMediaViewModel.importMediaState, + onSearchQueryChanged = importMediaViewModel::onSearchQueryChanged, + onConversationClicked = importMediaViewModel::onConversationClicked, + checkRestrictionsAndSendImportedMedia = { + importMediaViewModel.importMediaState.selectedConversationItem.firstOrNull()?.let { conversationItem -> + checkAssetRestrictionsViewModel.checkRestrictions( + importedMediaList = importMediaViewModel.importMediaState.importedAssets, + onSuccess = { + navigator.navigate( + NavigationCommand( + ConversationScreenDestination( + ConversationNavArgs( + conversationId = conversationItem.conversationId, + pendingBundles = ArrayList(it) + ) + ), + BackStackMode.UPDATE_EXISTED + ), + ) + } + ) + } + }, + onNewSelfDeletionTimerPicked = importMediaViewModel::onNewSelfDeletionTimerPicked, + infoMessage = importMediaViewModel.infoMessage, + navigateBack = navigator.finish, + onRemoveAsset = importMediaViewModel::onRemove + ) + AssetTooLargeDialog( + dialogState = checkAssetRestrictionsViewModel.assetTooLargeDialogState, + hideDialog = checkAssetRestrictionsViewModel::hideDialog + ) + + val context = LocalContext.current + LaunchedEffect(importMediaViewModel.importMediaState.importedAssets) { + if (importMediaViewModel.importMediaState.importedAssets.isEmpty()) { + context.getActivity() + ?.let { importMediaViewModel.handleReceivedDataFromSharingIntent(it) } + } + } + } +} + @Composable fun ImportMediaRestrictedContent( - fileSharingRestrictedState: FeatureFlagState.SharingRestrictedState, importMediaAuthenticatedState: ImportMediaAuthenticatedState, navigateBack: () -> Unit, modifier: Modifier = Modifier, @@ -207,7 +220,7 @@ fun ImportMediaRestrictedContent( content = { internalPadding -> FileSharingRestrictedContent( internalPadding, - fileSharingRestrictedState, + FeatureFlagState.SharingRestrictedState.RESTRICTED_IN_TEAM, navigateBack ) } @@ -282,6 +295,7 @@ fun ImportMediaRegularContent( fun ImportMediaLoggedOutContent( fileSharingRestrictedState: FeatureFlagState.SharingRestrictedState, navigateBack: () -> Unit, + openWireAction: () -> Unit, modifier: Modifier = Modifier ) { WireScaffold( @@ -296,9 +310,9 @@ fun ImportMediaLoggedOutContent( modifier = modifier.background(colorsScheme().background), content = { internalPadding -> FileSharingRestrictedContent( - internalPadding, - fileSharingRestrictedState, - navigateBack + internalPadding = internalPadding, + sharingRestrictedState = fileSharingRestrictedState, + openWireAction = openWireAction ) } ) @@ -525,27 +539,30 @@ private fun SnackBarMessage( } } -@Preview(showBackground = true) +@PreviewMultipleThemes @Composable fun PreviewImportMediaScreenLoggedOut() { WireTheme { - ImportMediaLoggedOutContent(FeatureFlagState.SharingRestrictedState.NO_USER, {}) + ImportMediaLoggedOutContent( + fileSharingRestrictedState = FeatureFlagState.SharingRestrictedState.NO_USER, + navigateBack = {}, + openWireAction = {}, + ) } } -@Preview(showBackground = true) +@PreviewMultipleThemes @Composable fun PreviewImportMediaScreenRestricted() { WireTheme { ImportMediaRestrictedContent( - fileSharingRestrictedState = FeatureFlagState.SharingRestrictedState.RESTRICTED_IN_TEAM, importMediaAuthenticatedState = ImportMediaAuthenticatedState(), - {} + navigateBack = {} ) } } -@Preview(showBackground = true) +@PreviewMultipleThemes @Composable fun PreviewImportMediaScreenRegular() { WireTheme { @@ -609,10 +626,14 @@ fun PreviewImportMediaScreenRegular() { } } -@Preview(showBackground = true) +@PreviewMultipleThemes @Composable fun PreviewImportMediaBottomBar() { WireTheme { - ImportMediaBottomBar(ImportMediaAuthenticatedState(), rememberImportMediaScreenState()) {} + ImportMediaBottomBar( + state = ImportMediaAuthenticatedState(), + importMediaScreenState = rememberImportMediaScreenState(), + checkRestrictionsAndSendImportedMedia = {}, + ) } }