Skip to content

olcayertas/prayer-time

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

58 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Namaz Vakti app icon

πŸ•Œ Namaz Vakti

Native macOS (menu bar) and iOS apps for Muslim prayer times β€” powered by the Turkish Directorate of Religious Affairs (Diyanet).

CI Platform Swift Concurrency Xcode SwiftUI Localization License: MIT


On macOS, Namaz Vakti lives in your menu bar with a live countdown to the next prayer and opens into a full window for more detail. On iOS, it's a tabbed app (Today / Monthly / Settings). Both are built from the same Core logic and the same SwiftUI views.

πŸ“Έ Screenshots

macOS

Menu bar Main window
macOS menu-bar dropdown β€” today's times with a live countdown macOS Today window β€” hero countdown and the six prayer times

iOS

Today Today (dark) Monthly Qibla Settings
Today β€” live countdown to the next prayer Today in dark mode Monthly β€” the cached month as a table Qibla finder β€” a live compass pointing toward the Kaaba Settings β€” location, notifications, and the Live Activity toggle

Lock Screen, Live Activity & Dynamic Island

The next-prayer Live Activity and a prayer-time notification, live on the Lock Screen:

Live Activity and a prayer-time notification on the iOS Lock Screen

Dynamic Island β€” the same Live Activity, compact / minimal / expanded (preview)

Dynamic Island previews: expanded, compact, and minimal

Lock Screen widgets β€” rectangular, circular, and inline accessory families (preview)

Lock Screen widget previews: rectangular, circular, and inline

The Dynamic Island and Lock Screen-widget images are previews β€” those surfaces don't render into headless Simulator captures (the Lock Screen shot above is a real-device capture).

✨ Features

  • Menu bar countdown β€” the next prayer with a live, jitter-free countdown (e.g. Afternoon 1:23:45).
  • Dropdown panel β€” today's six times with the next one highlighted, location, and the Gregorian + Hijri date.
  • Main window (macOS) β€” sidebar with Today (rich view), Monthly, and Settings. A Dock icon appears only while the window is open.
  • iOS app β€” the same Today / Monthly / Settings as a tab bar, with a responsive Today hero.
  • Monthly β€” a spacious Focus Card for one day over a compact month chart (each day a thin row, the six prayers as colored dots in equal columns); tap any day to promote it.
  • Home Screen widget β€” small / medium WidgetKit widget with the next prayer and a live countdown.
  • Lock Screen widgets (iOS) β€” rectangular, circular, and inline accessory families.
  • Dynamic Island & Live Activity (iOS) β€” a user-toggled next-prayer countdown in the Dynamic Island (compact / minimal / expanded) and on the Lock Screen.
  • Qibla finder (iOS) β€” a live compass that points to the Kaaba, using your location for a true-north bearing, with figure-8 calibration and a "facing the Qibla" cue (and haptic).
  • App icon β€” a flat crescent & star, shipped for both apps.
  • Notifications β€” optional local notifications at each prayer time.
  • Location β€” Automatic mode tracks your current city (reverse-geocoded to the nearest Diyanet district) or Pinned mode keeps a city you choose (country β†’ city β†’ district). Each location's month is cached, so revisiting one makes no extra request.
  • Localized β€” English, Turkish, and Arabic (right-to-left), including the app name and locale-aware Gregorian + Hijri dates. Adding a language β†’
  • Themes β€” a Default theme (the system look, auto light/dark) and a dark/gold Arc theme (with bundled Fraunces / Hanken Grotesk / Spline Sans Mono fonts), chosen in Settings β†’ Appearance and applied app-wide on both platforms.
  • Accessibility β€” full Dynamic Type scaling (including the hero countdown) and automatic dark mode.

πŸ“‹ Requirements

  • macOS 14 (Sonoma) or later, and/or iOS 17 or later
  • Xcode 26+ to build
  • XcodeGen β€” brew install xcodegen

πŸš€ Build & run

brew install xcodegen
xcodegen generate                       # regenerate NamazVakti.xcodeproj from project.yml
xcodebuild -scheme NamazVakti -destination 'platform=macOS' \
  -derivedDataPath build/DerivedData build
open build/DerivedData/Build/Products/Debug/NamazVakti.app

For iOS, build for the Simulator and launch it on a booted device:

xcodebuild -scheme NamazVaktiiOS -destination 'generic/platform=iOS Simulator' \
  -derivedDataPath build/DerivedData build
xcrun simctl install booted build/DerivedData/Build/Products/Debug-iphonesimulator/NamazVaktiiOS.app
xcrun simctl launch booted com.olcayertas.NamazVakti.iOS

Run the tests (pure schedule + decoding logic, no network):

xcodebuild test -scheme NamazVakti -destination 'platform=macOS' -derivedDataPath build/DerivedData

Uses local ad-hoc signing β€” no Apple Developer account required. Re-run xcodegen generate whenever you add or remove source files.

🧭 Data source

Prayer times come from the no-auth EzanVakti wrapper of Diyanet's published tables:

GET https://ezanvakti.emushaf.net/vakitler/{districtId}   # one call = a full month

The hierarchy endpoints (/ulkeler, /sehirler/{id}, /ilceler/{id}) drive the location picker. Everything goes through a PrayerTimesProvider protocol, so the official Diyanet AwqatSalah API can be dropped in later without touching the UI.

πŸ—οΈ Architecture

  • Sources/Core β€” UI-free, shared by every target: PrayerDay, PrayerSchedule (next-prayer math in Europe/Istanbul), PrayerCache, PrayerTimesProvider / PlacesProvider (EzanVakti), PrayerStore, NotificationScheduler, Qibla (great-circle bearing to the Kaaba β€” pure, so it's unit-tested without a device), LocationTracker (CoreLocation) + LocationResolver (reverse-geocode β†’ Diyanet district, with a pure, unit-tested Turkish-aware name matcher), and the shared Localizable.xcstrings.
  • Sources/Shared β€” cross-platform SwiftUI used by both apps: the Today / Settings views and the location picker; the Theme system (Theme/ThemeID/ThemeManager + \.theme environment + Default/Arc tokens) in Theme/; the redesigned Monthly (Monthly/ β€” MonthlyDay, DayRowLayout, MonthChart, the Focus Card) in MonthView; DateLocalizer; the Color.cardBackground shim; and the bundled Arc fonts in Fonts/.
  • Sources/App (macOS) β€” MenuBarExtra menu bar item + the MainWindowView sidebar shell.
  • Sources/iOS (iOS) β€” PrayerTimesApp entry point + RootTabView tab bar, and the Qibla compass (QiblaController wrapping CoreLocation heading/location + QiblaView). The compass is iOS-only β€” Macs have no magnetometer, so it's filtered out of the macOS sidebar.
  • Sources/Widget β€” WidgetKit timeline provider and views (Home Screen + iOS Lock Screen accessory families), built into both the macOS and iOS widget extensions.
  • Sources/LiveActivity (iOS) β€” the ActivityKit attributes and the Live Activity / Dynamic Island UI, shared by the iOS app and its widget.

Notable decisions

  • App Group (group.com.olcayertas.NamazVakti) β€” the app and widget share the selected district + cached month, so the widget follows your Automatic/Pinned location (not a fixed default). It degrades gracefully to per-process storage when the entitlement is absent, and a one-time migration carries over a district saved before the App Group existed.
  • Themes are a value-type token set in \.theme (Default = system semantics so it's pixel-identical to the un-themed look; Arc = fixed dark palette + bundled fonts, and forces .dark). The widget / Live Activity / Dynamic Island / menu-bar title can't read the runtime theme (separate processes / plain String), so they keep the system look.
  • Automatic location is Turkey-focused β€” it reverse-geocodes to a Diyanet (EzanVakti) district; outside TΓΌrkiye, or when permission is denied, it falls back to the pinned/default city.
  • Swift 6 language mode with complete strict concurrency. Networking is async/await (URLSession.data(from:)) behind a Sendable PrayerTimesProvider; the @MainActor PrayerStore awaits it from a cancellable Task, and a structured Task (not a GCD timer) drives the once-a-second countdown.
  • The menu bar uses a plain String title with monospaced digits: a rendered MenuBarExtra label hangs AppKit's status-item sizing on macOS 26. (This β€” not async/await β€” was the real cause of an earlier hang, so the data layer is free to use modern concurrency.)
  • Localized via String Catalogs (English source Β· Turkish Β· Arabic with RTL) β€” including the app/widget names and locale-aware Gregorian + Hijri dates. See docs/LOCALIZATION.md.

πŸ—ΊοΈ Roadmap

  • Official Diyanet AwqatSalah provider
  • Location-aware widget (per-widget configuration)
  • More languages β€” prioritized by Muslim population
  • Launch at login (macOS); localized Live Activity / Settings strings

πŸ“„ License

Released under the MIT License © 2026 Olcay Ertaş.

Prayer-time data © T.C. Diyanet İşleri Başkanlığı, accessed via the community EzanVakti service. This project is not affiliated with or endorsed by Diyanet.

About

Prayer time app for masOS

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors