From eedbfcb77c56c6dc5618850277ff2db7603c73ae Mon Sep 17 00:00:00 2001 From: Yun Cheng <129205442+ycheng-kickstarter@users.noreply.github.com> Date: Wed, 3 Dec 2025 09:26:19 -0500 Subject: [PATCH] MBL-2723 continued: After login, open pledge manager webview (#2450) * MBL-2723 start PM webview on login viewmodel * Move toolbar title logic out of SplashScreenActivity and into ActivityExt * Translations * Remove FPO * Wrong toolbar title displayed due to feature flag * Let WebViewActivity observe currentUser before loading url * Add comments * Add viewmodel * Add and fix tests * Clean up * Have the WebViewEvent interface live in the ViewModel file * Refactor with isa and fix tests --------- Co-authored-by: Isabel Martin --- app/src/main/assets/json/server-config.json | 7 ++ .../main/java/com/kickstarter/ui/IntentKey.kt | 1 - .../ui/activities/LoginToutActivity.kt | 2 +- .../ui/activities/ProjectPageActivity.kt | 2 +- .../ui/activities/SplashScreenActivity.kt | 32 +-------- .../ui/activities/WebViewActivity.kt | 51 +++++++++++++- .../kickstarter/ui/extensions/ActivityExt.kt | 12 +++- .../viewmodels/SplashScreenViewModel.kt | 10 +-- .../viewmodels/WebViewViewModel.kt | 64 +++++++++++++++++ app/src/main/res/values-de/strings_i18n.xml | 1 + app/src/main/res/values-es/strings_i18n.xml | 1 + app/src/main/res/values-fr/strings_i18n.xml | 1 + app/src/main/res/values-ja/strings_i18n.xml | 1 + app/src/main/res/values/strings.xml | 3 - app/src/main/res/values/strings_i18n.xml | 1 + .../viewmodels/DeepLinkViewModelTest.kt | 32 +-------- .../viewmodels/WebViewViewModelTest.kt | 69 +++++++++++++++++++ 17 files changed, 214 insertions(+), 76 deletions(-) create mode 100644 app/src/main/java/com/kickstarter/viewmodels/WebViewViewModel.kt create mode 100644 app/src/test/java/com/kickstarter/viewmodels/WebViewViewModelTest.kt diff --git a/app/src/main/assets/json/server-config.json b/app/src/main/assets/json/server-config.json index 7915764be..46c552792 100644 --- a/app/src/main/assets/json/server-config.json +++ b/app/src/main/assets/json/server-config.json @@ -741,6 +741,7 @@ "Retry": "Retry", "Retry_or_select_another_method": "Retry or select another method.", "Reusability_and_recyclability": "Reusability and recyclability", + "Review_edits_made_to_your_order": "Review edits made to your order", "reward_amount_plus_shipping_cost_each": "%{reward_amount} + %{shipping_cost} shipping each", "Reward_delivered": "Reward delivered?", "Reward_estimated_for_delivery_in_date": "Reward estimated for delivery in %{delivery_date}", @@ -3435,6 +3436,7 @@ "Retry": "Erneut versuchen", "Retry_or_select_another_method": "Versuche es erneut oder wähle eine andere Karte.", "Reusability_and_recyclability": "Wiederverwertung und Recyclingfähigkeit", + "Review_edits_made_to_your_order": "Änderungen an deiner Bestellung prüfen", "reward_amount_plus_shipping_cost_each": "Jeweils %{reward_amount} + %{shipping_cost} Versandkosten", "Reward_delivered": "Belohnung versandt?", "Reward_estimated_for_delivery_in_date": "Voraussichtliche Lieferung der Belohnung im %{delivery_date}", @@ -6129,6 +6131,7 @@ "Retry": "Volver a intentar", "Retry_or_select_another_method": "Vuelve a intentarlo o selecciona otro método.", "Reusability_and_recyclability": "Reutilización y reciclabilidad", + "Review_edits_made_to_your_order": "Revisa las modificaciones realizadas en tu pedido", "reward_amount_plus_shipping_cost_each": "%{reward_amount} + %{shipping_cost} de envío cada una", "Reward_delivered": "¿Recompensa entregada?", "Reward_estimated_for_delivery_in_date": "Recompensa estimada para entregarse en %{delivery_date}", @@ -8823,6 +8826,7 @@ "Retry": "Réessayer", "Retry_or_select_another_method": "Veuillez réessayer ou choisir un autre moyen de paiement.", "Reusability_and_recyclability": "Recyclage et valorisation des déchets", + "Review_edits_made_to_your_order": "Vérifions les modifications apportées à votre commande", "reward_amount_plus_shipping_cost_each": "%{reward_amount} + %{shipping_cost} de frais de port par unité", "Reward_delivered": "Récompense livrée ?", "Reward_estimated_for_delivery_in_date": "Récompense prévue pour %{delivery_date}", @@ -11517,6 +11521,7 @@ "Retry": "Retry", "Retry_or_select_another_method": "Retry or select another method.", "Reusability_and_recyclability": "Reusability and recyclability", + "Review_edits_made_to_your_order": "Review edits made to your order", "reward_amount_plus_shipping_cost_each": "%{reward_amount} + %{shipping_cost} shipping each", "Reward_delivered": "Reward delivered?", "Reward_estimated_for_delivery_in_date": "Reward estimated for delivery in %{delivery_date}", @@ -14211,6 +14216,7 @@ "Retry": "もう一度試す", "Retry_or_select_another_method": "再試行するか別のお支払い方法を選択してください。", "Reusability_and_recyclability": "再利用可能性とリサイクル可能性", + "Review_edits_made_to_your_order": "ご注文への編集内容を確認してください", "reward_amount_plus_shipping_cost_each": "%{reward_amount} + 送料各 %{shipping_cost} ", "Reward_delivered": "リワードを受け取りましたか?", "Reward_estimated_for_delivery_in_date": "リワードの配達予定日は%{delivery_date}", @@ -16905,6 +16911,7 @@ "Retry": "Retry", "Retry_or_select_another_method": "Retry or select another method.", "Reusability_and_recyclability": "Reusability and recyclability", + "Review_edits_made_to_your_order": "Review edits made to your order", "reward_amount_plus_shipping_cost_each": "%{reward_amount} + %{shipping_cost} shipping each", "Reward_delivered": "Reward delivered?", "Reward_estimated_for_delivery_in_date": "Reward estimated for delivery in %{delivery_date}", diff --git a/app/src/main/java/com/kickstarter/ui/IntentKey.kt b/app/src/main/java/com/kickstarter/ui/IntentKey.kt index f541b40ea..91cb5154d 100644 --- a/app/src/main/java/com/kickstarter/ui/IntentKey.kt +++ b/app/src/main/java/com/kickstarter/ui/IntentKey.kt @@ -32,7 +32,6 @@ object IntentKey { const val SURVEY_RESPONSE = "com.kickstarter.kickstarter.survey_response" const val NOTIFICATION_SURVEY_RESPONSE = "com.kickstarter.kickstarter.survey_response" const val DEEPLINK_SURVEY_RESPONSE = "com.kickstarter.kickstarter.deeplink_survey_response" - const val DEEPLINK_PM_ORDER_EDIT = "com.kickstarter.kickstarter.deeplink_pm_order_edit" const val NOTIFICATION_PLEDGE_REDEMPTION = "com.kickstarter.kickstarter.notification_pledge_redeption" const val TOOLBAR_TITLE = "com.kickstarter.kickstarter.intent_toolbar_title" const val TRACKING_CLIENT_TYPE_TAG = "com.kickstarter.kickstarter.intent_tracking_client_tag" diff --git a/app/src/main/java/com/kickstarter/ui/activities/LoginToutActivity.kt b/app/src/main/java/com/kickstarter/ui/activities/LoginToutActivity.kt index 39547b332..9f6c5b180 100644 --- a/app/src/main/java/com/kickstarter/ui/activities/LoginToutActivity.kt +++ b/app/src/main/java/com/kickstarter/ui/activities/LoginToutActivity.kt @@ -282,7 +282,7 @@ class LoginToutActivity : ComponentActivity() { private fun finishWithSuccessfulResult() { setResult(RESULT_OK) - goToSurveyIfSurveyPresent() + goToSurveyIfSurveyPresent() // TODO: Remove in MBL-2879 finish() } diff --git a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt index 4cf203e1e..0ef411912 100644 --- a/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt +++ b/app/src/main/java/com/kickstarter/ui/activities/ProjectPageActivity.kt @@ -470,7 +470,7 @@ class ProjectPageActivity : this.viewModel.outputs.openPledgeManagerWebview() .observeOn(AndroidSchedulers.mainThread()) - .subscribe { startWebViewActivity(it, getString(R.string.Pledge_manager)) } + .subscribe { startWebViewActivity(it) } .addToDisposable(disposables) this.viewModel.outputs.projectMedia() diff --git a/app/src/main/java/com/kickstarter/ui/activities/SplashScreenActivity.kt b/app/src/main/java/com/kickstarter/ui/activities/SplashScreenActivity.kt index fe189df1b..1e6ac32a4 100644 --- a/app/src/main/java/com/kickstarter/ui/activities/SplashScreenActivity.kt +++ b/app/src/main/java/com/kickstarter/ui/activities/SplashScreenActivity.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp -import androidx.core.net.toUri import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat import com.kickstarter.R @@ -34,8 +33,6 @@ import com.kickstarter.libs.utils.UrlUtils.saveFlag import com.kickstarter.libs.utils.extensions.addToDisposable import com.kickstarter.libs.utils.extensions.getEnvironment import com.kickstarter.libs.utils.extensions.getProjectIntent -import com.kickstarter.libs.utils.extensions.isPMOrderEditUri -import com.kickstarter.libs.utils.extensions.isPMUri import com.kickstarter.libs.utils.extensions.path import com.kickstarter.models.SurveyResponse import com.kickstarter.ui.IntentKey @@ -173,15 +170,9 @@ class SplashScreenActivity : AppCompatActivity() { viewModel.outputs.startPMWebview() .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - val uri = it.first - val isLoggedIn = it.second + .subscribe { uri -> - if (isLoggedIn) { - startPMActivity(uri.toString()) - } else { - startLoginForPMOrderEdit(uri.toString()) - } + startPMActivity(uri.toString()) }.addToDisposable(disposables) statsigClient.updateExperimentUser() @@ -284,26 +275,9 @@ class SplashScreenActivity : AppCompatActivity() { finish() } - private fun startLoginForPMOrderEdit(url: String) { - val intent = Intent(this, LoginToutActivity::class.java) - .putExtra(IntentKey.LOGIN_REASON, LoginReason.DEFAULT) - .putExtra(IntentKey.DEEPLINK_PM_ORDER_EDIT, url) - startActivityForResult(intent, ActivityRequestCodes.LOGIN_FLOW) - } - private fun startPMActivity(url: String) { ApplicationUtils.startNewDiscoveryActivity(this) - - val uri = url.toUri() - val webEndpoint = environment.webEndpoint() - - val toolbarTitle = when { - uri.isPMUri(webEndpoint) -> getString(R.string.Pledge_manager) - uri.isPMOrderEditUri(webEndpoint) -> getString(R.string.fpo_review_edits) - else -> getString(R.string.Pledge_manager) - } - - startWebViewActivity(url, toolbarTitle = toolbarTitle) + startWebViewActivity(url) finish() } diff --git a/app/src/main/java/com/kickstarter/ui/activities/WebViewActivity.kt b/app/src/main/java/com/kickstarter/ui/activities/WebViewActivity.kt index 8b18716c0..e9fde9f01 100644 --- a/app/src/main/java/com/kickstarter/ui/activities/WebViewActivity.kt +++ b/app/src/main/java/com/kickstarter/ui/activities/WebViewActivity.kt @@ -1,19 +1,38 @@ package com.kickstarter.ui.activities +import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.addCallback +import androidx.activity.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import com.kickstarter.databinding.WebViewLayoutBinding +import com.kickstarter.libs.ActivityRequestCodes +import com.kickstarter.libs.utils.extensions.getEnvironment import com.kickstarter.ui.IntentKey +import com.kickstarter.ui.data.LoginReason import com.kickstarter.ui.extensions.finishWithAnimation import com.kickstarter.ui.views.KSWebView import com.kickstarter.utils.WindowInsetsUtil +import com.kickstarter.viewmodels.WebViewEvent +import com.kickstarter.viewmodels.WebViewViewModel +import kotlinx.coroutines.launch class WebViewActivity : ComponentActivity() { private lateinit var binding: WebViewLayoutBinding + private lateinit var viewModelFactory: WebViewViewModel.Factory + private val viewModel: WebViewViewModel by viewModels { + viewModelFactory + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + this.getEnvironment()?.let { env -> + viewModelFactory = WebViewViewModel.Factory(env) + } + binding = WebViewLayoutBinding.inflate(layoutInflater) WindowInsetsUtil.manageEdgeToEdge( window, @@ -38,9 +57,6 @@ class WebViewActivity : ComponentActivity() { } }) - val url = intent.getStringExtra(IntentKey.URL) - url?.let { binding.webView.loadUrl(it) } - onBackPressedDispatcher.addCallback { if (binding.webView.canGoBack()) { binding.webView.goBack() @@ -48,5 +64,34 @@ class WebViewActivity : ComponentActivity() { finishWithAnimation() } } + + observeCurrentUserEvents() + } + + // Check if the user is logged in. + // If no, start the LoginToutActivity. Wait for its result within the same backstack. + // Once LoginToutActivity is finished successfully WebViewActivity can proceed to load the url to the webview. + private fun observeCurrentUserEvents() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.webViewUIState.collect { event -> + when (event) { + WebViewEvent.SHOW_LOGIN -> startLoginToutActivity() + WebViewEvent.LOAD_WEBVIEW -> loadUrl() + } + } + } + } + } + + private fun loadUrl() { + val url = intent.getStringExtra(IntentKey.URL) + url?.let { binding.webView.loadUrl(it) } + } + + private fun startLoginToutActivity() { + val intent = Intent(this, LoginToutActivity::class.java) + .putExtra(IntentKey.LOGIN_REASON, LoginReason.STAR_PROJECT) + startActivityForResult(intent, ActivityRequestCodes.LOGIN_FLOW) } } diff --git a/app/src/main/java/com/kickstarter/ui/extensions/ActivityExt.kt b/app/src/main/java/com/kickstarter/ui/extensions/ActivityExt.kt index 30cf4b2fc..bab0fa086 100644 --- a/app/src/main/java/com/kickstarter/ui/extensions/ActivityExt.kt +++ b/app/src/main/java/com/kickstarter/ui/extensions/ActivityExt.kt @@ -11,6 +11,7 @@ import android.view.View import android.view.inputmethod.InputMethodManager import androidx.activity.result.ActivityResultLauncher import androidx.annotation.AnimRes +import androidx.core.net.toUri import androidx.fragment.app.Fragment import androidx.lifecycle.Lifecycle import com.google.android.play.core.review.ReviewInfo @@ -32,6 +33,8 @@ import com.kickstarter.libs.utils.extensions.getRootCommentsActivityIntent import com.kickstarter.libs.utils.extensions.getSearchIntent import com.kickstarter.libs.utils.extensions.getUpdatesActivityIntent import com.kickstarter.libs.utils.extensions.getVideoActivityIntent +import com.kickstarter.libs.utils.extensions.isPMOrderEditUri +import com.kickstarter.libs.utils.extensions.isPMUri import com.kickstarter.libs.utils.extensions.reduceProjectPayload import com.kickstarter.libs.utils.extensions.withData import com.kickstarter.models.Project @@ -329,7 +332,14 @@ fun Activity.startBackingDetailsWebViewActivity(url: String) { ) } -fun Activity.startWebViewActivity(url: String, toolbarTitle: String) { +fun Activity.startWebViewActivity(url: String) { + val uri = url.toUri() + val toolbarTitle = when { + uri.isPMUri(url) -> getString(R.string.Pledge_manager) + uri.isPMOrderEditUri(url, isFFEnabled = true) -> getString(R.string.Review_edits_made_to_your_order) + else -> getString(R.string.Pledge_manager) + } + startActivity( Intent(this, WebViewActivity::class.java) .putExtra(IntentKey.URL, url) diff --git a/app/src/main/java/com/kickstarter/viewmodels/SplashScreenViewModel.kt b/app/src/main/java/com/kickstarter/viewmodels/SplashScreenViewModel.kt index 068185c3a..693df3e44 100644 --- a/app/src/main/java/com/kickstarter/viewmodels/SplashScreenViewModel.kt +++ b/app/src/main/java/com/kickstarter/viewmodels/SplashScreenViewModel.kt @@ -113,7 +113,7 @@ interface SplashScreenViewModel { fun startProjectSurvey(): Observable> - fun startPMWebview(): Observable> + fun startPMWebview(): Observable /** Emits a Project and RefTag pair when we should start the [com.kickstarter.ui.activities.PreLaunchProjectPageActivity]. */ fun startPreLaunchProjectActivity(): Observable> @@ -132,7 +132,7 @@ interface SplashScreenViewModel { private val startProjectActivityToSave = BehaviorSubject.create() private val startProjectSurvey = BehaviorSubject.create>() - private val startPMWebview = BehaviorSubject.create>() + private val startPMWebview = BehaviorSubject.create() private val updateUserPreferences = BehaviorSubject.create() private val finishDeeplinkActivity = BehaviorSubject.create() private val apolloClient = requireNotNull(environment.apolloClientV2()) @@ -379,10 +379,6 @@ interface SplashScreenViewModel { it.isPMOrderEditUri(webEndpoint, ffClient.getBoolean(FlagKey.ANDROID_EDIT_ORDER)) } .map { appendRefTagIfNone(it) } - .withLatestFrom(this.currentUser.isLoggedIn) { url, isLoggedIn -> - return@withLatestFrom Pair(url, isLoggedIn) - } - .filter { it.second.isTrue() } .subscribe { startPMWebview.onNext(it) }.addToDisposable(disposables) @@ -537,7 +533,7 @@ interface SplashScreenViewModel { override fun startProjectSurvey(): Observable> = startProjectSurvey - override fun startPMWebview(): Observable> = startPMWebview + override fun startPMWebview(): Observable = startPMWebview override fun startPreLaunchProjectActivity(): Observable> = startPreLaunchProjectActivity } diff --git a/app/src/main/java/com/kickstarter/viewmodels/WebViewViewModel.kt b/app/src/main/java/com/kickstarter/viewmodels/WebViewViewModel.kt new file mode 100644 index 000000000..e5b1d9de2 --- /dev/null +++ b/app/src/main/java/com/kickstarter/viewmodels/WebViewViewModel.kt @@ -0,0 +1,64 @@ +package com.kickstarter.viewmodels + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import com.kickstarter.libs.Environment +import com.kickstarter.models.User +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import kotlinx.coroutines.plus +import kotlinx.coroutines.rx2.asFlow +import kotlin.coroutines.EmptyCoroutineContext + +enum class WebViewEvent { + SHOW_LOGIN, + LOAD_WEBVIEW +} + +class WebViewViewModel( + val environment: Environment, + testDispatcher: CoroutineDispatcher? = null +) : ViewModel() { + + private val currentUser = requireNotNull(environment.currentUserV2()).observable() + private val scope = viewModelScope + (testDispatcher ?: EmptyCoroutineContext) + + private val _mutableWebViewUIState = MutableStateFlow(WebViewEvent.SHOW_LOGIN) + val webViewUIState = _mutableWebViewUIState.asStateFlow() + .stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(), + initialValue = WebViewEvent.SHOW_LOGIN + ) + + init { + scope.launch { + currentUser.asFlow() + .collect { + emitCurrentState(it.getValue()) + } + } + } + + suspend fun emitCurrentState(user: User?) { + if (user != null) { + _mutableWebViewUIState.emit(WebViewEvent.LOAD_WEBVIEW) + } else { + _mutableWebViewUIState.emit(WebViewEvent.SHOW_LOGIN) + } + } + + class Factory( + private val environment: Environment, + private val testDispatcher: CoroutineDispatcher? = null + ) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return WebViewViewModel(environment, testDispatcher) as T + } + } +} diff --git a/app/src/main/res/values-de/strings_i18n.xml b/app/src/main/res/values-de/strings_i18n.xml index 228186e93..8cf440cb6 100644 --- a/app/src/main/res/values-de/strings_i18n.xml +++ b/app/src/main/res/values-de/strings_i18n.xml @@ -659,6 +659,7 @@ Antippen und erneut versuchen Erneut versuchen Versuche es erneut oder wähle eine andere Karte. Wiederverwertung und Recyclingfähigkeit + Änderungen an deiner Bestellung prüfen %{reward_survey_count} Befragungen %{reward_survey_count} Befragungen Befragung diff --git a/app/src/main/res/values-es/strings_i18n.xml b/app/src/main/res/values-es/strings_i18n.xml index 72acbd11c..188438b51 100644 --- a/app/src/main/res/values-es/strings_i18n.xml +++ b/app/src/main/res/values-es/strings_i18n.xml @@ -660,6 +660,7 @@ Toca para intentar de nuevo. Volver a intentar Vuelve a intentarlo o selecciona otro método. Reutilización y reciclabilidad + Revisa las modificaciones realizadas en tu pedido %{reward_survey_count} cuestionarios %{reward_survey_count} cuestionarios Cuestionario diff --git a/app/src/main/res/values-fr/strings_i18n.xml b/app/src/main/res/values-fr/strings_i18n.xml index 5ee4a4e36..215eafa8a 100644 --- a/app/src/main/res/values-fr/strings_i18n.xml +++ b/app/src/main/res/values-fr/strings_i18n.xml @@ -660,6 +660,7 @@ n\'ont rien soutenu. Réessayer Veuillez réessayer ou choisir un autre moyen de paiement. Recyclage et valorisation des déchets + Vérifions les modifications apportées à votre commande %{reward_survey_count} questionnaires %{reward_survey_count} questionnaires Questionnaire diff --git a/app/src/main/res/values-ja/strings_i18n.xml b/app/src/main/res/values-ja/strings_i18n.xml index 47c255b97..58d1050ce 100644 --- a/app/src/main/res/values-ja/strings_i18n.xml +++ b/app/src/main/res/values-ja/strings_i18n.xml @@ -658,6 +658,7 @@ もう一度試す 再試行するか別のお支払い方法を選択してください。 再利用可能性とリサイクル可能性 + ご注文への編集内容を確認してください %{reward_survey_count} リワードのサーベイ %{reward_survey_count} リワードのサーベイ リワードサーベイ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9c2e9820d..619b8230c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -103,7 +103,4 @@ The creator has not collected your address. Please contact them to resolve the issue. - - - Review edits made to your order diff --git a/app/src/main/res/values/strings_i18n.xml b/app/src/main/res/values/strings_i18n.xml index 9a1017860..5d3fad054 100644 --- a/app/src/main/res/values/strings_i18n.xml +++ b/app/src/main/res/values/strings_i18n.xml @@ -662,6 +662,7 @@ daring ideas. Retry Retry or select another method. Reusability and recyclability + Review edits made to your order %{reward_survey_count} Reward Surveys %{reward_survey_count} Reward Surveys Reward Survey diff --git a/app/src/test/java/com/kickstarter/viewmodels/DeepLinkViewModelTest.kt b/app/src/test/java/com/kickstarter/viewmodels/DeepLinkViewModelTest.kt index a4b222a91..24a87ec0f 100644 --- a/app/src/test/java/com/kickstarter/viewmodels/DeepLinkViewModelTest.kt +++ b/app/src/test/java/com/kickstarter/viewmodels/DeepLinkViewModelTest.kt @@ -51,7 +51,7 @@ class DeepLinkViewModelTest : KSRobolectricTestCase() { private val startProjectActivityForCommentToUpdate = TestSubscriber() private val startPreLaunchProjectActivity = TestSubscriber>() private val startProjectSurveyActivity = TestSubscriber>() - private val startPMOrderEditWebview = TestSubscriber>() + private val startPMOrderEditWebview = TestSubscriber() private val finishDeeplinkActivity = TestSubscriber() private val disposables = CompositeDisposable() @@ -978,7 +978,7 @@ class DeepLinkViewModelTest : KSRobolectricTestCase() { } @Test - fun testPMOrderEditDeeplink_startsPMOrderEditWebview_featureFlagEnabled_UserLoggedIn() { + fun testPMOrderEditDeeplink_startsPMOrderEditWebview_featureFlagEnabled() { val url = "https://www.kickstarter.com/projects/1768690592/reclaimed-coffee-video-game/order_edits/5/checkout" val mockFeatureFlagClient: MockFeatureFlagClient = object : MockFeatureFlagClient() { @@ -1007,34 +1007,6 @@ class DeepLinkViewModelTest : KSRobolectricTestCase() { startPMOrderEditWebview.assertValueCount(1) } - @Test - fun testPMOrderEditDeeplink_startsPMOrderEditWebview_featureFlagEnabled_UserLoggedOut() { - val url = "https://www.kickstarter.com/projects/1768690592/reclaimed-coffee-video-game/order_edits/5/checkout" - val mockFeatureFlagClient: MockFeatureFlagClient = - object : MockFeatureFlagClient() { - override fun getBoolean(FlagKey: FlagKey): Boolean { - return true - } - } - val env = environment() - .toBuilder() - .currentUserV2(MockCurrentUserV2()) // using empty constructor means no user logged in - .featureFlagClient(mockFeatureFlagClient) - .build() - - setUpEnvironment(intent = intentWithData(url), environment = env) - - startBrowser.assertNoValues() - startDiscoveryActivity.assertNoValues() - startProjectActivity.assertNoValues() - startProjectActivityForCheckout.assertNoValues() - startProjectActivityForComment.assertNoValues() - startProjectActivityToSave.assertNoValues() - startPreLaunchProjectActivity.assertNoValues() - startProjectSurveyActivity.assertNoValues() - startPMOrderEditWebview.assertNoValues() - } - private fun mockApiSetBacking(backing: Backing, completed: Boolean): MockApiClientV2 { return object : MockApiClientV2() { override fun postBacking( diff --git a/app/src/test/java/com/kickstarter/viewmodels/WebViewViewModelTest.kt b/app/src/test/java/com/kickstarter/viewmodels/WebViewViewModelTest.kt new file mode 100644 index 000000000..25ba540dd --- /dev/null +++ b/app/src/test/java/com/kickstarter/viewmodels/WebViewViewModelTest.kt @@ -0,0 +1,69 @@ +package com.kickstarter.viewmodels + +import com.kickstarter.KSRobolectricTestCase +import com.kickstarter.libs.Environment +import com.kickstarter.libs.MockCurrentUserV2 +import com.kickstarter.mock.factories.UserFactory +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class WebViewViewModelTest : KSRobolectricTestCase() { + + lateinit var vm: WebViewViewModel + + fun setUpEnvironment( + environment: Environment? = null, + dispatcher: CoroutineDispatcher + ) { + this.vm = WebViewViewModel.Factory(environment ?: environment(), dispatcher).create(WebViewViewModel::class.java) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun emitsLoginEventWhenUserIsLoggedOut() = runTest { + val env = environment() + .toBuilder() + .currentUserV2(MockCurrentUserV2()) + .build() + val dispatcher = UnconfinedTestDispatcher(testScheduler) + + val webViewEvent = mutableListOf() + + backgroundScope.launch(dispatcher) { + setUpEnvironment(env, dispatcher) + vm.webViewUIState.toList(webViewEvent) + } + + advanceUntilIdle() + assertEquals(1, webViewEvent.size) + assertEquals(webViewEvent.first(), WebViewEvent.SHOW_LOGIN) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun emitsLoginEventWhenUserIsLoggedIn() = runTest { + val env = environment() + .toBuilder() + .currentUserV2(MockCurrentUserV2(UserFactory.user())) + .build() + val dispatcher = UnconfinedTestDispatcher(testScheduler) + + val webViewEvent = mutableListOf() + + backgroundScope.launch(dispatcher) { + setUpEnvironment(env, dispatcher) + vm.webViewUIState.toList(webViewEvent) + } + + advanceUntilIdle() + assertEquals(2, webViewEvent.size) + assertEquals(webViewEvent.first(), WebViewEvent.SHOW_LOGIN) // initial + assertEquals(webViewEvent.last(), WebViewEvent.LOAD_WEBVIEW) // actual + } +}