Skip to content

zinovevvv/macCalendarWidget

Repository files navigation

macCalendarWidget

macOS виджет, показывающий три месяца сразу: предыдущий, текущий и следующий. Сегодняшняя дата выделена цветным кружком. Нажатие на виджет открывает стандартное приложение Календарь.


Почему собственный виджет / Why a custom widget

RU: В работе часто нужно быстро смотреть даты не только текущего месяца, но и соседних периодов: месяц назад, текущий месяц и месяц вперёд. Это нужно для планирования задач, сверки дедлайнов, отчётов, оплат, графиков и событий, которые обычно лежат на границе месяцев.

Готовые решения не закрывают этот сценарий:

  • Widget Wizard — показывает несколько месяцев, но только от текущего вперёд; предыдущий месяц недоступен.
  • Mini Calendar — ориентирован на один текущий месяц, не даёт компактный обзор «прошлый / текущий / следующий».
  • Calendarique — удобен как menu bar widget, но не предлагает нужный трёхмесячный вид в одном medium-виджете.
  • Dato — хороший menu bar calendar, но это не постоянный виджет на рабочем столе.

Поэтому — собственный MVP: компактный macOS-виджет macCalendarWidget, который занимает один medium-слот и сразу показывает предыдущий, текущий и следующий месяц с выделением сегодняшней даты.


EN: When working, it's often necessary to quickly check dates not just for the current month but for adjacent periods: the previous month, the current month, and the next month. This is needed for planning tasks, verifying deadlines, reports, payments, schedules, and events that typically span month boundaries.

Existing solutions don't cover this scenario well:

  • Widget Wizard — shows multiple months but only forward from the current one; the previous month is not available.
  • Mini Calendar — focused on a single current month, doesn't offer a compact "previous / current / next" overview.
  • Calendarique — great as a menu bar widget but doesn't provide the needed three-month view in a single medium widget.
  • Dato — a good menu bar calendar, but not a persistent desktop widget.

Hence this MVP: a compact macOS widget that fits in one medium slot and immediately shows the previous, current, and next month with today highlighted.


Скриншот

macCalendarWidget

Виджет появляется в Notification Center / на рабочем столе (macOS 14+):

  • Левая колонка — прошлый месяц (приглушённый)
  • Центральная — текущий месяц (акцентный цвет, жирный заголовок)
  • Правая колонка — следующий месяц (приглушённый)
  • Сегодня выделен кружком системного акцентного цвета

Быстрая установка (без Xcode) / Quick install (no Xcode needed)

RU: Если не хочется собирать самому — скачайте готовый .zip из раздела Releases.

EN: If you don't want to build from source — download the pre-built .zip from Releases.

RU — Шаги:

  1. Скачать macCalendarWidget.zip из Releases и распаковать
  2. Открыть Terminal в папке с macCalendarWidget.app
  3. Запустить скрипт установки:
    bash install.sh
  4. Если macOS заблокировал запуск → правый клик на app → Открыть → Открыть
  5. В меню-баре кликнуть на часы → Edit Widgets → найти Three Month Calendar → добавить (Medium)

EN — Steps:

  1. Download macCalendarWidget.zip from Releases and unzip it
  2. Open Terminal in the folder containing macCalendarWidget.app
  3. Run the install script:
    bash install.sh
  4. If macOS blocks launch → right-click the app → Open → Open
  5. Click the clock in the menu bar → Edit Widgets → find Three Month Calendar → add it (Medium)

Note / Примечание: The app is signed with a personal development certificate, not a paid Developer ID. macOS may show a Gatekeeper warning on first launch — this is expected. Right-click → Open bypasses it. No personal data is collected; the widget only reads the system calendar locale (no calendar events, no permissions requested).


Требования

Что Версия
macOS 14.0 Sonoma или новее
Xcode 15 или новее
xcodegen 2.x (устанавливается через Homebrew)
Apple Developer Account Бесплатный (Personal Team)

Структура проекта

macCalendarWidget/
├── project.yml                          ← спецификация для xcodegen
├── .gitignore
├── README.md
│
├── macCalendarWidget/                   ← основное приложение (контейнер)
│   ├── macCalendarWidgetApp.swift       ← @main, открывает Calendar при тапе на виджет
│   ├── ContentView.swift                ← окно-инструкция + onOpenURL handler
│   ├── macCalendarWidget.entitlements   ← App Sandbox
│   ├── Info.plist                       ← генерируется xcodegen
│   └── Assets.xcassets/
│
└── macCalendarWidgetWidgetExtension/    ← WidgetKit расширение
    ├── ThreeMonthWidget.swift           ← вся логика виджета
    ├── macCalendarWidgetWidgetExtension.entitlements  ← App Sandbox
    ├── Info.plist                       ← генерируется xcodegen
    └── Assets.xcassets/

.xcodeproj не хранится в репозитории — он генерируется из project.yml. Это стандартная практика при использовании xcodegen.


Деплой с нуля (пошагово)

1. Клонировать репозиторий

git clone <ваш-репо-url>
cd macCalendarWidget

2. Установить зависимости

brew install xcodegen

3. Поменять Team ID в project.yml

Откройте project.yml и замените ZSS72DMBEZ на свой Team ID в двух местах:

# macCalendarWidget target
DEVELOPMENT_TEAM: ZSS72DMBEZ   ← заменить

# macCalendarWidgetWidgetExtension target  
DEVELOPMENT_TEAM: ZSS72DMBEZ   ← заменить

Как найти свой Team ID:

security find-identity -v -p codesigning
# Вывод: "Apple Development: email@example.com (XXXXXXXXXX)"
#                                                ^^^^^^^^^^
#                                           это Team ID (10 символов)

Или в Xcode → Settings → Accounts → выбрать аккаунт → нажать на команду.

Также замените bundle ID prefix если нужно (по умолчанию com.zinovevvv):

options:
  bundleIdPrefix: com.yourname   ← поменять

И bundle ID в обоих таргетах:

PRODUCT_BUNDLE_IDENTIFIER: com.yourname.macCalendarWidget
# и
PRODUCT_BUNDLE_IDENTIFIER: com.yourname.macCalendarWidget.widgetExtension

4. Сгенерировать .xcodeproj

xcodegen generate

После этого в папке появится macCalendarWidget.xcodeproj.

5. Открыть в Xcode и настроить подпись

open macCalendarWidget.xcodeproj

В Xcode:

  1. Кликнуть на macCalendarWidget в Project Navigator (синяя иконка)
  2. Выбрать target macCalendarWidget → вкладка Signing & Capabilities
  3. Убедиться: ✓ Automatically manage signing, Team = ваш Apple ID
  4. То же самое для target macCalendarWidgetWidgetExtension

Если Xcode показывает жёлтый треугольник → нажать Fix Issue (он сам создаст provisioning profile).

6. Собрать и запустить

В Xcode нажать ⌘R (схема: macCalendarWidget).

Откроется окно приложения — это нормально, оно является контейнером для виджета.

7. Установить в /Applications (для постоянной работы виджета)

После успешного запуска через Xcode:

APP_SRC=$(find ~/Library/Developer/Xcode/DerivedData -name "macCalendarWidget.app" -path "*/Debug/*" | grep -v Index | head -1)
cp -Rf "$APP_SRC" /Applications/macCalendarWidget.app

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister \
  -f /Applications/macCalendarWidget.app

open /Applications/macCalendarWidget.app

8. Добавить виджет

  1. Кликнуть на часы в правом верхнем углу menubar → Edit Widgets
  2. Или: правый клик на рабочем столе → Edit Widgets
  3. Найти Three Month Calendar → добавить, выбрать размер Medium

Обновление виджета после изменений в коде

# 1. Пересобрать
xcodebuild -scheme macCalendarWidget -destination "platform=macOS" -configuration Debug clean build

# 2. Заменить приложение
pkill -f macCalendarWidget 2>/dev/null && sleep 1
APP_SRC=$(find ~/Library/Developer/Xcode/DerivedData -name "macCalendarWidget.app" -path "*/Debug/*" | grep -v Index | head -1)
rm -rf /Applications/macCalendarWidget.app
cp -Rf "$APP_SRC" /Applications/macCalendarWidget.app
open /Applications/macCalendarWidget.app

# 3. Удалить и добавить виджет заново (WidgetKit кэширует рендер)

Как работает

Архитектура

macCalendarWidget.app
└── macCalendarWidgetWidgetExtension.appex   ← WidgetKit extension
    └── ThreeMonthWidget.swift
        ├── CalendarProvider    ← TimelineProvider, обновляет в полночь
        ├── ThreeMonthCalendarView  ← HStack из трёх MonthView + Divider
        ├── MonthView           ← заголовок + сетка дней через HStack/VStack
        └── DayCell             ← одна ячейка, today = Circle(accentColor)

Ключевые решения

Почему нужен App Sandbox: WidgetKit daemon на macOS отказывается регистрировать расширения без entitlement com.apple.security.app-sandbox. Без него виджет компилируется, но не появляется в Edit Widgets.

Почему HStack вместо LazyVGrid: LazyVGrid внутри HStack с тремя frame(maxWidth: .infinity) колонками некорректно вычисляет ширину ячеек в WidgetKit — числа обрезаются в "...". Явные HStack на каждую строку недели дают гарантированно равные ячейки.

Почему приложение нужно копировать в /Applications: Запуск из DerivedData (временная папка Xcode) работает при разработке, но macOS не сканирует её при регистрации виджетов системой. Виджет появляется в Edit Widgets только если приложение находится в /Applications.

Открытие Calendar при тапе: Widget URL macCalendarWidget://openCalendar → macOS открывает основное приложение → onOpenURLNSWorkspace.shared.open(...) по bundle ID com.apple.iCal.

Timeline

Виджет обновляется один раз в сутки, в полночь (policy: .after(nextMidnight)). Данные — только системный Calendar.current, никаких сетевых запросов и permissions.


Troubleshooting

Проблема Причина Решение
Виджет не появляется в Edit Widgets Нет App Sandbox entitlement, или приложение не в /Applications Проверить entitlements, скопировать в /Applications, сделать lsregister
WidgetKit_Simulator.WidgetDocument.Error error 5 Запущена схема Extension, а не основное приложение; или нет подписи Переключить схему на macCalendarWidget, настроить Signing
Виджет не обновляется после пересборки WidgetKit кэширует рендер Удалить виджет и добавить заново
No signing certificate "Mac Development" found Неверный Team ID в project.yml Найти правильный ID через security find-identity и обновить project.yml + xcodegen generate
Числа обрезаются в "..." LazyVGrid неверно считает ширину в WidgetKit Использовать ручной HStack на каждую строку (уже исправлено)

Технологии

  • Swift 5 / SwiftUI
  • WidgetKit (macOS 14+)
  • xcodegen — генерация .xcodeproj из project.yml
  • Подпись: Apple Development certificate (Personal Team, бесплатно)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors