Skip to content

Commit b4d98ef

Browse files
PX-621 Release 2.6.0 (#12)
1 parent bce412e commit b4d98ef

File tree

5 files changed

+87
-96
lines changed

5 files changed

+87
-96
lines changed

app/build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ def localProperties = new Properties()
88
localProperties.load(new FileInputStream(rootProject.file("local.properties")))
99

1010
android {
11-
compileSdk 33
11+
compileSdk 34
1212

1313
defaultConfig {
1414
applicationId "com.truelayer.demo"
1515
minSdk 24
16-
targetSdk 33
16+
targetSdk 34
1717
versionCode 1
1818
versionName "1.0"
1919

@@ -56,7 +56,7 @@ android {
5656
dependencies {
5757
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:$desugar_jdk_libs"
5858

59-
implementation 'androidx.core:core-ktx:1.10.1'
59+
implementation 'androidx.core:core-ktx:1.12.0'
6060
implementation "androidx.appcompat:appcompat:$appcompat_version"
6161
implementation "androidx.compose.ui:ui:$compose_version"
6262
implementation "androidx.compose.material:material-icons-extended:$compose_icons_version"
@@ -71,5 +71,5 @@ dependencies {
7171
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$json_serialization_version"
7272
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:$retrofit2_kotlinx_serialization"
7373

74-
implementation "com.truelayer.payments:ui:2.5.0"
74+
implementation "com.truelayer.payments:ui:2.6.0"
7575
}

app/src/main/java/com/truelayer/demo/payments/PaymentStatusViewModel.kt renamed to app/src/main/java/com/truelayer/demo/payments/MandateStatusViewModel.kt

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ import kotlinx.coroutines.launch
1616
/**
1717
* ViewModel for fetching the Payment's status
1818
*/
19-
class PaymentStatusViewModel(
20-
private val paymentId: String?,
19+
class MandateStatusViewModel(
2120
private val mandateId: String?,
2221
private val apiUrl: String,
2322
private val retryInterval: Long = 2_000,
@@ -32,34 +31,6 @@ class PaymentStatusViewModel(
3231
private val _error = MutableStateFlow("")
3332
val error: StateFlow<String> = _error
3433

35-
// Polls the payment status API to receive updates to the payment
36-
fun pollPaymentStatus() {
37-
_status.tryEmit(PaymentStatus.Status.AUTHORIZING)
38-
viewModelScope.launch(dispatcher) {
39-
var retryCount = 5
40-
var canRetry = true
41-
while (canRetry) {
42-
retryCount -= 1
43-
canRetry = retryCount > 0
44-
when (val paymentStatus = processorContextProvider.getPaymentStatus(paymentId!!)) {
45-
is Ok -> {
46-
if (paymentStatus.value.status != PaymentStatus.Status.AUTHORIZED && canRetry) {
47-
delay(retryInterval)
48-
continue
49-
} else {
50-
_status.emit(paymentStatus.value.status)
51-
break
52-
}
53-
}
54-
is Fail -> {
55-
_error.emit(paymentStatus.error.localizedMessage ?: "Unknown Error")
56-
break
57-
}
58-
}
59-
}
60-
}
61-
}
62-
6334
// Polls the mandate status API to receive updates to the payment
6435
fun pollMandateStatus() {
6536
_status.tryEmit(PaymentStatus.Status.AUTHORIZING)
@@ -90,13 +61,11 @@ class PaymentStatusViewModel(
9061
}
9162

9263
@Suppress("UNCHECKED_CAST")
93-
internal fun paymentStatusViewModel(
94-
paymentId: String?,
64+
internal fun mandateStatusViewModel(
9565
mandateId: String?,
9666
apiUrl: String
9767
) = object : ViewModelProvider.Factory {
98-
override fun <T : ViewModel> create(modelClass: Class<T>): T = PaymentStatusViewModel(
99-
paymentId = paymentId,
68+
override fun <T : ViewModel> create(modelClass: Class<T>): T = MandateStatusViewModel(
10069
mandateId = mandateId,
10170
apiUrl = apiUrl
10271
) as T

app/src/main/java/com/truelayer/demo/payments/PaymentStatusActivity.kt

Lines changed: 73 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import androidx.compose.material.icons.filled.Error
1515
import androidx.compose.material3.CircularProgressIndicator
1616
import androidx.compose.material3.MaterialTheme
1717
import androidx.compose.material3.Text
18+
import androidx.compose.runtime.Composable
1819
import androidx.compose.runtime.collectAsState
1920
import androidx.compose.runtime.getValue
2021
import androidx.compose.ui.Alignment
@@ -28,6 +29,8 @@ import com.truelayer.demo.R
2829
import com.truelayer.demo.payments.api.PaymentStatus
2930
import com.truelayer.demo.utils.PrefUtils
3031
import com.truelayer.payments.core.utils.extractTrueLayerRedirectParams
32+
import com.truelayer.payments.ui.screens.processor.ResultProcessor
33+
import com.truelayer.payments.ui.screens.processor.ResultProcessorContext
3134
import com.truelayer.payments.ui.theme.Theme
3235
import com.truelayer.payments.ui.theme.stackNavigation
3336

@@ -45,67 +48,87 @@ class PaymentStatusActivity : AppCompatActivity() {
4548
setContent {
4649
val paymentId = params["payment_id"]
4750
val mandateId = params["mandate_id"]
48-
val viewModel = viewModel<PaymentStatusViewModel>(
49-
factory = paymentStatusViewModel(paymentId, mandateId, PrefUtils.getQuickstartUrl(this))
50-
)
51-
val status by viewModel.status.collectAsState()
52-
val error by viewModel.error.collectAsState()
5351

54-
// Start polling for status updates
55-
if (paymentId != null) {
56-
viewModel.pollPaymentStatus()
57-
} else {
58-
viewModel.pollMandateStatus()
59-
}
52+
val activity = this
6053

6154
Theme(
6255
navigationTransition = { current, transition, direction ->
6356
stackNavigation(current, transition, direction)
6457
}
6558
) {
66-
Box(
67-
modifier = Modifier.fillMaxSize(),
68-
contentAlignment = Alignment.Center
69-
) {
70-
Column(
71-
horizontalAlignment = Alignment.CenterHorizontally,
72-
verticalArrangement = Arrangement.spacedBy(16.dp),
73-
modifier = Modifier.padding(horizontal = 16.dp)
74-
) {
75-
Text(text = stringResource(id = R.string.status_title), style = MaterialTheme.typography.titleMedium)
76-
when (status) {
77-
PaymentStatus.Status.AUTHORIZING -> {
78-
// If the SDK has done it's work already, it will be ok
79-
// to wait for status change
80-
CircularProgressIndicator()
81-
}
82-
PaymentStatus.Status.AUTHORIZATION_REQUIRED -> {
83-
// If you encounter this state, it's most likely that the SDK didn't
84-
// get chance to do its work yet. Start the CoordinatorFlow.
85-
// If the SDK has done its work, then this state would be considered
86-
// an error.
87-
// Because we are using this view to query the state of the payment
88-
// after redirect from the bank this should never happen.
89-
Image(imageVector = Icons.Filled.Error, contentDescription = null)
90-
}
91-
PaymentStatus.Status.AUTHORIZED,
92-
PaymentStatus.Status.SETTLED,
93-
PaymentStatus.Status.EXECUTED -> {
94-
Image(
95-
imageVector = Icons.Filled.CheckCircle,
96-
colorFilter = ColorFilter.tint(Color.Green),
97-
contentDescription = null
98-
)
99-
}
100-
PaymentStatus.Status.FAILED -> {
101-
Image(imageVector = Icons.Filled.Error, contentDescription = null)
102-
}
59+
if (paymentId != null) {
60+
// If this activity is launched at the end of a payment creation flow then you can use
61+
// the payment result screen to fetch and display the result
62+
ResultProcessor(
63+
resultContext = ResultProcessorContext(paymentId),
64+
onSuccess = {
65+
activity.finish()
66+
},
67+
onFailure = {
68+
activity.finish()
10369
}
70+
)
71+
} else if (mandateId != null) {
72+
// If this activity is launched at the end of a mandate flow then you will need to manually
73+
// fetch and display the status
74+
MandateStatus(mandateId)
75+
}
76+
}
77+
}
78+
}
79+
80+
@Composable
81+
fun MandateStatus(mandateId: String) {
82+
val viewModel = viewModel<MandateStatusViewModel>(
83+
factory = mandateStatusViewModel(mandateId, PrefUtils.getQuickstartUrl(this))
84+
)
85+
val status by viewModel.status.collectAsState()
86+
val error by viewModel.error.collectAsState()
10487

105-
Text(text = status.toString(), style = MaterialTheme.typography.bodyLarge)
106-
Text(text = error, color = Color.Red)
88+
// Start polling for mandate status updates
89+
viewModel.pollMandateStatus()
90+
91+
Box(
92+
modifier = Modifier.fillMaxSize(),
93+
contentAlignment = Alignment.Center
94+
) {
95+
Column(
96+
horizontalAlignment = Alignment.CenterHorizontally,
97+
verticalArrangement = Arrangement.spacedBy(16.dp),
98+
modifier = Modifier.padding(horizontal = 16.dp)
99+
) {
100+
Text(text = stringResource(id = R.string.status_title), style = MaterialTheme.typography.titleMedium)
101+
when (status) {
102+
PaymentStatus.Status.AUTHORIZING -> {
103+
// If the SDK has done it's work already, it will be ok
104+
// to wait for status change
105+
CircularProgressIndicator()
106+
}
107+
PaymentStatus.Status.AUTHORIZATION_REQUIRED -> {
108+
// If you encounter this state, it's most likely that the SDK didn't
109+
// get chance to do its work yet. Start the CoordinatorFlow.
110+
// If the SDK has done its work, then this state would be considered
111+
// an error.
112+
// Because we are using this view to query the state of the payment
113+
// after redirect from the bank this should never happen.
114+
Image(imageVector = Icons.Filled.Error, contentDescription = null)
115+
}
116+
PaymentStatus.Status.AUTHORIZED,
117+
PaymentStatus.Status.SETTLED,
118+
PaymentStatus.Status.EXECUTED -> {
119+
Image(
120+
imageVector = Icons.Filled.CheckCircle,
121+
colorFilter = ColorFilter.tint(Color.Green),
122+
contentDescription = null
123+
)
124+
}
125+
PaymentStatus.Status.FAILED -> {
126+
Image(imageVector = Icons.Filled.Error, contentDescription = null)
107127
}
108128
}
129+
130+
Text(text = status.toString(), style = MaterialTheme.typography.bodyLarge)
131+
Text(text = error, color = Color.Red)
109132
}
110133
}
111134
}

app/src/main/java/com/truelayer/demo/payments/ProcessorContextProvider.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,13 @@ import java.util.UUID
2525
/**
2626
* Utility class used to create payments via the Payments Quickstart API for testing the integrations
2727
*/
28-
@Suppress("BlockingMethodInNonBlockingContext")
2928
class ProcessorContextProvider(
3029
// The URI to the Payments Quickstart API
31-
private val apiURL: String
30+
private val apiURL: String,
3231
) {
3332

3433
// The redirect URI of this demo app that is specified in the AndroidManifest.xml
35-
// The same URI needs to be also registered in the TrueLayer console
34+
// The same URI needs to be also registered in the TrueLayer console
3635
// in `App Settings` as `Allowed redirect URIs`.
3736
private val redirectUri: String = "truelayer://demo"
3837

build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@ buildscript {
22
ext {
33
activity_compose_version="1.7.2"
44
appcompat_version = "1.6.1"
5-
compose_version = "1.4.3"
6-
compose_icons_version = "1.4.3"
5+
compose_version = "1.5.1"
6+
compose_icons_version = "1.5.1"
77
compose_compiler_version = "1.4.4"
88
json_serialization_version = "1.3.3"
99
kotlin_version = "1.8.10"
10-
lifecycle_version = "2.6.1"
10+
lifecycle_version = "2.6.2"
1111
material_version = "1.9.0"
1212
retrofit2_kotlinx_serialization = "1.0.0"
1313
material3_compose_version = "1.1.1"
1414
desugar_jdk_libs = "1.2.2"
1515
}
1616
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
1717
plugins {
18-
id 'com.android.application' version '8.0.2' apply false
19-
id 'com.android.library' version '8.0.2' apply false
18+
id 'com.android.application' version '8.1.0' apply false
19+
id 'com.android.library' version '8.1.0' apply false
2020
id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
2121
}
2222

0 commit comments

Comments
 (0)