Skip to content

Commit e3edb98

Browse files
PX-2962 4.1.1 Release (#25)
1 parent 0eace0c commit e3edb98

File tree

9 files changed

+494
-98
lines changed

9 files changed

+494
-98
lines changed

MigrateTo3.8.0.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,3 +714,82 @@ Other libraries have been updated:
714714
- `org.jetbrains.kotlinx.kotlinx-coroutines-android` : `1.10.2`
715715
- `org.jetbrains.kotlinx.kotlinx-coroutines-core` : `1.10.2`
716716
- `org.jetbrains.kotlinx.kotlinx-coroutines-test` : `1.10.2`
717+
718+
# Version 4.1.0
719+
720+
Version 4.1.0 includes all the features of 4.x.x, including
721+
a refreshed user experience with a new, seamless UI and support for payment retries.
722+
723+
The following new features are available automatically for all GBP single payments and EUR payments in Ireland:
724+
725+
- A single-screen, modern, declarative UI system under the hood, allowing for smooth transitions and improved user experience.
726+
- Retries: allow your users to change bank on the fly, or retry failed payments without restarting the SDK.
727+
- Cancellation screen streamlining: more insight on why users are abandoning their payments.
728+
- Preselected providers for returning users: automatically select the last used provider, allowing for faster one-click payments and more engaged, better converting users.
729+
730+
- This update contains minor bug fixes, improvements and underlying library updates.
731+
732+
The most important version changes:
733+
- `Kotlin` : `2.2.20`
734+
- `androidx.compose.compose-bom` : `2025.10.01`
735+
- `gradle` : `gradle-8.13`
736+
737+
Other library updates:
738+
- `androidx.activity.activity-compose` : `1.11.0`
739+
- `androidx.compose.runtime.runtime-tracing` : `1.9.4`
740+
- `androidx.core.core-ktx` : `1.17.0`
741+
- `androidx.fragment.fragment-ktx` : `1.8.9`
742+
- `androidx.fragment.fragment-testing` : `1.8.9`
743+
- `androidx.lifecycle.lifecycle-livedata-ktx` : `2.9.4`
744+
- `androidx.lifecycle.lifecycle-runtime-compose-android` : `2.9.4`
745+
- `androidx.lifecycle.lifecycle-runtime-ktx` : `2.9.4`
746+
- `androidx.lifecycle.lifecycle-viewmodel-compose` : `2.9.4`
747+
- `androidx.lifecycle.lifecycle-viewmodel-ktx` : `2.9.4`
748+
- `androidx.navigation.navigation-compose` : `2.9.5`
749+
- `androidx.work.work-multiprocess` : `2.11.0`
750+
- `androidx.work.work-runtime-ktx` : `2.11.0`
751+
- `com.google.android.material.material` : `1.13.0`
752+
753+
## The new way to theme the SDK
754+
755+
When integrating via Compose you no longer need to wrapp the `Processor` composable with `Theme`.
756+
The `Theme` will be applied automatically. If you want to customise the theme the `Processor` composable
757+
now accepts a `theme` parameter.
758+
It also worth mentioning that the SDK will only allow theming for approved merchants. If you are trying
759+
to apply a custom theme and you are not an approved merchant the SDK will fallback to the default theme.
760+
If you have questions about this please contact TrueLayer support.
761+
762+
```kotlin
763+
// Your payments custom theme or use the provided defaults as below
764+
// theme is optional, if not provided default theme will be applied
765+
val theme = TrueLayerTheme(
766+
lightPalette = LightColorDefaults,
767+
darkPalette = DarkColorDefaults,
768+
typography = TypographyDefaults
769+
)
770+
771+
// Obtain your payment context from your backend
772+
val paymentContext = PaymentContext(
773+
id = "your-payment-identifier",
774+
resourceToken = "payment-resource-token",
775+
redirectUri = "redirect-uri-that-will-be-invoked-when-coming-back-from-bank"
776+
)
777+
778+
setContent {
779+
Processor(
780+
context = paymentContext,
781+
// theme is optional, if not provided default theme will be applied
782+
theme = theme,
783+
onSuccess = { successStep ->
784+
// action on success
785+
},
786+
onFailure = { failureReason ->
787+
// action on failure
788+
}
789+
)
790+
}
791+
```
792+
793+
Because the SDK is using `Scaffold` and `BottomSheetScaffold` under the hood to present its UI components
794+
you need to make sure that you don't have nested `Scaffold` or `BottomSheetScaffold` in your app when integrating the SDK via Compose.
795+
Although the SDK will work the UI may and will not behave as expected.

README.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,95 @@ Other libraries have been updated:
101101
- `org.jetbrains.kotlinx.kotlinx-coroutines-core` : `1.10.2`
102102
- `org.jetbrains.kotlinx.kotlinx-coroutines-test` : `1.10.2`
103103

104+
## Version 4.1.0
105+
106+
Version 4.1.0 includes all the features of 4.x.x, including
107+
a refreshed user experience with a new, seamless UI and support for payment retries.
108+
109+
The following new features are available automatically for all GBP single payments and EUR payments in Ireland:
110+
111+
- A single-screen, modern, declarative UI system under the hood, allowing for smooth transitions and improved user experience.
112+
- Retries: allow your users to change bank on the fly, or retry failed payments without restarting the SDK.
113+
- Cancellation screen streamlining: more insight on why users are abandoning their payments.
114+
- Preselected providers for returning users: automatically select the last used provider, allowing for faster one-click payments and more engaged, better converting users.
115+
116+
- This update contains minor bug fixes, improvements and underlying library updates.
117+
118+
The most important version changes:
119+
- `Kotlin` : `2.2.20`
120+
- `androidx.compose.compose-bom` : `2025.10.01`
121+
- `gradle` : `gradle-8.13`
122+
123+
Other library updates:
124+
- `androidx.activity.activity-compose` : `1.11.0`
125+
- `androidx.compose.runtime.runtime-tracing` : `1.9.4`
126+
- `androidx.core.core-ktx` : `1.17.0`
127+
- `androidx.fragment.fragment-ktx` : `1.8.9`
128+
- `androidx.fragment.fragment-testing` : `1.8.9`
129+
- `androidx.lifecycle.lifecycle-livedata-ktx` : `2.9.4`
130+
- `androidx.lifecycle.lifecycle-runtime-compose-android` : `2.9.4`
131+
- `androidx.lifecycle.lifecycle-runtime-ktx` : `2.9.4`
132+
- `androidx.lifecycle.lifecycle-viewmodel-compose` : `2.9.4`
133+
- `androidx.lifecycle.lifecycle-viewmodel-ktx` : `2.9.4`
134+
- `androidx.navigation.navigation-compose` : `2.9.5`
135+
- `androidx.work.work-multiprocess` : `2.11.0`
136+
- `androidx.work.work-runtime-ktx` : `2.11.0`
137+
- `com.google.android.material.material` : `1.13.0`
138+
139+
### The new way to theme the SDK
140+
141+
When integrating via Compose you no longer need to wrapp the `Processor` composable with `Theme`.
142+
The `Theme` will be applied automatically. If you want to customise the theme the `Processor` composable
143+
now accepts a `theme` parameter.
144+
It also worth mentioning that the SDK will only allow theming for approved merchants. If you are trying
145+
to apply a custom theme and you are not an approved merchant the SDK will fallback to the default theme.
146+
If you have questions about this please contact TrueLayer support.
147+
148+
```kotlin
149+
// Your payments custom theme or use the provided defaults as below
150+
// theme is optional, if not provided default theme will be applied
151+
val theme = TrueLayerTheme(
152+
lightPalette = LightColorDefaults,
153+
darkPalette = DarkColorDefaults,
154+
typography = TypographyDefaults
155+
)
156+
157+
// Obtain your payment context from your backend
158+
val paymentContext = PaymentContext(
159+
id = "your-payment-identifier",
160+
resourceToken = "payment-resource-token",
161+
redirectUri = "redirect-uri-that-will-be-invoked-when-coming-back-from-bank"
162+
)
163+
164+
setContent {
165+
Processor(
166+
context = paymentContext,
167+
// theme is optional, if not provided default theme will be applied
168+
theme = theme,
169+
onSuccess = { successStep ->
170+
// action on success
171+
},
172+
onFailure = { failureReason ->
173+
// action on failure
174+
}
175+
)
176+
}
177+
```
178+
179+
Because the SDK is using `Scaffold` and `BottomSheetScaffold` under the hood to present its UI components
180+
you need to make sure that you don't have nested `Scaffold` or `BottomSheetScaffold` in your app when integrating the SDK via Compose.
181+
Although the SDK will work the UI may and will not behave as expected.
182+
183+
## 4.1.1
184+
185+
This patch version contains bugfixes and improvements, all the libraries and version
186+
and the integration method remain as with the 4.1.0.
187+
188+
### General improvements and bug fixes
189+
- Improved the bottom sheet behaviour.
190+
- Handling edge cases of certain SDK integrations.
191+
- Improving user journey in some GBP payments.
192+
104193
## How does the payment flow with the SDK works?
105194

106195
```mermaid

app/build.gradle

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

1111
android {
12-
compileSdk 35
13-
12+
compileSdk = 36
1413
defaultConfig {
1514
applicationId "com.truelayer.demo"
1615
minSdk 24
17-
targetSdk 35
16+
targetSdk 36
1817
versionCode 1
1918
versionName "1.0"
2019

@@ -67,11 +66,15 @@ dependencies {
6766
implementation "androidx.compose.material3:material3"
6867
implementation "com.google.android.material:material:$material_version"
6968

69+
// Android Studio Preview support
70+
implementation 'androidx.compose.ui:ui-tooling-preview'
71+
debugImplementation 'androidx.compose.ui:ui-tooling'
72+
7073
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
7174
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
7275

7376
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$json_serialization_version"
7477
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:$retrofit2_kotlinx_serialization"
7578

76-
implementation "com.truelayer.payments:ui:4.0.1"
79+
implementation "com.truelayer.payments:ui:4.1.1"
7780
}

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@
1414
android:supportsRtl="true"
1515
android:theme="@style/Theme.SDKDemo"
1616
android:usesCleartextTraffic="true"
17-
tools:targetApi="34">
17+
tools:targetApi="36">
1818
<activity
1919
android:name=".MainActivity"
2020
android:exported="true"
2121
android:theme="@style/Theme.SDKDemo">
2222
<intent-filter>
2323
<action android:name="android.intent.action.MAIN" />
24-
2524
<category android:name="android.intent.category.LAUNCHER" />
2625
</intent-filter>
2726
</activity>
@@ -45,10 +44,11 @@
4544
<activity
4645
android:name=".integrations.ActivityIntegrationActivity"
4746
android:parentActivityName=".MainActivity"
47+
android:launchMode="singleTask"
4848
android:label="@string/integration_activity"/>
4949
<activity
5050
android:name=".integrations.ActivityXIntegrationActivity"
51-
android:exported="true"
51+
android:launchMode="singleTask"
5252
android:label="@string/integration_activityx">
5353
</activity>
5454
<activity
@@ -59,6 +59,7 @@
5959
<activity
6060
android:name=".integrations.JavaIntegrationActivity"
6161
android:parentActivityName=".MainActivity"
62+
android:launchMode="singleTask"
6263
android:label="@string/integration_java"/>
6364
</application>
6465

app/src/main/java/com/truelayer/demo/integrations/ActivityIntegrationActivity.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.truelayer.demo.integrations
33
import android.app.Activity
44
import android.content.Intent
55
import android.os.Bundle
6+
import android.util.Log
67
import android.widget.Toast
78
import com.truelayer.demo.R
89
import com.truelayer.demo.databinding.ActivityIntegrationBinding
@@ -21,6 +22,7 @@ import kotlinx.coroutines.CoroutineScope
2122
import kotlinx.coroutines.Dispatchers
2223
import kotlinx.coroutines.launch
2324
import kotlinx.coroutines.withContext
25+
import kotlinx.serialization.json.Json
2426

2527
/**
2628
* Example integration of the SDK with the Activity component
@@ -29,6 +31,12 @@ class ActivityIntegrationActivity : Activity() {
2931

3032
private val scope = CoroutineScope(Dispatchers.IO)
3133

34+
private var currentProcessorContext: ProcessorContext? = null
35+
36+
companion object {
37+
const val TAG = "Activity"
38+
}
39+
3240
override fun onCreate(savedInstanceState: Bundle?) {
3341
super.onCreate(savedInstanceState)
3442

@@ -56,6 +64,31 @@ class ActivityIntegrationActivity : Activity() {
5664
super.onNewIntent(intent)
5765
intent?.let {
5866
tryHandleIntentWithRedirectFromBankData(it)
67+
this.intent = it
68+
}
69+
}
70+
71+
override fun onSaveInstanceState(outState: Bundle) {
72+
super.onSaveInstanceState(outState)
73+
currentProcessorContext?.let {
74+
try {
75+
val ctx = Json.encodeToString(it)
76+
outState.putString("processorContext", ctx)
77+
} catch (e: Throwable) {
78+
Log.e(TAG, e.toString())
79+
}
80+
}
81+
}
82+
83+
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
84+
super.onRestoreInstanceState(savedInstanceState)
85+
savedInstanceState.getString("processorContext")?.let {
86+
try {
87+
currentProcessorContext = Json.Default.decodeFromString(it)
88+
} catch (e: Throwable) {
89+
// failed to decode
90+
Log.e(TAG, e.toString())
91+
}
5992
}
6093
}
6194

@@ -68,10 +101,15 @@ class ActivityIntegrationActivity : Activity() {
68101
// and the payment/mandate ID matches the one we have stored
69102
// so we can fetch the payment status
70103
startPaymentActivity(storedProcessorContext)
104+
} else {
105+
currentProcessorContext?.let {
106+
startPaymentActivity(it)
107+
}
71108
}
72109
}
73110

74111
private fun startPaymentActivity(processorContext: ProcessorContext) {
112+
currentProcessorContext = processorContext
75113
// Create an intent with the payment context to start the payment flow
76114
val intent = ProcessorActivityContract().createIntent(this, processorContext)
77115
// Start activity for result to receive the results of the payment flow
@@ -103,6 +141,11 @@ class ActivityIntegrationActivity : Activity() {
103141
super.onActivityResult(requestCode, resultCode, data)
104142
// Extract the result of the payment flow from the intent
105143
val result = ProcessorResult.unwrapResult(data)
144+
?: // in this case the Processor was terminated without setting a result
145+
// this is a common case when a redirect from bank is coming
146+
// and the same activity that is holding the SDK is not brought forward
147+
// but a new one is created. In such case it is safe to ignore it.
148+
return
106149
Toast.makeText(this, result.toString(), Toast.LENGTH_LONG).show()
107150
}
108151
}

0 commit comments

Comments
 (0)