A calm, offline-first Android app for students to run their whole term in one place: attendance, tasks, habits, and focus - tied together into a single "ecosystem" view. Built with Jetpack Compose, Room, Hilt, and DataStore. All data stays on the device.
- Daily routine grid with present / absent / no-class marking.
- Target percentage, "can I skip?" guidance, holidays and weekly-off handling.
- Location-based automatic marking (opt-in):
- Save class places by GPS or by picking on an OpenStreetMap map (no API key needed).
- Adjustable radius per place, rename, edit-on-map, and delete.
- One-tap "check in with location" on the Today screen (foreground, battery-friendly).
- Optional background geofencing that marks you present on arrival and notifies you.
- Optional per-subject matching, so a place only counts for its assigned subjects.
- Configurable late buffer with a "running late" reminder.
- Natural-language quick add (for example: "Essay tomorrow 5pm !high #History").
- Priorities, due dates and times, recurrence, subtasks, notes, and labels.
- Productivity stats (completed per day, streak) and per-subject filtering.
- Swipe to complete or archive, with undo.
- Daily rituals with streaks and a 12-week consistency heatmap.
- Deep-work timer with ambience, presets, and a daily focus goal.
- Pomodoro work / break cycles with a strict mode.
- Focus history plus a 12-week focus heatmap.
- Unified ecosystem health score and cross-pillar insights.
- Milestone celebrations, count-up numbers, and premium haptics.
- Daily digest and streak-at-risk notifications.
- Full custom theming, Material You, and per-section backgrounds.
- Local ".stk" backups: scheduled, integrity-hashed, optional AES-256 passphrase encryption, and reinstall-safe (stored in Downloads). Restore on first launch.
- JSON export / import and per-section resets.
- In-app over-the-air updates (see below).
Requirements: JDK 17 and the Android SDK (compileSdk 35, minSdk 26).
./gradlew :app:assembleDebug # debug APK
./gradlew :app:assembleRelease # signed release APK
Outputs land in app/build/outputs/apk/.
Release builds are signed with a dedicated key at signing/rollcall-release.jks
(kept out of git). The signing config reads env vars with local fallbacks:
RELEASE_STORE_FILE, RELEASE_STORE_PASSWORD, RELEASE_KEY_ALIAS, RELEASE_KEY_PASSWORD.
Keeping the same key across versions is what lets the OTA updater install over an old build.
The app checks for a newer build on launch and from Settings > App and updates.
Releases are automated: push a tag and GitHub Actions builds the signed APK, generates
update.json, and publishes a GitHub Release with both assets.
# 1. bump versionCode / versionName in app/build.gradle.kts
# 2. commit, then tag and push
git tag v1.1
git push origin v1.1
See docs/OTA_UPDATES.md for details, and the CI secrets it needs:
RELEASE_KEYSTORE_B64, RELEASE_STORE_PASSWORD, RELEASE_KEY_ALIAS, RELEASE_KEY_PASSWORD.
Everything is stored locally on the device. Location is used only for opt-in attendance marking and never leaves the phone. Map tiles are fetched from OpenStreetMap only when you open the map picker. Backups are written to local storage that you control.
Kotlin, Jetpack Compose, Room, Hilt, DataStore, WorkManager, Coil, osmdroid, Play Services Location.