Inspiration

Screen-time dashboards show you a number and a guilty feeling. Hard blockers work until the first time you genuinely need the app — then you switch them off for good. I wanted something in between: a reason to stay away that feels good, and an honest way back in that doesn't break the habit.

What it does

QuestLog flips the screen-time tracker around: instead of scolding you for time spent, it rewards the time you didn't spend. Pick your distracting apps (with optional daily allowances), and every minute you stay off them earns XP and gold.

  • Build a city — gold buys buildings for your realm: Market, Library, Zen Garden and more.
  • Daily quests and streaks — three fresh quests a day, and a streak that multiplies your rewards.
  • Mindful Unlocks — need the app anyway? Type why. A small AI judgment model (TypeSafe) checks whether it's a real task. If it is, you get five minutes that don't count against you. Just bored? It tells you honestly and still lets you in. No lectures, no blocking, and what you typed is never stored.
  • Progress — all-time time reclaimed, best day, level and a 7-day chart.
  • Share your skyline — a card of your city and the hours you've taken back.

How RevenueCat powers it

  • QuestLog Pro is a RevenueCat subscription: double XP and gold, a weekly Streak Freeze, unlimited Mindful Unlocks (free players get one a day) and two exclusive buildings.
  • Offer-driven paywall — price and trial text come live from the current RevenueCat Offering, so pricing and trial experiments are dashboard-only changes.
  • The trial appears when it's earned — the first time a free player reaches a 7-day streak, the paywall slides up once with a 1-week free trial. Trial eligibility comes from Google Play, so ineligible users never see false "free trial" copy.
  • Safe entitlement handling — "Pro status unknown" is treated differently from "free", so a paying user on a slow cold start never sees a paywall.

How I built it

  • Kotlin Multiplatform core with all the domain logic, plus a Jetpack Compose Android UI.
  • Room (KMP) with versioned, tested migrations; Koin for DI; MVI-style ViewModels.
  • Screen time comes from Android's UsageStatsManager, and stays on the device.
  • Idempotent reward accounting — a daily high-water mark means rewards are never double-counted, however often the tracker ticks.
  • A Cloudflare Worker proxy for the AI call: the API key never ships in the app, with per-install rate limiting and request-size limits.
  • 228 automated tests run in CI on every change.

Challenges I ran into

  • Making rewards fair: an app blocked at any point today keeps counting until midnight, so unblocking can't game the reward, and allowances only charge overage.
  • Keeping the AI useful without being preachy — the verdict is typed (purposeful or not, and what kind of task), and it never blocks you.
  • Google Play's new-account rule: a closed test with 12 testers for 14 days before production. QuestLog is complete and in closed testing, and I'm recruiting testers to go public.

Accomplishments I'm proud of

A calm, single-accent editorial design; a skyline realm that grows as you scroll less; and a paywall that shows up at a moment of pride (your first 7-day streak) instead of as a nag.

What I learned

How to design entitlement logic that fails safe, how to run AI as a small decision-maker rather than a chatbot, and everything involved in shipping a real app to Google Play.

What's next

  • Public launch on Google Play once the closed test completes.
  • iOS — the Kotlin Multiplatform core is already shared; the UI is the remaining work.
  • RevenueCat Experiments on trial length and price.
  • More buildings and seasonal quests.

Built With

  • android
  • cloudflare-workers
  • jetpack-compose
  • koin
  • kotlin
  • kotlin-multiplatform
  • revenuecat
  • room
  • sqlite
  • typesafe
Share this project:

Updates

Submission history