From 2f88dbf1387528d8b3a6dee3f7e808df4da2f3ad Mon Sep 17 00:00:00 2001 From: Natthawut Haematulin Date: Wed, 4 Oct 2023 14:08:04 +0700 Subject: [PATCH 01/10] feat: revamp UiCustomization config --- .../omise/android/example/CheckoutActivity.kt | 96 ++-- .../omise/android/config/UiCustomization.kt | 468 ++++++------------ 2 files changed, 217 insertions(+), 347 deletions(-) diff --git a/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt b/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt index 1952ed6d1..6a34833d8 100644 --- a/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt +++ b/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt @@ -129,47 +129,63 @@ class CheckoutActivity : AppCompatActivity() { * Here's the sample of initializing 3D Secure 2. * This should be call before start the [AuthorizingPaymentActivity]. */ + private fun initializeAuthoringPaymentConfig() { - val uiCustomization = UiCustomization.Builder() - .labelCustomization(UiCustomization.LabelCustomization.Builder() - .textFontName("fonts/RobotoMono-Regular.ttf") - .textFontColor("#000000") - .textFontSize(16) - .headingTextColor("#000000") - .headingTextFontName("fonts/RobotoMono-Bold.ttf") - .headingTextFontSize(20) - .build()) - .textBoxCustomization(UiCustomization.TextBoxCustomization.Builder() - .textFontName("fonts/RobotoMono-Regular.ttf") - .textFontColor("#000000") - .textFontSize(16) - .borderWidth(1) - .cornerRadius(4) - .borderColor("#1A56F0") - .build()) - .toolbarCustomization(UiCustomization.ToolbarCustomization.Builder() - .textFontName("fonts/RobotoMono-Bold.ttf") - .textFontColor("#000000") - .textFontSize(20) - .backgroundColor("#FFFFFF") - .headerText("Secure Checkout") - .buttonText("Close") - .build()) - .buttonCustomization(UiCustomization.ButtonType.SUBMIT_BUTTON, UiCustomization.ButtonCustomization.Builder() - .textFontName("fonts/RobotoMono-Bold.ttf") - .textFontColor("#FFFFFF") - .textFontSize(20) - .backgroundColor("#1A56F0") - .cornerRadius(4) - .build()) - .buttonCustomization(UiCustomization.ButtonType.RESEND_BUTTON, UiCustomization.ButtonCustomization.Builder() - .textFontName("fonts/RobotoMono-Bold.ttf") - .textFontColor("#000000") - .textFontSize(20) - .backgroundColor("#FFFFFF") - .cornerRadius(4) - .build()) - .build() + val labelCustomization = UiCustomization.LabelCustomization.LabelCustomizationBuilder() + .headingDarkTextColor("#000000") + .headingTextColor("#000000") + .headingTextFontName("fonts/RobotoMono-Bold.ttf") + .headingTextFontSize(20) + .textFontName("fonts/RobotoMono-Regular.ttf") + .textColor("#000000") + .textFontSize(16) + .build() + + val textBoxCustomization = UiCustomization.TextBoxCustomization.TextBoxCustomizationBuilder() + .textFontName("fonts/RobotoMono-Regular.ttf") + .textColor("#000000") + .textFontSize(16) + .borderWidth(1) + .cornerRadius(4) + .borderColor("#1A56F0") + .build() + + val toolbarCustomization = UiCustomization.ToolbarCustomization.ToolbarCustomizationBuilder() + .textFontName("fonts/RobotoMono-Bold.ttf") + .textColor("#000000") + .textFontSize(20) + .backgroundColor("#FFFFFF") + .headText("Secure Checkout") + .buttonText("Close") + .build() + + val primaryButtonCustomization = UiCustomization.ButtonCustomization.ButtonCustomizationBuilder() + .textFontName("fonts/RobotoMono-Bold.ttf") + .textColor("#000000") + .textFontSize(20) + .backgroundColor("#FFFFFF") + .cornerRadius(4) + .build() + + val secondaryButtonCustomization = UiCustomization.ButtonCustomization.ButtonCustomizationBuilder() + .textFontName("fonts/RobotoMono-Bold.ttf") + .textColor("#000000") + .textFontSize(20) + .backgroundColor("#FFFFFF") + .cornerRadius(4) + .build() + + val uiCustomization = UiCustomization.UiCustomizationBuilder() + .labelCustomization(labelCustomization) + .textBoxCustomization(textBoxCustomization) + .toolbarCustomization(toolbarCustomization) + .buttonCustomization(UiCustomization.ButtonType.SUBMIT, primaryButtonCustomization) + .buttonCustomization(UiCustomization.ButtonType.CONTINUE, primaryButtonCustomization) + .buttonCustomization(UiCustomization.ButtonType.NEXT, primaryButtonCustomization) + .buttonCustomization(UiCustomization.ButtonType.OPEN_OOB_APP, primaryButtonCustomization) + .buttonCustomization(UiCustomization.ButtonType.RESEND, primaryButtonCustomization) + .buttonCustomization(UiCustomization.ButtonType.CANCEL, secondaryButtonCustomization) + .build() val threeDSConfig = ThreeDSConfig.Builder() .uiCustomization(uiCustomization) diff --git a/sdk/src/main/java/co/omise/android/config/UiCustomization.kt b/sdk/src/main/java/co/omise/android/config/UiCustomization.kt index a3d99b5ea..12bcf37f4 100644 --- a/sdk/src/main/java/co/omise/android/config/UiCustomization.kt +++ b/sdk/src/main/java/co/omise/android/config/UiCustomization.kt @@ -1,23 +1,31 @@ package co.omise.android.config -import androidx.annotation.StyleRes - +import com.netcetera.threeds.sdk.api.ui.logic.ButtonCustomization +import com.netcetera.threeds.sdk.api.ui.logic.LabelCustomization +import com.netcetera.threeds.sdk.api.ui.logic.TextBoxCustomization +import com.netcetera.threeds.sdk.api.ui.logic.ToolbarCustomization + + +abstract class CustomizationBuilder { + protected var textFontSize: Int? = null + protected var textColor: String? = null + protected var textFontName: String? = null + protected var darkTextColor: String? = null + abstract fun build(): T +} /** * Configuration for UI customization in the challenge flow. */ -data class UiCustomization internal constructor(internal val uiCustomization: co.omise.android.threeds.customization.UiCustomization) { +data class UiCustomization internal constructor(internal val uiCustomization: com.netcetera.threeds.sdk.api.ui.logic.UiCustomization) { companion object { - val default = UiCustomization(co.omise.android.threeds.customization.UiCustomization( - labelCustomization = co.omise.android.threeds.customization.LabelCustomization(), - toolbarCustomization = co.omise.android.threeds.customization.ToolbarCustomization(), - buttonCustomizations = emptyMap(), - textBoxCustomization = co.omise.android.threeds.customization.TextBoxCustomization() - )) + val default = UiCustomization(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization()) } - class Builder { - private var uiCustomization: UiCustomization = default + class UiCustomizationBuilder { + private var labelCustomization: LabelCustomization? = null + private var toolbarCustomization: ToolbarCustomization? = null + private var textBoxCustomization: TextBoxCustomization? = null private var buttonCustomizations: MutableMap = mutableMapOf() /** @@ -25,12 +33,8 @@ data class UiCustomization internal constructor(internal val uiCustomization: co * * @param labelCustomization Label customization data. */ - fun labelCustomization(labelCustomization: LabelCustomization): Builder = apply { - uiCustomization = uiCustomization.copy( - uiCustomization = uiCustomization.uiCustomization.copy( - labelCustomization = labelCustomization.labelCustomization - ) - ) + fun labelCustomization(labelCustomization: LabelCustomization): UiCustomizationBuilder = apply { + this@UiCustomizationBuilder.labelCustomization = labelCustomization } /** @@ -38,12 +42,8 @@ data class UiCustomization internal constructor(internal val uiCustomization: co * * @param textBoxCustomization Text box customization data. */ - fun textBoxCustomization(textBoxCustomization: TextBoxCustomization): Builder = apply { - uiCustomization = uiCustomization.copy( - uiCustomization = uiCustomization.uiCustomization.copy( - textBoxCustomization = textBoxCustomization.textBoxCustomization - ) - ) + fun textBoxCustomization(textBoxCustomization: TextBoxCustomization): UiCustomizationBuilder = apply { + this@UiCustomizationBuilder.textBoxCustomization = textBoxCustomization } /** @@ -51,12 +51,8 @@ data class UiCustomization internal constructor(internal val uiCustomization: co * * @param toolbarCustomization Toolbar customization data. */ - fun toolbarCustomization(toolbarCustomization: ToolbarCustomization): Builder = apply { - uiCustomization = uiCustomization.copy( - uiCustomization = uiCustomization.uiCustomization.copy( - toolbarCustomization = toolbarCustomization.toolbarCustomization - ) - ) + fun toolbarCustomization(toolbarCustomization: ToolbarCustomization): UiCustomizationBuilder = apply { + this@UiCustomizationBuilder.toolbarCustomization = toolbarCustomization } /** @@ -65,106 +61,65 @@ data class UiCustomization internal constructor(internal val uiCustomization: co * @param buttonType Type of button. * @param buttonCustomization Button customization data. */ - fun buttonCustomization(buttonType: ButtonType, buttonCustomization: ButtonCustomization): Builder = apply { - buttonCustomizations[buttonType] = buttonCustomization - uiCustomization = uiCustomization.copy( - uiCustomization = uiCustomization.uiCustomization.copy( - buttonCustomizations = buttonCustomizations.map { co.omise.android.threeds.customization.ButtonType.buttonTypeOf(it.key.value) to it.value.buttonCustomization }.toMap() - ) - ) + fun buttonCustomization(buttonType: ButtonType, buttonCustomization: ButtonCustomization): UiCustomizationBuilder = apply { + this@UiCustomizationBuilder.buttonCustomizations[buttonType] = buttonCustomization } - /** - * Set the theme resource to override the default theme. The theme resource will not override the EditText and Button - * because they are custom widgets. However you can you [TextBoxCustomization] and [ButtonCustomization] to customize those elements. - * - * @param theme Theme resource. - */ - fun theme(@StyleRes theme: Int): Builder = apply { - uiCustomization = uiCustomization.copy( - uiCustomization = uiCustomization.uiCustomization.copy( - theme = theme - ) - ) - } + /** * Create an instance of [UiCustomization]. * * @return [UiCustomization] */ fun build(): UiCustomization { - return UiCustomization(uiCustomization.uiCustomization) + val uiCustomization = com.netcetera.threeds.sdk.api.ui.logic.UiCustomization().apply { + labelCustomization?.let { this.labelCustomization = it } + toolbarCustomization?.let { this.toolbarCustomization = it } + textBoxCustomization?.let { this.textBoxCustomization = it } + buttonCustomizations.forEach { (buttonType, buttonCustomization) -> + this.setButtonCustomization(buttonCustomization.buttonCustomization, buttonType.value) + } + } + return UiCustomization(uiCustomization) } } /** * Configuration for label customization. */ - data class LabelCustomization internal constructor(internal val labelCustomization: co.omise.android.threeds.customization.LabelCustomization) { - class Builder { - private var labelCustomization = co.omise.android.threeds.customization.LabelCustomization() - - /** - * Set the text font for texts. - * - * @param fontName Font path in the assets directory. - */ - fun textFontName(fontName: String): Builder = apply { - labelCustomization = labelCustomization.copy(textFontName = fontName) - } - - /** - * Set the text color for texts. - * - * @param hexColor Color in hex format e.g. #FFFFFF - */ - fun textFontColor(hexColor: String): Builder = apply { - labelCustomization = labelCustomization.copy(textFontColor = hexColor) - } - - /** - * Set the text size for texts. - * - * @param fontSize Font size in scalable pixels (sp). - */ - fun textFontSize(fontSize: Int): Builder = apply { - labelCustomization = labelCustomization.copy(textFontSize = fontSize) - } - - /** - * Set the text color for headers. - * - * @param hexColor Color in hex format e.g. #FFFFFF - */ - fun headingTextColor(hexColor: String): Builder = apply { - labelCustomization = labelCustomization.copy(headingTextColor = hexColor) - } - - /** - * Set the text font for headers. - * - * @param fontName Font path in the assets directory. - */ - fun headingTextFontName(fontName: String): Builder = apply { - labelCustomization = labelCustomization.copy(headingTextFontName = fontName) - } - - /** - * Set the text size for headers. - * - * @param fontSize Font size in scalable pixels (sp). - */ - fun headingTextFontSize(fontSize: Int): Builder = apply { - labelCustomization = labelCustomization.copy(headingTextFontSize = fontSize) - } - - /** - * Create an instance of [LabelCustomization]. - * - * @return [LabelCustomization] - */ - fun build(): LabelCustomization { - return LabelCustomization(labelCustomization) + data class LabelCustomization internal constructor(internal val labelCustomization: com.netcetera.threeds.sdk.api.ui.logic.LabelCustomization) { + class LabelCustomizationBuilder : CustomizationBuilder() { + private var headingTextColor: String? = null + private var headingTextFontName: String? = null + private var headingTextFontSize: Int? = null + private var headingDarkTextColor: String? = null + + fun headingTextColor(headingTextColor: String): LabelCustomizationBuilder = apply { this.headingTextColor = headingTextColor } + fun headingTextFontName(headingTextFontName: String): LabelCustomizationBuilder = + apply { this.headingTextFontName = headingTextFontName } + + fun headingTextFontSize(headingTextFontSize: Int): LabelCustomizationBuilder = + apply { this.headingTextFontSize = headingTextFontSize } + + fun headingDarkTextColor(headingDarkTextColor: String): LabelCustomizationBuilder = + apply { this.headingDarkTextColor = headingDarkTextColor } + + fun textColor(textColor: String): LabelCustomizationBuilder = apply { this.textColor = textColor } + fun textFontSize(textFontSize: Int): LabelCustomizationBuilder = apply { this.textFontSize = textFontSize } + fun textFontName(textFontName: String): LabelCustomizationBuilder = apply { this.textFontName = textFontName } + fun darkTextColor(darkTextColor: String): LabelCustomizationBuilder = apply { this.darkTextColor = darkTextColor } + + override fun build(): LabelCustomization { + return LabelCustomization(LabelCustomization().apply { + this@LabelCustomizationBuilder.headingTextColor?.let { this.headingTextColor = it } + this@LabelCustomizationBuilder.headingTextFontName?.let { this.headingTextFontName = it } + this@LabelCustomizationBuilder.headingTextFontSize?.let { this.headingTextFontSize = it } + this@LabelCustomizationBuilder.headingDarkTextColor?.let { this.headingDarkTextColor = it } + this@LabelCustomizationBuilder.textColor?.let { this.textColor = it } + this@LabelCustomizationBuilder.textFontSize?.let { this.textFontSize = it } + this@LabelCustomizationBuilder.textFontName?.let { this.textFontName = it } + this@LabelCustomizationBuilder.darkTextColor?.let { this.darkTextColor = it } + }) } } } @@ -172,71 +127,35 @@ data class UiCustomization internal constructor(internal val uiCustomization: co /** * Configuration for Text box customization. */ - data class TextBoxCustomization internal constructor(internal val textBoxCustomization: co.omise.android.threeds.customization.TextBoxCustomization) { - class Builder { - private var textBoxCustomization = co.omise.android.threeds.customization.TextBoxCustomization() - - /** - * Set the text font for the text box. - * - * @param fontName Font path in the assets directory. - */ - fun textFontName(fontName: String): Builder = apply { - textBoxCustomization = textBoxCustomization.copy(textFontName = fontName) - } - - /** - * Set the text color for the text box. - * - * @param hexColor Color in hex format e.g. #FFFFFF - */ - fun textFontColor(hexColor: String): Builder = apply { - textBoxCustomization = textBoxCustomization.copy(textFontColor = hexColor) - } - - /** - * Set the text size for the text box. - * - * @param fontSize Font size in scalable pixels (sp). - */ - fun textFontSize(fontSize: Int): Builder = apply { - textBoxCustomization = textBoxCustomization.copy(textFontSize = fontSize) - } - - /** - * Set the border width for the text box. - * - * @param borderWidth Border width in density-independent pixels (dp). - */ - fun borderWidth(borderWidth: Int): Builder = apply { - textBoxCustomization = textBoxCustomization.copy(borderWidth = borderWidth) - } - - /** - * Set the border color for the text box. - * - * @param hexColor Color in hex format e.g. #FFFFFF - */ - fun borderColor(hexColor: String): Builder = apply { - textBoxCustomization = textBoxCustomization.copy(borderColor = hexColor) - } - - /** - * Set the corner radius for the text box. - * - * @param cornerRadius Corner radius in density-independent pixels (dp). - */ - fun cornerRadius(cornerRadius: Int): Builder = apply { - textBoxCustomization = textBoxCustomization.copy(cornerRadius = cornerRadius) - } - - /** - * Create an instance of [TextBoxCustomization]. - * - * @return [TextBoxCustomization] - */ - fun build(): TextBoxCustomization { - return TextBoxCustomization(textBoxCustomization) + data class TextBoxCustomization internal constructor( + internal val textBoxCustomization: com.netcetera.threeds.sdk.api.ui.logic.TextBoxCustomization + ) { + class TextBoxCustomizationBuilder : CustomizationBuilder() { + private var borderWidth: Int? = null + private var borderColor: String? = null + private var cornerRadius: Int? = null + private var darkBorderColor: String? = null + + fun borderWidth(borderWidth: Int): TextBoxCustomizationBuilder = apply { this.borderWidth = borderWidth } + fun borderColor(borderColor: String): TextBoxCustomizationBuilder = apply { this.borderColor = borderColor } + fun cornerRadius(cornerRadius: Int): TextBoxCustomizationBuilder = apply { this.cornerRadius = cornerRadius } + fun darkBorderColor(darkBorderColor: String): TextBoxCustomizationBuilder = apply { this.darkBorderColor = darkBorderColor } + fun textColor(textColor: String): TextBoxCustomizationBuilder = apply { this.textColor = textColor } + fun textFontSize(textFontSize: Int): TextBoxCustomizationBuilder = apply { this.textFontSize = textFontSize } + fun textFontName(textFontName: String): TextBoxCustomizationBuilder = apply { this.textFontName = textFontName } + fun darkTextColor(darkTextColor: String): TextBoxCustomizationBuilder = apply { this.darkTextColor = darkTextColor } + + override fun build(): TextBoxCustomization { + return TextBoxCustomization(TextBoxCustomization().apply { + borderWidth?.let { this.borderWidth = it } + borderColor?.let { this.borderColor = it } + cornerRadius?.let { this.cornerRadius = it } + darkBorderColor?.let { this.darkBorderColor = it } + textColor?.let { this.textColor = it } + textFontSize?.let { this.textFontSize = it } + textFontName?.let { this.textFontName = it } + darkTextColor?.let { this.darkTextColor = it } + }) } } } @@ -244,71 +163,35 @@ data class UiCustomization internal constructor(internal val uiCustomization: co /** * Configuration for Toolbar customization. */ - data class ToolbarCustomization internal constructor(internal val toolbarCustomization: co.omise.android.threeds.customization.ToolbarCustomization) { - class Builder { - private var toolbarCustomization = co.omise.android.threeds.customization.ToolbarCustomization() - - /** - * Set the text font for the toolbar's title and cancel button. - * - * @param fontName Font path in the assets directory. - */ - fun textFontName(fontName: String): Builder = apply { - toolbarCustomization = toolbarCustomization.copy(textFontName = fontName) - } - - /** - * Set the text color for the toolbar's title and cancel button. - * - * @param hexColor Color in hex format e.g. #FFFFFF - */ - fun textFontColor(hexColor: String): Builder = apply { - toolbarCustomization = toolbarCustomization.copy(textFontColor = hexColor) - } - - /** - * Set the text size for the toolbar's title. - * - * @param fontSize Font size in scalable pixels (sp). - */ - fun textFontSize(fontSize: Int): Builder = apply { - toolbarCustomization = toolbarCustomization.copy(textFontSize = fontSize) - } - - /** - * Set the color for the toolbar's background. - * - * @param hexColor Color in hex format e.g. #FFFFFF - */ - fun backgroundColor(hexColor: String): Builder = apply { - toolbarCustomization = toolbarCustomization.copy(backgroundColor = hexColor) - } - - /** - * Set the title text for toolbar's title. - * - * @param text Toolbar title's text. - */ - fun headerText(text: String): Builder = apply { - toolbarCustomization = toolbarCustomization.copy(headerText = text) - } - - /** - * Set the text for toolbar's cancel button. - * - * @param text Cancel button's text. - */ - fun buttonText(text: String): Builder = apply { - toolbarCustomization = toolbarCustomization.copy(buttonText = text) - } - - /** - * Create an instance of [ToolbarCustomization]. - * - * @return [ToolbarCustomization] - */ - fun build(): ToolbarCustomization { - return ToolbarCustomization(toolbarCustomization) + data class ToolbarCustomization internal constructor(internal val toolbarCustomization: com.netcetera.threeds.sdk.api.ui.logic.ToolbarCustomization) { + class ToolbarCustomizationBuilder : CustomizationBuilder() { + private var headText: String? = null + private var buttonText: String? = null + private var backgroundColor: String? = null + private var darkBackgroundColor: String? = null + + fun headText(headText: String): ToolbarCustomizationBuilder = apply { this.headText = headText } + fun buttonText(buttonText: String): ToolbarCustomizationBuilder = apply { this.buttonText = buttonText } + fun backgroundColor(backgroundColor: String): ToolbarCustomizationBuilder = apply { this.backgroundColor = backgroundColor } + fun darkBackgroundColor(darkBackgroundColor: String): ToolbarCustomizationBuilder = + apply { this.darkBackgroundColor = darkBackgroundColor } + + fun textColor(textColor: String): ToolbarCustomizationBuilder = apply { this.textColor = textColor } + fun textFontSize(textFontSize: Int): ToolbarCustomizationBuilder = apply { this.textFontSize = textFontSize } + fun textFontName(textFontName: String): ToolbarCustomizationBuilder = apply { this.textFontName = textFontName } + fun darkTextColor(darkTextColor: String): ToolbarCustomizationBuilder = apply { this.darkTextColor = darkTextColor } + + override fun build(): ToolbarCustomization { + return ToolbarCustomization(ToolbarCustomization().apply { + headText?.let { this.headerText = it } + buttonText?.let { this.buttonText = it } + backgroundColor?.let { this.backgroundColor = it } + darkBackgroundColor?.let { this.darkBackgroundColor = it } + textColor?.let { this.textColor = it } + textFontSize?.let { this.textFontSize = it } + textFontName?.let { this.textFontName = it } + darkTextColor?.let { this.darkTextColor = it } + }) } } } @@ -316,73 +199,44 @@ data class UiCustomization internal constructor(internal val uiCustomization: co /** * Type of button in the challenge flow. */ - enum class ButtonType(val value: String) { - SUBMIT_BUTTON("SUBMIT"), - CONTINUE_BUTTON("CONTINUE"), - NEXT_BUTTON("NEXT"), - CANCEL_BUTTON("CANCEL"), - RESEND_BUTTON("RESEND") + enum class ButtonType(val value: com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType) { + SUBMIT(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.SUBMIT), + CONTINUE(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.CONTINUE), + NEXT(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.NEXT), + CANCEL(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.CANCEL), + RESEND(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.RESEND), + OPEN_OOB_APP(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.OPEN_OOB_APP); } /** * Configuration for button customization. */ - data class ButtonCustomization internal constructor(internal val buttonCustomization: co.omise.android.threeds.customization.ButtonCustomization) { - class Builder { - private var buttonCustomization = co.omise.android.threeds.customization.ButtonCustomization() - - /** - * Set the text font for the toolbar's title and cancel button. - * - * @param fontName Font path in the assets directory. - */ - fun textFontName(fontName: String): Builder = apply { - buttonCustomization = buttonCustomization.copy(textFontName = fontName) - } - - /** - * Set the color for the button text's color. - * - * @param hexColor Color in hex format e.g. #FFFFFF - */ - fun textFontColor(hexColor: String): Builder = apply { - buttonCustomization = buttonCustomization.copy(textFontColor = hexColor) - } - - /** - * Set the text size for the button's text. - * - * @param fontSize Font size in scalable pixels (sp). - */ - fun textFontSize(fontSize: Int): Builder = apply { - buttonCustomization = buttonCustomization.copy(textFontSize = fontSize) - } - - /** - * Set the color for the button's background. - * - * @param hexColor Color in hex format e.g. #FFFFFF - */ - fun backgroundColor(hexColor: String): Builder = apply { - buttonCustomization = buttonCustomization.copy(backgroundColor = hexColor) - } - - /** - * Set the corner radius for the button. - * - * @param cornerRadius Corner radius in density-independent pixels (dp). - */ - fun cornerRadius(cornerRadius: Int): Builder = apply { - buttonCustomization = buttonCustomization.copy(cornerRadius = cornerRadius) - } - - /** - * Create an instance of [ButtonCustomization]. - * - * @return [ButtonCustomization]. - */ - fun build(): ButtonCustomization { - return ButtonCustomization(buttonCustomization) + data class ButtonCustomization internal constructor(internal val buttonCustomization: com.netcetera.threeds.sdk.api.ui.logic.ButtonCustomization) { + class ButtonCustomizationBuilder : CustomizationBuilder() { + private var cornerRadius: Int? = null + private var backgroundColor: String? = null + private var darkBackgroundColor: String? = null + + fun cornerRadius(cornerRadius: Int): ButtonCustomizationBuilder = apply { this.cornerRadius = cornerRadius } + fun backgroundColor(backgroundColor: String): ButtonCustomizationBuilder = apply { this.backgroundColor = backgroundColor } + fun darkBackgroundColor(darkBackgroundColor: String): ButtonCustomizationBuilder = + apply { this.darkBackgroundColor = darkBackgroundColor } + + fun textColor(textColor: String): ButtonCustomizationBuilder = apply { this.textColor = textColor } + fun textFontSize(textFontSize: Int): ButtonCustomizationBuilder = apply { this.textFontSize = textFontSize } + fun textFontName(textFontName: String): ButtonCustomizationBuilder = apply { this.textFontName = textFontName } + fun darkTextColor(darkTextColor: String): ButtonCustomizationBuilder = apply { this.darkTextColor = darkTextColor } + + override fun build(): ButtonCustomization { + return ButtonCustomization(ButtonCustomization().apply { + cornerRadius?.let { this.cornerRadius = it } + backgroundColor?.let { this.backgroundColor = it } + darkBackgroundColor?.let { this.darkBackgroundColor = it } + textColor?.let { this.textColor = it } + textFontSize?.let { this.textFontSize = it } + textFontName?.let { this.textFontName = it } + darkTextColor?.let { this.darkTextColor = it } + }) } } } From ec98730b56a70ba668f58256f2fbabc6d71ce8be Mon Sep 17 00:00:00 2001 From: Natthawut Haematulin Date: Wed, 4 Oct 2023 14:44:39 +0700 Subject: [PATCH 02/10] feat: update sample app --- .../android/example/CheckoutActivity.java | 107 +++-- .../omise/android/example/CheckoutActivity.kt | 67 +-- .../omise/android/config/UiCustomization.kt | 410 +++++++++--------- 3 files changed, 317 insertions(+), 267 deletions(-) diff --git a/app/src/java/java/co/omise/android/example/CheckoutActivity.java b/app/src/java/java/co/omise/android/example/CheckoutActivity.java index 7e48d4115..48c252a07 100644 --- a/app/src/java/java/co/omise/android/example/CheckoutActivity.java +++ b/app/src/java/java/co/omise/android/example/CheckoutActivity.java @@ -18,8 +18,18 @@ import co.omise.android.api.Request; import co.omise.android.api.RequestListener; import co.omise.android.config.AuthorizingPaymentConfig; +import co.omise.android.config.ButtonCustomization; +import co.omise.android.config.ButtonCustomizationBuilder; +import co.omise.android.config.ButtonType; +import co.omise.android.config.LabelCustomization; +import co.omise.android.config.LabelCustomizationBuilder; +import co.omise.android.config.TextBoxCustomization; +import co.omise.android.config.TextBoxCustomizationBuilder; import co.omise.android.config.ThreeDSConfig; +import co.omise.android.config.ToolbarCustomization; +import co.omise.android.config.ToolbarCustomizationBuilder; import co.omise.android.config.UiCustomization; +import co.omise.android.config.UiCustomizationBuilder; import co.omise.android.models.Amount; import co.omise.android.models.Capability; import co.omise.android.models.Source; @@ -134,45 +144,64 @@ private void payByCreditCard() { * This should be call before start the {@link AuthorizingPaymentActivity}. */ private void initializeAuthoringPaymentConfig() { - UiCustomization uiCustomization = new UiCustomization.Builder() - .labelCustomization(new UiCustomization.LabelCustomization.Builder() - .textFontName("fonts/RobotoMono-Regular.ttf") - .textFontColor("#000000") - .textFontSize(16) - .headingTextColor("#000000") - .headingTextFontName("fonts/RobotoMono-Bold.ttf") - .headingTextFontSize(20) - .build()) - .textBoxCustomization(new UiCustomization.TextBoxCustomization.Builder() - .textFontName("fonts/RobotoMono-Regular.ttf") - .textFontColor("#000000") - .textFontSize(16) - .borderWidth(1) - .cornerRadius(4) - .borderColor("#1A56F0") - .build()) - .toolbarCustomization(new UiCustomization.ToolbarCustomization.Builder() - .textFontName("fonts/RobotoMono-Bold.ttf") - .textFontColor("#000000") - .textFontSize(20) - .backgroundColor("#FFFFFF") - .headerText("Secure Checkout") - .buttonText("Close") - .build()) - .buttonCustomization(UiCustomization.ButtonType.SUBMIT_BUTTON, new UiCustomization.ButtonCustomization.Builder() - .textFontName("fonts/RobotoMono-Bold.ttf") - .textFontColor("#FFFFFF") - .textFontSize(20) - .backgroundColor("#1A56F0") - .cornerRadius(4) - .build()) - .buttonCustomization(UiCustomization.ButtonType.RESEND_BUTTON, new UiCustomization.ButtonCustomization.Builder() - .textFontName("fonts/RobotoMono-Bold.ttf") - .textFontColor("#000000") - .textFontSize(20) - .backgroundColor("#FFFFFF") - .cornerRadius(4) - .build()) + LabelCustomization labelCustomization = new LabelCustomizationBuilder() + .headingDarkTextColor("#000000") + .headingTextColor("#000000") + .headingTextFontName("fonts/RobotoMono-Bold.ttf") + .headingTextFontSize(20) + .textFontName("fonts/RobotoMono-Regular.ttf") + .textColor("#000000") + .textFontSize(16) + .build(); + + TextBoxCustomization textBoxCustomization = new TextBoxCustomizationBuilder() + .textFontName("fonts/RobotoMono-Regular.ttf") + .textColor("#000000") + .textFontSize(16) + .borderWidth(1) + .cornerRadius(4) + .borderColor("#1A56F0") + .build(); + + ToolbarCustomization toolbarCustomization = new ToolbarCustomizationBuilder() + .textFontName("fonts/RobotoMono-Bold.ttf") + .textColor("#000000") + .textFontSize(20) + .backgroundColor("#FFFFFF") + .headText("Secure Checkout") + .buttonText("Close") + .build(); + + ButtonCustomization primaryButtonCustomization = new ButtonCustomizationBuilder() + .textFontName("fonts/RobotoMono-Bold.ttf") + .textColor("#000000") + .textFontSize(20) + .backgroundColor("#FFFFFF") + .cornerRadius(4) + .darkTextColor("#000000") + .darkBackgroundColor("#FFFFFF") + .build(); + + ButtonCustomization secondaryButtonCustomization = new ButtonCustomizationBuilder() + .textFontName("fonts/RobotoMono-Bold.ttf") + .textColor("#000000") + .textFontSize(20) + .backgroundColor("#FFFFFF") + .darkTextColor("#000000") + .darkBackgroundColor("#FFFFFF") + .cornerRadius(4) + .build(); + + UiCustomization uiCustomization = new UiCustomizationBuilder() + .labelCustomization(labelCustomization) + .textBoxCustomization(textBoxCustomization) + .toolbarCustomization(toolbarCustomization) + .buttonCustomization(ButtonType.SUBMIT, primaryButtonCustomization) + .buttonCustomization(ButtonType.CONTINUE, primaryButtonCustomization) + .buttonCustomization(ButtonType.NEXT, primaryButtonCustomization) + .buttonCustomization(ButtonType.OPEN_OOB_APP, primaryButtonCustomization) + .buttonCustomization(ButtonType.RESEND, primaryButtonCustomization) + .buttonCustomization(ButtonType.CANCEL, secondaryButtonCustomization) .build(); ThreeDSConfig threeDSConfig = new ThreeDSConfig.Builder() diff --git a/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt b/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt index 6a34833d8..36317cb13 100644 --- a/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt +++ b/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt @@ -13,8 +13,13 @@ import co.omise.android.AuthorizingPaymentURLVerifier.Companion.EXTRA_EXPECTED_R import co.omise.android.api.Client import co.omise.android.api.RequestListener import co.omise.android.config.AuthorizingPaymentConfig +import co.omise.android.config.ButtonCustomizationBuilder +import co.omise.android.config.ButtonType +import co.omise.android.config.LabelCustomizationBuilder +import co.omise.android.config.TextBoxCustomizationBuilder import co.omise.android.config.ThreeDSConfig -import co.omise.android.config.UiCustomization +import co.omise.android.config.ToolbarCustomizationBuilder +import co.omise.android.config.UiCustomizationBuilder import co.omise.android.models.Amount import co.omise.android.models.Capability import co.omise.android.models.Source @@ -69,8 +74,8 @@ class CheckoutActivity : AppCompatActivity() { choosePaymentMethodButton.setOnClickListener { choosePaymentMethod() } creditCardButton.setOnClickListener { payByCreditCard() } authorizeUrlButton.setOnClickListener { - AuthorizingPaymentDialog.showAuthorizingPaymentDialog(this) {authorizeUrl, returnUrl -> - startAuthoringPaymentActivity(authorizeUrl, returnUrl) + AuthorizingPaymentDialog.showAuthorizingPaymentDialog(this) { authorizeUrl, returnUrl -> + startAuthoringPaymentActivity(authorizeUrl, returnUrl) } } @@ -131,7 +136,7 @@ class CheckoutActivity : AppCompatActivity() { */ private fun initializeAuthoringPaymentConfig() { - val labelCustomization = UiCustomization.LabelCustomization.LabelCustomizationBuilder() + val labelCustomization = LabelCustomizationBuilder() .headingDarkTextColor("#000000") .headingTextColor("#000000") .headingTextFontName("fonts/RobotoMono-Bold.ttf") @@ -141,7 +146,7 @@ class CheckoutActivity : AppCompatActivity() { .textFontSize(16) .build() - val textBoxCustomization = UiCustomization.TextBoxCustomization.TextBoxCustomizationBuilder() + val textBoxCustomization = TextBoxCustomizationBuilder() .textFontName("fonts/RobotoMono-Regular.ttf") .textColor("#000000") .textFontSize(16) @@ -150,7 +155,7 @@ class CheckoutActivity : AppCompatActivity() { .borderColor("#1A56F0") .build() - val toolbarCustomization = UiCustomization.ToolbarCustomization.ToolbarCustomizationBuilder() + val toolbarCustomization = ToolbarCustomizationBuilder() .textFontName("fonts/RobotoMono-Bold.ttf") .textColor("#000000") .textFontSize(20) @@ -159,49 +164,55 @@ class CheckoutActivity : AppCompatActivity() { .buttonText("Close") .build() - val primaryButtonCustomization = UiCustomization.ButtonCustomization.ButtonCustomizationBuilder() + val primaryButtonCustomization = ButtonCustomizationBuilder() .textFontName("fonts/RobotoMono-Bold.ttf") - .textColor("#000000") .textFontSize(20) - .backgroundColor("#FFFFFF") .cornerRadius(4) + .textColor("#000000") + .backgroundColor("#FFFFFF") + .darkTextColor("#000000") + .darkBackgroundColor("#FFFFFF") .build() - val secondaryButtonCustomization = UiCustomization.ButtonCustomization.ButtonCustomizationBuilder() + val secondaryButtonCustomization = ButtonCustomizationBuilder() .textFontName("fonts/RobotoMono-Bold.ttf") - .textColor("#000000") .textFontSize(20) - .backgroundColor("#FFFFFF") .cornerRadius(4) + .textColor("#000000") + .backgroundColor("#FFFFFF") + .darkTextColor("#000000") + .darkBackgroundColor("#FFFFFF") .build() - val uiCustomization = UiCustomization.UiCustomizationBuilder() + val uiCustomization = UiCustomizationBuilder() .labelCustomization(labelCustomization) .textBoxCustomization(textBoxCustomization) .toolbarCustomization(toolbarCustomization) - .buttonCustomization(UiCustomization.ButtonType.SUBMIT, primaryButtonCustomization) - .buttonCustomization(UiCustomization.ButtonType.CONTINUE, primaryButtonCustomization) - .buttonCustomization(UiCustomization.ButtonType.NEXT, primaryButtonCustomization) - .buttonCustomization(UiCustomization.ButtonType.OPEN_OOB_APP, primaryButtonCustomization) - .buttonCustomization(UiCustomization.ButtonType.RESEND, primaryButtonCustomization) - .buttonCustomization(UiCustomization.ButtonType.CANCEL, secondaryButtonCustomization) + .buttonCustomization(ButtonType.SUBMIT, primaryButtonCustomization) + .buttonCustomization(ButtonType.CONTINUE, primaryButtonCustomization) + .buttonCustomization(ButtonType.NEXT, primaryButtonCustomization) + .buttonCustomization(ButtonType.OPEN_OOB_APP, primaryButtonCustomization) + .buttonCustomization(ButtonType.RESEND, primaryButtonCustomization) + .buttonCustomization(ButtonType.CANCEL, secondaryButtonCustomization) .build() val threeDSConfig = ThreeDSConfig.Builder() - .uiCustomization(uiCustomization) - .timeout(5) - .build() + .uiCustomization(uiCustomization) + .timeout(5) + .build() val authPaymentConfig = AuthorizingPaymentConfig.Builder() - .threeDSConfig(threeDSConfig) - .build() + .threeDSConfig(threeDSConfig) + .build() AuthorizingPaymentConfig.initialize(authPaymentConfig) } private fun startAuthoringPaymentActivity(authorizeUrl: String, returnUrl: String) { - Log.d(TAG, """ + Log.d( + TAG, """ authorizeUrl=$authorizeUrl returnUrl=$returnUrl - """.trimIndent()) + """.trimIndent() + ) Intent(this, AuthorizingPaymentActivity::class.java).run { putExtra(EXTRA_AUTHORIZED_URLSTRING, authorizeUrl) putExtra(EXTRA_EXPECTED_RETURN_URLSTRING_PATTERNS, arrayOf(returnUrl)) @@ -250,12 +261,14 @@ class CheckoutActivity : AppCompatActivity() { Log.e(TAG, throwable.message, throwable.cause) throwable.message ?: "Unknown error." } + null -> "Not found the authorization result." } Log.d(TAG, resultMessage) snackbar.setText(resultMessage).show() } } + PAYMENT_CREATOR_REQUEST_CODE -> { if (data.hasExtra(OmiseActivity.EXTRA_SOURCE_OBJECT)) { val source = data.getParcelableExtra(OmiseActivity.EXTRA_SOURCE_OBJECT) @@ -267,11 +280,13 @@ class CheckoutActivity : AppCompatActivity() { Log.d(TAG, "token: ${token?.id}") } } + CREDIT_CARD_REQUEST_CODE -> { val token = data.getParcelableExtra(OmiseActivity.EXTRA_TOKEN_OBJECT) snackbar.setText(token?.id ?: "No token object.").show() Log.d(TAG, "token: ${token?.id}") } + else -> { super.onActivityResult(requestCode, resultCode, data) } diff --git a/sdk/src/main/java/co/omise/android/config/UiCustomization.kt b/sdk/src/main/java/co/omise/android/config/UiCustomization.kt index 12bcf37f4..2c29559c4 100644 --- a/sdk/src/main/java/co/omise/android/config/UiCustomization.kt +++ b/sdk/src/main/java/co/omise/android/config/UiCustomization.kt @@ -1,10 +1,5 @@ package co.omise.android.config -import com.netcetera.threeds.sdk.api.ui.logic.ButtonCustomization -import com.netcetera.threeds.sdk.api.ui.logic.LabelCustomization -import com.netcetera.threeds.sdk.api.ui.logic.TextBoxCustomization -import com.netcetera.threeds.sdk.api.ui.logic.ToolbarCustomization - abstract class CustomizationBuilder { protected var textFontSize: Int? = null @@ -15,229 +10,240 @@ abstract class CustomizationBuilder { } /** - * Configuration for UI customization in the challenge flow. + * configuration for the challenge screen. */ data class UiCustomization internal constructor(internal val uiCustomization: com.netcetera.threeds.sdk.api.ui.logic.UiCustomization) { companion object { val default = UiCustomization(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization()) } +} - class UiCustomizationBuilder { - private var labelCustomization: LabelCustomization? = null - private var toolbarCustomization: ToolbarCustomization? = null - private var textBoxCustomization: TextBoxCustomization? = null - private var buttonCustomizations: MutableMap = mutableMapOf() - - /** - * Set the label customization. - * - * @param labelCustomization Label customization data. - */ - fun labelCustomization(labelCustomization: LabelCustomization): UiCustomizationBuilder = apply { - this@UiCustomizationBuilder.labelCustomization = labelCustomization - } - - /** - * Set the text box customization. - * - * @param textBoxCustomization Text box customization data. - */ - fun textBoxCustomization(textBoxCustomization: TextBoxCustomization): UiCustomizationBuilder = apply { - this@UiCustomizationBuilder.textBoxCustomization = textBoxCustomization - } - - /** - * Set the toolbar customization. - * - * @param toolbarCustomization Toolbar customization data. - */ - fun toolbarCustomization(toolbarCustomization: ToolbarCustomization): UiCustomizationBuilder = apply { - this@UiCustomizationBuilder.toolbarCustomization = toolbarCustomization - } - - /** - * Set the button customization for the particular button. - * - * @param buttonType Type of button. - * @param buttonCustomization Button customization data. - */ - fun buttonCustomization(buttonType: ButtonType, buttonCustomization: ButtonCustomization): UiCustomizationBuilder = apply { - this@UiCustomizationBuilder.buttonCustomizations[buttonType] = buttonCustomization - } - - - /** - * Create an instance of [UiCustomization]. - * - * @return [UiCustomization] - */ - fun build(): UiCustomization { - val uiCustomization = com.netcetera.threeds.sdk.api.ui.logic.UiCustomization().apply { - labelCustomization?.let { this.labelCustomization = it } - toolbarCustomization?.let { this.toolbarCustomization = it } - textBoxCustomization?.let { this.textBoxCustomization = it } - buttonCustomizations.forEach { (buttonType, buttonCustomization) -> - this.setButtonCustomization(buttonCustomization.buttonCustomization, buttonType.value) - } - } - return UiCustomization(uiCustomization) - } - } +/** + * Builder for building [UiCustomization] data. + */ +class UiCustomizationBuilder { + private var labelCustomization: LabelCustomization? = null + private var toolbarCustomization: ToolbarCustomization? = null + private var textBoxCustomization: TextBoxCustomization? = null + private var buttonCustomizations: MutableMap = mutableMapOf() /** - * Configuration for label customization. + * Set the label customization. + * + * @param labelCustomization Label customization data. */ - data class LabelCustomization internal constructor(internal val labelCustomization: com.netcetera.threeds.sdk.api.ui.logic.LabelCustomization) { - class LabelCustomizationBuilder : CustomizationBuilder() { - private var headingTextColor: String? = null - private var headingTextFontName: String? = null - private var headingTextFontSize: Int? = null - private var headingDarkTextColor: String? = null - - fun headingTextColor(headingTextColor: String): LabelCustomizationBuilder = apply { this.headingTextColor = headingTextColor } - fun headingTextFontName(headingTextFontName: String): LabelCustomizationBuilder = - apply { this.headingTextFontName = headingTextFontName } - - fun headingTextFontSize(headingTextFontSize: Int): LabelCustomizationBuilder = - apply { this.headingTextFontSize = headingTextFontSize } - - fun headingDarkTextColor(headingDarkTextColor: String): LabelCustomizationBuilder = - apply { this.headingDarkTextColor = headingDarkTextColor } - - fun textColor(textColor: String): LabelCustomizationBuilder = apply { this.textColor = textColor } - fun textFontSize(textFontSize: Int): LabelCustomizationBuilder = apply { this.textFontSize = textFontSize } - fun textFontName(textFontName: String): LabelCustomizationBuilder = apply { this.textFontName = textFontName } - fun darkTextColor(darkTextColor: String): LabelCustomizationBuilder = apply { this.darkTextColor = darkTextColor } - - override fun build(): LabelCustomization { - return LabelCustomization(LabelCustomization().apply { - this@LabelCustomizationBuilder.headingTextColor?.let { this.headingTextColor = it } - this@LabelCustomizationBuilder.headingTextFontName?.let { this.headingTextFontName = it } - this@LabelCustomizationBuilder.headingTextFontSize?.let { this.headingTextFontSize = it } - this@LabelCustomizationBuilder.headingDarkTextColor?.let { this.headingDarkTextColor = it } - this@LabelCustomizationBuilder.textColor?.let { this.textColor = it } - this@LabelCustomizationBuilder.textFontSize?.let { this.textFontSize = it } - this@LabelCustomizationBuilder.textFontName?.let { this.textFontName = it } - this@LabelCustomizationBuilder.darkTextColor?.let { this.darkTextColor = it } - }) - } - } + fun labelCustomization(labelCustomization: LabelCustomization): UiCustomizationBuilder = apply { + this@UiCustomizationBuilder.labelCustomization = labelCustomization } /** - * Configuration for Text box customization. + * Set the text box customization. + * + * @param textBoxCustomization Text box customization data. */ - data class TextBoxCustomization internal constructor( - internal val textBoxCustomization: com.netcetera.threeds.sdk.api.ui.logic.TextBoxCustomization - ) { - class TextBoxCustomizationBuilder : CustomizationBuilder() { - private var borderWidth: Int? = null - private var borderColor: String? = null - private var cornerRadius: Int? = null - private var darkBorderColor: String? = null - - fun borderWidth(borderWidth: Int): TextBoxCustomizationBuilder = apply { this.borderWidth = borderWidth } - fun borderColor(borderColor: String): TextBoxCustomizationBuilder = apply { this.borderColor = borderColor } - fun cornerRadius(cornerRadius: Int): TextBoxCustomizationBuilder = apply { this.cornerRadius = cornerRadius } - fun darkBorderColor(darkBorderColor: String): TextBoxCustomizationBuilder = apply { this.darkBorderColor = darkBorderColor } - fun textColor(textColor: String): TextBoxCustomizationBuilder = apply { this.textColor = textColor } - fun textFontSize(textFontSize: Int): TextBoxCustomizationBuilder = apply { this.textFontSize = textFontSize } - fun textFontName(textFontName: String): TextBoxCustomizationBuilder = apply { this.textFontName = textFontName } - fun darkTextColor(darkTextColor: String): TextBoxCustomizationBuilder = apply { this.darkTextColor = darkTextColor } - - override fun build(): TextBoxCustomization { - return TextBoxCustomization(TextBoxCustomization().apply { - borderWidth?.let { this.borderWidth = it } - borderColor?.let { this.borderColor = it } - cornerRadius?.let { this.cornerRadius = it } - darkBorderColor?.let { this.darkBorderColor = it } - textColor?.let { this.textColor = it } - textFontSize?.let { this.textFontSize = it } - textFontName?.let { this.textFontName = it } - darkTextColor?.let { this.darkTextColor = it } - }) - } - } + fun textBoxCustomization(textBoxCustomization: TextBoxCustomization): UiCustomizationBuilder = apply { + this@UiCustomizationBuilder.textBoxCustomization = textBoxCustomization } /** - * Configuration for Toolbar customization. + * Set the toolbar customization. + * + * @param toolbarCustomization Toolbar customization data. */ - data class ToolbarCustomization internal constructor(internal val toolbarCustomization: com.netcetera.threeds.sdk.api.ui.logic.ToolbarCustomization) { - class ToolbarCustomizationBuilder : CustomizationBuilder() { - private var headText: String? = null - private var buttonText: String? = null - private var backgroundColor: String? = null - private var darkBackgroundColor: String? = null - - fun headText(headText: String): ToolbarCustomizationBuilder = apply { this.headText = headText } - fun buttonText(buttonText: String): ToolbarCustomizationBuilder = apply { this.buttonText = buttonText } - fun backgroundColor(backgroundColor: String): ToolbarCustomizationBuilder = apply { this.backgroundColor = backgroundColor } - fun darkBackgroundColor(darkBackgroundColor: String): ToolbarCustomizationBuilder = - apply { this.darkBackgroundColor = darkBackgroundColor } - - fun textColor(textColor: String): ToolbarCustomizationBuilder = apply { this.textColor = textColor } - fun textFontSize(textFontSize: Int): ToolbarCustomizationBuilder = apply { this.textFontSize = textFontSize } - fun textFontName(textFontName: String): ToolbarCustomizationBuilder = apply { this.textFontName = textFontName } - fun darkTextColor(darkTextColor: String): ToolbarCustomizationBuilder = apply { this.darkTextColor = darkTextColor } - - override fun build(): ToolbarCustomization { - return ToolbarCustomization(ToolbarCustomization().apply { - headText?.let { this.headerText = it } - buttonText?.let { this.buttonText = it } - backgroundColor?.let { this.backgroundColor = it } - darkBackgroundColor?.let { this.darkBackgroundColor = it } - textColor?.let { this.textColor = it } - textFontSize?.let { this.textFontSize = it } - textFontName?.let { this.textFontName = it } - darkTextColor?.let { this.darkTextColor = it } - }) - } - } + fun toolbarCustomization(toolbarCustomization: ToolbarCustomization): UiCustomizationBuilder = apply { + this@UiCustomizationBuilder.toolbarCustomization = toolbarCustomization } /** - * Type of button in the challenge flow. + * Set the button customization for the particular button. + * + * @param buttonType Type of button. + * @param buttonCustomization Button customization data. */ - enum class ButtonType(val value: com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType) { - SUBMIT(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.SUBMIT), - CONTINUE(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.CONTINUE), - NEXT(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.NEXT), - CANCEL(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.CANCEL), - RESEND(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.RESEND), - OPEN_OOB_APP(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.OPEN_OOB_APP); + fun buttonCustomization(buttonType: ButtonType, buttonCustomization: ButtonCustomization): UiCustomizationBuilder = apply { + this@UiCustomizationBuilder.buttonCustomizations[buttonType] = buttonCustomization } + /** - * Configuration for button customization. + * Create an instance of [UiCustomization]. + * + * @return [UiCustomization] */ - data class ButtonCustomization internal constructor(internal val buttonCustomization: com.netcetera.threeds.sdk.api.ui.logic.ButtonCustomization) { - class ButtonCustomizationBuilder : CustomizationBuilder() { - private var cornerRadius: Int? = null - private var backgroundColor: String? = null - private var darkBackgroundColor: String? = null - - fun cornerRadius(cornerRadius: Int): ButtonCustomizationBuilder = apply { this.cornerRadius = cornerRadius } - fun backgroundColor(backgroundColor: String): ButtonCustomizationBuilder = apply { this.backgroundColor = backgroundColor } - fun darkBackgroundColor(darkBackgroundColor: String): ButtonCustomizationBuilder = - apply { this.darkBackgroundColor = darkBackgroundColor } - - fun textColor(textColor: String): ButtonCustomizationBuilder = apply { this.textColor = textColor } - fun textFontSize(textFontSize: Int): ButtonCustomizationBuilder = apply { this.textFontSize = textFontSize } - fun textFontName(textFontName: String): ButtonCustomizationBuilder = apply { this.textFontName = textFontName } - fun darkTextColor(darkTextColor: String): ButtonCustomizationBuilder = apply { this.darkTextColor = darkTextColor } - - override fun build(): ButtonCustomization { - return ButtonCustomization(ButtonCustomization().apply { - cornerRadius?.let { this.cornerRadius = it } - backgroundColor?.let { this.backgroundColor = it } - darkBackgroundColor?.let { this.darkBackgroundColor = it } - textColor?.let { this.textColor = it } - textFontSize?.let { this.textFontSize = it } - textFontName?.let { this.textFontName = it } - darkTextColor?.let { this.darkTextColor = it } - }) + fun build(): UiCustomization { + val uiCustomization = com.netcetera.threeds.sdk.api.ui.logic.UiCustomization().apply { + labelCustomization?.let { this.labelCustomization = it } + toolbarCustomization?.let { this.toolbarCustomization = it } + textBoxCustomization?.let { this.textBoxCustomization = it } + buttonCustomizations.forEach { (buttonType, buttonCustomization) -> + this.setButtonCustomization(buttonCustomization.buttonCustomization, buttonType.value) } } + return UiCustomization(uiCustomization) + } +} + +/** + * Configuration for label customization. + */ +data class LabelCustomization internal constructor(internal val labelCustomization: com.netcetera.threeds.sdk.api.ui.logic.LabelCustomization) + +class LabelCustomizationBuilder : CustomizationBuilder() { + private var headingTextColor: String? = null + private var headingTextFontName: String? = null + private var headingTextFontSize: Int? = null + private var headingDarkTextColor: String? = null + + fun headingTextColor(headingTextColor: String): LabelCustomizationBuilder = apply { this.headingTextColor = headingTextColor } + fun headingTextFontName(headingTextFontName: String): LabelCustomizationBuilder = + apply { this.headingTextFontName = headingTextFontName } + + fun headingTextFontSize(headingTextFontSize: Int): LabelCustomizationBuilder = + apply { this.headingTextFontSize = headingTextFontSize } + + fun headingDarkTextColor(headingDarkTextColor: String): LabelCustomizationBuilder = + apply { this.headingDarkTextColor = headingDarkTextColor } + + fun textColor(textColor: String): LabelCustomizationBuilder = apply { this.textColor = textColor } + fun textFontSize(textFontSize: Int): LabelCustomizationBuilder = apply { this.textFontSize = textFontSize } + fun textFontName(textFontName: String): LabelCustomizationBuilder = apply { this.textFontName = textFontName } + fun darkTextColor(darkTextColor: String): LabelCustomizationBuilder = apply { this.darkTextColor = darkTextColor } + + override fun build(): LabelCustomization { + return LabelCustomization( + com.netcetera.threeds.sdk.api.ui.logic.LabelCustomization().apply { + this@LabelCustomizationBuilder.headingTextColor?.let { this.headingTextColor = it } + this@LabelCustomizationBuilder.headingTextFontName?.let { this.headingTextFontName = it } + this@LabelCustomizationBuilder.headingTextFontSize?.let { this.headingTextFontSize = it } + this@LabelCustomizationBuilder.headingDarkTextColor?.let { this.headingDarkTextColor = it } + this@LabelCustomizationBuilder.textColor?.let { this.textColor = it } + this@LabelCustomizationBuilder.textFontSize?.let { this.textFontSize = it } + this@LabelCustomizationBuilder.textFontName?.let { this.textFontName = it } + this@LabelCustomizationBuilder.darkTextColor?.let { this.darkTextColor = it } + } + ) + } +} + +/** + * Configuration for Text box customization. + */ +data class TextBoxCustomization internal constructor( + internal val textBoxCustomization: com.netcetera.threeds.sdk.api.ui.logic.TextBoxCustomization +) + +class TextBoxCustomizationBuilder : CustomizationBuilder() { + private var borderWidth: Int? = null + private var borderColor: String? = null + private var cornerRadius: Int? = null + private var darkBorderColor: String? = null + + fun borderWidth(borderWidth: Int): TextBoxCustomizationBuilder = apply { this.borderWidth = borderWidth } + fun borderColor(borderColor: String): TextBoxCustomizationBuilder = apply { this.borderColor = borderColor } + fun cornerRadius(cornerRadius: Int): TextBoxCustomizationBuilder = apply { this.cornerRadius = cornerRadius } + fun darkBorderColor(darkBorderColor: String): TextBoxCustomizationBuilder = apply { this.darkBorderColor = darkBorderColor } + fun textColor(textColor: String): TextBoxCustomizationBuilder = apply { this.textColor = textColor } + fun textFontSize(textFontSize: Int): TextBoxCustomizationBuilder = apply { this.textFontSize = textFontSize } + fun textFontName(textFontName: String): TextBoxCustomizationBuilder = apply { this.textFontName = textFontName } + fun darkTextColor(darkTextColor: String): TextBoxCustomizationBuilder = apply { this.darkTextColor = darkTextColor } + + override fun build(): TextBoxCustomization { + return TextBoxCustomization( + com.netcetera.threeds.sdk.api.ui.logic.TextBoxCustomization().apply { + borderWidth.let { this.borderWidth = it } + borderColor?.let { this.borderColor = it } + cornerRadius.let { this.cornerRadius = it } + darkBorderColor?.let { this.darkBorderColor = it } + textColor?.let { this.textColor = it } + textFontSize.let { this.textFontSize = it } + textFontName?.let { this.textFontName = it } + darkTextColor?.let { this.darkTextColor = it } + } + ) + } +} + +/** + * Configuration for Toolbar customization. + */ +data class ToolbarCustomization internal constructor(internal val toolbarCustomization: com.netcetera.threeds.sdk.api.ui.logic.ToolbarCustomization) + +class ToolbarCustomizationBuilder : CustomizationBuilder() { + private var headText: String? = null + private var buttonText: String? = null + private var backgroundColor: String? = null + private var darkBackgroundColor: String? = null + + fun headText(headText: String): ToolbarCustomizationBuilder = apply { this.headText = headText } + fun buttonText(buttonText: String): ToolbarCustomizationBuilder = apply { this.buttonText = buttonText } + fun backgroundColor(backgroundColor: String): ToolbarCustomizationBuilder = apply { this.backgroundColor = backgroundColor } + fun darkBackgroundColor(darkBackgroundColor: String): ToolbarCustomizationBuilder = + apply { this.darkBackgroundColor = darkBackgroundColor } + + fun textColor(textColor: String): ToolbarCustomizationBuilder = apply { this.textColor = textColor } + fun textFontSize(textFontSize: Int): ToolbarCustomizationBuilder = apply { this.textFontSize = textFontSize } + fun textFontName(textFontName: String): ToolbarCustomizationBuilder = apply { this.textFontName = textFontName } + fun darkTextColor(darkTextColor: String): ToolbarCustomizationBuilder = apply { this.darkTextColor = darkTextColor } + + override fun build(): ToolbarCustomization { + return ToolbarCustomization( + com.netcetera.threeds.sdk.api.ui.logic.ToolbarCustomization().apply { + headText?.let { this.headerText = it } + buttonText?.let { this.buttonText = it } + backgroundColor?.let { this.backgroundColor = it } + darkBackgroundColor?.let { this.darkBackgroundColor = it } + textColor?.let { this.textColor = it } + textFontSize.let { this.textFontSize = it } + textFontName?.let { this.textFontName = it } + darkTextColor?.let { this.darkTextColor = it } + } + ) + } +} + +/** + * Type of button in the challenge flow. + */ +enum class ButtonType(val value: com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType) { + SUBMIT(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.SUBMIT), + CONTINUE(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.CONTINUE), + NEXT(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.NEXT), + CANCEL(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.CANCEL), + RESEND(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.RESEND), + OPEN_OOB_APP(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.OPEN_OOB_APP); +} + +/** + * Configuration for button customization. + */ +data class ButtonCustomization internal constructor(internal val buttonCustomization: com.netcetera.threeds.sdk.api.ui.logic.ButtonCustomization) + +class ButtonCustomizationBuilder : CustomizationBuilder() { + private var cornerRadius: Int? = null + private var backgroundColor: String? = null + private var darkBackgroundColor: String? = null + + fun cornerRadius(cornerRadius: Int): ButtonCustomizationBuilder = apply { this.cornerRadius = cornerRadius } + fun backgroundColor(backgroundColor: String): ButtonCustomizationBuilder = apply { this.backgroundColor = backgroundColor } + fun darkBackgroundColor(darkBackgroundColor: String): ButtonCustomizationBuilder = + apply { this.darkBackgroundColor = darkBackgroundColor } + + fun textColor(textColor: String): ButtonCustomizationBuilder = apply { this.textColor = textColor } + fun textFontSize(textFontSize: Int): ButtonCustomizationBuilder = apply { this.textFontSize = textFontSize } + fun textFontName(textFontName: String): ButtonCustomizationBuilder = apply { this.textFontName = textFontName } + fun darkTextColor(darkTextColor: String): ButtonCustomizationBuilder = apply { this.darkTextColor = darkTextColor } + + override fun build(): ButtonCustomization { + return ButtonCustomization( + com.netcetera.threeds.sdk.api.ui.logic.ButtonCustomization().apply { + cornerRadius.let { this.cornerRadius = it } + backgroundColor?.let { this.backgroundColor = it } + darkBackgroundColor?.let { this.darkBackgroundColor = it } + textColor?.let { this.textColor = it } + textFontSize.let { this.textFontSize = it } + textFontName?.let { this.textFontName = it } + darkTextColor?.let { this.darkTextColor = it } + } + ) } } From 0dd6c6c97f951a69829c17e70ac821039245cdf1 Mon Sep 17 00:00:00 2001 From: Natthawut Haematulin Date: Thu, 5 Oct 2023 10:20:29 +0700 Subject: [PATCH 03/10] feat: add EXTRA_UI_CUSTOMIZATION parameter and set ui customization to 3DS SDK --- .../omise/android/example/CheckoutActivity.kt | 24 +----- .../example/AuthorizingPaymentDialog.kt | 1 + .../omise/android/ThreeDS2ServiceWrapper.kt | 7 +- .../co/omise/android/config/ThreeDSConfig.kt | 3 +- .../omise/android/config/UiCustomization.kt | 82 +++++++++++-------- .../android/ui/AuthorizingPaymentActivity.kt | 21 +++-- .../android/ui/AuthorizingPaymentViewModel.kt | 31 +++---- .../ui/AuthorizingPaymentViewModelTest.kt | 34 ++++---- 8 files changed, 100 insertions(+), 103 deletions(-) diff --git a/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt b/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt index 36317cb13..33de8735a 100644 --- a/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt +++ b/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt @@ -12,12 +12,10 @@ import co.omise.android.AuthorizingPaymentURLVerifier.Companion.EXTRA_AUTHORIZED import co.omise.android.AuthorizingPaymentURLVerifier.Companion.EXTRA_EXPECTED_RETURN_URLSTRING_PATTERNS import co.omise.android.api.Client import co.omise.android.api.RequestListener -import co.omise.android.config.AuthorizingPaymentConfig import co.omise.android.config.ButtonCustomizationBuilder import co.omise.android.config.ButtonType import co.omise.android.config.LabelCustomizationBuilder import co.omise.android.config.TextBoxCustomizationBuilder -import co.omise.android.config.ThreeDSConfig import co.omise.android.config.ToolbarCustomizationBuilder import co.omise.android.config.UiCustomizationBuilder import co.omise.android.models.Amount @@ -25,6 +23,7 @@ import co.omise.android.models.Capability import co.omise.android.models.Source import co.omise.android.models.Token import co.omise.android.ui.AuthorizingPaymentActivity +import co.omise.android.ui.AuthorizingPaymentActivity.Companion.EXTRA_UI_CUSTOMIZATION import co.omise.android.ui.AuthorizingPaymentResult import co.omise.android.ui.CreditCardActivity import co.omise.android.ui.OmiseActivity @@ -67,7 +66,7 @@ class CheckoutActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_checkout) - initializeAuthoringPaymentConfig() +// initializeAuthoringPaymentConfig() supportActionBar?.title = getString(R.string.activity_checkout) @@ -130,12 +129,7 @@ class CheckoutActivity : AppCompatActivity() { } } - /** - * Here's the sample of initializing 3D Secure 2. - * This should be call before start the [AuthorizingPaymentActivity]. - */ - - private fun initializeAuthoringPaymentConfig() { + private fun startAuthoringPaymentActivity(authorizeUrl: String, returnUrl: String) { val labelCustomization = LabelCustomizationBuilder() .headingDarkTextColor("#000000") .headingTextColor("#000000") @@ -196,17 +190,6 @@ class CheckoutActivity : AppCompatActivity() { .buttonCustomization(ButtonType.CANCEL, secondaryButtonCustomization) .build() - val threeDSConfig = ThreeDSConfig.Builder() - .uiCustomization(uiCustomization) - .timeout(5) - .build() - val authPaymentConfig = AuthorizingPaymentConfig.Builder() - .threeDSConfig(threeDSConfig) - .build() - AuthorizingPaymentConfig.initialize(authPaymentConfig) - } - - private fun startAuthoringPaymentActivity(authorizeUrl: String, returnUrl: String) { Log.d( TAG, """ authorizeUrl=$authorizeUrl @@ -216,6 +199,7 @@ class CheckoutActivity : AppCompatActivity() { Intent(this, AuthorizingPaymentActivity::class.java).run { putExtra(EXTRA_AUTHORIZED_URLSTRING, authorizeUrl) putExtra(EXTRA_EXPECTED_RETURN_URLSTRING_PATTERNS, arrayOf(returnUrl)) + putExtra(EXTRA_UI_CUSTOMIZATION, uiCustomization) startActivityForResult(this, AUTHORIZING_PAYMENT_REQUEST_CODE) } } diff --git a/app/src/main/java/co/omise/android/example/AuthorizingPaymentDialog.kt b/app/src/main/java/co/omise/android/example/AuthorizingPaymentDialog.kt index 3f8abd5ab..908b8c02e 100644 --- a/app/src/main/java/co/omise/android/example/AuthorizingPaymentDialog.kt +++ b/app/src/main/java/co/omise/android/example/AuthorizingPaymentDialog.kt @@ -20,6 +20,7 @@ class AuthorizingPaymentDialog { } hint = "Authorize URL" + setText("https://3dsms.staging-omise.co/payments/pay2_5xaujsv7zh2miq3tki0/authorize") } val returnUrlEditText = EditText(context).apply { layoutParams = LinearLayout.LayoutParams( diff --git a/sdk/src/main/java/co/omise/android/ThreeDS2ServiceWrapper.kt b/sdk/src/main/java/co/omise/android/ThreeDS2ServiceWrapper.kt index 538cad906..cf8b65689 100644 --- a/sdk/src/main/java/co/omise/android/ThreeDS2ServiceWrapper.kt +++ b/sdk/src/main/java/co/omise/android/ThreeDS2ServiceWrapper.kt @@ -18,7 +18,11 @@ import kotlin.coroutines.suspendCoroutine /** * Encapsulates the [ThreeDS2Service] to allow for easier testing. */ -internal class ThreeDS2ServiceWrapper(private val context: Context, private val threeDS2Service: ThreeDS2Service) { +internal class ThreeDS2ServiceWrapper( + private val context: Context, + private val threeDS2Service: ThreeDS2Service, + private val uiCustomization: UiCustomization = UiCustomization(), +) { lateinit var transaction: Transaction private set @@ -37,7 +41,6 @@ internal class ThreeDS2ServiceWrapper(private val context: Context, private val .configureScheme(schemeConfig) .build() val locale = getLocale() - val uiCustomization = UiCustomization() threeDS2Service.initialize(context, configParameters, locale, uiCustomization) continuation.resume(Result.success(Unit)) } catch (e: Exception) { diff --git a/sdk/src/main/java/co/omise/android/config/ThreeDSConfig.kt b/sdk/src/main/java/co/omise/android/config/ThreeDSConfig.kt index 9f23fa61e..1665941d4 100644 --- a/sdk/src/main/java/co/omise/android/config/ThreeDSConfig.kt +++ b/sdk/src/main/java/co/omise/android/config/ThreeDSConfig.kt @@ -55,7 +55,8 @@ class ThreeDSConfig private constructor(internal val threeDSConfig: co.omise.and * @return [ThreeDSConfig] */ fun build(): ThreeDSConfig { - return ThreeDSConfig(co.omise.android.threeds.core.ThreeDSConfig(uiCustomization.uiCustomization, timeout)) + TODO("The below is not compatible with Netcetera's 3DS SDK.") + // return ThreeDSConfig(co.omise.android.threeds.core.ThreeDSConfig(uiCustomization.uiCustomization, timeout)) } } } diff --git a/sdk/src/main/java/co/omise/android/config/UiCustomization.kt b/sdk/src/main/java/co/omise/android/config/UiCustomization.kt index 2c29559c4..d5ea3a293 100644 --- a/sdk/src/main/java/co/omise/android/config/UiCustomization.kt +++ b/sdk/src/main/java/co/omise/android/config/UiCustomization.kt @@ -1,5 +1,8 @@ package co.omise.android.config +import android.os.Parcelable +import kotlinx.android.parcel.Parcelize + abstract class CustomizationBuilder { protected var textFontSize: Int? = null @@ -12,7 +15,10 @@ abstract class CustomizationBuilder { /** * configuration for the challenge screen. */ -data class UiCustomization internal constructor(internal val uiCustomization: com.netcetera.threeds.sdk.api.ui.logic.UiCustomization) { +@Parcelize +data class UiCustomization internal constructor( + internal val uiCustomization: com.netcetera.threeds.sdk.api.ui.logic.UiCustomization +) : Parcelable { companion object { val default = UiCustomization(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization()) } @@ -72,10 +78,10 @@ class UiCustomizationBuilder { */ fun build(): UiCustomization { val uiCustomization = com.netcetera.threeds.sdk.api.ui.logic.UiCustomization().apply { - labelCustomization?.let { this.labelCustomization = it } - toolbarCustomization?.let { this.toolbarCustomization = it } - textBoxCustomization?.let { this.textBoxCustomization = it } - buttonCustomizations.forEach { (buttonType, buttonCustomization) -> + this@UiCustomizationBuilder.labelCustomization?.let { this.labelCustomization = it.labelCustomization } + this@UiCustomizationBuilder.toolbarCustomization?.let { this.toolbarCustomization = it.toolbarCustomization } + this@UiCustomizationBuilder.textBoxCustomization?.let { this.textBoxCustomization = it.textBoxCustomization } + this@UiCustomizationBuilder.buttonCustomizations.forEach { (buttonType, buttonCustomization) -> this.setButtonCustomization(buttonCustomization.buttonCustomization, buttonType.value) } } @@ -86,7 +92,10 @@ class UiCustomizationBuilder { /** * Configuration for label customization. */ -data class LabelCustomization internal constructor(internal val labelCustomization: com.netcetera.threeds.sdk.api.ui.logic.LabelCustomization) +@Parcelize +data class LabelCustomization internal constructor( + internal val labelCustomization: com.netcetera.threeds.sdk.api.ui.logic.LabelCustomization +) : Parcelable class LabelCustomizationBuilder : CustomizationBuilder() { private var headingTextColor: String? = null @@ -128,9 +137,10 @@ class LabelCustomizationBuilder : CustomizationBuilder() { /** * Configuration for Text box customization. */ +@Parcelize data class TextBoxCustomization internal constructor( internal val textBoxCustomization: com.netcetera.threeds.sdk.api.ui.logic.TextBoxCustomization -) +) : Parcelable class TextBoxCustomizationBuilder : CustomizationBuilder() { private var borderWidth: Int? = null @@ -150,14 +160,14 @@ class TextBoxCustomizationBuilder : CustomizationBuilder() override fun build(): TextBoxCustomization { return TextBoxCustomization( com.netcetera.threeds.sdk.api.ui.logic.TextBoxCustomization().apply { - borderWidth.let { this.borderWidth = it } - borderColor?.let { this.borderColor = it } - cornerRadius.let { this.cornerRadius = it } - darkBorderColor?.let { this.darkBorderColor = it } - textColor?.let { this.textColor = it } - textFontSize.let { this.textFontSize = it } - textFontName?.let { this.textFontName = it } - darkTextColor?.let { this.darkTextColor = it } + this@TextBoxCustomizationBuilder.borderWidth?.let { this.borderWidth = it } + this@TextBoxCustomizationBuilder.borderColor?.let { this.borderColor = it } + this@TextBoxCustomizationBuilder.cornerRadius?.let { this.cornerRadius = it } + this@TextBoxCustomizationBuilder.darkBorderColor?.let { this.darkBorderColor = it } + this@TextBoxCustomizationBuilder.textColor?.let { this.textColor = it } + this@TextBoxCustomizationBuilder.textFontSize?.let { this.textFontSize = it } + this@TextBoxCustomizationBuilder.textFontName?.let { this.textFontName = it } + this@TextBoxCustomizationBuilder.darkTextColor?.let { this.darkTextColor = it } } ) } @@ -166,7 +176,10 @@ class TextBoxCustomizationBuilder : CustomizationBuilder() /** * Configuration for Toolbar customization. */ -data class ToolbarCustomization internal constructor(internal val toolbarCustomization: com.netcetera.threeds.sdk.api.ui.logic.ToolbarCustomization) +@Parcelize +data class ToolbarCustomization internal constructor( + internal val toolbarCustomization: com.netcetera.threeds.sdk.api.ui.logic.ToolbarCustomization +) : Parcelable class ToolbarCustomizationBuilder : CustomizationBuilder() { private var headText: String? = null @@ -188,14 +201,14 @@ class ToolbarCustomizationBuilder : CustomizationBuilder() override fun build(): ToolbarCustomization { return ToolbarCustomization( com.netcetera.threeds.sdk.api.ui.logic.ToolbarCustomization().apply { - headText?.let { this.headerText = it } - buttonText?.let { this.buttonText = it } - backgroundColor?.let { this.backgroundColor = it } - darkBackgroundColor?.let { this.darkBackgroundColor = it } - textColor?.let { this.textColor = it } - textFontSize.let { this.textFontSize = it } - textFontName?.let { this.textFontName = it } - darkTextColor?.let { this.darkTextColor = it } + this@ToolbarCustomizationBuilder.headText?.let { this.headerText = it } + this@ToolbarCustomizationBuilder.buttonText?.let { this.buttonText = it } + this@ToolbarCustomizationBuilder.backgroundColor?.let { this.backgroundColor = it } + this@ToolbarCustomizationBuilder.darkBackgroundColor?.let { this.darkBackgroundColor = it } + this@ToolbarCustomizationBuilder.textColor?.let { this.textColor = it } + this@ToolbarCustomizationBuilder.textFontSize?.let { this.textFontSize = it } + this@ToolbarCustomizationBuilder.textFontName?.let { this.textFontName = it } + this@ToolbarCustomizationBuilder.darkTextColor?.let { this.darkTextColor = it } } ) } @@ -210,13 +223,16 @@ enum class ButtonType(val value: com.netcetera.threeds.sdk.api.ui.logic.UiCustom NEXT(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.NEXT), CANCEL(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.CANCEL), RESEND(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.RESEND), - OPEN_OOB_APP(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.OPEN_OOB_APP); + OPEN_OOB_APP(com.netcetera.threeds.sdk.api.ui.logic.UiCustomization.ButtonType.OPEN_OOB_APP) } /** * Configuration for button customization. */ -data class ButtonCustomization internal constructor(internal val buttonCustomization: com.netcetera.threeds.sdk.api.ui.logic.ButtonCustomization) +@Parcelize +data class ButtonCustomization internal constructor( + internal val buttonCustomization: com.netcetera.threeds.sdk.api.ui.logic.ButtonCustomization +) : Parcelable class ButtonCustomizationBuilder : CustomizationBuilder() { private var cornerRadius: Int? = null @@ -236,13 +252,13 @@ class ButtonCustomizationBuilder : CustomizationBuilder() { override fun build(): ButtonCustomization { return ButtonCustomization( com.netcetera.threeds.sdk.api.ui.logic.ButtonCustomization().apply { - cornerRadius.let { this.cornerRadius = it } - backgroundColor?.let { this.backgroundColor = it } - darkBackgroundColor?.let { this.darkBackgroundColor = it } - textColor?.let { this.textColor = it } - textFontSize.let { this.textFontSize = it } - textFontName?.let { this.textFontName = it } - darkTextColor?.let { this.darkTextColor = it } + this@ButtonCustomizationBuilder.cornerRadius?.let { this.cornerRadius = it } + this@ButtonCustomizationBuilder.backgroundColor?.let { this.backgroundColor = it } + this@ButtonCustomizationBuilder.darkBackgroundColor?.let { this.darkBackgroundColor = it } + this@ButtonCustomizationBuilder.textColor?.let { this.textColor = it } + this@ButtonCustomizationBuilder.textFontSize?.let { this.textFontSize = it } + this@ButtonCustomizationBuilder.textFontName?.let { this.textFontName = it } + this@ButtonCustomizationBuilder.darkTextColor?.let { this.darkTextColor = it } } ) } diff --git a/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentActivity.kt b/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentActivity.kt index b9bec2767..8593f1c7d 100644 --- a/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentActivity.kt +++ b/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentActivity.kt @@ -23,11 +23,8 @@ import co.omise.android.AuthorizingPaymentURLVerifier.Companion.EXTRA_RETURNED_U import co.omise.android.AuthorizingPaymentURLVerifier.Companion.REQUEST_EXTERNAL_CODE import co.omise.android.OmiseException import co.omise.android.R -import co.omise.android.config.AuthorizingPaymentConfig +import co.omise.android.config.UiCustomization import co.omise.android.models.Authentication -import co.omise.android.threeds.challenge.ProgressView -import co.omise.android.threeds.core.ThreeDSConfig -import co.omise.android.threeds.events.CompletionEvent import co.omise.android.ui.AuthorizingPaymentResult.Failure import co.omise.android.ui.AuthorizingPaymentResult.ThreeDS1Completed import co.omise.android.ui.AuthorizingPaymentResult.ThreeDS2Completed @@ -42,24 +39,24 @@ import org.jetbrains.annotations.TestOnly */ class AuthorizingPaymentActivity : AppCompatActivity() { - private val progressDialog: ProgressView by lazy { ProgressView.newInstance(this) } private val webView: WebView by lazy { authorizing_payment_webview } private val verifier: AuthorizingPaymentURLVerifier by lazy { AuthorizingPaymentURLVerifier(intent) } + private val uiCustomization: UiCustomization by lazy { intent.getParcelableExtra(EXTRA_UI_CUSTOMIZATION) ?: UiCustomization.default } private val viewModel: AuthorizingPaymentViewModel by viewModels { viewModelFactory ?: AuthorizingPaymentViewModelFactory( - this, - verifier + activity = this, + urlVerifier = verifier, + uiCustomization = uiCustomization, ) } private var viewModelFactory: ViewModelProvider.Factory? = null - private val threeDSConfig: ThreeDSConfig by lazy { AuthorizingPaymentConfig.get().threeDSConfig.threeDSConfig } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_authorizing_payment) - supportActionBar?.title = threeDSConfig.uiCustomization?.toolbarCustomization?.headerText + supportActionBar?.title = uiCustomization.uiCustomization.toolbarCustomization.headerText ?: getString(R.string.title_authorizing_payment) if (verifier.verifyExternalURL(verifier.authorizedURL)) { @@ -258,5 +255,11 @@ class AuthorizingPaymentActivity : AppCompatActivity() { * [AuthorizingPaymentResult] intent result from [AuthorizingPaymentActivity]. */ const val EXTRA_AUTHORIZING_PAYMENT_RESULT = "OmiseActivity.authorizingPaymentResult" + + /** + * [co.omise.android.config.UiCustomization] intent extra for [AuthorizingPaymentActivity] to configure the UI in the challenge flow. + * This is an optional parameter. If not provided, the default UI will be used. + */ + const val EXTRA_UI_CUSTOMIZATION = "OmiseActivity.uiCustomization" } } diff --git a/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentViewModel.kt b/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentViewModel.kt index 5907f5c70..9da82982c 100644 --- a/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentViewModel.kt +++ b/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentViewModel.kt @@ -11,11 +11,9 @@ import co.omise.android.BuildConfig import co.omise.android.OmiseException import co.omise.android.ThreeDS2ServiceWrapper import co.omise.android.api.Client -import co.omise.android.config.AuthorizingPaymentConfig +import co.omise.android.config.UiCustomization import co.omise.android.models.Authentication import co.omise.android.models.Serializer -import co.omise.android.threeds.ThreeDS -import co.omise.android.threeds.core.ThreeDSConfig import com.netcetera.threeds.sdk.ThreeDS2ServiceInstance import com.netcetera.threeds.sdk.api.transaction.Transaction import com.netcetera.threeds.sdk.api.transaction.challenge.ChallengeParameters @@ -23,27 +21,26 @@ import com.netcetera.threeds.sdk.api.transaction.challenge.ChallengeStatusReceiv import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancel import kotlinx.coroutines.launch internal class AuthorizingPaymentViewModelFactory( private val activity: Activity, - private val urlVerifier - : AuthorizingPaymentURLVerifier + private val urlVerifier: AuthorizingPaymentURLVerifier, + private val uiCustomization: UiCustomization, ) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { - // TODO: Remove this after replacing with Netcetera's 3DS SDK. - ThreeDSConfig.initialize(AuthorizingPaymentConfig.get().threeDSConfig.threeDSConfig) - val threeDS = ThreeDS(activity) val client = Client("") - val wrapper = ThreeDS2ServiceWrapper(activity.application, ThreeDS2ServiceInstance.get()) - return AuthorizingPaymentViewModel(threeDS, client, urlVerifier, wrapper) as T + val wrapper = ThreeDS2ServiceWrapper( + context = activity.application, + threeDS2Service = ThreeDS2ServiceInstance.get(), + uiCustomization = uiCustomization.uiCustomization, + ) + return AuthorizingPaymentViewModel(client, urlVerifier, wrapper) as T } } internal class AuthorizingPaymentViewModel( - private val threeDS: ThreeDS, private val client: Client, private val urlVerifier: AuthorizingPaymentURLVerifier, private val threeDS2Service: ThreeDS2ServiceWrapper, @@ -67,7 +64,7 @@ internal class AuthorizingPaymentViewModel( val error: LiveData = _error private val coroutineExceptionHandler = CoroutineExceptionHandler { _, e -> - _isLoading.postValue(false) +// _isLoading.postValue(false) threeDS2Service.transaction.close() if (e is OmiseException) { _error.postValue(e) @@ -124,7 +121,7 @@ internal class AuthorizingPaymentViewModel( _isLoading.postValue(true) val authentication = client.send(request) - // Reccomended by Netcetera's 3DS SDK. + // Recommended by Netcetera's 3DS SDK. // If the challenge flow is required // - Do not close the transaction // - Do not hide the progress view @@ -164,12 +161,6 @@ internal class AuthorizingPaymentViewModel( return threeDS2Service.transaction } - // TODO: Remove this after removing Omise's 3DS SDK. - fun cleanup() { - viewModelScope.cancel() - threeDS.cleanup() - } - /** [ChallengeStatusReceiver] implementation. */ override fun completed(event: com.netcetera.threeds.sdk.api.transaction.challenge.events.CompletionEvent?) { when (event?.transactionStatus) { diff --git a/sdk/src/test/java/co/omise/android/ui/AuthorizingPaymentViewModelTest.kt b/sdk/src/test/java/co/omise/android/ui/AuthorizingPaymentViewModelTest.kt index 02be6709b..eed77d332 100644 --- a/sdk/src/test/java/co/omise/android/ui/AuthorizingPaymentViewModelTest.kt +++ b/sdk/src/test/java/co/omise/android/ui/AuthorizingPaymentViewModelTest.kt @@ -9,7 +9,6 @@ import co.omise.android.api.Request import co.omise.android.models.Authentication import co.omise.android.models.Authentication.AuthenticationStatus import co.omise.android.models.AuthenticationAPIError -import co.omise.android.threeds.ThreeDS import com.netcetera.threeds.sdk.api.exceptions.InvalidInputException import com.netcetera.threeds.sdk.api.exceptions.SDKRuntimeException import com.netcetera.threeds.sdk.api.transaction.AuthenticationRequestParameters @@ -43,7 +42,6 @@ class AuthorizingPaymentViewModelTest { @get:Rule val instanceExecutor = InstantTaskExecutorRule() - private val threeDS: ThreeDS = mock() private val client: Client = mock() private val urlVerifier: AuthorizingPaymentURLVerifier = mock() private val threeDS2Service: ThreeDS2ServiceWrapper = mock() @@ -74,7 +72,7 @@ class AuthorizingPaymentViewModelTest { @Test fun initialize3DS_shouldInitialize3DS2ServiceAndSendAuthenticationRequest() = runTest { - AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) verify(threeDS2Service).initialize() verify(client).send(any>()) @@ -85,7 +83,7 @@ class AuthorizingPaymentViewModelTest { threeDS2Service.stub { onBlocking { initialize() } doReturn Result.failure(InvalidInputException("Something went wrong.")) } - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) verify(threeDS2Service).initialize() verify(client, never()).send(any>()) @@ -99,7 +97,7 @@ class AuthorizingPaymentViewModelTest { status = AuthenticationStatus.SUCCESS ) } - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) verify(client).send(any>()) verify(transaction).close() @@ -113,7 +111,7 @@ class AuthorizingPaymentViewModelTest { status = AuthenticationStatus.CHALLENGE ) } - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) verify(client).send(any>()) verify(transaction, never()).close() @@ -128,7 +126,7 @@ class AuthorizingPaymentViewModelTest { status = AuthenticationStatus.CHALLENGE_V1 ) } - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) verify(client).send(any>()) verify(transaction).close() @@ -142,7 +140,7 @@ class AuthorizingPaymentViewModelTest { status = AuthenticationStatus.FAILED ) } - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) verify(client).send(any>()) verify(transaction).close() @@ -157,7 +155,7 @@ class AuthorizingPaymentViewModelTest { message = "Something went wrong." ) } - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) verify(client).send(any>()) verify(transaction).close() @@ -178,7 +176,7 @@ class AuthorizingPaymentViewModelTest { ) ) } - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) viewModel.doChallenge(mock()) @@ -200,7 +198,7 @@ class AuthorizingPaymentViewModelTest { ) } whenever(threeDS2Service.doChallenge(any(), any(), any(), any())).doThrow(SDKRuntimeException("Something went wrong.", null)) - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) viewModel.doChallenge(mock()) @@ -210,7 +208,7 @@ class AuthorizingPaymentViewModelTest { @Test fun completed_whenReceivedTransactionStatusYThenSetAuthenticatedStatus() { val completionEvent = CompletionEvent(UUID.randomUUID().toString(), "Y") - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) viewModel.completed(completionEvent) @@ -219,7 +217,7 @@ class AuthorizingPaymentViewModelTest { @Test fun completed_whenReceivedTransactionStatusNThenSetNotAuthenticatedStatus() { - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) viewModel.completed(CompletionEvent(UUID.randomUUID().toString(), "N")) @@ -228,7 +226,7 @@ class AuthorizingPaymentViewModelTest { @Test fun completed_whenReceivedUnknownTransactionStatusThenSetError() { - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) viewModel.completed(CompletionEvent(UUID.randomUUID().toString(), "unknown")) @@ -237,7 +235,7 @@ class AuthorizingPaymentViewModelTest { @Test fun cancelled_whenReceivedCancelledEventThenSetError() { - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) viewModel.cancelled() @@ -246,7 +244,7 @@ class AuthorizingPaymentViewModelTest { @Test fun timedout_whenReceivedTimedoutEventThenSetError() { - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) viewModel.timedout() @@ -255,7 +253,7 @@ class AuthorizingPaymentViewModelTest { @Test fun protocolError_whenReceivedProtocolErrorEventThenSetError() { - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) viewModel.protocolError( ProtocolErrorEvent( @@ -276,7 +274,7 @@ class AuthorizingPaymentViewModelTest { @Test fun runtimeError_whenReceivedRuntimeErrorEventThenSetError() { - val viewModel = AuthorizingPaymentViewModel(threeDS, client, urlVerifier, threeDS2Service, testDispatcher) + val viewModel = AuthorizingPaymentViewModel(client, urlVerifier, threeDS2Service, testDispatcher) viewModel.runtimeError( RuntimeErrorEvent( From 40d961f838b4d5c730c53866c1dc8690609302d7 Mon Sep 17 00:00:00 2001 From: Natthawut Haematulin Date: Thu, 5 Oct 2023 13:42:28 +0700 Subject: [PATCH 04/10] feat: add support dark mode --- .../main/java/co/omise/android/ThreeDS2ServiceWrapper.kt | 2 +- .../main/java/co/omise/android/config/UiCustomization.kt | 6 ++++++ .../java/co/omise/android/ui/AuthorizingPaymentActivity.kt | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sdk/src/main/java/co/omise/android/ThreeDS2ServiceWrapper.kt b/sdk/src/main/java/co/omise/android/ThreeDS2ServiceWrapper.kt index cf8b65689..38b0a48b7 100644 --- a/sdk/src/main/java/co/omise/android/ThreeDS2ServiceWrapper.kt +++ b/sdk/src/main/java/co/omise/android/ThreeDS2ServiceWrapper.kt @@ -21,7 +21,7 @@ import kotlin.coroutines.suspendCoroutine internal class ThreeDS2ServiceWrapper( private val context: Context, private val threeDS2Service: ThreeDS2Service, - private val uiCustomization: UiCustomization = UiCustomization(), + private val uiCustomization: UiCustomization, ) { lateinit var transaction: Transaction private set diff --git a/sdk/src/main/java/co/omise/android/config/UiCustomization.kt b/sdk/src/main/java/co/omise/android/config/UiCustomization.kt index d5ea3a293..4a26d65f0 100644 --- a/sdk/src/main/java/co/omise/android/config/UiCustomization.kt +++ b/sdk/src/main/java/co/omise/android/config/UiCustomization.kt @@ -28,11 +28,16 @@ data class UiCustomization internal constructor( * Builder for building [UiCustomization] data. */ class UiCustomizationBuilder { + private var supportDarkMode: Boolean? = null private var labelCustomization: LabelCustomization? = null private var toolbarCustomization: ToolbarCustomization? = null private var textBoxCustomization: TextBoxCustomization? = null private var buttonCustomizations: MutableMap = mutableMapOf() + fun supportDarkMode(supportDarkMode: Boolean): UiCustomizationBuilder = apply { + this@UiCustomizationBuilder.supportDarkMode = supportDarkMode + } + /** * Set the label customization. * @@ -78,6 +83,7 @@ class UiCustomizationBuilder { */ fun build(): UiCustomization { val uiCustomization = com.netcetera.threeds.sdk.api.ui.logic.UiCustomization().apply { + this@UiCustomizationBuilder.supportDarkMode?.let { this.supportDarkMode(it) } this@UiCustomizationBuilder.labelCustomization?.let { this.labelCustomization = it.labelCustomization } this@UiCustomizationBuilder.toolbarCustomization?.let { this.toolbarCustomization = it.toolbarCustomization } this@UiCustomizationBuilder.textBoxCustomization?.let { this.textBoxCustomization = it.textBoxCustomization } diff --git a/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentActivity.kt b/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentActivity.kt index 8593f1c7d..4ce45ce1a 100644 --- a/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentActivity.kt +++ b/sdk/src/main/java/co/omise/android/ui/AuthorizingPaymentActivity.kt @@ -56,7 +56,7 @@ class AuthorizingPaymentActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_authorizing_payment) - supportActionBar?.title = uiCustomization.uiCustomization.toolbarCustomization.headerText + supportActionBar?.title = uiCustomization.uiCustomization.toolbarCustomization?.headerText ?: getString(R.string.title_authorizing_payment) if (verifier.verifyExternalURL(verifier.authorizedURL)) { From d213702a26e6624bfe5d93e3c90599710cb979d5 Mon Sep 17 00:00:00 2001 From: Natthawut Haematulin Date: Thu, 5 Oct 2023 15:05:53 +0700 Subject: [PATCH 05/10] chore: update sample code --- .../android/example/CheckoutActivity.java | 56 +++++++----------- .../omise/android/example/CheckoutActivity.kt | 33 ++++++----- .../example/AuthorizingPaymentDialog.kt | 1 - app/src/main/res/font/roboto_mono.xml | 12 ++++ .../font/roboto_mono_bold.ttf} | Bin .../font/roboto_mono_regular.ttf} | Bin app/src/main/res/values/styles.xml | 1 + 7 files changed, 51 insertions(+), 52 deletions(-) create mode 100644 app/src/main/res/font/roboto_mono.xml rename app/src/main/{assets/fonts/RobotoMono-Bold.ttf => res/font/roboto_mono_bold.ttf} (100%) rename app/src/main/{assets/fonts/RobotoMono-Regular.ttf => res/font/roboto_mono_regular.ttf} (100%) diff --git a/app/src/java/java/co/omise/android/example/CheckoutActivity.java b/app/src/java/java/co/omise/android/example/CheckoutActivity.java index 48c252a07..00d1cd0a0 100644 --- a/app/src/java/java/co/omise/android/example/CheckoutActivity.java +++ b/app/src/java/java/co/omise/android/example/CheckoutActivity.java @@ -17,7 +17,6 @@ import co.omise.android.api.Client; import co.omise.android.api.Request; import co.omise.android.api.RequestListener; -import co.omise.android.config.AuthorizingPaymentConfig; import co.omise.android.config.ButtonCustomization; import co.omise.android.config.ButtonCustomizationBuilder; import co.omise.android.config.ButtonType; @@ -25,7 +24,6 @@ import co.omise.android.config.LabelCustomizationBuilder; import co.omise.android.config.TextBoxCustomization; import co.omise.android.config.TextBoxCustomizationBuilder; -import co.omise.android.config.ThreeDSConfig; import co.omise.android.config.ToolbarCustomization; import co.omise.android.config.ToolbarCustomizationBuilder; import co.omise.android.config.UiCustomization; @@ -34,8 +32,8 @@ import co.omise.android.models.Capability; import co.omise.android.models.Source; import co.omise.android.models.Token; -import co.omise.android.ui.AuthorizingPaymentResult; import co.omise.android.ui.AuthorizingPaymentActivity; +import co.omise.android.ui.AuthorizingPaymentResult; import co.omise.android.ui.CreditCardActivity; import co.omise.android.ui.OmiseActivity; import co.omise.android.ui.PaymentCreatorActivity; @@ -44,6 +42,7 @@ import static co.omise.android.AuthorizingPaymentURLVerifier.EXTRA_AUTHORIZED_URLSTRING; import static co.omise.android.AuthorizingPaymentURLVerifier.EXTRA_EXPECTED_RETURN_URLSTRING_PATTERNS; +import static co.omise.android.ui.AuthorizingPaymentActivity.EXTRA_UI_CUSTOMIZATION; public class CheckoutActivity extends AppCompatActivity { @@ -71,8 +70,6 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_checkout); - initializeAuthoringPaymentConfig(); - ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setTitle(R.string.activity_checkout); @@ -139,23 +136,19 @@ private void payByCreditCard() { startActivityForResult(intent, CREDIT_CARD_REQUEST_CODE); } - /** - * Here's the sample of initializing 3D Secure 2. - * This should be call before start the {@link AuthorizingPaymentActivity}. - */ - private void initializeAuthoringPaymentConfig() { + private Unit startAuthoringPaymentActivity(String authorizeUrl, String returnUrl) { LabelCustomization labelCustomization = new LabelCustomizationBuilder() - .headingDarkTextColor("#000000") + .headingDarkTextColor("#FFFFFF") .headingTextColor("#000000") - .headingTextFontName("fonts/RobotoMono-Bold.ttf") + .headingTextFontName("roboto_mono") .headingTextFontSize(20) - .textFontName("fonts/RobotoMono-Regular.ttf") + .textFontName("roboto_mono") .textColor("#000000") .textFontSize(16) .build(); TextBoxCustomization textBoxCustomization = new TextBoxCustomizationBuilder() - .textFontName("fonts/RobotoMono-Regular.ttf") + .textFontName("font/roboto_mono_regular.ttf") .textColor("#000000") .textFontSize(16) .borderWidth(1) @@ -164,35 +157,38 @@ private void initializeAuthoringPaymentConfig() { .build(); ToolbarCustomization toolbarCustomization = new ToolbarCustomizationBuilder() - .textFontName("fonts/RobotoMono-Bold.ttf") + .textFontName("font/roboto_mono_bold.ttf") .textColor("#000000") .textFontSize(20) .backgroundColor("#FFFFFF") .headText("Secure Checkout") .buttonText("Close") + .darkBackgroundColor("#262626") + .darkTextColor("#FFFFFF") .build(); ButtonCustomization primaryButtonCustomization = new ButtonCustomizationBuilder() - .textFontName("fonts/RobotoMono-Bold.ttf") - .textColor("#000000") + .textFontName("font/roboto_mono_bold.ttf") .textFontSize(20) - .backgroundColor("#FFFFFF") .cornerRadius(4) - .darkTextColor("#000000") - .darkBackgroundColor("#FFFFFF") + .textColor("#FFFFFF") + .backgroundColor("#1A56F0") + .darkTextColor("#FFFFFF") + .darkBackgroundColor("#4777F3") .build(); ButtonCustomization secondaryButtonCustomization = new ButtonCustomizationBuilder() - .textFontName("fonts/RobotoMono-Bold.ttf") - .textColor("#000000") + .textFontName("font/roboto_mono_bold.ttf") .textFontSize(20) + .cornerRadius(4) + .textColor("#1A56F0") .backgroundColor("#FFFFFF") - .darkTextColor("#000000") + .darkTextColor("#1E1E1E") .darkBackgroundColor("#FFFFFF") - .cornerRadius(4) .build(); UiCustomization uiCustomization = new UiCustomizationBuilder() + .supportDarkMode(true) .labelCustomization(labelCustomization) .textBoxCustomization(textBoxCustomization) .toolbarCustomization(toolbarCustomization) @@ -204,20 +200,10 @@ private void initializeAuthoringPaymentConfig() { .buttonCustomization(ButtonType.CANCEL, secondaryButtonCustomization) .build(); - ThreeDSConfig threeDSConfig = new ThreeDSConfig.Builder() - .uiCustomization(uiCustomization) - .timeout(5) - .build(); - AuthorizingPaymentConfig authPaymentConfig = new AuthorizingPaymentConfig.Builder() - .threeDSConfig(threeDSConfig) - .build(); - AuthorizingPaymentConfig.initialize(authPaymentConfig); - } - - private Unit startAuthoringPaymentActivity(String authorizeUrl, String returnUrl) { Intent intent = new Intent(this, AuthorizingPaymentActivity.class); intent.putExtra(EXTRA_AUTHORIZED_URLSTRING, authorizeUrl); intent.putExtra(EXTRA_EXPECTED_RETURN_URLSTRING_PATTERNS, new String[]{returnUrl}); + intent.putExtra(EXTRA_UI_CUSTOMIZATION, uiCustomization); startActivityForResult(intent, CheckoutActivity.AUTHORIZING_PAYMENT_REQUEST_CODE); return Unit.INSTANCE; } diff --git a/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt b/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt index 33de8735a..4af116854 100644 --- a/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt +++ b/app/src/kotlin/java/co/omise/android/example/CheckoutActivity.kt @@ -66,8 +66,6 @@ class CheckoutActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_checkout) -// initializeAuthoringPaymentConfig() - supportActionBar?.title = getString(R.string.activity_checkout) choosePaymentMethodButton.setOnClickListener { choosePaymentMethod() } @@ -131,17 +129,17 @@ class CheckoutActivity : AppCompatActivity() { private fun startAuthoringPaymentActivity(authorizeUrl: String, returnUrl: String) { val labelCustomization = LabelCustomizationBuilder() - .headingDarkTextColor("#000000") + .headingDarkTextColor("#FFFFFF") .headingTextColor("#000000") - .headingTextFontName("fonts/RobotoMono-Bold.ttf") + .headingTextFontName("roboto_mono") .headingTextFontSize(20) - .textFontName("fonts/RobotoMono-Regular.ttf") + .textFontName("roboto_mono") .textColor("#000000") .textFontSize(16) .build() val textBoxCustomization = TextBoxCustomizationBuilder() - .textFontName("fonts/RobotoMono-Regular.ttf") + .textFontName("font/roboto_mono_regular.ttf") .textColor("#000000") .textFontSize(16) .borderWidth(1) @@ -150,35 +148,38 @@ class CheckoutActivity : AppCompatActivity() { .build() val toolbarCustomization = ToolbarCustomizationBuilder() - .textFontName("fonts/RobotoMono-Bold.ttf") + .textFontName("font/roboto_mono_bold.ttf") .textColor("#000000") .textFontSize(20) .backgroundColor("#FFFFFF") .headText("Secure Checkout") .buttonText("Close") + .darkBackgroundColor("#262626") + .darkTextColor("#FFFFFF") .build() val primaryButtonCustomization = ButtonCustomizationBuilder() - .textFontName("fonts/RobotoMono-Bold.ttf") + .textFontName("font/roboto_mono_bold.ttf") .textFontSize(20) .cornerRadius(4) - .textColor("#000000") - .backgroundColor("#FFFFFF") - .darkTextColor("#000000") - .darkBackgroundColor("#FFFFFF") + .textColor("#FFFFFF") + .backgroundColor("#1A56F0") + .darkTextColor("#FFFFFF") + .darkBackgroundColor("#4777F3") .build() val secondaryButtonCustomization = ButtonCustomizationBuilder() - .textFontName("fonts/RobotoMono-Bold.ttf") + .textFontName("font/roboto_mono_bold.ttf") .textFontSize(20) .cornerRadius(4) - .textColor("#000000") + .textColor("#1A56F0") .backgroundColor("#FFFFFF") - .darkTextColor("#000000") + .darkTextColor("#1E1E1E") .darkBackgroundColor("#FFFFFF") .build() val uiCustomization = UiCustomizationBuilder() + .supportDarkMode(true) .labelCustomization(labelCustomization) .textBoxCustomization(textBoxCustomization) .toolbarCustomization(toolbarCustomization) @@ -186,7 +187,7 @@ class CheckoutActivity : AppCompatActivity() { .buttonCustomization(ButtonType.CONTINUE, primaryButtonCustomization) .buttonCustomization(ButtonType.NEXT, primaryButtonCustomization) .buttonCustomization(ButtonType.OPEN_OOB_APP, primaryButtonCustomization) - .buttonCustomization(ButtonType.RESEND, primaryButtonCustomization) + .buttonCustomization(ButtonType.RESEND, secondaryButtonCustomization) .buttonCustomization(ButtonType.CANCEL, secondaryButtonCustomization) .build() diff --git a/app/src/main/java/co/omise/android/example/AuthorizingPaymentDialog.kt b/app/src/main/java/co/omise/android/example/AuthorizingPaymentDialog.kt index 908b8c02e..3f8abd5ab 100644 --- a/app/src/main/java/co/omise/android/example/AuthorizingPaymentDialog.kt +++ b/app/src/main/java/co/omise/android/example/AuthorizingPaymentDialog.kt @@ -20,7 +20,6 @@ class AuthorizingPaymentDialog { } hint = "Authorize URL" - setText("https://3dsms.staging-omise.co/payments/pay2_5xaujsv7zh2miq3tki0/authorize") } val returnUrlEditText = EditText(context).apply { layoutParams = LinearLayout.LayoutParams( diff --git a/app/src/main/res/font/roboto_mono.xml b/app/src/main/res/font/roboto_mono.xml new file mode 100644 index 000000000..c0ed8904e --- /dev/null +++ b/app/src/main/res/font/roboto_mono.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/assets/fonts/RobotoMono-Bold.ttf b/app/src/main/res/font/roboto_mono_bold.ttf similarity index 100% rename from app/src/main/assets/fonts/RobotoMono-Bold.ttf rename to app/src/main/res/font/roboto_mono_bold.ttf diff --git a/app/src/main/assets/fonts/RobotoMono-Regular.ttf b/app/src/main/res/font/roboto_mono_regular.ttf similarity index 100% rename from app/src/main/assets/fonts/RobotoMono-Regular.ttf rename to app/src/main/res/font/roboto_mono_regular.ttf diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index e1b7a3e82..7b3913f47 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -12,6 +12,7 @@ @style/SampleButton @style/SampleEditTextLabel @style/SampleEditTextError + @font/roboto_mono