From d17d18470a1ba7e9cbf692e4693c9e0127b8759d Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <54908981+konstantiniiv@users.noreply.github.com> Date: Mon, 25 Mar 2024 12:58:16 +0100 Subject: [PATCH] DROID-1776 Gallery experience | Error handling (#1024) --- .../ui/gallery/GalleryInstallationFragment.kt | 34 ++++++++++++++++++- .../models/GalleryInstallationState.kt | 1 - .../viewmodel/GalleryInstallationViewModel.kt | 33 +++++++++++------- 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/anytypeio/anytype/ui/gallery/GalleryInstallationFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/gallery/GalleryInstallationFragment.kt index 52af68f7ad..e428bef3a0 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/gallery/GalleryInstallationFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/gallery/GalleryInstallationFragment.kt @@ -5,8 +5,13 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.compose.material.MaterialTheme +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.res.stringResource import androidx.core.os.bundleOf import androidx.fragment.app.viewModels import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -14,7 +19,10 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import com.anytypeio.anytype.R +import com.anytypeio.anytype.core_models.NO_VALUE import com.anytypeio.anytype.core_ui.common.ComposeDialogView +import com.anytypeio.anytype.core_ui.views.BaseAlertDialog import com.anytypeio.anytype.core_utils.ext.argString import com.anytypeio.anytype.core_utils.ext.subscribe import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment @@ -42,7 +50,7 @@ class GalleryInstallationFragment : BaseBottomSheetComposeFragment() { private val vm by viewModels { factory } private lateinit var navController: NavHostController - @OptIn(ExperimentalMaterialNavigationApi::class) + @OptIn(ExperimentalMaterialNavigationApi::class, ExperimentalMaterial3Api::class) override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -54,7 +62,31 @@ class GalleryInstallationFragment : BaseBottomSheetComposeFragment() { MaterialTheme { val bottomSheetNavigator = rememberBottomSheetNavigator() navController = rememberNavController(bottomSheetNavigator) + val errorText = remember { mutableStateOf(NO_VALUE) } + val isErrorDialogVisible = remember { mutableStateOf(false) } SetupNavigation(bottomSheetNavigator, navController) + LaunchedEffect(key1 = Unit) { + vm.errorState.collect { error -> + if (!error.isNullOrBlank()) { + errorText.value = error + isErrorDialogVisible.value = true + } + } + } + if (isErrorDialogVisible.value) { + BaseAlertDialog( + dialogText = errorText.value, + buttonText = stringResource(id = R.string.alert_qr_camera_ok), + onButtonClick = { + isErrorDialogVisible.value = false + errorText.value = NO_VALUE + }, + onDismissRequest = { + isErrorDialogVisible.value = false + errorText.value = NO_VALUE + } + ) + } } } } diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/models/GalleryInstallationState.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/models/GalleryInstallationState.kt index e441dacf3a..1b702fb244 100644 --- a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/models/GalleryInstallationState.kt +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/models/GalleryInstallationState.kt @@ -19,7 +19,6 @@ sealed class GalleryInstallationNavigation(val route: String) { object Main : GalleryInstallationNavigation("main") object Spaces : GalleryInstallationNavigation("spaces") object Success : GalleryInstallationNavigation("success") - object Error : GalleryInstallationNavigation("error") object Dismiss : GalleryInstallationNavigation("") object Exit : GalleryInstallationNavigation("exit") } diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt index bf64b2f9e0..40abd4c0cb 100644 --- a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt @@ -22,6 +22,7 @@ import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationState import com.anytypeio.anytype.gallery_experience.models.GallerySpaceView import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider import com.anytypeio.anytype.presentation.spaces.spaceIcon +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch import timber.log.Timber @@ -43,6 +44,7 @@ class GalleryInstallationViewModel( val spacesViewState = MutableStateFlow(GalleryInstallationSpacesState(emptyList(), false)) val command = MutableStateFlow(null) + val errorState = MutableSharedFlow(replay = 0) private val MAX_SPACES = 10 @@ -61,12 +63,12 @@ class GalleryInstallationViewModel( mainState.value = GalleryInstallationState.Success(manifestInfo) } else { Timber.e("DownloadGalleryManifest failed, manifestInfo is null") - command.value = GalleryInstallationNavigation.Error + errorState.emit("Download manifest error: manifestInfo is null") } }, onFailure = { error -> Timber.e(error, "DownloadGalleryManifest failed") - command.value = GalleryInstallationNavigation.Dismiss + errorState.emit("Download manifest error: ${error.message}") } ) } @@ -88,20 +90,21 @@ class GalleryInstallationViewModel( }, onFailure = { error -> Timber.e(error, "GetSpaceViews failed") + errorState.emit("Get Spaces error: ${error.message}") } ) } } fun onNewSpaceClick() { + val state = (mainState.value as? GalleryInstallationState.Success) ?: return subscribeToEventProcessChannel() command.value = GalleryInstallationNavigation.Dismiss - val manifestInfo = (mainState.value as? GalleryInstallationState.Success)?.info ?: return - mainState.value = - (mainState.value as? GalleryInstallationState.Success)?.copy(isLoading = true) ?: return + val manifestInfo = state.info + mainState.value = state.copy(isLoading = true) val params = CreateSpace.Params( details = mapOf( - Relations.NAME to manifestInfo.name, + Relations.NAME to manifestInfo.title, Relations.ICON_OPTION to spaceGradientProvider.randomId().toDouble() ) ) @@ -112,10 +115,13 @@ class GalleryInstallationViewModel( proceedWithInstallation( spaceId = SpaceId(space), isNewSpace = true, - manifestInfo = manifestInfo + manifestInfo = manifestInfo, + state = state ) }, onFailure = { error -> + mainState.value = state.copy(isLoading = false) + errorState.emit("Space creation error: ${error.message}") Timber.e(error, "CreateSpace failed") } ) @@ -123,12 +129,11 @@ class GalleryInstallationViewModel( } fun onSpaceClick(space: GallerySpaceView) { + val state = (mainState.value as? GalleryInstallationState.Success) ?: return subscribeToEventProcessChannel() Timber.d("onSpaceClick, space: $space") command.value = GalleryInstallationNavigation.Dismiss - mainState.value = - (mainState.value as? GalleryInstallationState.Success)?.copy(isLoading = true) ?: return - val manifestInfo = (mainState.value as? GalleryInstallationState.Success)?.info ?: return + mainState.value = state.copy(isLoading = true) val spaceId = space.obj.targetSpaceId if (spaceId == null) { Timber.e("onSpaceClick, spaceId is null") @@ -137,7 +142,8 @@ class GalleryInstallationViewModel( proceedWithInstallation( spaceId = SpaceId(spaceId), isNewSpace = false, - manifestInfo = manifestInfo + manifestInfo = state.info, + state = state ) } @@ -146,6 +152,7 @@ class GalleryInstallationViewModel( } private fun proceedWithInstallation( + state: GalleryInstallationState.Success, spaceId: SpaceId, isNewSpace: Boolean, manifestInfo: ManifestInfo @@ -161,10 +168,12 @@ class GalleryInstallationViewModel( onSuccess = { Timber.d("ObjectImportExperience success") command.value = GalleryInstallationNavigation.Success + mainState.value = state.copy(isLoading = false) }, onFailure = { error -> Timber.e(error, "ObjectImportExperience failed") - command.value = GalleryInstallationNavigation.Error + mainState.value = state.copy(isLoading = false) + errorState.emit("Import experience error: ${error.message}") } ) }