Prayer Time Calendar Scheduler
A native macOS desktop app that fetches Islamic prayer times for any city worldwide and writes them straight into Google Calendar, with smart deduplication, an Islamic visual identity, and a self-contained .app bundle.
Prayer Time Calendar Scheduler is a standalone macOS app that removes the manual work from maintaining a prayer schedule in Google Calendar. The user picks a city or coordinates, sets a date range, and the app fetches accurate prayer times from the Aladhan API, rounds them to clean 5-minute slots, deduplicates against existing calendar events, and writes Fajr, Dhuhr, Asr, Maghrib, and Isha as 30-minute events with reminders, a chosen color, and the correct local timezone, directly into the user's Google Calendar.
The app works for any city in the world. Location can be detected automatically via macOS GPS, looked up by city name from a global offline database, searched by place name, or entered as raw coordinates. A full year of prayer events across 5 prayers is created in a few minutes from a single run.
It ships as a self-contained .app bundle via PyInstaller. No Python install, no Terminal, no dependencies to manage. The user double-clicks it like any native macOS app.
Worldwide prayer coverage
Aladhan API with the Muslim World League calculation method. Any city, any country, the same engine used across global Islamic apps.
Three location modes
Browse continent to country to major city offline, search any place name via OpenStreetMap, or enter raw coordinates. Auto-detect via macOS GPS with IP fallback.
Smart deduplication
Scans the calendar before writing. Exact matches are skipped, outdated events are replaced. Running the app twice is safe.
5-minute rounding
Prayer times are rounded to clean 5-minute slots with second-precision logic, keeping the calendar tidy and readable.
Reminders and colors
Seven reminder options and eleven Google Calendar event colors, applied consistently across all 5 prayers.
Self-contained .app
Packaged with PyInstaller into a double-clickable macOS bundle. No Python, no pip, no Terminal required.
The one-time Google Cloud Console setup, walked through end-to-end: creating a project, enabling the Calendar API, configuring Google Auth Platform, adding a test user, creating a Desktop OAuth client, downloading credentials.json, and importing it into the app. This matches the 7-step onboarding checklist built directly into the app's setup screen.
Pick a location
Browse offline from continent to country to city, search any place via OpenStreetMap, type coordinates directly, or auto-detect via macOS GPS with IP geolocation as fallback.
Set a date range and preferences
Use the quick range chips (3, 6, or 12 months) or open the styled date picker. Pick a target calendar, a reminder offset, and an event color. Preview mode shows a full event count without touching the calendar.
Create or update events
The app fetches prayer times, rounds them, dedupes against existing entries, and writes Fajr, Dhuhr, Asr, Maghrib, and Isha in batches of 50 via the Google Calendar API. The activity log streams progress in real time.
- Built as a single ~2,660 line Python file. No internal modules, no build pipeline beyond PyInstaller. Easy to audit, easy to rebuild.
- Non-blocking async model. Every network call runs in a QThread with Signal callbacks. The UI never freezes and progress streams to the activity log in real time.
- QStackedWidget navigation. Onboarding and the main app are two pages in a stack; the app transitions automatically once OAuth is verified.
- Credentials live in ~/Library/Application Support/Prayer Time Calendar Scheduler/. Tokens auto-refresh on expiry. The build script wipes this folder so every fresh .app starts at onboarding.
- Deduplication compares summary, start, end, timezone, color, and reminders. Exact matches are silently skipped, non-matching events are deleted before the new event is inserted.
- Batch API operations. Events are created and deleted in batches of 50 via service.new_batch_http_request(), with a configurable delay to stay within Google's rate limits.
- Midnight overflow fix. Prayer times at or after 23:57:30 would mathematically round past midnight; the rounding function caps output at 23:55:00 before adding to the base date.
- Islamic geometric sidebar. A QLinearGradient midnight background is tiled with a repeating 8-pointed Islamic star pattern (rub el hizb) rendered in gold via QPolygonF, pure vector geometry, no image assets.
- Arabic typography. Section headers carry Arabic counterparts (المكان, الجدول, التقويم, الإطلاق), the sidebar reads أوقات الصلاة, and workflow step badges use Eastern Arabic numerals (١ ٢ ٣ ٤).
- Custom restyled calendar popup: gold gradient header, Islamic green selected-day highlight, warm terracotta weekend columns, no grid lines, ivory background.
- PyInstaller spec collects PySide6, geonamescache, googleapiclient, certifi, and charset_normalizer; lists hidden imports for the Google auth stack and pyobjc; injects the icon and Info.plist keys including NSLocationWhenInUseUsageDescription.
- 143 automated checks cover syntax, all self.* attribute wiring, every selftest string, logic functions (rounding, time cleaning, event construction, deduplication, cache), credential validation, spec completeness, and build script integrity.
Full-stack native app from scratch
Not a web app in a browser shell, a genuine native macOS desktop application with custom-painted UI components, async threading, OAuth authentication, and a packaged binary. The full stack from data fetching to platform packaging is owned.
Islamic design as a first-class requirement
The visual identity was designed to feel authentically Muslim, not generically styled. The geometric star pattern, Arabic labels, Eastern Arabic numerals, gold palette, and crescent branding were each deliberate choices and required custom implementation via QPainter, Unicode, and custom widgets.
Production-quality UX thinking
Onboarding checklist, drag-and-drop credential import, contextual error messages with specific fix instructions for Google's OAuth access_denied, preview mode, smart deduplication, and the fresh-start credential wipe all reflect what happens when a real person actually uses the tool.
Packaging and distribution
Solving PyInstaller packaging for PySide6, including collecting Qt plugins, pyobjc binaries, geonamescache data files, and Google API discovery documents, and producing a signed double-clickable .app that just works is a non-trivial engineering task on its own.
