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 @@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension

buildscript {
ext {
androidGradlePluginVersion = '9.3.1'
androidGradlePluginVersion = '9.4.1'
kotlinVersion = '2.1.20'
kspVersion = '2.1.20-1.0.32'
dokkaVersion = '1.9.20'
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<activity
android:name=".ui.web.customtab.POCustomTabAuthorizationActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden|uiMode|colorMode|density|fontScale|fontWeightAdjustment|layoutDirection|locale"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|uiMode|colorMode|density|fontScale|fontWeightAdjustment|layoutDirection|locale"
android:exported="false"
android:launchMode="singleTask"
android:theme="@style/Theme.ProcessOut.Transparent" />
Expand All @@ -39,7 +39,7 @@

<activity
android:name=".ui.web.webview.POWebViewAuthorizationActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden|uiMode|colorMode|density|fontScale|fontWeightAdjustment|layoutDirection|locale"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|uiMode|colorMode|density|fontScale|fontWeightAdjustment|layoutDirection|locale"
android:exported="false"
android:launchMode="singleTop"
android:theme="@style/Theme.ProcessOut.Transparent" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package com.processout.sdk.ui.web.customtab

import android.app.Activity
import android.content.Intent
import android.content.pm.ActivityInfo
import android.net.Uri
import android.os.Build
import android.os.Bundle
import androidx.activity.addCallback
import androidx.activity.viewModels
Expand Down Expand Up @@ -61,12 +59,6 @@ class POCustomTabAuthorizationActivity : AppCompatActivity() {
@Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This is a workaround for crash on Android 8.0 (API level 26).
// https://issuetracker.google.com/issues/68454482
// https://stackoverflow.com/questions/48072438/java-lang-illegalstateexception-only-fullscreen-opaque-activities-can-request-o
requestedOrientation = if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O)
ActivityInfo.SCREEN_ORIENTATION_BEHIND else ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

onBackPressedDispatcher.addCallback(this) {
// Ignore back press to avoid finishing activity without a result.
// Cancelled result will be provided from onResume() when going back from the Custom Tab.
Expand Down Expand Up @@ -168,8 +160,8 @@ class POCustomTabAuthorizationActivity : AppCompatActivity() {
result.onFailure { POLogger.info("Custom Chrome Tabs failure: %s", it) }
when (configuration.resultApi) {
Android -> when (result) {
is ProcessOutActivityResult.Success -> setActivityResult(Activity.RESULT_OK, result)
is ProcessOutActivityResult.Failure -> setActivityResult(Activity.RESULT_CANCELED, result)
is ProcessOutActivityResult.Success -> setActivityResult(RESULT_OK, result)
is ProcessOutActivityResult.Failure -> setActivityResult(RESULT_CANCELED, result)
}
Dispatcher -> resultDispatcher.dispatch(result)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.processout.sdk.ui.web.webview

import android.app.Activity
import android.content.Intent
import android.content.pm.ActivityInfo
import android.net.Uri
import android.os.Build
import android.os.Bundle
Expand Down Expand Up @@ -33,12 +31,6 @@ class POWebViewAuthorizationActivity : AppCompatActivity() {
@Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// This is a workaround for crash on Android 8.0 (API level 26).
// https://issuetracker.google.com/issues/68454482
// https://stackoverflow.com/questions/48072438/java-lang-illegalstateexception-only-fullscreen-opaque-activities-can-request-o
requestedOrientation = if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O)
ActivityInfo.SCREEN_ORIENTATION_BEHIND else ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

if (intent.getBooleanExtra(EXTRA_FORCE_FINISH, false)) {
POLogger.info("Activity is started to clear the back stack and finished immediately before it's created.")
finish()
Expand Down Expand Up @@ -87,8 +79,8 @@ class POWebViewAuthorizationActivity : AppCompatActivity() {
if (!isFinishing) {
when (configuration.resultApi) {
Android -> when (result) {
is ProcessOutActivityResult.Success -> setActivityResult(Activity.RESULT_OK, result)
is ProcessOutActivityResult.Failure -> setActivityResult(Activity.RESULT_CANCELED, result)
is ProcessOutActivityResult.Success -> setActivityResult(RESULT_OK, result)
is ProcessOutActivityResult.Failure -> setActivityResult(RESULT_CANCELED, result)
}
Dispatcher -> resultDispatcher.dispatch(result)
}
Expand All @@ -104,7 +96,7 @@ class POWebViewAuthorizationActivity : AppCompatActivity() {
super.finish()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
overrideActivityTransition(
Activity.OVERRIDE_TRANSITION_CLOSE,
OVERRIDE_TRANSITION_CLOSE,
R.anim.po_slide_in_left,
R.anim.po_slide_out_right
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ internal class CardTokenizationInteractor(
private val cardsRepository: POCardsRepository,
private val cardSchemeProvider: CardSchemeProvider,
private val addressSpecificationProvider: AddressSpecificationProvider,
private val eventDispatcher: POEventDispatcher
val eventDispatcher: POEventDispatcher
) : BaseInteractor() {

private companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ internal class CardTokenizationViewModel private constructor(

val sideEffects = interactor.sideEffects

val eventDispatcher = interactor.eventDispatcher

init {
addCloseable(interactor.interactorScope)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.processout.sdk.ui.card.tokenization.screen.CardTokenizationScreen
import com.processout.sdk.ui.core.theme.ProcessOutTheme
import com.processout.sdk.ui.shared.configuration.POBottomSheetConfiguration
import com.processout.sdk.ui.shared.configuration.POBottomSheetConfiguration.Height.WrapContent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
Expand All @@ -50,15 +51,12 @@ class POCardTokenizationViewComponent private constructor(
val view: View,
private var configuration: POCardTokenizationConfiguration,
private val viewModel: CardTokenizationViewModel,
private val lifecycleOwner: LifecycleOwner,
private val cardScannerLauncher: POCardScannerLauncher,
private val delegate: POCardTokenizationDelegate,
private val callback: (ProcessOutResult<POCard>) -> Unit,
private val eventDispatcher: POEventDispatcher
) {

private val scope = lifecycleOwner.lifecycleScope

companion object {
/**
* Creates the card tokenization view component from a Fragment.
Expand All @@ -71,12 +69,11 @@ class POCardTokenizationViewComponent private constructor(
callback: (ProcessOutResult<POCard>) -> Unit
): POCardTokenizationViewComponent {
val configuration = configuration.map()
val eventDispatcher = POEventDispatcher()
val viewModel: CardTokenizationViewModel by from.viewModels {
CardTokenizationViewModel.Factory(
app = from.requireActivity().application,
configuration = configuration,
eventDispatcher = eventDispatcher
eventDispatcher = POEventDispatcher()
)
}
return POCardTokenizationViewComponent(
Expand All @@ -87,7 +84,6 @@ class POCardTokenizationViewComponent private constructor(
),
configuration = configuration,
viewModel = viewModel,
lifecycleOwner = from,
cardScannerLauncher = POCardScannerLauncher.create(
from = from,
callback = { result ->
Expand All @@ -96,8 +92,12 @@ class POCardTokenizationViewComponent private constructor(
),
delegate = delegate,
callback = callback,
eventDispatcher = eventDispatcher
)
eventDispatcher = viewModel.eventDispatcher
).apply {
from.viewLifecycleOwnerLiveData.observe(from) { lifecycleOwner ->
init(lifecycleOwner)
}
}
}

/**
Expand All @@ -111,12 +111,11 @@ class POCardTokenizationViewComponent private constructor(
callback: (ProcessOutResult<POCard>) -> Unit
): POCardTokenizationViewComponent {
val configuration = configuration.map()
val eventDispatcher = POEventDispatcher()
val viewModel: CardTokenizationViewModel by from.viewModels {
CardTokenizationViewModel.Factory(
app = from.application,
configuration = configuration,
eventDispatcher = eventDispatcher
eventDispatcher = POEventDispatcher()
)
}
return POCardTokenizationViewComponent(
Expand All @@ -127,7 +126,6 @@ class POCardTokenizationViewComponent private constructor(
),
configuration = configuration,
viewModel = viewModel,
lifecycleOwner = from,
cardScannerLauncher = POCardScannerLauncher.create(
from = from,
callback = { result ->
Expand All @@ -136,8 +134,10 @@ class POCardTokenizationViewComponent private constructor(
),
delegate = delegate,
callback = callback,
eventDispatcher = eventDispatcher
)
eventDispatcher = viewModel.eventDispatcher
).apply {
init(lifecycleOwner = from)
}
}

private fun POCardTokenizationViewComponentConfiguration.map() =
Expand Down Expand Up @@ -180,35 +180,36 @@ class POCardTokenizationViewComponent private constructor(
}
}

init {
dispatchEvents()
dispatchState()
dispatchTokenizedCard()
dispatchEligibility()
dispatchPreferredScheme()
dispatchShouldContinue()
collectSideEffects()
collectCompletion()
private fun init(lifecycleOwner: LifecycleOwner) {
val coroutineScope = lifecycleOwner.lifecycleScope
dispatchEvents(coroutineScope)
dispatchState(coroutineScope)
dispatchTokenizedCard(coroutineScope)
dispatchEligibility(coroutineScope)
dispatchPreferredScheme(coroutineScope)
dispatchShouldContinue(coroutineScope)
collectSideEffects(lifecycleOwner)
collectCompletion(lifecycleOwner)
viewModel.start()
Comment thread
vitalii-vanziak-cko marked this conversation as resolved.
Resolved
}

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

private fun dispatchState() {
private fun dispatchState(coroutineScope: CoroutineScope) {
eventDispatcher.subscribe<POCardTokenizationState>(
coroutineScope = scope
coroutineScope
) { delegate.onStateChanged(it) }
}

private fun dispatchTokenizedCard() {
private fun dispatchTokenizedCard(coroutineScope: CoroutineScope) {
eventDispatcher.subscribeForRequest<CardTokenizationProcessingRequest>(
coroutineScope = scope
coroutineScope
) { request ->
scope.launch {
coroutineScope.launch {
Comment thread
vitalii-vanziak-cko marked this conversation as resolved.
Resolved
val result = delegate.processTokenizedCard(
card = request.card,
saveCard = request.saveCard
Expand All @@ -218,11 +219,11 @@ class POCardTokenizationViewComponent private constructor(
}
}

private fun dispatchEligibility() {
private fun dispatchEligibility(coroutineScope: CoroutineScope) {
eventDispatcher.subscribeForRequest<CardTokenizationEligibilityRequest>(
coroutineScope = scope
coroutineScope
) { request ->
scope.launch {
coroutineScope.launch {
val eligibility = delegate.evaluateEligibility(
iin = request.iin,
issuerInformation = request.issuerInformation
Expand All @@ -232,30 +233,30 @@ class POCardTokenizationViewComponent private constructor(
}
}

private fun dispatchPreferredScheme() {
private fun dispatchPreferredScheme(coroutineScope: CoroutineScope) {
eventDispatcher.subscribeForRequest<CardTokenizationPreferredSchemeRequest>(
coroutineScope = scope
coroutineScope
) { request ->
scope.launch {
coroutineScope.launch {
val preferredScheme = delegate.preferredScheme(request.issuerInformation)
eventDispatcher.send(request.toResponse(preferredScheme))
}
}
}

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

private fun collectSideEffects() {
scope.launch {
private fun collectSideEffects(lifecycleOwner: LifecycleOwner) {
lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(state = Lifecycle.State.STARTED) {
withContext(Dispatchers.Main.immediate) {
viewModel.sideEffects.collect { sideEffect ->
Expand All @@ -270,8 +271,8 @@ class POCardTokenizationViewComponent private constructor(
}
}

private fun collectCompletion() {
scope.launch {
private fun collectCompletion(lifecycleOwner: LifecycleOwner) {
lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(state = Lifecycle.State.STARTED) {
viewModel.completion.collect { completion ->
Comment thread
andrii-vysotskyi-cko marked this conversation as resolved.
Resolved
when (completion) {
Expand Down
Loading