PriceLog (Android App)

Jetpack Compose purchase tracker with camera and backup support

A native Android app for logging purchases. Each item stores a name, price, notes, and a photo taken with the device camera. Data lives in a local Room (SQLite) database with a reactive list UI, and the entire database plus images can be exported to a ZIP file and restored later.

Download

PriceLog runs on Android devices. You can download the APK by clicking the button below:.

Download APK

Tech Stack

Kotlin
🎨Jetpack Compose
🗄️Room (SQLite)

Screenshots

Item list screenItem list screenItem list screenItem list screenItem list screenItem list screen

Item Tracking

  • Add items with name and price (in Riyals)
  • Reactive list that updates instantly via Kotlin Flow
  • Detail page with view and edit modes
  • Free-form notes per item
  • Delete with confirmation dialog

Camera & Images

  • Attach a photo to any item straight from the camera
  • Images stored in app-private storage via FileProvider
  • Placeholder image fallback for items without photos
  • Image files cleaned up when an item is deleted

Backup & Restore

  • Export database and all images into a single ZIP
  • WAL checkpoint before export for a consistent snapshot
  • User picks the save/open location via system file picker
  • Safe restore using a temp file swap, then app restart
  • Room auto-migrations across schema versions

App Architecture

Core Components

  • Room Database: Entity + DAO layer with Flow queries for reactive reads and suspend functions for writes
  • Navigation Compose: Two-screen NavHost (list → detail/{id}) passing the item ID as a route argument
  • ActivityResult APIs: TakePicture contract for the camera, CreateDocument and OpenDocument for backup files
  • Material 3 Theming: App-wide color scheme and typography from a shared AppTheme

Data Safety

  • Consistent Backups: Forces a full WAL checkpoint so the exported database file contains every committed write
  • Lock-Safe Restore: Writes the incoming database to a temp file first, since Room holds an open handle on the live one, then swaps and restarts cleanly