Caffeine-in started from a small frustration: most caffeine trackers record what you drank, but they do not tell you what is still active in your body. I built a native Android prototype that treats each intake as a time-decaying signal, then updates the displayed level continuously as the day changes.

What it does
The app stores custom caffeine sources, lets you log them with one tap, and keeps a running estimate of your current caffeine level using a five-hour half-life model. When a new drink is logged, the ViewModel first calculates the decayed value of the existing caffeine, adds the new amount, persists the new baseline, and restarts the live decay loop.
It also tracks intake over the previous 24 hours and maps it into Normal, Caution, and Warning bands. That makes the app feel less like a static log and more like a small decision aid: current level, recent total, source history, and safety context are all visible without digging through menus.
Implementation notes
- Built with Kotlin, Jetpack Compose, and Navigation Compose.
- Uses Android DataStore to persist caffeine state, source history, and intake history.
- Recomputes live caffeine decay every two seconds while the tracker is active.
- Includes undo flows for accidental logs and deleted sources through snackbar actions.
- Adds an analysis screen with two-hour histogram intervals over the last 24 hours.
What I focused on
This project was a good exercise in turning a simple scientific model into product state. The tricky part was not the half-life formula itself; it was making the estimate survive app restarts, handle undo/redo cleanly, and update the UI in a way that felt immediate without losing the underlying calculation.