Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass injector directly into FormViewModel #5738

Merged
merged 2 commits into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions config/detekt/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ console-reports:

output-reports:
active: true
exclude:
# exclude:
# - 'TxtOutputReport'
# - 'XmlOutputReport'
# - 'HtmlOutputReport'
Expand Down Expand Up @@ -150,7 +150,7 @@ complexity:
thresholdInObjects: 11
thresholdInEnums: 11
ignoreDeprecated: false
ignorePrivate: false
ignorePrivate: true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What’s the reason for the changes in this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detekt was failing for one of the files for having more than 11 methods, I think ignoring private methods is a good change to make it a little more flexible.

ignoreOverridden: false

coroutines:
Expand Down
4 changes: 0 additions & 4 deletions paymentsheet/api/paymentsheet.api
Original file line number Diff line number Diff line change
Expand Up @@ -1173,10 +1173,6 @@ public final class com/stripe/android/paymentsheet/injection/DaggerFlowControlle
public static fun builder ()Lcom/stripe/android/paymentsheet/injection/FlowControllerComponent$Builder;
}

public final class com/stripe/android/paymentsheet/injection/DaggerFormViewModelComponent {
public static fun builder ()Lcom/stripe/android/paymentsheet/injection/FormViewModelComponent$Builder;
}

public final class com/stripe/android/paymentsheet/injection/DaggerPaymentOptionsViewModelFactoryComponent {
public static fun builder ()Lcom/stripe/android/paymentsheet/injection/PaymentOptionsViewModelFactoryComponent$Builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidViewBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.stripe.android.core.injection.InjectorKey
import com.stripe.android.link.LinkPaymentLauncher
import com.stripe.android.link.model.AccountStatus
import com.stripe.android.link.ui.inline.InlineSignupViewState
Expand Down Expand Up @@ -210,6 +209,7 @@ internal abstract class BaseAddPaymentMethodFragment : Fragment() {
enabled = enabled,
onFormFieldValuesChanged = onFormFieldValuesChanged,
showCheckboxFlow = showCheckboxFlow,
injector = sheetViewModel.injector,
modifier = Modifier.padding(horizontal = horizontalPadding)
)
}
Expand Down Expand Up @@ -324,7 +324,6 @@ internal abstract class BaseAddPaymentMethodFragment : Fragment() {
config = sheetViewModel.config,
merchantName = sheetViewModel.merchantName,
amount = sheetViewModel.amount.value,
injectorKey = sheetViewModel.injectorKey,
newLpm = sheetViewModel.newPaymentSelection,
isShowingLinkInlineSignup = showLinkInlineSignup
)
Expand Down Expand Up @@ -372,7 +371,6 @@ internal abstract class BaseAddPaymentMethodFragment : Fragment() {
config: PaymentSheet.Configuration?,
merchantName: String,
amount: Amount? = null,
@InjectorKey injectorKey: String,
newLpm: PaymentSelection.New?,
isShowingLinkInlineSignup: Boolean = false
): FormFragmentArguments {
Expand All @@ -389,7 +387,6 @@ internal abstract class BaseAddPaymentMethodFragment : Fragment() {
amount = amount,
billingDetails = config?.defaultBillingDetails,
shippingDetails = config?.shippingDetails,
injectorKey = injectorKey,
initialPaymentMethodCreateParams =
if (newLpm is PaymentSelection.New.LinkInline) {
newLpm.linkPaymentDetails.originalParams
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.ActivityResultRegistry
import androidx.fragment.app.Fragment
import com.stripe.android.core.injection.Injectable
import com.stripe.android.core.injection.Injector
import com.stripe.android.core.injection.InjectorKey
import com.stripe.android.core.injection.WeakMapInjectorRegistry
import com.stripe.android.paymentsheet.forms.FormViewModel
import com.stripe.android.paymentsheet.injection.DaggerPaymentSheetLauncherComponent
import com.stripe.android.paymentsheet.injection.PaymentSheetLauncherComponent
import com.stripe.android.ui.core.injection.NonFallbackInjector
import org.jetbrains.annotations.TestOnly

/**
Expand All @@ -21,7 +21,7 @@ import org.jetbrains.annotations.TestOnly
internal class DefaultPaymentSheetLauncher(
private val activityResultLauncher: ActivityResultLauncher<PaymentSheetContract.Args>,
application: Application
) : PaymentSheetLauncher, Injector {
) : PaymentSheetLauncher, NonFallbackInjector {
@InjectorKey
private val injectorKey: String =
WeakMapInjectorRegistry.nextKey(requireNotNull(PaymentSheetLauncher::class.simpleName))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.savedstate.SavedStateRegistryOwner
import com.stripe.android.core.BuildConfig
import com.stripe.android.core.Logger
import com.stripe.android.core.injection.IOContext
import com.stripe.android.core.injection.Injectable
import com.stripe.android.core.injection.InjectorKey
import com.stripe.android.core.injection.injectWithFallback
import com.stripe.android.core.injection.WeakMapInjectorRegistry
import com.stripe.android.link.LinkPaymentDetails
import com.stripe.android.link.LinkPaymentLauncher
import com.stripe.android.link.LinkPaymentLauncher.Companion.LINK_ENABLED
Expand All @@ -24,6 +25,7 @@ import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.StripeIntent
import com.stripe.android.payments.paymentlauncher.PaymentResult
import com.stripe.android.paymentsheet.analytics.EventReporter
import com.stripe.android.paymentsheet.forms.FormViewModel
import com.stripe.android.paymentsheet.injection.DaggerPaymentOptionsViewModelFactoryComponent
import com.stripe.android.paymentsheet.injection.PaymentOptionsViewModelSubcomponent
import com.stripe.android.paymentsheet.model.FragmentConfig
Expand All @@ -35,6 +37,7 @@ import com.stripe.android.paymentsheet.viewmodels.BaseSheetViewModel
import com.stripe.android.ui.core.address.AddressRepository
import com.stripe.android.ui.core.forms.resources.LpmRepository
import com.stripe.android.ui.core.forms.resources.ResourceRepository
import com.stripe.android.ui.core.injection.NonFallbackInjector
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import javax.inject.Inject
Expand Down Expand Up @@ -317,17 +320,12 @@ internal class PaymentOptionsViewModel @Inject constructor(
val productUsage: Set<String>
)

override fun fallbackInitialize(arg: FallbackInitializeParam) {
DaggerPaymentOptionsViewModelFactoryComponent.builder()
.context(arg.application)
.productUsage(arg.productUsage)
.build().inject(this)
}

@Inject
lateinit var subComponentBuilderProvider:
Provider<PaymentOptionsViewModelSubcomponent.Builder>

private lateinit var injector: NonFallbackInjector

@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
key: String,
Expand All @@ -336,15 +334,52 @@ internal class PaymentOptionsViewModel @Inject constructor(
): T {
val application = applicationSupplier()
val starterArgs = starterArgsSupplier()
injectWithFallback(
starterArgsSupplier().injectorKey,
FallbackInitializeParam(application, starterArgs.productUsage)
)
return subComponentBuilderProvider.get()
val logger = Logger.getInstance(BuildConfig.DEBUG)

WeakMapInjectorRegistry.retrieve(starterArgs.injectorKey)?.let {
it as? NonFallbackInjector
}?.let {
logger.info(
"Injector available, " +
"injecting dependencies into ${this::class.java.canonicalName}"
)
injector = it
it.inject(this)
} ?: run {
logger.info(
"Injector unavailable, " +
"initializing dependencies of ${this::class.java.canonicalName}"
)
fallbackInitialize(FallbackInitializeParam(application, starterArgs.productUsage))
}

val subcomponent = subComponentBuilderProvider.get()
.application(application)
.args(starterArgs)
.savedStateHandle(savedStateHandle)
.build().viewModel as T
.build()
val viewModel = subcomponent.viewModel
viewModel.injector = injector
return viewModel as T
}

override fun fallbackInitialize(arg: FallbackInitializeParam) {
val component = DaggerPaymentOptionsViewModelFactoryComponent.builder()
.context(arg.application)
.productUsage(arg.productUsage)
.build()

injector = object : NonFallbackInjector {
override fun inject(injectable: Injectable<*>) {
when (injectable) {
is FormViewModel.Factory -> component.inject(injectable)
else -> {
throw IllegalArgumentException("invalid Injectable $injectable requested in $this")
}
}
}
}
component.inject(this)
Comment on lines 335 to +382
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is now replicated in PaymentOptionsViewModel, PaymentSheetViewModel and LinkActivityViewModel. I'll refactor to make it generic and part of the stripe-core module in the next PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.viewModelScope
import androidx.savedstate.SavedStateRegistryOwner
import com.stripe.android.PaymentConfiguration
import com.stripe.android.core.BuildConfig
import com.stripe.android.core.Logger
import com.stripe.android.core.injection.DUMMY_INJECTOR_KEY
import com.stripe.android.core.injection.IOContext
import com.stripe.android.core.injection.Injectable
import com.stripe.android.core.injection.InjectorKey
import com.stripe.android.core.injection.injectWithFallback
import com.stripe.android.core.injection.WeakMapInjectorRegistry
import com.stripe.android.googlepaylauncher.GooglePayEnvironment
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherContract
Expand All @@ -48,6 +49,7 @@ import com.stripe.android.paymentsheet.addresselement.toConfirmPaymentIntentShip
import com.stripe.android.paymentsheet.analytics.EventReporter
import com.stripe.android.paymentsheet.extensions.registerPollingAuthenticator
import com.stripe.android.paymentsheet.extensions.unregisterPollingAuthenticator
import com.stripe.android.paymentsheet.forms.FormViewModel
import com.stripe.android.paymentsheet.injection.DaggerPaymentSheetLauncherComponent
import com.stripe.android.paymentsheet.injection.PaymentSheetViewModelModule
import com.stripe.android.paymentsheet.injection.PaymentSheetViewModelSubcomponent
Expand All @@ -66,6 +68,7 @@ import com.stripe.android.paymentsheet.viewmodels.BaseSheetViewModel
import com.stripe.android.ui.core.address.AddressRepository
import com.stripe.android.ui.core.forms.resources.LpmRepository
import com.stripe.android.ui.core.forms.resources.ResourceRepository
import com.stripe.android.ui.core.injection.NonFallbackInjector
import dagger.Lazy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -686,28 +689,62 @@ internal class PaymentSheetViewModel @Inject internal constructor(
lateinit var subComponentBuilderProvider:
Provider<PaymentSheetViewModelSubcomponent.Builder>

private lateinit var injector: NonFallbackInjector

@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
savedStateHandle: SavedStateHandle
): T {
val args = starterArgsSupplier()
val logger = Logger.getInstance(BuildConfig.DEBUG)

WeakMapInjectorRegistry.retrieve(args.injectorKey)?.let {
it as? NonFallbackInjector
}?.let {
logger.info(
"Injector available, " +
"injecting dependencies into ${this::class.java.canonicalName}"
)
injector = it
it.inject(this)
} ?: run {
logger.info(
"Injector unavailable, " +
"initializing dependencies of ${this::class.java.canonicalName}"
)
fallbackInitialize(FallbackInitializeParam(applicationSupplier()))
}

injectWithFallback(args.injectorKey, FallbackInitializeParam(applicationSupplier()))

return subComponentBuilderProvider.get()
val subcomponent = subComponentBuilderProvider.get()
.paymentSheetViewModelModule(PaymentSheetViewModelModule(args))
.savedStateHandle(savedStateHandle)
.build().viewModel as T
.build()
val viewModel = subcomponent.viewModel
viewModel.injector = injector
return viewModel as T
}

override fun fallbackInitialize(arg: FallbackInitializeParam) {
DaggerPaymentSheetLauncherComponent
val component = DaggerPaymentSheetLauncherComponent
.builder()
.application(arg.application)
.injectorKey(DUMMY_INJECTOR_KEY)
.build().inject(this)
.build()

injector = object : NonFallbackInjector {
override fun inject(injectable: Injectable<*>) {
when (injectable) {
is FormViewModel.Factory -> component.inject(injectable)
else -> {
throw IllegalArgumentException("invalid Injectable $injectable requested in $this")
}
}
}
}

component.inject(this)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import androidx.lifecycle.ViewModelStoreOwner
import com.stripe.android.PaymentConfiguration
import com.stripe.android.core.injection.ENABLE_LOGGING
import com.stripe.android.core.injection.Injectable
import com.stripe.android.core.injection.Injector
import com.stripe.android.core.injection.InjectorKey
import com.stripe.android.core.injection.UIContext
import com.stripe.android.core.injection.WeakMapInjectorRegistry
Expand Down Expand Up @@ -61,6 +60,7 @@ import com.stripe.android.paymentsheet.validate
import com.stripe.android.ui.core.address.AddressRepository
import com.stripe.android.ui.core.forms.resources.LpmRepository
import com.stripe.android.ui.core.forms.resources.ResourceRepository
import com.stripe.android.ui.core.injection.NonFallbackInjector
import dagger.Lazy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
Expand Down Expand Up @@ -107,7 +107,7 @@ internal class DefaultFlowController @Inject internal constructor(
@Named(PRODUCT_USAGE) private val productUsage: Set<String>,
private val googlePayPaymentMethodLauncherFactory: GooglePayPaymentMethodLauncherFactory,
private val linkLauncher: LinkPaymentLauncher
) : PaymentSheet.FlowController, Injector {
) : PaymentSheet.FlowController, NonFallbackInjector {
private val paymentOptionActivityLauncher: ActivityResultLauncher<PaymentOptionContract.Args>
private val googlePayActivityLauncher:
ActivityResultLauncher<GooglePayPaymentMethodLauncherContract.Args>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import android.content.Context
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.stripe.android.core.injection.Injectable
import com.stripe.android.core.injection.injectWithFallback
import com.stripe.android.paymentsheet.addresselement.toIdentifierMap
import com.stripe.android.paymentsheet.injection.DaggerFormViewModelComponent
import com.stripe.android.paymentsheet.injection.FormViewModelSubcomponent
import com.stripe.android.paymentsheet.model.PaymentSelection
import com.stripe.android.paymentsheet.paymentdatacollection.FormFragmentArguments
Expand All @@ -21,6 +18,8 @@ import com.stripe.android.ui.core.elements.SectionElement
import com.stripe.android.ui.core.forms.TransformSpecToElements
import com.stripe.android.ui.core.forms.resources.LpmRepository
import com.stripe.android.ui.core.forms.resources.ResourceRepository
import com.stripe.android.ui.core.injection.NonFallbackInjectable
import com.stripe.android.ui.core.injection.NonFallbackInjector
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
Expand Down Expand Up @@ -52,31 +51,19 @@ internal class FormViewModel @Inject internal constructor(
internal class Factory(
val config: FormFragmentArguments,
val showCheckboxFlow: Flow<Boolean>,
private val contextSupplier: () -> Context
) : ViewModelProvider.Factory,
Injectable<Factory.FallbackInitializeParam> {
internal data class FallbackInitializeParam(
val context: Context
)

private val injector: NonFallbackInjector
) : ViewModelProvider.Factory, NonFallbackInjectable {
@Inject
lateinit var subComponentBuilderProvider: Provider<FormViewModelSubcomponent.Builder>

@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
val context = contextSupplier()
injectWithFallback(config.injectorKey, FallbackInitializeParam(context))
injector.inject(this)
return subComponentBuilderProvider.get()
.formFragmentArguments(config)
.showCheckboxFlow(showCheckboxFlow)
.build().viewModel as T
}

override fun fallbackInitialize(arg: FallbackInitializeParam) {
DaggerFormViewModelComponent.builder()
.context(arg.context)
.build()
.inject(this)
}
}

val elementsFlow = flowOf(
Expand Down
Loading