showwaiyan_

← home · all projects

Moment Quest

An Android app that turns personal challenges into memories, with a photo, a place and a timeline.

KotlinAndroidSQLiteCoroutines

Overview

Moment Quest is a native Android app I built on my own in Kotlin. You set yourself challenges (travel, learning, fitness and so on) and log spontaneous moments. When you complete a challenge, the app saves a memory with your notes, a photo and your location. Everything is stored on the phone, with SQLite for the data and files for the photos, and a timeline brings challenges and moments together.

At a glance

Platform
Android, Kotlin, minimum SDK 32
Architecture
Activities and fragments, ViewModels, repositories
Storage
SQLite database, photos saved as files
Async
Kotlin coroutines on the IO dispatcher
Location
Google Play Services fused location
Images
Glide

From challenge to memory

  1. Create a challenge
  2. Complete it with a note and photo
  3. One database transaction
  4. Memory saved with location
  5. Timeline and stats update

What it shows

  • Completing is one transaction. Marking a challenge completed and inserting its memory happen in a single SQLite transaction, so the two can never get out of step. A challenge can hold several memories, and deleting the last one puts it back to pending.
  • Two kinds of entry, one timeline. A sealed TimelineItem type merges challenges and moments into one list sorted by time. You can filter it by category and status, or search it.
  • Photos on disk, paths in the database. Photos are saved as JPEG files in the app storage and only the path is stored in the row. Deleting a moment removes the photo file first, and memories are deleted with their challenge through a cascading foreign key.
  • Location with a fallback. The location comes from the fused location provider and falls back to the GPS and network providers. Place names are looked up with the geocoder and cached in memory.
  • Stats by category. The stats screen shows total and completed challenges, the completion rate, and completed against total for each of six categories: Travel, Learning, Fitness, Social, Career and Others.
  • Usability testing built in. A small A/B test tool compares two ways of adding an entry, a full screen and a bottom sheet. It records the time taken, an ease rating from 1 to 5 and the error count for each participant, and shows the results in a dashboard.
  • Local first. Firebase was removed, so the app works fully on the device with no account and no network. A mock-data helper fills the app with sample entries for demos and leaves real data alone.

How it works

  1. Screens call ViewModels, and ViewModels call repository classes that run their database work on the IO dispatcher.
  2. The repositories read and write SQLite through a SQLiteOpenHelper, and save photos through a file storage helper.
  3. A new moment or memory asks for the last known location and attaches the coordinates.
  4. The timeline and stats ViewModels read the same data, so completing a challenge shows up in both.

Build it

Build the debug app (Android Studio or the Gradle wrapper)
./gradlew assembleDebug