diff --git a/.github/workflows/create-release-and-publish.yml b/.github/workflows/create-release-and-publish.yml index 6a45613a..2c8c4b2a 100644 --- a/.github/workflows/create-release-and-publish.yml +++ b/.github/workflows/create-release-and-publish.yml @@ -27,11 +27,15 @@ jobs: run: | ./gradlew :sdk:assembleProductionRelease ./gradlew :checkout-3ds:assembleProductionRelease + ./gradlew :ui-core:assembleProductionRelease + ./gradlew :ui:assembleProductionRelease - name: Publish To Maven Central run: | ./gradlew :sdk:publishProductionReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository --max-workers=1 ./gradlew :checkout-3ds:publishProductionReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository --max-workers=1 + ./gradlew :ui-core:publishProductionReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository --max-workers=1 + ./gradlew :ui:publishProductionReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository --max-workers=1 env: OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} diff --git a/.github/workflows/release_documentation.yml b/.github/workflows/release-documentation.yml similarity index 100% rename from .github/workflows/release_documentation.yml rename to .github/workflows/release-documentation.yml diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index f8467b45..e805548a 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0f3036e7..d6610c5f 100644 --- a/build.gradle +++ b/build.gradle @@ -2,10 +2,10 @@ buildscript { ext { - androidGradlePluginVersion = '8.1.4' - kotlinVersion = '1.9.10' - kspVersion = '1.9.10-1.0.13' - dokkaVersion = '1.9.0' + androidGradlePluginVersion = '8.2.0' + kotlinVersion = '1.9.20' + kspVersion = '1.9.20-1.0.14' + dokkaVersion = '1.9.10' androidxNavigationVersion = '2.7.5' nexusPublishPluginVersion = '1.3.0' } @@ -46,24 +46,24 @@ ext { androidxBrowserVersion = '1.7.0' androidxComposeBOMVersion = '2023.10.01' - androidxComposeCompilerVersion = '1.5.3' + androidxComposeCompilerVersion = '1.5.5' materialVersion = '1.10.0' retrofitVersion = '2.9.0' moshiVersion = '1.15.0' - okhttpVersion = '4.11.0' - okioVersion = '3.5.0' - coilVersion = '2.4.0' + okhttpVersion = '4.12.0' + okioVersion = '3.6.0' + coilVersion = '2.5.0' commonMarkVersion = '0.21.0' - checkout3dsSdkVersion = '3.1.1' + checkout3dsSdkVersion = '3.2.0' adyen3dsSdkVersion = '2.2.15' junitVersion = '4.13.2' - mockitoVersion = '5.5.0' + mockitoVersion = '5.8.0' mockitoInlineVersion = '5.2.0' - mockitoKotlinVersion = '5.1.0' + mockitoKotlinVersion = '5.2.1' robolectricVersion = '4.11.1' androidxTestCoreVersion = '1.5.0' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c58072fa..d354f381 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Oct 05 19:43:19 EEST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/ui-core/build.gradle b/ui-core/build.gradle index 3e2b405c..4b462c43 100644 --- a/ui-core/build.gradle +++ b/ui-core/build.gradle @@ -4,6 +4,13 @@ plugins { id 'kotlin-parcelize' } +ext { + publishArtifactId = 'processout-android-ui-core' + publishDescription = 'ProcessOut Android SDK - UI Core' +} + +apply from: "${rootProject.projectDir}/scripts/publish-module.gradle" + android { namespace 'com.processout.sdk.ui.core' compileSdk rootProject.ext.compileSdkVersion @@ -53,6 +60,13 @@ android { composeOptions { kotlinCompilerExtensionVersion = rootProject.ext.androidxComposeCompilerVersion } + + publishing { + singleVariant("productionRelease") { + withSourcesJar() + withJavadocJar() + } + } } @SuppressWarnings('GrMethodMayBeStatic') diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POActionsContainer.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POActionsContainer.kt index 9ea76311..da145d57 100644 --- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POActionsContainer.kt +++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POActionsContainer.kt @@ -89,9 +89,9 @@ object POActionsContainer { data class Style( val primary: POButton.Style, val secondary: POButton.Style, - val axis: POAxis, val dividerColor: Color, - val backgroundColor: Color + val backgroundColor: Color, + val axis: POAxis ) val default: Style @@ -99,9 +99,9 @@ object POActionsContainer { Style( primary = POButton.primary, secondary = POButton.secondary, - axis = POAxis.Vertical, dividerColor = colors.border.subtle, - backgroundColor = colors.surface.level1 + backgroundColor = colors.surface.level1, + axis = POAxis.Vertical ) } @@ -110,9 +110,9 @@ object POActionsContainer { Style( primary = POButton.custom(style = primary), secondary = POButton.custom(style = secondary), - axis = axis, dividerColor = colorResource(id = dividerColorResId), - backgroundColor = colorResource(id = backgroundColorResId) + backgroundColor = colorResource(id = backgroundColorResId), + axis = axis ) } diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POButton.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POButton.kt index 933afdf1..6d85d541 100644 --- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POButton.kt +++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/POButton.kt @@ -44,7 +44,7 @@ fun POButton( CompositionLocalProvider(LocalRippleTheme provides NoRippleTheme) { Button( onClick = onClick, - modifier = modifier.defaultMinSize(minHeight = ProcessOutTheme.dimensions.formComponentHeight), + modifier = modifier.height(ProcessOutTheme.dimensions.formComponentHeight), enabled = enabled && !loading, colors = POButton.colors(enabled = enabled, loading = loading, pressed = pressed, style = style), shape = if (enabled) style.normal.shape else style.disabled.shape, diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/POTextField.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/POTextField.kt index 17a7be6b..3cad4a50 100644 --- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/POTextField.kt +++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/component/field/POTextField.kt @@ -4,14 +4,15 @@ package com.processout.sdk.ui.core.component.field import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.selection.LocalTextSelectionColors -import androidx.compose.material3.* +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember @@ -50,7 +51,7 @@ fun POTextField( BasicTextField( value = value, onValueChange = onValueChange, - modifier = modifier.defaultMinSize(minHeight = ProcessOutTheme.dimensions.formComponentHeight), + modifier = modifier.height(ProcessOutTheme.dimensions.formComponentHeight), enabled = enabled, textStyle = POField.textStyle( isError = isError, diff --git a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POActionsContainerStyle.kt b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POActionsContainerStyle.kt index 58dcfbfa..88c62794 100644 --- a/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POActionsContainerStyle.kt +++ b/ui-core/src/main/kotlin/com/processout/sdk/ui/core/style/POActionsContainerStyle.kt @@ -8,9 +8,9 @@ import kotlinx.parcelize.Parcelize data class POActionsContainerStyle( val primary: POButtonStyle, val secondary: POButtonStyle, - val axis: POAxis, @ColorRes val dividerColorResId: Int, @ColorRes - val backgroundColorResId: Int + val backgroundColorResId: Int, + val axis: POAxis = POAxis.Vertical ) : Parcelable diff --git a/ui/build.gradle b/ui/build.gradle index af2a123c..26469292 100644 --- a/ui/build.gradle +++ b/ui/build.gradle @@ -1,9 +1,17 @@ plugins { id 'com.android.library' id 'org.jetbrains.kotlin.android' + id 'org.jetbrains.dokka' id 'kotlin-parcelize' } +ext { + publishArtifactId = 'processout-android-ui' + publishDescription = 'ProcessOut Android SDK - UI' +} + +apply from: "${rootProject.projectDir}/scripts/publish-module.gradle" + android { namespace 'com.processout.sdk.ui' compileSdk rootProject.ext.compileSdkVersion @@ -54,6 +62,15 @@ android { composeOptions { kotlinCompilerExtensionVersion = rootProject.ext.androidxComposeCompilerVersion } + + publishing { + singleVariant("productionRelease") { + withSourcesJar() + // FIXME: This fails build with error "PermittedSubclasses requires ASM9" while publishing to Maven Central. + // Test by running: ./gradlew :ui:publishProductionReleasePublicationToMavenLocal +// withJavadocJar() + } + } } @SuppressWarnings('GrMethodMayBeStatic') diff --git a/ui/documentation/ProcessOutUI.md b/ui/documentation/ProcessOutUI.md new file mode 100644 index 00000000..8a1501d4 --- /dev/null +++ b/ui/documentation/ProcessOutUI.md @@ -0,0 +1,72 @@ +# Module ProcessOut Android SDK - UI + +## Card Update + +### Launch Card Update Bottom Sheet + +```kotlin +// 1) It is required to initialize launcher in onCreate() method of Activity or Fragment. + +private lateinit var launcher: POCardUpdateLauncher + +override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + launcher = POCardUpdateLauncher.create(from = this) { result -> + result.onSuccess { card -> + TODO() + }.onFailure { TODO() } + } +} + +// 2) Launch the activity. + +launcher.launch( + POCardUpdateConfiguration( + cardId = "card_" + ) +) +``` + +### Configuration + +```kotlin +POCardUpdateConfiguration( + cardId = "card_", + options = POCardUpdateConfiguration.Options( + title = "Payment details", + cardInformation = POCardUpdateConfiguration.CardInformation( + maskedNumber = "4010 **** **** **21", + iin = "401000", + scheme = "visa", + preferredScheme = "carte bancaire" + ), + primaryActionText = "Submit", + secondaryActionText = "Cancel", + cancellation = POCancellationConfiguration( + secondaryAction = true, + backPressed = false, + dragDown = true, + touchOutside = false + ) + ), + style = POCardUpdateConfiguration.Style( + // Customize the look and feel. + ) +) +``` + +### Lifecycle Events + +```kotlin +viewModelScope.launch { + ProcessOut.instance.dispatchers.cardUpdate + .events.collect { event -> + when (event) { + POCardUpdateEvent.DidStart -> TODO() + POCardUpdateEvent.ParametersChanged -> TODO() + POCardUpdateEvent.WillUpdateCard -> TODO() + POCardUpdateEvent.DidComplete -> TODO() + } + } +} +``` diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/POCardUpdateConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/POCardUpdateConfiguration.kt index 1bbdaadf..8b6fe936 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/card/update/POCardUpdateConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/card/update/POCardUpdateConfiguration.kt @@ -8,6 +8,13 @@ import com.processout.sdk.ui.core.style.POTextStyle import com.processout.sdk.ui.shared.configuration.POCancellationConfiguration import kotlinx.parcelize.Parcelize +/** + * Defines card update configuration. + * + * @param[cardId] Card ID. + * @param[options] Allows to customize behaviour and pre-define the values. + * @param[style] Allows to customize the look and feel. + */ @Parcelize data class POCardUpdateConfiguration( val cardId: String, @@ -15,6 +22,15 @@ data class POCardUpdateConfiguration( val style: Style? = null ) : Parcelable { + /** + * Allows to customize behaviour and pre-define the values. + * + * @param[title] Custom title. + * @param[cardInformation] Allows to provide card information that will be visible in UI. + * @param[primaryActionText] Custom primary action text (e.g. "Submit"). + * @param[secondaryActionText] Custom secondary action text (e.g. "Cancel"). + * @param[cancellation] Specifies cancellation behaviour. + */ @Parcelize data class Options( val title: String? = null, @@ -24,6 +40,16 @@ data class POCardUpdateConfiguration( val cancellation: POCancellationConfiguration = POCancellationConfiguration() ) : Parcelable + /** + * Allows to provide card information that will be visible in UI. + * + * @param[maskedNumber] Masked card number displayed to user as is. + * @param[iin] Card issuer identification number. Corresponds to the first 6 or 8 digits of the main card number. + * When this property is _null_ implementation will attempt to extract IIN from [maskedNumber]. + * You may want to set this property explicitly if IIN is hidden in masked number. + * @param[scheme] Scheme of the card. + * @param[preferredScheme] Preferred scheme of the card previously selected by the user if any. + */ @Parcelize data class CardInformation( val maskedNumber: String? = null, @@ -32,6 +58,17 @@ data class POCardUpdateConfiguration( val preferredScheme: String? = null ) : Parcelable + /** + * Allows to customize the look and feel. + * + * @param[title] Title style. + * @param[field] Field style. + * @param[errorMessage] Error message style. + * @param[actionsContainer] Style of action buttons and their container. + * @param[backgroundColorResId] Color resource ID for background. + * @param[dividerColorResId] Color resource ID for title divider. + * @param[dragHandleColorResId] Color resource ID for bottom sheet drag handle. + */ @Parcelize data class Style( val title: POTextStyle? = null, diff --git a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POCancellationConfiguration.kt b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POCancellationConfiguration.kt index 0c87fb83..29f24f7c 100644 --- a/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POCancellationConfiguration.kt +++ b/ui/src/main/kotlin/com/processout/sdk/ui/shared/configuration/POCancellationConfiguration.kt @@ -3,6 +3,14 @@ package com.processout.sdk.ui.shared.configuration import android.os.Parcelable import kotlinx.parcelize.Parcelize +/** + * Specifies cancellation behaviour. + * + * @param[secondaryAction] Enables secondary cancel action button. Default value is _true_. + * @param[backPressed] Cancel on back button press or back gesture. Default value is _true_. + * @param[dragDown] Cancel when bottom sheet is dragged down out of the screen. Default value is _true_. + * @param[touchOutside] Cancel on touch of the outside dimmed area of the bottom sheet. Default value is _true_. + */ @Parcelize data class POCancellationConfiguration( val secondaryAction: Boolean = true,