Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OfflineTodo

Android learning app that demonstrates offline-first architecture and data synchronization.

User actions always write to Room first. The UI observes Room only. A fake backend is updated later by WorkManager. There is no real HTTP server and no Retrofit.

Compose UI
    ↓
ViewModel  (StateFlow<TodoUiState>)
    ↓
Use cases → Repository
    ↓
Room  ←  Single Source of Truth
    ↓
TodoSyncWorker
    ↓
FakeRemoteDataSource

What you can do

  • Add, complete, and delete todos
  • Use the app with no internet
  • See local changes immediately
  • Watch pending rows sync when connectivity (real or simulated) returns
  • Force server success, server error, or slow responses from the Debug screen

Tech stack

Layer Library
Language Kotlin
UI Jetpack Compose, Material 3
Architecture MVVM
Async Coroutines, Flow
Local DB Room
DI Hilt
Background sync WorkManager
Network awareness ConnectivityManager / NetworkCallback

Primary color: #6200EE (Material Purple 500). Dynamic/wallpaper colors are disabled so the purple theme stays consistent.

Requirements

  • Android Studio that supports Android Gradle Plugin 9.3 (recent Otter / Narwhal or newer)
  • JDK 17 (Studio’s bundled JDK is fine)
  • Android SDK with compile SDK 37 installed
  • An emulator or device on API 24+

This project uses AGP 9’s built-in Kotlin. You do not apply org.jetbrains.kotlin.android yourself.

Setup

  1. Clone or copy the project and open the root folder (OfflineTodoApp) in Android Studio.
  2. Let Gradle sync. The first sync downloads the Gradle 9.5 wrapper and dependencies.
  3. If sync fails on Hilt / KSP:
    • Hilt 2.60.1 is required for AGP 9 (BaseExtension was removed in older Hilt plugins).
    • gradle.properties sets android.disallowKotlinSourceSets=false so KSP 2.2.x can register generated sources under built-in Kotlin.
  4. Create or select a virtual device (API 24 or higher).
  5. Run the app configuration (green Run button) or:
./gradlew :app:installDebug

On Windows use gradlew.bat.

How the data flow works

  1. The user adds, toggles, or deletes a todo.
  2. TodoRepository writes Room immediately with syncStatus = PENDING.
  3. Compose collects TodoDao.observeVisible() — the list updates without waiting on the network.
  4. SyncScheduler enqueues unique TodoSyncWorker work (NetworkType.CONNECTED).
  5. The worker calls FakeRemoteDataSource one pending row at a time:
    • Success: SYNCED, or a hard delete after a confirmed soft-delete
    • No network: rows stay PENDING, worker returns Result.retry()
    • Server error: row becomes FAILED (Retry on the row)

Sync is entity state, not an operation log. Offline “add A, then complete A” is still one row whose latest fields are pushed.

Deletes are soft (isDeleted = true) until the fake server confirms, then the row is removed from Room.

Debug lab

Open Debug in the top bar.

Control What it does
Network ON / OFF Fake API + the “Network:” banner. Does not toggle airplane mode.
Server Success Normal ~400 ms call
Server Error Marks the item Failed
Slow Response ~4 s delay
Sync logs In-app copy of TODO_CREATED, SYNC_* events

The banner is ONLINE only when the device radio and the simulator are both on.

Filter Logcat by tag OfflineTodo.

Scenarios to try

1. Add offline

  1. Debug → Network OFF
  2. Add Learn Kotlin — it appears as Pending
  3. Network ON — status becomes Synced

2. Several offline edits

  1. Network OFF
  2. Add A, add B, complete A, delete B
  3. Network ON — A is completed and synced; B is purged after the fake delete

3. Server failure

  1. Server Error
  2. Add a todo (or tap Sync) — status Failed
  3. Switch to Server Success, tap Retry

Project structure

app/src/main/java/com/offlinetodo/app/
├── data/
│   ├── local/          TodoEntity, TodoDao, TodoDatabase
│   ├── remote/         FakeRemoteDataSource, NetworkSimulator
│   └── repository/     TodoRepository
├── domain/
│   ├── model/          Todo, SyncStatus
│   └── usecase/        AddTodo, ToggleTodo, DeleteTodo, SyncTodos
├── presentation/       TodoScreen, TodoViewModel
│   ├── components/     Shared scaffold + gradient chrome
│   └── debug/          DebugScreen
├── worker/             TodoSyncWorker, SyncScheduler, SyncTrigger
├── di/                 AppModule
└── util/               ConnectivityObserver, AppLog

Theme

Light theme primary is #6200EE. Screens sit on a vertical purple gradient that fades into the surface color. Layout and actions (add, checkbox, delete, retry, Debug, Sync) are unchanged; the gradient is background only.

Build notes

./gradlew :app:assembleDebug

WorkManager is initialized through OfflineTodoApplication (Configuration.Provider + HiltWorkerFactory). The default WorkManager InitializationProvider is removed in the manifest so Hilt can inject TodoSyncWorker.

About

OfflineTodo is an Android lab app for offline-first todos. You add, complete, and delete items locally in Room (the UI always reads from the database), then WorkManager syncs pending changes to a fake backend when the network is back. A Debug screen lets you simulate offline, server errors, and slow responses.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages