2 things to consider when adding subscriptions to your mobile app
Tags: mobile, kotlin, android, tristan
Published: 2023-06-12 14:58:28

### Table of contents
1. [The 2 things to consider](#things)
2. [Loading screen](#loading)
3. [Disabling buy button after first click](#disable)

### My app on the Google Playstore
- [HERE](https://play.google.com/store/apps/details?id=com.elliottsoftware.calftracker)

### GitHub code <a name="github"></a>
- [HERE](https://github.com/thePlebDev/CalfTracker)


### Introduction <a name="intro"></a>
- This series will be an informal demonstration of any problems I face or any observations I make while developing Android apps. Each blog post in this series will be unique and separate from the others, so feel free to look around.

### The two things <a name="things"></a>
**1) Loading screen**
**2) Disabling the buy button**

- These may seen obvious to you more experienced developers, however, this may be helpful to those starting out like myself. By implementing these two features, our app will start behaving like much larger and more professional apps

### 1) Loading screen <a name="loading"></a>
- If you look at [THIS](https://github.com/android/play-billing-samples/tree/main/ClassyTaxiAppKotlin#classy-taxi-google-play-billing-android-app-kotlin-sample) code example. You will notice there is no loading screen, just simple waiting and the Google play Billing library modal appears. Which is fine, however, it can be a little jarring to the user if they click the subscribe button and there is no indication that loading is happening.

### Creating a simple loading screen
- A simple loading screen can be created in Jetpack compose like so:
```
Box(modifier = Modifier.fillMaxSize()){
// The rest of your compose code
//will explain isUserBuying later 
val isUserBuying = billingViewModel.state.value.userBuying
if(isUserBuying){
            Spacer(
                modifier = Modifier
                    .matchParentSize()
                    .background(color = Color.Gray.copy(alpha = .7f))
            )
            CircularProgressIndicator(
                color= MaterialTheme.colors.onSecondary,
                modifier = Modifier
                    .align(Alignment.Center)
                    .size(60.dp)
            )
        }
}

```

- The spacer will cover the entire screen with a light transparent gray and the `CircularProgressIndicator` rotating in the center of the screen.

- Now, `isUserBuying` is a conditional I am storing in my Viewmodel like so:
```
data class BillingUiState(

    val userBuying:Boolean = false

)
private val _uiState = mutableStateOf(BillingUiState())
val state = _uiState // exposed to the UI
```
- Whenever the [buy()](https://github.com/android/play-billing-samples/blob/047d2eb8eef8fe32ec07a115580faea8eb865e43/PlayBillingCodelab/finished/src/main/java/com/sample/subscriptionscodelab/ui/MainViewModel.kt#L243) method is clicked we simply set this to false:
```
fun buy(
        productDetails: ProductDetails,
        currentPurchases: List<Purchase>?,
        activity: Activity,
        tag: String
    ) {

        _uiState.value = _uiState.value.copy(
            userBuying = true
        )
// the rest of the buy method
}
```
- The [buy()](https://github.com/android/play-billing-samples/blob/047d2eb8eef8fe32ec07a115580faea8eb865e43/PlayBillingCodelab/finished/src/main/java/com/sample/subscriptionscodelab/ui/MainViewModel.kt#L243) method will reach out to the Google play billing library and cause the purchases modal to pop up like so:



![Google play billing library modal](https://developer.android.com/static/images/google/play/billing/purchase-screen.png)

### When to close the loading screen.
- When the modal pops, up our app enters the [onPause()](https://developer.android.com/guide/components/activities/activity-lifecycle#onpause) lifecycle state.

- Which means the user will have to interact with the modal by either making a successful purchase or dismissing the modal. This interaction will make our app call the [onResume](https://developer.android.com/guide/components/activities/activity-lifecycle#onresume) method. So to close our loading screen we should do so in the `onResume()` method like so:
```
override fun onResume(owner: LifecycleOwner) {
        _uiState.value = _uiState.value.copy(
            userBuying = false
        )
    }

```
- I would like to point out that this will only work if your ViewModel is Lifecycle aware.

### 2) Disabling the buy button <a name="disable"></a>
- If you do not disable the buy button after the first click, there is the possibility of the user pressing it multiple times. Causing the launch of multiple purchase modals, Which can be very confusing to the user. To make sure this does not happen we simply put a conditional in the onClick method of a Button composable:
```
Button(
            onClick={
                if(!isUserBuying){
                    billingViewModel.state.value.productDetails?.let{
                        billingViewModel.buy(
                            productDetails = it,
                            currentPurchases = null,
                            activity = activity,
                            tag = "calf_tracker_premium"
                        )
                    }
                }

            }
        ){
            Text("Upgrade $10.00", fontSize = 30.sp)
        }

```  
- With `!isUserBuying` I am simply stating, if the user has already clicked the button remove the method call to `billingViewModel.buy()`.

- Technically we could remove the user's ability to click the button all together. By moving our conditional to the Button's `enabled` parameter but I really don't like the UI for it. So I choose to simply remove the call to the method.


### Recap
- So to wrap things up, to make our app behave more professionaly we need to make sure we do two things:

**1) Add a loading screen**
**2) Disable the buy button after first click**


### Conclusion
- Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on [Twitter](https://twitter.com/AndroidTristan).