More Projects
59 in totalAttendance Recorder (Android)
2023
Unfinished Android app for tracking class attendance — a Java/viewBinding project over a hand-written SQLiteOpenHelper with four tables, navigating between six activities by explicit intent while the generated nav graph sits untouched. Screens exist for user details, adding subjects and entering a recurring or one-off timetable; the method the app is named for, mark_present(), is declared with an empty body. The repo describes itself as "app under progress" and stopped there.
Every attendance app on the Play Store treats a course as one number. A timetable at Thapar does not work that way — lectures, tutorials and labs are counted separately, and the percentage that matters is the one per component. So the data model came first.
The other thing those apps get wrong is the question. Counting classes attended over classes held is a report on the past, and nobody opens an attendance app to read a report. The question is "can I skip Thursday", and answering it needs the classes that have not happened yet: the recurring timetable, the semester start and end dates, and the requirement you are being held to. That is a forward-looking calculation, and it is what shaped the schema.
Four tables and a pseudo-subject
database_manager extends SQLiteOpenHelper over attendance.db at version 1, and creates
four tables:
SUBJECTScarries the counters. Beyond name, code and the requirement, it holds a now/left/present triple for each of lectures, labs and tutorials, plus the aggregateTOTAL_NOW,ATTENDED_NOW,CLASSES_LEFTandLEAVES_AVAILAIBLE— seventeen columns, because a per-component percentage needs a per-component denominator.CLASSESis the timetable: subject name and code, time, day, L/T/P type, a repeat flag, location and a date. One table serves both recurring slots and one-off classes, which is why the repeat flag exists.HISTORYlogs each marked class as name, code, time, date and state, so the percentage is derivable rather than stored blind.USERholds the name, the semester code and the semester start and end dates. Those two dates are the whole reason "classes remaining" is computable.
There is one row in SUBJECTS that is not a subject. On first launch splash_screen_logo
inserts a subject called Overall with the code OVERALL, and every timetable write updates
twice — once against the real subject code, once against OVERALL — so the aggregate is
maintained by the same code path rather than recomputed by a scan. The cost is that every list
query has to hide it, which it does by skipping the first cursor row. The home screen then
reads its headline number straight out of that row.
Turning a semester into a class count
update_subject_overall is where the forward projection lives. get_days_between takes the
semester start, the semester end and a weekday, walks forward to the first occurrence and back
to the last with TemporalAdjusters, counts the weeks between them and adds one. Adding a
recurring Thursday lab therefore immediately credits the subject with every Thursday left in
the term. Leaves available comes out of the projected total, the requirement percentage and the
classes already missed.
Two things in that arithmetic are worth flagging. The day index written by the timetable screen
is matched in todays_classes against Calendar.DAY_OF_WEEK, where Sunday is 1, but read in
get_days_between as a java.time.DayOfWeek, where Monday is 1 — the two calendars disagree
by one. And the allowance is computed as projected total times the requirement, minus classes
missed, which is the number of classes you must attend rather than the number you may miss.
Everything runs off two threads
- A fixed two-thread
ExecutorServiceper worker class, each with its own single-method callback interface:thread_get_todays_class,thread_get_all_subjects, and three validation workers for user details, new subjects and timetable entries. - Validation runs on the worker too.
thread_verify_user_detailschecks the name against a Unicode-letter regex and the semester against empty, then writes the row and calls back with an error flag and a message — no exceptions crossing the boundary. - Callbacks land on the background thread, so each caller hops back itself; the home
fragment wraps its adapter setup in
runOnUiThread. - An
LruCachesingleton sized at 1024 entries holds the onboarding bitmaps under keyswlcm_bitmap1to3, written by a downloader and read by the slider. - Screens wired up: splash, welcome slider, home with a subject card list and a floating add
button, user details, add subject, add timetable, the last with separate recurring and
non-recurring entry fragments over a spinner, a day picker and a
TimePickerDialog. - Firebase is in the build (BoM 31.1.1) but only analytics is pulled in.
Where it stopped
The data layer is well ahead of the UI. mark_present() is declared on the database manager
and its body is empty — the one operation the app is named for was never written. onUpgrade
is likewise empty, so the version-1 schema had no way forward. Six activities are declared in
the manifest, and nav_graph.xml is still the Android Studio template pointing at a
FirstFragment and SecondFragment that do not exist in the source; navigation is all explicit
intents.
Some of the rest is the kind of thing you write at 2am and never revisit. home_page refreshes
by finishing and restarting its own activity in onRestart. isInternetAvailable shells out to
ping -c 1 google.com, and the splash screen gates the entire app on it, so a purely local
SQLite notebook shows "Server not availaible!" and stops when you are offline — while the
manifest never declares INTERNET at all, only ACCESS_WIFI_STATE, ACCESS_NETWORK_STATE and
a WRITE_INTERNAL_STORAGE permission that Android does not have. Every query is built by string
concatenation with no bound parameters, and todays_classes runs a fresh SUBJECTS lookup
inside the loop over today's classes. Roughly 2,500 lines across 24 Java files. Abandoned in
early 2023.