DEV Community

RithyTep
RithyTep

Posted on

Building a macOS Menu Bar App for the Khmer Lunisolar Calendar with SwiftUI

I recently built KhmerCalendarBar, a macOS menu bar app that displays the Cambodian Chhankitek lunisolar calendar. Here's what I learned.

Why

Cambodia uses a lunisolar calendar called Chhankitek alongside the Gregorian calendar. Public holidays like Khmer New Year, Pchum Ben, and Water Festival are determined by this system. I wanted quick access to Khmer dates without opening a browser.

The Stack

  • SwiftUI with MenuBarExtra (.window style)
  • Swift Package Manager — zero external dependencies
  • create-dmg for styled DMG installers

Architecture

The app uses a single CalendarViewModel (@MainActor, ObservableObject) that manages all state. Views are composable SwiftUI components:

KhmerCalendarBarApp
  └─ MenuBarExtra (popover)
       └─ PopoverContentView
            ├─ TodayHeaderView
            ├─ MonthNavigationView
            ├─ CalendarGridView
            ├─ HolidayListView
            ├─ YearOverviewView
            ├─ ClockView
            ├─ SettingsView
            └─ FooterView
Enter fullscreen mode Exit fullscreen mode

The Hard Part: Chhankitek Conversion

The Khmer lunisolar calendar is complex:

  • Months alternate between 29 and 30 days
  • Intercalary months (Adhikameas) are added periodically
  • The Buddhist era year differs from Gregorian by 543
  • Each year has an animal cycle (like Chinese zodiac but different)
  • Waxing and waning phases are tracked per day

The conversion engine maps Gregorian dates to Khmer dates including lunar day, month name, era year, and animal cycle.

Live Menu Bar Updates

The menu bar shows Khmer date + time. Two timers handle updates:

  1. Midnight timer — recalculates date at day change
  2. Minute timer — updates time display every 30 seconds

Key Takeaways

  1. MenuBarExtra with .window style gives you a proper popover
  2. @MainActor on the ViewModel prevents threading issues
  3. Timer-based updates need [weak self] to avoid retain cycles
  4. UNUserNotificationCenter requires explicit authorization on macOS
  5. create-dmg makes distribution easy without an Apple Developer account

Try It

Contributions welcome!

Top comments (0)