Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed a few code comments #54

Merged
merged 3 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
package com.komoju.android.sdk

/**
* This annotation means that this option is experimental and subject to change in Future.
* Please test your behaviour overall once you update the komoju SDK Version
* Annotation used to mark APIs in the Komoju SDK as experimental.
* This indicates that the annotated feature or API is subject to change in future releases.
* Users should be cautious and thoroughly test their code after updating the SDK version.
*
* - The annotation requires explicit opt-in to use the marked elements.
* - A warning will be shown when using experimental APIs.
*
* @see [RequiresOptIn] to learn more about Kotlin's opt-in mechanism.
*/
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Retention(AnnotationRetention.BINARY)
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.PROPERTY,
AnnotationTarget.FIELD,
AnnotationTarget.LOCAL_VARIABLE,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.TYPEALIAS,
AnnotationTarget.CLASS, // Can annotate classes
AnnotationTarget.ANNOTATION_CLASS, // Can annotate other annotations
AnnotationTarget.PROPERTY, // Can annotate properties
AnnotationTarget.FIELD, // Can annotate fields
AnnotationTarget.LOCAL_VARIABLE, // Can annotate local variables
AnnotationTarget.VALUE_PARAMETER, // Can annotate function parameters
AnnotationTarget.CONSTRUCTOR, // Can annotate constructors
AnnotationTarget.FUNCTION, // Can annotate functions
AnnotationTarget.PROPERTY_GETTER, // Can annotate property getters
AnnotationTarget.PROPERTY_SETTER, // Can annotate property setters
AnnotationTarget.TYPEALIAS, // Can annotate type aliases
)
annotation class ExperimentalKomojuPaymentApi
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ internal class KomojuPaymentActivity : ComponentActivity() {
}

@Composable
fun NewIntentEffect(context: Context, onNewDeeplink: (String) -> Unit) {
private fun NewIntentEffect(context: Context, onNewDeeplink: (String) -> Unit) {
LaunchedEffect(Unit) {
callbackFlow {
val componentActivity = context as ComponentActivity
Expand Down
3 changes: 2 additions & 1 deletion android/src/main/java/com/komoju/android/sdk/KomojuSDK.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.activity.result.contract.ActivityResultContract
import com.komoju.android.sdk.types.Currency
import com.komoju.android.sdk.types.Language
import com.komoju.android.sdk.ui.theme.ConfigurableTheme
import com.komoju.android.sdk.utils.empty
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlinx.parcelize.Parcelize
Expand All @@ -29,7 +30,7 @@ object KomojuSDK {
internal val publishableKey: String?, // Public API key for Komoju integration.
internal val isDebugMode: Boolean, // Debug mode flag for logging and testing.
internal val sessionId: String?, // Unique session ID for payment transaction.
internal val redirectURL: String = "", // URL to redirect after payment completion.
internal val redirectURL: String = String.empty, // URL to redirect after payment completion.
internal val configurableTheme: ConfigurableTheme, // Custom theme for UI elements.
internal val inlinedProcessing: Boolean, // Flag to enable inlined processing.
) : Parcelable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ internal class PaymentResultScreenModel : ScreenModel {
}

@Composable
internal fun Navigator.paymentResultScreenModel() = rememberNavigatorScreenModel(PaymentResultScreenModel::class.simpleName) {
PaymentResultScreenModel()
}
internal fun Navigator.paymentResultScreenModel() = rememberNavigatorScreenModel(
tag = PaymentResultScreenModel::class.simpleName,
factory = ::PaymentResultScreenModel,
)
26 changes: 26 additions & 0 deletions android/src/main/java/com/komoju/android/sdk/types/Currency.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,43 @@ package com.komoju.android.sdk.types

import java.util.Locale

/**
* Enum class representing supported currencies with corresponding ISO 4217 currency codes.
* Each currency is associated with a specific locale.
*/
enum class Currency(val currencyCode: String) {

/**
* Japanese Yen currency with code "JPY".
*/
JPY(currencyCode = "JPY"),

/**
* United States Dollar currency with code "USD".
*/
USD(currencyCode = "USD"),
;

/**
* Converts the current currency to its corresponding locale.
*
* @return [Locale] for the currency.
* - JPY returns [Locale.JAPAN]
* - USD returns [Locale.US]
*/
fun toLocale(): Locale = when (this) {
JPY -> Locale.JAPAN
USD -> Locale.US
}

companion object {
/**
* Parses the given language code and returns the corresponding [Currency] enum constant.
* If the code does not match any currency, USD is returned as the default.
*
* @param languageCode A string representing the currency code (e.g., "JPY", "USD").
* @return The matching [Currency] enum constant or [USD] if no match is found.
*/
fun parse(languageCode: String): Currency = entries.firstOrNull { it.currencyCode == languageCode } ?: USD
}
}
27 changes: 27 additions & 0 deletions android/src/main/java/com/komoju/android/sdk/types/Language.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,43 @@ package com.komoju.android.sdk.types

import java.util.Locale

/**
* Enum class representing supported languages with their respective language codes.
* Each language is associated with a specific locale.
*/
enum class Language(val languageCode: String) {

/**
* English language with code "en".
*/
ENGLISH(languageCode = "en"),

/**
* Japanese language with code "ja".
*/
JAPANESE(languageCode = "ja"),
;

/**
* Converts the current language to its corresponding locale.
*
* @return [Locale] for the language.
* - ENGLISH returns [Locale.ENGLISH]
* - JAPANESE returns [Locale.JAPANESE]
*/
internal fun toLocale(): Locale = when (this) {
ENGLISH -> Locale.ENGLISH
JAPANESE -> Locale.JAPANESE
}

companion object {
/**
* Provides the default [Language] based on the system's default locale.
*
* @return The corresponding [Language] based on the system's default language:
* - Returns [JAPANESE] if the default language is Japanese.
* - Returns [ENGLISH] for all other cases.
*/
val default
get() = when (Locale.getDefault().language) {
Locale.JAPANESE.language -> JAPANESE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ internal fun InlinedPaymentPrimaryButton(
}
}

enum class InlinedPaymentPrimaryButtonState {
internal enum class InlinedPaymentPrimaryButtonState {
LOADING,
IDLE,
SUCCESS,
ERROR,
}

@Composable
fun rememberInlinedPaymentPrimaryButtonState(
internal fun rememberInlinedPaymentPrimaryButtonState(
default: InlinedPaymentPrimaryButtonState = InlinedPaymentPrimaryButtonState.IDLE,
): MutableState<InlinedPaymentPrimaryButtonState> = rememberSaveable { mutableStateOf(default) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import com.komoju.mobile.sdk.entities.PaymentStatus
internal data class KonbiniAwaitingPaymentScreen(val route: KomojuPaymentRoute.KonbiniAwaitingPayment) : Screen {
@Composable
override fun Content() {
val screenModel = rememberScreenModel { KonbiniAwaitingPaymentScreenModel(route.configuration, route.payment) }
val screenModel = rememberScreenModel { KonbiniAwaitingPaymentScreenModel(route.payment) }
val uiState by screenModel.state.collectAsStateWithLifecycle()
RouterEffect(screenModel.router.collectAsStateWithLifecycle(), screenModel::onRouteConsumed)
uiState.payment?.let {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package com.komoju.android.sdk.ui.screens.awating

import cafe.adriel.voyager.core.model.screenModelScope
import com.komoju.android.sdk.KomojuSDK
import com.komoju.android.sdk.navigation.RouterStateScreenModel
import com.komoju.android.sdk.ui.screens.KomojuPaymentRoute
import com.komoju.android.sdk.ui.screens.Router
import com.komoju.mobile.sdk.entities.Payment
import com.komoju.mobile.sdk.remote.apis.KomojuRemoteApi
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

internal class KonbiniAwaitingPaymentScreenModel(private val config: KomojuSDK.Configuration, private val payment: Payment? = null) :
RouterStateScreenModel<KonbiniAwaitingPaymentUiState>(KonbiniAwaitingPaymentUiState(payment)) {
private val komojuApi = KomojuRemoteApi(config.publishableKey, config.language.languageCode)
internal class KonbiniAwaitingPaymentScreenModel(payment: Payment? = null) :
RouterStateScreenModel<KonbiniAwaitingPaymentUiState>(
KonbiniAwaitingPaymentUiState(payment),
) {

fun onPrimaryButtonClicked() {
when (val payment = state.value.payment) {
Expand All @@ -22,28 +18,6 @@ internal class KonbiniAwaitingPaymentScreenModel(private val config: KomojuSDK.C
}

fun onSecondaryButtonClicked() {
// when (state.value.payment) {
// is Payment.Konbini -> refreshPayment()
// else -> Unit
// }
mutableRouter.value = Router.Pop
}

fun refreshPayment() {
screenModelScope.launch {
val sessionId = config.sessionId ?: return@launch
mutableState.update {
it.copy(isLoading = true)
}
komojuApi.sessions.verifyPaymentBySessionID(sessionId).onSuccess { payment ->
mutableState.update {
it.copy(payment = payment, isLoading = false)
}
}.onFailure {
mutableState.update {
it.copy(isLoading = false)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import kotlinx.coroutines.launch

internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configuration) :
RouterStateScreenModel<KomojuPaymentUIState>(KomojuPaymentUIState()) {
private val komojuApi: KomojuRemoteApi = KomojuRemoteApi(config.publishableKey, config.language.languageCode)
private val komojuApi: KomojuRemoteApi = KomojuRemoteApi.create(config.publishableKey, config.language.languageCode)
private val _offSitePaymentURL = MutableStateFlow<String?>(null)
val offSitePaymentURL = _offSitePaymentURL.asStateFlow()

Expand Down Expand Up @@ -467,4 +467,9 @@ internal class KomojuPaymentScreenModel(private val config: KomojuSDK.Configurat
fun onOffSitePaymentURLConsumed() {
_offSitePaymentURL.value = null
}

override fun onDispose() {
komojuApi.close()
super.onDispose()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import kotlinx.coroutines.launch

internal class VerifyPaymentScreenModel(private val config: KomojuSDK.Configuration) : RouterStateScreenModel<Unit>(Unit) {

private val komojuApi: KomojuRemoteApi = KomojuRemoteApi(config.publishableKey, config.language.languageCode)
private val komojuApi: KomojuRemoteApi = KomojuRemoteApi.create(config.publishableKey, config.language.languageCode)

fun process(type: KomojuPaymentRoute.ProcessPayment.ProcessType) {
screenModelScope.launch {
Expand Down Expand Up @@ -70,4 +70,9 @@ internal class VerifyPaymentScreenModel(private val config: KomojuSDK.Configurat
mutableRouter.value = Router.ReplaceAll(KomojuPaymentRoute.PaymentFailed(Reason.CREDIT_CARD_ERROR))
}
}

override fun onDispose() {
komojuApi.close()
super.onDispose()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,66 @@ import android.os.Parcelable
import androidx.annotation.ColorInt
import kotlinx.parcelize.Parcelize

/**
* Interface representing a configurable theme with customizable UI properties.
* This interface extends [Parcelable], allowing themes to be passed between Android components.
*/
interface ConfigurableTheme : Parcelable {
@get:ColorInt val primaryButtonColor: Int

@get:ColorInt val primaryButtonContentColor: Int
/**
* Color value for the primary button background.
*
* @return An integer representing a color value annotated with [ColorInt].
*/
@get:ColorInt
val primaryButtonColor: Int

@get:ColorInt val primaryButtonCornerRadiusInDP: Int
/**
* Color value for the content (e.g., text or icon) inside the primary button.
*
* @return An integer representing a color value annotated with [ColorInt].
*/
@get:ColorInt
val primaryButtonContentColor: Int

@get:ColorInt val loaderColor: Int
/**
* Corner radius for the primary button in density-independent pixels (DP).
*
* @return An integer representing the corner radius in DP annotated with [ColorInt].
*/
@get:ColorInt
val primaryButtonCornerRadiusInDP: Int

/**
* Color value for the loader/spinner.
*
* @return An integer representing a color value annotated with [ColorInt].
*/
@get:ColorInt
val loaderColor: Int

companion object {
/**
* Provides a default implementation of the [ConfigurableTheme].
*/
val default = DefaultConfigurableTheme()
}
}

/**
* Data class representing the default implementation of [ConfigurableTheme].
* This class uses default values for UI elements such as buttons and loaders.
* It is annotated with [Parcelize] to allow it to be passed between Android components.
*
* @param primaryButtonColor The background color of the primary button.
* @param primaryButtonContentColor The color of the content inside the primary button.
* @param primaryButtonCornerRadiusInDP The corner radius of the primary button in DP.
* @param loaderColor The color of the loader/spinner.
*/
@Parcelize
data class DefaultConfigurableTheme(
override val primaryButtonColor: Int = Color.parseColor("#FF297FE7"),
override val primaryButtonContentColor: Int = Color.WHITE,
override val primaryButtonCornerRadiusInDP: Int = 8,
override val loaderColor: Int = Color.parseColor("#FF3CC239"),
override val primaryButtonColor: Int = Color.parseColor("#FF297FE7"), // Default blue color for primary button.
override val primaryButtonContentColor: Int = Color.WHITE, // Default white color for primary button content.
override val primaryButtonCornerRadiusInDP: Int = 8, // Default corner radius of 8 DP for primary button.
override val loaderColor: Int = Color.parseColor("#FF3CC239"), // Default green color for loader.
) : ConfigurableTheme
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,25 @@ package com.komoju.mobile.sdk.remote.apis
import com.komoju.mobile.sdk.i18n.I18nTexts
import com.komoju.mobile.sdk.remote.createNetworkClient

class KomojuRemoteApi(publishableKey: String?, language: String) {
interface KomojuRemoteApi : AutoCloseable {
val sessions: SessionApi
val tokens: TokensApi

companion object {
fun create(publishableKey: String?, language: String): KomojuRemoteApi = KomojuRemoteApiImpl(publishableKey, language)
}
}

internal class KomojuRemoteApiImpl(publishableKey: String?, language: String) : KomojuRemoteApi {
private val networkClient by lazy { createNetworkClient(publishableKey) }

private val i18nTexts by lazy { I18nTexts(language) }

val sessions: SessionApi by lazy { SessionApiImpl(i18nTexts, networkClient) }
val tokens: TokensApi by lazy { TokenApiImpl(networkClient) }
override val sessions: SessionApi by lazy { SessionApiImpl(i18nTexts, networkClient) }

override val tokens: TokensApi by lazy { TokenApiImpl(networkClient) }

override fun close() {
networkClient.close()
}
}
Loading