Native macOS (menu bar) and iOS apps for Muslim prayer times β powered by the Turkish Directorate of Religious Affairs (Diyanet).
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.
| Menu bar | Main window |
|---|---|
![]() |
![]() |
| Today | Today (dark) | Monthly | Qibla | Settings |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
The next-prayer Live Activity and a prayer-time notification, live on the Lock Screen:
Dynamic Island β the same Live Activity, compact / minimal / expanded (preview)
Lock Screen widgets β rectangular, circular, and inline accessory families (preview)
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).
- 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.
- macOS 14 (Sonoma) or later, and/or iOS 17 or later
- Xcode 26+ to build
- XcodeGen β
brew install xcodegen
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.appFor 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.iOSRun the tests (pure schedule + decoding logic, no network):
xcodebuild test -scheme NamazVakti -destination 'platform=macOS' -derivedDataPath build/DerivedDataUses local ad-hoc signing β no Apple Developer account required. Re-run
xcodegen generate whenever you add or remove source files.
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.
Sources/Coreβ UI-free, shared by every target:PrayerDay,PrayerSchedule(next-prayer math inEurope/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 sharedLocalizable.xcstrings.Sources/Sharedβ cross-platform SwiftUI used by both apps: the Today / Settings views and the location picker; theThemesystem (Theme/ThemeID/ThemeManager+\.themeenvironment + Default/Arc tokens) inTheme/; the redesigned Monthly (Monthly/βMonthlyDay,DayRowLayout,MonthChart, the Focus Card) inMonthView;DateLocalizer; theColor.cardBackgroundshim; and the bundled Arc fonts inFonts/.Sources/App(macOS) βMenuBarExtramenu bar item + theMainWindowViewsidebar shell.Sources/iOS(iOS) βPrayerTimesAppentry point +RootTabViewtab bar, and the Qibla compass (QiblaControllerwrapping 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.
- 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 aSendablePrayerTimesProvider; the@MainActorPrayerStoreawaits it from a cancellableTask, and a structuredTask(not a GCD timer) drives the once-a-second countdown. - The menu bar uses a plain
Stringtitle with monospaced digits: a renderedMenuBarExtralabel 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.
- Official Diyanet
AwqatSalahprovider - Location-aware widget (per-widget configuration)
- More languages β prioritized by Muslim population
- Launch at login (macOS); localized Live Activity / Settings strings
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.









