How to Build "MediBihar" – An Online Medical Store App in Jetpack Compose

How to Build "MediBihar" – An Online Medical Store App in Jetpack Compose

MediBihar – An Online Medical Store App in Jetpack Compose PART - 1

In today’s fast-moving world, healthcare should be as fast and accessible as everything else. That’s the idea behind MediBihar — a modern, reliable, and user-friendly online medical store app built with Jetpack Compose for Android. Whether you need a strip of Paracetamol or a complete prescription refill, MediBihar delivers medicine at your fingertips.

This app allows users to:
  • Search for medicines
  • View detailed information
  • Add items to a cart
  • Modify quantity
  • Checkout via a modern payment screen

📱 Features at a Glance

🔍 Search Medicine Instantly

Just type in the name of the medicine in the search bar and MediBihar instantly filters the list. No more scrolling endlessly or going store to store.

💊 Live Medicine List

A default list of common medicines is shown on the home screen. Each medicine shows its:
  • Name
  • Company
  • Composition
  • Price
  • Dose
  • Precautions
  • Image

🛒 Smart Cart Integration

Each medicine has an Add to Cart button. If it’s already in the cart, it becomes a Go to Cart button for quick checkout. Smart, right?

➕➖ Modify Quantity

Inside the cart screen, we can increase or decrease the quantity of each medicine. The total price updates instantly, helping us keep track of costs.

💸 Clean Payment Screen

MediBihar features a modern Material You–style payment screen with options like:
  • UPI
  • Debit/Credit Card
  • Wallet
  • Simple, elegant, and efficient.
By the end of this tutorial, you'll have a working Android app following modern Android development practices.

📦 Tools & Libraries Used

  • Jetpack Compose UI toolkit
  • Material 3 design components
  • MVVM Architecture
  • StateFlow for reactive UI updates
  • NavHost for screen navigation

🛠️ Step 1: Setup Your Project

MediBihar – An Online Medical Store App in Jetpack Compose
  1. Create a new Jetpack Compose project in Android Studio the official integrated development environment for Google's Android operating system.
  2. Use Empty Activity with Kotlin and minimum SDK 21+.
  3. Add the following dependencies in build.gradle(:app):
implementation("io.coil-kt:coil-compose:2.6.0")
implementation ("androidx.compose.material:material-icons-extended")
implementation("androidx.navigation:navigation-compose:2.9.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.9.1")
Sync your project.

🧠 Step 2: Define the Medicine Model

Create a Medicine.kt data class:
package com.codingbihar.medibihar


/// STEP 1: Data Model
// Medicine.kt
data class Medicine(
val id: Int,
val name: String,
val company: String,
val composition: String,
val dose: String,
val precautions: String,
val price: Double,
val imageResId: Int,
var quantity: Int = 0
)

Add medicine images to your res/drawable folder (e.g., paracetamol.png, aspirin.png, etc.).

👨‍⚕️ Step 3: ViewModel for State Management

package com.codingbihar.medibihar

import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf
import androidx.lifecycle.ViewModel


class MediViewModel : ViewModel() {

private val _medicineList = mutableStateListOf<Medicine>()
val medicineList: List<Medicine> get() = _medicineList

private val _cart = mutableStateMapOf<Medicine, Int>()
val cart: Map<Medicine, Int> get() = _cart

init {
_medicineList.addAll(getSampleMedicines())
}

private fun getSampleMedicines(): List<Medicine> = listOf(
Medicine(
1,
"Paracetamol",
"Pharma Co.",
"500mg Paracetamol",
"1 tablet every 6 hours",
"Avoid alcohol",
20.0,
R.drawable.paracetamol
),
Medicine(
2,
"Ibuprofen",
"HealthMed",
"200mg Ibuprofen",
"1 tablet every 8 hours",
"Take with food",
25.0,
R.drawable.ibuprofen
),
Medicine(
3,
"Amoxicillin",
"ABC Pharma",
"500mg Amoxicillin",
"1 capsule every 12 hours",
"Complete full course",
40.0,
R.drawable.amoxicillin
),
Medicine(
id = 4,
name = "Cetirizine",
company = "AllergyCare",
composition = "Cetirizine 10mg",
dose = "1 tablet daily",
precautions = "May cause drowsiness",
price = 25.00,
imageResId = R.drawable.cetirizine,
quantity = 0
),
Medicine(
id = 21,
name = "Dolo 650",
company = "Micro Labs",
composition = "Paracetamol 650mg",
dose = "1 tablet every 6-8 hours",
precautions = "Do not exceed 4 tablets in 24 hours. Take with water. Avoid if allergic to paracetamol.",
price = 25.13,
imageResId = R.drawable.dolo650, // Replace with your actual drawable resource ID
quantity = 0
)

// Add more medicines and your drawable resources accordingly
)

fun addToCart(medicine: Medicine) {
_cart[medicine] = (_cart[medicine] ?: 0) + 1
}

fun updateQuantity(medicine: Medicine, qty: Int) {
if (qty <= 0) {
_cart.remove(medicine)
} else {
_cart[medicine] = qty
}
}

fun totalPrice(): Double {
return _cart.entries.sumOf { it.key.price * it.value }
}

fun clearCart() {
_cart.clear()
}
}
Use a List<Medicine> for your demo medicines.

🏠 Step 4: Home Screen


@Composable
fun HomeScreen(
viewModel: MediViewModel,
onMedicineClick: (Medicine) -> Unit,
onCartClick: () -> Unit
) {
var query by remember { mutableStateOf("") }
val filtered = viewModel.medicineList.filter {
it.name.contains(query, ignoreCase = true)
}

Column(modifier = Modifier.fillMaxSize().systemBarsPadding()) {
TextButton(onClick = {}
) {
Text("MediBihar - An online Medical Store",
style = MaterialTheme.typography.displayMedium)
}
TextField(
value = query,
onValueChange = { query = it },
label = { Text("Search Medicines") },
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
)
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(filtered) { medicine ->
val isInCart = viewModel.cart.keys.any { it.id == medicine.id }
MedicineCard(
medicine = medicine,
isInCart = isInCart,
onClick = { onMedicineClick(medicine) },
onAddToCart = { viewModel.addToCart(medicine) },
onGoToCartClick = onCartClick
)
}
}
}
}

@Composable
fun MedicineCard(
medicine: Medicine,
isInCart: Boolean,
onClick: () -> Unit,
onAddToCart: () -> Unit,
onGoToCartClick: () -> Unit
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.clickable { onClick() },
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Row(Modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically) {
Image(
painter = painterResource(id = medicine.imageResId),
contentDescription = medicine.name,
modifier = Modifier
.size(80.dp)
.padding(end = 8.dp)
)
Column(modifier = Modifier.weight(1f)) {
Text(medicine.name, style = MaterialTheme.typography.titleMedium)
Text("${medicine.price}", style = MaterialTheme.typography.bodyLarge)
Text(medicine.company, style = MaterialTheme.typography.bodySmall)
}
if (isInCart) {
Button(onClick = onGoToCartClick) {
Text("Go to Cart")
}
} else {
Button(onClick = onAddToCart) {
Text("Add")
}
}
}
}
}
Show only 10 by default with "Load More" logic.

🛒 Step 5: Cart Screen

package com.codingbihar.medibihar

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material.icons.filled.Remove
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.Alignment
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color

@Composable
fun CartScreen(
viewModel: MediViewModel,
onCheckout: () -> Unit,
onBack: () -> Unit
) {
val cartItems = viewModel.cart.entries.toList()

Column(modifier = Modifier
.fillMaxSize()
.systemBarsPadding()) {

IconButton(onClick = onBack) {
Icon(Icons.Filled.ArrowBackIosNew, contentDescription = "Back")
}

if (cartItems.isEmpty()) {
Text("Your cart is empty.", modifier = Modifier.padding(16.dp))
} else {
LazyColumn(modifier = Modifier.weight(1f)) {
items(cartItems) { (item, qty) ->
val totalItemPrice = item.price * qty
Row(
Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
// Show medicine image

Image(painterResource(id = item.imageResId),
contentDescription = item.name,
modifier = Modifier
.size(104.dp)
.clip(RoundedCornerShape(8.dp))
.background(Color.LightGray)
)

Column {
Text(item.name)
Text("${item.price} × $qty = $totalItemPrice", style = MaterialTheme.typography.bodySmall)
}

Row(verticalAlignment = Alignment.CenterVertically) {
IconButton(onClick = {
viewModel.updateQuantity(item, qty - 1)
}) {
Icon(Icons.Default.Remove, contentDescription = "Decrease")
}
Text(qty.toString(), modifier = Modifier.padding(horizontal = 8.dp))
IconButton(onClick = {
viewModel.updateQuantity(item, qty + 1)
}) {
Icon(Icons.Default.Add, contentDescription = "Increase")
}
}
}
}
}

Text(
"Total: ${"%.2f".format(viewModel.totalPrice())}",
modifier = Modifier.padding(16.dp),
style = MaterialTheme.typography.titleMedium
)

Button(
onClick = onCheckout,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text("Proceed to Checkout")
}
}
}
}

💳 Step 6: Payment Screen

@Composable
fun CheckoutScreen(viewModel: MediViewModel, onOrderPlaced: () -> Unit, onBack: () -> Unit) {
Column(Modifier.padding(16.dp)) {
IconButton(onClick = onBack) {
Icon(Icons.Default.Remove, contentDescription = "Back")
}
Text("Payment Screen", style = MaterialTheme.typography.headlineSmall)
Spacer(Modifier.height(16.dp))
Text("Total Payable: ${viewModel.totalPrice()}")
Spacer(Modifier.height(24.dp))
Button(onClick = {
viewModel.clearCart()
onOrderPlaced()
}) {
Text("Place Order & Pay")
}
}
}
Use Material 3 components and icons.

🧭 Step 7: Navigation Setup


@Composable
fun AppNav(viewModel: MediViewModel) {
val navController = rememberNavController()

NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomeScreen(
viewModel = viewModel,
onMedicineClick = { medicine ->
navController.navigate("detail/${medicine.id}")
},
onCartClick = {
navController.navigate("cart")
},
)
}

composable(
"detail/{medicineId}",
arguments = listOf(navArgument("medicineId") { type = NavType.IntType })
) { backStackEntry ->
val medicineId = backStackEntry.arguments?.getInt("medicineId") ?: 0
val medicine = viewModel.medicineList.find { it.id == medicineId }
medicine?.let {
DetailScreen(
medicine = it,
onAddToCart = { viewModel.addToCart(it) },
onBack = { navController.popBackStack() }
)
}
}

composable("cart") {
CartScreen(
viewModel = viewModel,
onCheckout = { navController.navigate("checkout") },
onBack = { navController.popBackStack() }
)
}

composable("checkout") {
CheckoutScreen(
viewModel = viewModel,
onOrderPlaced = {
navController.popBackStack("home", inclusive = false)
},
onBack = { navController.popBackStack() }
)
}

}
}

Step8: MainActivity

class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
MediBiharTheme {
/*Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}*/

val viewModel: MediViewModel = viewModel()
AppNav(viewModel)
}
}
}
}

🧪 Step 9: Testing & Improvements

✅ Try searching
✅ Add items to cart
✅ Adjust quantities
✅ Complete a payment

OUTPUT:

MediBihar Screenshot 1

MediBihar Screenshot 2

MediBihar Screenshot 3

MediBihar Screenshot 4

MediBihar Screenshot 5

You can expand this by:

  • Adding real-time search
  • Firebase integration
  • Local DB with Room
  • Lottie animation on success
  • Add Firebase Auth
  • Push Notifications
MediBihar is not just an app — it’s a complete Jetpack Compose learning project for modern Android development. It’s simple, practical, and scalable. It shows how Jetpack Compose can build fast, responsive, and beautiful apps for real use cases.

From search to checkout, you’ve now built a complete online medicine shopping experience using 100% Kotlin Compose!

In the Next Part 2

To take it further and make it more like a real-world system, we will add:
  1. 👨‍⚕️ Doctor Prescription Upload
  2. 🔐 User Login / Sign-Up
  3. 📦 Order History / Status Tracking
  4. 📞 Contact or Help Screen
  5. 🌐 Firebase or Backend Integration

Previous Post Next Post

Contact Form