Skip to content

Commit

Permalink
Merge pull request #8053 from woocommerce/feature/iap-payment-flow
Browse files Browse the repository at this point in the history
Feature/iap payment flow
  • Loading branch information
JorgeMucientes authored Dec 30, 2022
2 parents a06bbd1 + a5751a8 commit 9b57349
Show file tree
Hide file tree
Showing 22 changed files with 585 additions and 284 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ import com.woocommerce.android.iapshowcase.IAPDebugLogWrapper
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

private const val REMOTE_SITE_ID = 1L
private const val MILLION = 1_000_000.0

@AndroidEntryPoint
class IAPShowcasePurchaseFragment : Fragment(R.layout.fragment_iap_showcase_purchase) {
@Inject
Expand All @@ -38,7 +35,6 @@ class IAPShowcasePurchaseFragment : Fragment(R.layout.fragment_iap_showcase_purc
return IAPShowcasePurchaseViewModel(
IAPSitePurchasePlanFactory.createIAPSitePurchasePlan(
this@IAPShowcasePurchaseFragment.requireActivity().application,
REMOTE_SITE_ID,
debugLogWrapper,
mobilePayAPIProvider::buildMobilePayAPI,
)
Expand Down Expand Up @@ -74,7 +70,7 @@ class IAPShowcasePurchaseFragment : Fragment(R.layout.fragment_iap_showcase_purc
viewModel.productInfo.observe(viewLifecycleOwner) {
view.findViewById<TextView>(R.id.tvProductInfoTitle).text = it.localizedTitle
view.findViewById<TextView>(R.id.tvProductInfoDescription).text = it.localizedDescription
view.findViewById<TextView>(R.id.tvProductInfoPrice).text = "${it.price / MILLION} ${it.currency}"
view.findViewById<TextView>(R.id.tvProductInfoPrice).text = "${it.price} ${it.currency}"
}
viewModel.iapEvent.observe(viewLifecycleOwner) {
Log.w("IAP_SHOWCASE", it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch

class IAPShowcasePurchaseViewModel(private val iapManager: PurchaseWPComPlanActions) : ViewModel(iapManager) {
private companion object {
const val REMOTE_SITE_ID = 1L
}

private val _productInfo = MutableLiveData<WPComPlanProduct>()
val productInfo: LiveData<WPComPlanProduct> = _productInfo

Expand All @@ -29,7 +33,7 @@ class IAPShowcasePurchaseViewModel(private val iapManager: PurchaseWPComPlanActi

init {
viewModelScope.launch {
iapManager.purchaseWpComPlanResult.collectLatest { result ->
iapManager.getPurchaseWpComPlanResult(REMOTE_SITE_ID).collectLatest { result ->
_iapLoading.value = false
when (result) {
is WPComPurchaseResult.Success -> _iapEvent.value = "Plan has been successfully purchased"
Expand All @@ -42,7 +46,7 @@ class IAPShowcasePurchaseViewModel(private val iapManager: PurchaseWPComPlanActi
fun purchasePlan(activityWrapper: IAPActivityWrapper) {
viewModelScope.launch {
_iapLoading.value = true
iapManager.purchaseWPComPlan(activityWrapper)
iapManager.purchaseWPComPlan(activityWrapper, REMOTE_SITE_ID)
}
}

Expand All @@ -60,6 +64,7 @@ class IAPShowcasePurchaseViewModel(private val iapManager: PurchaseWPComPlanActi
PurchaseStatus.NOT_PURCHASED -> "Plan hasn't been purchased yet"
}
}

is WPComIsPurchasedResult.Error -> handleError(response.errorType)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,9 @@ enum class AnalyticsEvent(val siteless: Boolean = false) {
SITE_CREATION_STORE_MANAGEMENT_OPENED,
SITE_CREATION_STEP(siteless = true),
SITE_CREATION_IAP_ELIGIBILITY(siteless = true),
SITE_CREATION_IAP_ERROR(siteless = true),
SITE_CREATION_IAP_ELIGIBILITY_ERROR(siteless = true),
SITE_CREATION_IAP_PURCHASE_SUCCESS(siteless = true),
SITE_CREATION_IAP_PURCHASE_ERROR(siteless = true),

APPLICATION_PASSWORDS_NEW_PASSWORD_CREATED,
APPLICATION_PASSWORDS_TEST_INITIATED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,25 @@ import com.woocommerce.android.ui.login.storecreation.iap.WooIapLogWrapper
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.android.scopes.ViewModelScoped

@InstallIn(SingletonComponent::class)
@InstallIn(ViewModelComponent::class)
@Module
class InAppPurchasesModule {
@ViewModelScoped
@Provides
fun providePurchaseWPComPlanActions(
context: Application,
mobilePayAPIProvider: IAPShowcaseMobilePayAPIProvider
): PurchaseWPComPlanActions =
IAPSitePurchasePlanFactory.createIAPSitePurchasePlan(
context,
1L,
WooIapLogWrapper(),
mobilePayAPIProvider::buildMobilePayAPI
)

@ViewModelScoped
@Provides
fun providePurchaseWpComPlanSupportChecker(application: Application): PurchaseWpComPlanSupportChecker =
IAPSitePurchasePlanFactory.createIAPPurchaseWpComPlanSupportChecker(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import com.woocommerce.android.analytics.AnalyticsTrackerWrapper
import com.woocommerce.android.iap.pub.PurchaseWpComPlanSupportChecker
import com.woocommerce.android.iap.pub.model.IAPSupportedResult
import com.woocommerce.android.ui.login.storecreation.iap.IapEligibilityViewModel.IapEligibilityEvent.NavigateToNextStep
import com.woocommerce.android.util.FeatureFlag
import com.woocommerce.android.viewmodel.MultiLiveEvent
import com.woocommerce.android.viewmodel.ScopedViewModel
import com.woocommerce.android.viewmodel.getStateFlow
Expand All @@ -22,13 +21,14 @@ import javax.inject.Inject
class IapEligibilityViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val planSupportChecker: PurchaseWpComPlanSupportChecker,
private val analyticsTrackerWrapper: AnalyticsTrackerWrapper
) : ScopedViewModel(savedStateHandle) {
private val analyticsTrackerWrapper: AnalyticsTrackerWrapper,
private val isIAPEnabled: IsIAPEnabled
) : ScopedViewModel(savedStateHandle, planSupportChecker) {
private val _isCheckingIapEligibility = savedState.getStateFlow(scope = this, initialValue = true)
val isCheckingIapEligibility: LiveData<Boolean> = _isCheckingIapEligibility.asLiveData()

fun checkIapEligibility() {
if (FeatureFlag.IAP_FOR_STORE_CREATION.isEnabled()) {
if (isIAPEnabled()) {
launch {
when (val result = planSupportChecker.isIAPSupported()) {
is IAPSupportedResult.Success -> onSuccess(result)
Expand All @@ -42,7 +42,7 @@ class IapEligibilityViewModel @Inject constructor(

private fun onError(result: IAPSupportedResult.Error) {
analyticsTrackerWrapper.track(
AnalyticsEvent.SITE_CREATION_IAP_ERROR,
AnalyticsEvent.SITE_CREATION_IAP_ELIGIBILITY_ERROR,
mapOf(AnalyticsTracker.KEY_ERROR_TYPE to result.errorType.toString())
)
onUserNotEligibleForIAP()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.woocommerce.android.ui.login.storecreation.iap

import com.woocommerce.android.util.FeatureFlag
import javax.inject.Inject

class IsIAPEnabled @Inject constructor() {
operator fun invoke(): Boolean = FeatureFlag.IAP_FOR_STORE_CREATION.isEnabled()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.viewModels
Expand Down Expand Up @@ -33,8 +35,10 @@ class PlansFragment : BaseFragment() {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
WooThemeWithBackground {
PlanScreen(viewModel = viewModel, authenticator, userAgent)
CompositionLocalProvider(LocalActivity provides requireActivity() as AppCompatActivity) {
WooThemeWithBackground {
PlanScreen(viewModel = viewModel, authenticator, userAgent)
}
}
}
}
Expand Down
Loading

0 comments on commit 9b57349

Please sign in to comment.