How to Build AdSense and AdMob Earnings Calculator App Using Jetpack Compose

How to Build AdSense and AdMob Earnings Calculator App Using Jetpack Compose

How to Build AdSense and AdMob Earnings Calculator App Using Jetpack Compose

Are you a blogger or app developer curious about how much you could earn from Google ads? Whether you run a website or a mobile app, knowing your potential AdSense or AdMob earnings can help you plan better and optimize your strategies.

In this article, I’ll guide you through creating a simple yet powerful Android app using Jetpack Compose — Google’s modern toolkit for building native UI — to estimate your AdSense (for websites) or AdMob (for apps) revenue easily.

Why Build an Earnings Calculator App?

Many content creators and developers want a quick way to calculate estimated earnings without diving deep into analytics dashboards. An earnings calculator app:
  • Provides instant revenue estimates based on your traffic or app usage
  • Helps in forecasting and decision-making
  • Educates beginners on ad monetization concepts
  • Can be extended into a full-featured earnings tracking tool

By building it yourself in Jetpack Compose, you gain hands-on experience with:

  • Modern Android UI development
  • Managing state and user inputs
  • Animations and beautiful interfaces
  • Data persistence to save user history

Understanding the Difference: AdSense vs AdMob

Before we dive into building the app, let’s clarify the difference between Adsense and Admob:
  • AdSense is for monetizing websites and blogs. Your earnings from AdSense mainly depend on how many people visit your site, how often they click on ads (CTR), and how much each click is worth (CPC).
  • AdMob is designed for mobile apps, earning from in-app ads shown to users. Earnings depend on daily active users, impressions, CTR, CPC, or CPM (cost per thousand impressions).
Our calculator should adjust inputs and formulas accordingly.

Designing the Calculator Inputs

For AdSense, typical inputs are:
  • Monthly visitors
  • Click-through rate (CTR %)
  • Cost per click (CPC)
The formula looks like:
Earnings = Monthly Visitors × (CTR / 100) × CPC
For AdMob, inputs could be:
  • Daily active users
  • Average ads shown per user per day
  • CTR or fill rate
  • CPC or CPM
Example formula:
Earnings = Daily Users × Ads per User × CTR × CPC
Or
Earnings = Daily Users × Ads per User × CPM / 1000

A Simple AdSense and AdMob Earnings Calculator App

A Simple AdSense and AdMob Earnings Calculator App

Building the App with Jetpack Compose

  1. User-friendly input fields with validation
  2. Animated background using Lottie for a professional look
  3. Calculate button that shows earnings instantly
  4. Confetti animation to celebrate high earnings
  5. Persistent storage of last 5 calculations using DataStore
  6. Clean layout following Material Design 3 guidelines

Step-by-Step Guide

  • Set up a new Android project with Compose support
  • Add dependencies: Material3, Lottie Compose, DataStore
  • Design input UI with OutlinedTextFields for numbers only
  • Add a button that calculates earnings based on user input
  • Display results dynamically and format currency nicely
  • Integrate Lottie animation in the background with low opacity
  • Add a confetti effect for earnings above a certain threshold
  • Save calculation history locally and display it in the UI

Benefits of This Approach

  • Modern UI: Compose makes UI building intuitive and reactive
  • Customization: Easy to switch themes and animations
  • User Engagement: Confetti and animations make the app fun
  • Data Persistence: Keeps user history for better experience
  • Extensible: Add features like sharing, graphs, or more ad networks

Let's Build

Below is a complete Jetpack Compose app code for a multi-mode AdSense & AdMob earnings calculator featuring:
  • Unique, attractive background (using custom Compose shapes and colors)
  • Mode selector (AdSense / AdMob)
  • Dynamic input fields per mode
  • CPC/CPM toggle for AdMob
  • Instant calculation and formatted earnings display
  • Confetti animation for big earnings
  • Dark/light theme toggle
  • History of last 5 calculations saved with DataStore
  • Clean, modern Material3 UI

Dependency needed for this project

implementation ("com.airbnb.android:lottie-compose:6.3.0")
implementation ("androidx.datastore:datastore-preferences:1.1.6")

MainActivity

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
RevenueCalculatorTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
EarningsCalculatorApp()
}
}
}
}

Earnings Calculator App

package com.cdingbihar.revenuecalculator

import android.content.Context
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Person
import androidx.compose.material3.Button
import androidx.compose.material3.FilterChip
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import androidx.compose.runtime.setValue
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.platform.LocalContext
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.rememberLottieComposition
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.map

@Composable
fun EarningsCalculatorApp() {
val isDarkTheme = rememberSaveable { mutableStateOf(false) }
MaterialTheme(colorScheme = if (isDarkTheme.value) darkColorScheme() else lightColorScheme()) {
Surface(modifier = Modifier.fillMaxSize()) {
Box(modifier = Modifier.fillMaxSize()) {
BackgroundShapes()
CalculatorContent(isDarkTheme)
}
}
}
}

@Composable
fun BackgroundShapes() {
Canvas(modifier = Modifier.fillMaxSize()) {
val width = size.width
val height = size.height

// Soft large background circle
drawCircle(
color = Color(0xFFE3F2FD),
radius = width * 0.7f,
center = Offset(width * 0.25f, height * 0.25f)
)

// Deeper blue large circle at bottom-left
drawCircle(
color = Color(0xFFBBDEFB),
radius = width * 0.9f,
center = Offset(0f, height)
)

// Transparent top-right glow circle
drawCircle(
color = Color(0x802196F3),
radius = width * 0.6f,
center = Offset(width * 0.9f, height * 0.1f)
)

// Bottom-right faint blue circle
drawCircle(
color = Color(0x403F51B5),
radius = width * 0.4f,
center = Offset(width * 1.1f, height * 1.1f)
)
}
}

@Composable
fun CalculatorContent(isDarkTheme: MutableState<Boolean>) {
var mode by remember { mutableStateOf("AdSense") }
var cpc by remember { mutableDoubleStateOf(0.0) }
var cpm by remember { mutableDoubleStateOf(0.0) }
var clicks by remember { androidx.compose.runtime.mutableIntStateOf(0) }
var impressions by remember { androidx.compose.runtime.mutableIntStateOf(0) }
var useCpc by remember { mutableStateOf(true) }
var earnings by remember { mutableDoubleStateOf(0.0) }
val showConfetti = remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val context = LocalContext.current

Column(modifier = Modifier.padding(16.dp).systemBarsPadding()) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Text("Ad Earnings Calculator", style = MaterialTheme.typography.titleLarge)
IconButton(onClick = { isDarkTheme.value = !isDarkTheme.value }) {
Icon(Icons.Default.Person, contentDescription = "Toggle Theme")
}
}

Spacer(Modifier.height(16.dp))

ModeSelector(mode) { mode = it }

Spacer(Modifier.height(8.dp))

if (mode == "AdMob") {
Row(verticalAlignment = Alignment.CenterVertically) {
Text("Use CPC")
Switch(checked = useCpc, onCheckedChange = { useCpc = it })
}
}

Spacer(Modifier.height(8.dp))

if (mode == "AdSense" || (mode == "AdMob" && useCpc)) {
CustomInputField("CPC ($)", cpc.toString()) { cpc = it.toDoubleOrNull() ?: 0.0 }
CustomInputField("Clicks", clicks.toString()) { clicks = it.toIntOrNull() ?: 0 }
} else {
CustomInputField("CPM ($)", cpm.toString()) { cpm = it.toDoubleOrNull() ?: 0.0 }
CustomInputField("Impressions", impressions.toString()) { impressions = it.toIntOrNull() ?: 0 }
}

Spacer(Modifier.height(16.dp))

Button(onClick = {
earnings = if (mode == "AdSense" || (mode == "AdMob" && useCpc)) {
cpc * clicks
} else {
(cpm * impressions) / 1000
}
if (earnings > 100) showConfetti.value = true
// saveToHistory(scope, earnings)
saveToHistory(context, scope, earnings) // Correct
}) {
Text("Calculate")
}

Spacer(Modifier.height(16.dp))
Text("Estimated Earnings: $${"%.2f".format(earnings)}", style = MaterialTheme.typography.headlineSmall)

if (showConfetti.value) {
LottieAnimationConfetti()
}

Spacer(Modifier.height(24.dp))
HistoryList()
}
}

@Composable
fun ModeSelector(current: String, onSelect: (String) -> Unit) {
Row(Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly) {
listOf("AdSense", "AdMob").forEach {
FilterChip(selected = current == it, onClick = { onSelect(it) }, label = { Text(it) })
}
}
}

@Composable
fun CustomInputField(label: String, value: String, onValueChange: (String) -> Unit) {
OutlinedTextField(
value = value,
onValueChange = onValueChange,
label = { Text(label) },
modifier = Modifier.fillMaxWidth()
)
}


@Composable
fun LottieAnimationConfetti() {
val composition by rememberLottieComposition(LottieCompositionSpec.Asset("confetti.json"))
LottieAnimation(composition = composition, iterations = 1)
}

// DataStore helper for saving history
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "history")

fun saveToHistory(context: Context, scope: CoroutineScope, earnings: Double) {
scope.launch {
val prefsKey = stringPreferencesKey("calc_history")
val history = context.dataStore.data.first()[prefsKey].orEmpty()
val entries = history.split("|").filter { it.isNotBlank() }.toMutableList()
entries.add(0, "$${"%.2f".format(earnings)}")
// if (entries.size > 5) entries.removeLast()
if (entries.size > 5) entries.removeAt(entries.lastIndex)
context.dataStore.edit { it[prefsKey] = entries.joinToString("|") }
}
}

@Composable
fun HistoryList() {
val context = LocalContext.current
val prefsKey = stringPreferencesKey("calc_history")
val history = produceState<List<String>>(initialValue = emptyList()) {
context.dataStore.data.map { prefs ->
prefs[prefsKey]?.split("|")?.filter { it.isNotBlank() } ?: emptyList()
}.collect { value = it }
}
Column {
Text("Last 5 Calculations:", style = MaterialTheme.typography.labelLarge)
history.value.forEach {
Text(it, style = MaterialTheme.typography.bodyMedium)
}
}
}

Output:

Earnings Calculator App Output 1

Earnings Calculator App Output 2

Output How to Build AdSense and AdMob Earnings Calculator App Using Jetpack Compose

Previous Post Next Post

Contact Form