From 02b01b18af1b7da6119ce5fcac97652c2933fb8c Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Tue, 1 Nov 2022 17:20:29 +0100 Subject: [PATCH 1/5] Add web back button handler and exit confirmation dialog --- .../webview/WebViewStoreCreationScreen.kt | 38 +++++++++++++++- .../webview/WebViewStoreCreationViewModel.kt | 43 ++++++++++++++++--- WooCommerce/src/main/res/values/strings.xml | 2 + 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt index 2621ceb5457f..c3170c2c55cd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Scaffold import androidx.compose.material.Text +import androidx.compose.material.TextButton import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons.Filled import androidx.compose.material.icons.filled.ArrowBack @@ -28,8 +29,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.woocommerce.android.R.string import com.woocommerce.android.ui.common.wpcomwebview.WPComWebViewAuthenticator +import com.woocommerce.android.ui.compose.component.AlertDialog import com.woocommerce.android.ui.compose.component.WCColoredButton import com.woocommerce.android.ui.compose.component.WCWebView +import com.woocommerce.android.ui.login.storecreation.webview.WebViewStoreCreationViewModel.DialogState import com.woocommerce.android.ui.login.storecreation.webview.WebViewStoreCreationViewModel.ViewState.ErrorState import com.woocommerce.android.ui.login.storecreation.webview.WebViewStoreCreationViewModel.ViewState.StoreCreationState import com.woocommerce.android.ui.login.storecreation.webview.WebViewStoreCreationViewModel.ViewState.StoreLoadingState @@ -73,6 +76,13 @@ fun WebViewStoreCreationScreen(viewModel: WebViewStoreCreationViewModel) { } } } + + viewModel.dialogViewState.observeAsState().value?.let { + if (it.isDialogVisible) { + ConfirmExitDialog(it) + } + } + } @SuppressLint("SetJavaScriptEnabled") @@ -102,9 +112,11 @@ private fun StoreCreationWebView( viewState.onSiteAddressFound(it) } - if (url.contains(viewState.exitTriggerKeyword, ignoreCase = true) && !storeCreationTriggered) { + if (url.contains(viewState.successTriggerKeyword, ignoreCase = true) && !storeCreationTriggered) { storeCreationTriggered = true viewState.onStoreCreated() + } else if (url == viewState.exitTriggerKeyword) { + viewState.onExitTriggered() } }, modifier = modifier.fillMaxSize() @@ -152,6 +164,30 @@ private fun StoreCreationInProgress() { } } +@Composable +private fun ConfirmExitDialog(viewState: DialogState) { + AlertDialog( + onDismissRequest = { viewState.onDialogDismissed() }, + title = { + Text(text = stringResource(id = string.store_creation_exit_dialog_title)) + }, + text = { + Text(text = stringResource(id = string.store_creation_exit_dialog_message)) + }, + confirmButton = { + TextButton(onClick = { viewState.onExitConfirmed() }) { + Text(stringResource(id = string.link_dialog_button_ok)) + } + }, + dismissButton = { + TextButton(onClick = { viewState.onDialogDismissed() }) { + Text(stringResource(id = string.cancel)) + } + }, + neutralButton = {} + ) +} + @Preview @Composable private fun PreviewStoreCreationInProgress() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt index 06076f95dac1..cd2bfed13f2c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt @@ -17,6 +17,7 @@ import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit import com.woocommerce.android.viewmodel.ScopedViewModel import com.woocommerce.android.viewmodel.getStateFlow import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize @@ -33,10 +34,14 @@ class WebViewStoreCreationViewModel @Inject constructor( companion object { private const val STORE_CREATION_URL = "https://woocommerce.com/start" private const val SITE_URL_KEYWORD = "checkout/thank-you/" - private const val WEBVIEW_EXIT_TRIGGER_KEYWORD = "calypso/images/wpcom-ecommerce" + private const val WEBVIEW_SUCCESS_TRIGGER_KEYWORD = "calypso/images/wpcom-ecommerce" + private const val WEBVIEW_EXIT_TRIGGER_KEYWORD = "https://woocommerce.com/" private const val STORE_LOAD_RETRIES_LIMIT = 10 } + private val _dialogViewState = savedStateHandle.getStateFlow(viewModelScope, setDialogState(isVisible = false)) + val dialogViewState = _dialogViewState.asStateFlow().asLiveData() + private val step = savedStateHandle.getStateFlow(viewModelScope, Step.StoreCreation) val viewState: LiveData = step.map { step -> when (step) { @@ -51,17 +56,27 @@ class WebViewStoreCreationViewModel @Inject constructor( private fun prepareStoreCreationState() = StoreCreationState( storeCreationUrl = STORE_CREATION_URL, siteUrlKeyword = SITE_URL_KEYWORD, + successTriggerKeyword = WEBVIEW_SUCCESS_TRIGGER_KEYWORD, exitTriggerKeyword = WEBVIEW_EXIT_TRIGGER_KEYWORD, onStoreCreated = ::onStoreCreated, - onSiteAddressFound = ::onSiteAddressFound + onSiteAddressFound = ::onSiteAddressFound, + onExitTriggered = ::exitStoreCreation ) private fun prepareErrorState() = ErrorState( - onRetryButtonClick = { - onStoreCreated() - } + onRetryButtonClick = ::onStoreCreated + ) + + private fun setDialogState(isVisible: Boolean) = DialogState( + isDialogVisible = isVisible, + onExitConfirmed = ::exitStoreCreation, + onDialogDismissed = ::onDialogDismissed ) + private fun onDialogDismissed() { + _dialogViewState.value = setDialogState(isVisible = false) + } + private fun onStoreCreated() { step.value = Step.StoreLoading launch { @@ -92,19 +107,25 @@ class WebViewStoreCreationViewModel @Inject constructor( possibleStoreUrls.add(url) } - fun onBackPressed() { + private fun exitStoreCreation() { + _dialogViewState.value = setDialogState(false) triggerEvent(Exit) } + fun onBackPressed() { + _dialogViewState.value = setDialogState(true) + } + sealed interface ViewState { data class StoreCreationState( val storeCreationUrl: String, val siteUrlKeyword: String, + val successTriggerKeyword: String, val exitTriggerKeyword: String, val onStoreCreated: () -> Unit, + val onExitTriggered: () -> Unit, val onSiteAddressFound: (url: String) -> Unit ) : ViewState - object StoreLoadingState : ViewState data class ErrorState( @@ -112,6 +133,14 @@ class WebViewStoreCreationViewModel @Inject constructor( ) : ViewState } + @Parcelize + data class DialogState( + val isDialogVisible: Boolean, + val onExitConfirmed: () -> Unit, + val onDialogDismissed: () -> Unit + ) : Parcelable + + object NavigateToNewStore : MultiLiveEvent.Event() private sealed interface Step : Parcelable { diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index d3c5a6fe47d9..95c7f8810830 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -2679,4 +2679,6 @@ Create a new store Couldn\'t load your store.\nPlease try again… Creating your store… + Do you want to leave? + You will lose all your store information. From ab26b934bc0ea916a8829ae59deef9e40f552f9e Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Tue, 1 Nov 2022 17:21:19 +0100 Subject: [PATCH 2/5] Fix the detekt issues --- .../ui/login/storecreation/webview/WebViewStoreCreationScreen.kt | 1 - .../login/storecreation/webview/WebViewStoreCreationViewModel.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt index c3170c2c55cd..01787e22a8e2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt @@ -82,7 +82,6 @@ fun WebViewStoreCreationScreen(viewModel: WebViewStoreCreationViewModel) { ConfirmExitDialog(it) } } - } @SuppressLint("SetJavaScriptEnabled") diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt index cd2bfed13f2c..149eeacd361a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt @@ -140,7 +140,6 @@ class WebViewStoreCreationViewModel @Inject constructor( val onDialogDismissed: () -> Unit ) : Parcelable - object NavigateToNewStore : MultiLiveEvent.Event() private sealed interface Step : Parcelable { From 8dc0913905f3673ccaedd4d620ceee954164ba56 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Tue, 1 Nov 2022 17:34:29 +0100 Subject: [PATCH 3/5] Reformat code --- .../storecreation/webview/WebViewStoreCreationViewModel.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt index 149eeacd361a..781f17c2cb81 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationViewModel.kt @@ -108,12 +108,12 @@ class WebViewStoreCreationViewModel @Inject constructor( } private fun exitStoreCreation() { - _dialogViewState.value = setDialogState(false) + _dialogViewState.value = setDialogState(isVisible = false) triggerEvent(Exit) } fun onBackPressed() { - _dialogViewState.value = setDialogState(true) + _dialogViewState.value = setDialogState(isVisible = true) } sealed interface ViewState { @@ -126,6 +126,7 @@ class WebViewStoreCreationViewModel @Inject constructor( val onExitTriggered: () -> Unit, val onSiteAddressFound: (url: String) -> Unit ) : ViewState + object StoreLoadingState : ViewState data class ErrorState( From 59764b0c440710c594482df93081ff98eca7fc2b Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Wed, 2 Nov 2022 09:06:33 +0100 Subject: [PATCH 4/5] Update the confirmation dialog button text --- .../login/storecreation/webview/WebViewStoreCreationScreen.kt | 2 +- WooCommerce/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt index 01787e22a8e2..c3e3ecfa49ad 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt @@ -175,7 +175,7 @@ private fun ConfirmExitDialog(viewState: DialogState) { }, confirmButton = { TextButton(onClick = { viewState.onExitConfirmed() }) { - Text(stringResource(id = string.link_dialog_button_ok)) + Text(stringResource(id = string.store_creation_confirm_and_leave)) } }, dismissButton = { diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index 95c7f8810830..22fb57e54405 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -2681,4 +2681,5 @@ Creating your store… Do you want to leave? You will lose all your store information. + Confirm and leave From 6eb42016b6a286498854f54b84642a3337cf5000 Mon Sep 17 00:00:00 2001 From: Ondrej Ruttkay Date: Wed, 2 Nov 2022 09:59:38 +0100 Subject: [PATCH 5/5] Simplify the callback reference --- .../login/storecreation/webview/WebViewStoreCreationScreen.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt index c3e3ecfa49ad..c4e2340e840f 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/storecreation/webview/WebViewStoreCreationScreen.kt @@ -50,9 +50,7 @@ fun WebViewStoreCreationScreen(viewModel: WebViewStoreCreationViewModel) { backgroundColor = MaterialTheme.colors.surface, title = { Text(stringResource(id = string.store_creation_create_new_store_label)) }, navigationIcon = { - IconButton(onClick = { - viewModel.onBackPressed() - }) { + IconButton(onClick = viewModel::onBackPressed) { Icon(Filled.ArrowBack, contentDescription = "Back") } },