Skip to content
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
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

buildscript {
ext {
androidGradlePluginVersion = '8.9.1'
androidGradlePluginVersion = '8.9.2'
kotlinVersion = '2.1.20'
kspVersion = '2.1.20-1.0.32'
dokkaVersion = '1.9.20'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.processout.sdk.ui.card.scanner.POCardScannerLauncher
import com.processout.sdk.ui.card.scanner.recognition.POScannedCard
import com.processout.sdk.ui.card.update.POCardUpdateConfiguration
import com.processout.sdk.ui.card.update.POCardUpdateConfiguration.CardInformation
import com.processout.sdk.ui.card.update.POCardUpdateDelegate
import com.processout.sdk.ui.card.update.POCardUpdateLauncher
import com.processout.sdk.ui.googlepay.POGooglePayCardTokenizationLauncher
import com.processout.sdk.ui.shared.configuration.POBottomSheetConfiguration
Expand All @@ -45,6 +46,7 @@ class FeaturesFragment : BaseFragment<FragmentFeaturesBinding>(
super.onCreate(savedInstanceState)
cardUpdateLauncher = POCardUpdateLauncher.create(
from = this,
delegate = object : POCardUpdateDelegate {},
callback = ::handleCardUpdateResult
)
cardScannerLauncher = POCardScannerLauncher.create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ interface POEventDispatchers {
val cardTokenization: POCardTokenizationEventDispatcher

/** Dispatcher that allows to handle events during card updates. */
@Deprecated(message = "Use API with POCardUpdateDelegate instead.")
val cardUpdate: POCardUpdateEventDispatcher
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import kotlinx.coroutines.flow.SharedFlow
/**
* Dispatcher that allows to handle events during card updates.
*/
@Deprecated(message = "Use API with POCardUpdateDelegate instead.")
interface POCardUpdateEventDispatcher {

/** Allows to subscribe for card update lifecycle events. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.processout.sdk.api.model.request

import com.processout.sdk.api.dispatcher.POEventDispatcher
import com.processout.sdk.core.ProcessOutResult
import com.processout.sdk.core.annotation.ProcessOutInternalApi
import java.util.UUID
Expand All @@ -14,5 +15,5 @@ import java.util.UUID
data class POCardUpdateShouldContinueRequest @ProcessOutInternalApi constructor(
val cardId: String,
val failure: ProcessOutResult.Failure,
val uuid: UUID = UUID.randomUUID()
)
override val uuid: UUID = UUID.randomUUID()
) : POEventDispatcher.Request
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.processout.sdk.api.model.response

import com.processout.sdk.api.dispatcher.POEventDispatcher
import com.processout.sdk.api.model.request.POCardUpdateShouldContinueRequest
import com.processout.sdk.core.ProcessOutResult
import java.util.UUID
Expand All @@ -13,10 +14,10 @@ import java.util.UUID
* @param[shouldContinue] Boolean that indicates whether the flow should continue or complete after the [failure].
*/
data class POCardUpdateShouldContinueResponse internal constructor(
val uuid: UUID,
override val uuid: UUID,
val failure: ProcessOutResult.Failure,
val shouldContinue: Boolean
)
) : POEventDispatcher.Response

/**
* Creates [POCardUpdateShouldContinueResponse] from [POCardUpdateShouldContinueRequest].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.processout.sdk.R
import com.processout.sdk.api.ProcessOut
import com.processout.sdk.api.dispatcher.POEventDispatcher
import com.processout.sdk.api.dispatcher.card.update.PODefaultCardUpdateEventDispatcher
import com.processout.sdk.api.model.event.POCardUpdateEvent
import com.processout.sdk.api.model.event.POCardUpdateEvent.*
import com.processout.sdk.api.model.request.POCardUpdateRequest
import com.processout.sdk.api.model.request.POCardUpdateShouldContinueRequest
import com.processout.sdk.api.model.response.POCardUpdateShouldContinueResponse
import com.processout.sdk.api.repository.POCardsRepository
import com.processout.sdk.core.POFailure.Code.Cancelled
import com.processout.sdk.core.POFailure.Code.Generic
Expand Down Expand Up @@ -43,7 +45,8 @@ internal class CardUpdateViewModel private constructor(
private val app: Application,
private val configuration: POCardUpdateConfiguration,
private val cardsRepository: POCardsRepository,
private val eventDispatcher: PODefaultCardUpdateEventDispatcher,
private val legacyEventDispatcher: PODefaultCardUpdateEventDispatcher, // TODO: remove before next major release.
private val eventDispatcher: POEventDispatcher,
private val logAttributes: Map<String, String>
) : ViewModel() {

Expand All @@ -57,7 +60,8 @@ internal class CardUpdateViewModel private constructor(
app = app,
configuration = configuration,
cardsRepository = ProcessOut.instance.cards,
eventDispatcher = PODefaultCardUpdateEventDispatcher,
legacyEventDispatcher = PODefaultCardUpdateEventDispatcher,
eventDispatcher = POEventDispatcher,
logAttributes = mapOf(POLogAttribute.CARD_ID to configuration.cardId)
) as T
}
Expand Down Expand Up @@ -346,11 +350,7 @@ internal class CardUpdateViewModel private constructor(
dispatch(DidComplete)
_completion.update { Success(card) }
}.onFailure { failure ->
if (eventDispatcher.subscribedForShouldContinueRequest()) {
requestIfShouldContinue(failure)
} else {
handle(failure)
}
requestIfShouldContinue(failure)
}
}
}
Expand All @@ -362,7 +362,11 @@ internal class CardUpdateViewModel private constructor(
failure = failure
)
latestShouldContinueRequest = request
eventDispatcher.send(request)
if (legacyEventDispatcher.subscribedForShouldContinueRequest()) {
legacyEventDispatcher.send(request)
} else {
eventDispatcher.send(request)
}
POLogger.info(
message = "Requested to decide whether the flow should continue or complete after the failure: %s", failure,
attributes = logAttributes
Expand All @@ -372,19 +376,28 @@ internal class CardUpdateViewModel private constructor(

private fun shouldContinueOnFailure() {
viewModelScope.launch {
eventDispatcher.shouldContinueResponse.collect { response ->
if (response.uuid == latestShouldContinueRequest?.uuid) {
latestShouldContinueRequest = null
if (response.shouldContinue) {
handle(response.failure)
} else {
POLogger.info(
message = "Completed after the failure: %s", response.failure,
attributes = logAttributes
)
_completion.update { Failure(response.failure) }
}
}
legacyEventDispatcher.shouldContinueResponse.collect { response ->
handleShouldContinue(response)
}
}
eventDispatcher.subscribeForResponse<POCardUpdateShouldContinueResponse>(
coroutineScope = viewModelScope
) { response ->
handleShouldContinue(response)
}
}

private fun handleShouldContinue(response: POCardUpdateShouldContinueResponse) {
if (response.uuid == latestShouldContinueRequest?.uuid) {
latestShouldContinueRequest = null
if (response.shouldContinue) {
handle(response.failure)
} else {
POLogger.info(
message = "Completed after the failure: %s", response.failure,
attributes = logAttributes
)
_completion.update { Failure(response.failure) }
}
}
}
Expand Down Expand Up @@ -449,6 +462,7 @@ internal class CardUpdateViewModel private constructor(

private fun dispatch(event: POCardUpdateEvent) {
viewModelScope.launch {
legacyEventDispatcher.send(event)
eventDispatcher.send(event)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.processout.sdk.ui.card.update

import com.processout.sdk.api.model.event.POCardUpdateEvent
import com.processout.sdk.core.ProcessOutResult

/**
* Delegate that allows to handle events during card update.
*/
interface POCardUpdateDelegate {

/**
* Invoked on card update lifecycle events.
*/
fun onEvent(event: POCardUpdateEvent) {}

/**
* Allows to decide whether the card update should continue or complete after the failure.
* Returns _true_ by default.
*/
suspend fun shouldContinue(
failure: ProcessOutResult.Failure
): Boolean = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,26 @@ import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.core.app.ActivityOptionsCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.processout.sdk.R
import com.processout.sdk.api.dispatcher.POEventDispatcher
import com.processout.sdk.api.model.event.POCardUpdateEvent
import com.processout.sdk.api.model.request.POCardUpdateShouldContinueRequest
import com.processout.sdk.api.model.response.POCard
import com.processout.sdk.api.model.response.toResponse
import com.processout.sdk.core.ProcessOutActivityResult
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

/**
* Launcher that starts [CardUpdateActivity] and provides the result.
*/
class POCardUpdateLauncher private constructor(
private val scope: CoroutineScope,
private val launcher: ActivityResultLauncher<POCardUpdateConfiguration>,
private val activityOptions: ActivityOptionsCompat
private val activityOptions: ActivityOptionsCompat,
private val delegate: POCardUpdateDelegate,
private val eventDispatcher: POEventDispatcher = POEventDispatcher
) {

companion object {
Expand All @@ -24,13 +34,34 @@ class POCardUpdateLauncher private constructor(
*/
fun create(
from: Fragment,
delegate: POCardUpdateDelegate,
callback: (ProcessOutActivityResult<POCard>) -> Unit
) = POCardUpdateLauncher(
scope = from.lifecycleScope,
launcher = from.registerForActivityResult(
CardUpdateActivityContract(),
callback
),
activityOptions = createActivityOptions(from.requireContext())
activityOptions = createActivityOptions(from.requireContext()),
delegate = delegate
)

/**
* Creates the launcher from Fragment.
* __Note:__ Required to call in _onCreate()_ to register for activity result.
*/
@Deprecated(message = "Use alternative function.")
fun create(
from: Fragment,
callback: (ProcessOutActivityResult<POCard>) -> Unit
) = POCardUpdateLauncher(
scope = from.lifecycleScope,
launcher = from.registerForActivityResult(
CardUpdateActivityContract(),
callback
),
activityOptions = createActivityOptions(from.requireContext()),
delegate = object : POCardUpdateDelegate {}
)

/**
Expand All @@ -39,14 +70,36 @@ class POCardUpdateLauncher private constructor(
*/
fun create(
from: ComponentActivity,
delegate: POCardUpdateDelegate,
callback: (ProcessOutActivityResult<POCard>) -> Unit
) = POCardUpdateLauncher(
scope = from.lifecycleScope,
launcher = from.registerForActivityResult(
CardUpdateActivityContract(),
from.activityResultRegistry,
callback
),
activityOptions = createActivityOptions(from)
activityOptions = createActivityOptions(from),
delegate = delegate
)

/**
* Creates the launcher from Activity.
* __Note:__ Required to call in _onCreate()_ to register for activity result.
*/
@Deprecated(message = "Use alternative function.")
fun create(
from: ComponentActivity,
callback: (ProcessOutActivityResult<POCard>) -> Unit
) = POCardUpdateLauncher(
scope = from.lifecycleScope,
launcher = from.registerForActivityResult(
CardUpdateActivityContract(),
from.activityResultRegistry,
callback
),
activityOptions = createActivityOptions(from),
delegate = object : POCardUpdateDelegate {}
)

private fun createActivityOptions(context: Context) =
Expand All @@ -55,6 +108,28 @@ class POCardUpdateLauncher private constructor(
)
}

init {
dispatchEvents()
dispatchShouldContinue()
}

private fun dispatchEvents() {
eventDispatcher.subscribe<POCardUpdateEvent>(
coroutineScope = scope
) { delegate.onEvent(it) }
}

private fun dispatchShouldContinue() {
eventDispatcher.subscribeForRequest<POCardUpdateShouldContinueRequest>(
coroutineScope = scope
) { request ->
scope.launch {
val shouldContinue = delegate.shouldContinue(request.failure)
eventDispatcher.send(request.toResponse(shouldContinue))
}
}
}

/**
* Launches the activity.
*/
Expand Down