StudySphere
Offline-first Android planner for attendance, lectures, and assignments.
Year
2025
Status
Released — APK available
Stack
Kotlin · Jetpack Compose · Room · DataStore · Material 3 · Android
Problem
Attendance defaulter status in Indian engineering colleges has two thresholds. Below 75% triggers mandatory compensatory assignments. Below 50% — critical defaulter — means disqualification from semester examinations. I was sitting just above 50% with no reliable way to track which subjects were safe, which were recoverable, and which were approaching the line. The college portal had a two-day update lag. My mental model was clearly not working.
Why it matters
The information needed to manage attendance is a ratio — but spread across six or seven subjects, each with a different minimum target, different lecture frequency, and different remaining classes. The cognitive load of maintaining this manually while tracking assignment deadlines is high enough that most students don't do it correctly. The consequence ranges from unnecessary extra work to exam disqualification.
Approach
Built the tool I needed. The core logic is the attendance recovery model: for each subject, the app calculates not just the current percentage but how many consecutive classes you can still skip and remain safe, and how many you must attend consecutively to recover from an unsafe position. This converts a ratio into an actionable number. Risk labels — Safe, Warning, Danger, Critical — surface the same information visually at a glance. The two questions I was asking every morning defined the entire feature set: am I safe, and what's due today.
Architecture
Kotlin + Jetpack Compose + Material 3. Room Database for all local persistence — subjects, lecture slots, attendance records, assignments. DataStore Preferences for user settings and theme state. Navigation Compose for screen routing. Kotlin Coroutines + Flow for reactive UI updates — Room queries return Flow, ViewModel collects them, Compose recomposes automatically on any data change. No network calls, no account, no sync. Everything stored locally on-device. The attendance calculation logic lives in the repository layer as pure functions: current attended over total held, projected percentage with remaining lectures, can-skip-N and must-attend-N recovery calculations, risk threshold evaluation.
System flow
Create subject with minimum attendance target→Add recurring lecture slots→Mark attendance daily (Present / Absent / Cancelled)→App recalculates recovery figures in real time→Dashboard shows risk label per subject→Add assignment with due date and priority→Overdue assignments highlighted automatically
Execution Context
I'm a full-stack web developer — TypeScript and React are my primary environment. Kotlin and Jetpack Compose were new territory, learned during the build while covering semester coursework simultaneously. The constraint — learning a new stack while actively needing the tool I was building — kept the scope honest.
Tradeoffs
No cloud sync by design — the absence of a network layer removes a failure surface and a privacy surface simultaneously. The recovery calculation assumes lectures are scheduled at fixed intervals, which doesn't account for cancelled or rescheduled classes mid-semester. This is tracked manually, which is a UX limitation worth addressing in a future release.
Learnings
Building something because you genuinely need it produces different quality decisions than building it as an exercise. Every feature exists because I specifically needed it. The features that aren't there — cloud sync, social features, shared timetables — aren't absent because I couldn't build them. The attendance recovery logic was the feature I was most careful about getting exactly right, because I was going to rely on it.