The Android application is the original implementation of PunctuOwlity. It was built first, and the static web app was later created to reproduce the same interface and workflow in a browser. The Android source lives in theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/PunctuOwlity/llms.txt
Use this file to discover all available pages before exploring further.
android-fixed-source/ directory of the repository and contains a standard Gradle project targeting the com.example.punctuowlityeventtracker package. All application logic is written in Java; the project also declares Kotlin and Compose dependencies in build.gradle but the five screen-level classes are plain Java Activity subclasses backed by XML layouts.
Directory Structure
The key paths within the Android project are:Activity Classes
The application declares five activities inAndroidManifest.xml. LoginActivity carries the LAUNCHER intent filter and is the entry point; all other activities are exported="false".
LoginActivity — Launcher
The first screen the user sees. Reads the username and password fields, then calls
DatabaseHelper.checkUser(username, password). On success it starts MainActivity and calls finish() so the user cannot navigate back to the login screen. The “Sign Up” button starts SignupActivity without finishing the current activity.SignupActivity
Collects an email address (used as the username), a password, and a confirmation password. If the two password fields do not match, a toast is shown and no record is written. On a successful call to
DatabaseHelper.insertUser(), the activity shows a success toast, starts LoginActivity, and calls finish().SmsPermissionActivity
Presents two buttons: Allow SMS Notifications and No, thanks. The allow button calls
ActivityCompat.requestPermissions() for Manifest.permission.SEND_SMS if the permission has not already been granted. Both paths ultimately call goToMainActivity(), which starts MainActivity and finishes the current activity. The result of the permission dialog is handled in onRequestPermissionsResult(), which also calls goToMainActivity() regardless of whether the user granted or denied the permission.AddEventActivity
Serves as both the add and edit form. On
onCreate(), the activity checks getIntent().hasExtra("event_id"). If the extra is present, it retrieves the integer ID, loads the corresponding record with DatabaseHelper.getEventById(eventId), and pre-fills the title, date, and time fields. The save button calls db.insertEvent() for new records or db.updateEvent(eventId, …) for existing ones, shows a toast, and calls finish() to return to MainActivity. A back ImageButton also calls finish().MainActivity
The main events screen. Sets up a
DatabaseHelper instance and a reference to the GridLayout with id eventsGrid, then calls loadEvents(). The FAB (fabAddEvent) starts AddEventActivity with a plain intent (no extras) for the add-new-event flow. MainActivity also checks whether SEND_SMS permission has been granted; if not, it starts SmsPermissionActivity. onResume() calls loadEvents() again so the grid refreshes after returning from AddEventActivity.DatabaseHelper
DatabaseHelper extends SQLiteOpenHelper with database name punctuowlity.db and version 1. It exposes the following public methods used by the activities:
| Method | Used by | Description |
|---|---|---|
insertUser(username, password) | SignupActivity | Inserts a new row into users; returns false if the username already exists (UNIQUE constraint) |
checkUser(username, password) | LoginActivity | Queries users for a matching username + password pair; returns true if found |
insertEvent(title, date, time) | AddEventActivity | Inserts a new row into events |
updateEvent(id, title, date, time) | AddEventActivity | Updates an existing events row by primary key |
deleteEvent(id) | MainActivity | Deletes an events row by primary key |
getAllEvents() | MainActivity | Returns all rows as an ArrayList<Event> via SELECT * FROM events |
getEventById(id) | AddEventActivity | Returns a single Event for pre-filling the edit form, or null if not found |
Build Configuration
The project is configured inapp/build.gradle with the following settings:
| Setting | Value |
|---|---|
namespace | com.example.punctuowlityeventtracker |
compileSdk | 35 |
minSdk | 21 |
targetSdk | 35 |
versionCode | 1 |
versionName | "1.0" |
sourceCompatibility | JavaVersion.VERSION_11 |
targetCompatibility | JavaVersion.VERSION_11 |
Key Dependencies
gridlayout dependency provides the GridLayout widget used to render event cards in MainActivity. The Compose BOM and related libraries are declared but the current screen-level classes use traditional XML layouts, not Compose UI.
Permissions
AndroidManifest.xml declares one permission:
uses-feature is set to required="false" so the app is not filtered out of the Play Store for devices without telephony hardware (e.g. tablets). The runtime permission request is handled in SmsPermissionActivity.
Loading Events in MainActivity
TheloadEvents() method is the core rendering loop for the events grid. It clears the GridLayout, fetches all records from SQLite, inflates a CardView for each one, binds the data fields, and attaches edit and delete listeners.
event.getDayOfWeek() and event.getDateDay() calls are methods on the Event model class that parse the stored MM/dd/yyyy date string using SimpleDateFormat to produce the three-letter weekday abbreviation and the zero-padded day number respectively.
The
res/font/ directory contains 136 XML font reference files covering a wide selection of Google Fonts (ABeeZee, Abril Fatface, Aclonica, Acme, and many more). These are declared as downloadable font resources and referenced in AndroidManifest.xml via a preloaded_fonts metadata entry. The large font catalogue was included during the design exploration phase of the project and does not affect app size at build time because only the fonts actually referenced in layouts are bundled into the APK.