Skip to content

titeha/ShiftAlarm

Repository files navigation

Будильник работяги

Нишевый Android-будильник для сменщиков и вахтовиков: не «умный будильник», а надёжный инструмент для тех, у кого график не «5/2». Опора продукта — сменная работа (есть в любой стране), а не календарь конкретного государства.

  • applicationId / namespace: ru.titeha.shiftalarm
  • Стек: Kotlin + Jetpack Compose (Material 3), Room, минимум зависимостей.
  • Циферблат выбора времени — наш отдельный компонент AnalogTimePicker (подключён с JitPack).

Возможности

  • Надёжный звонок через AlarmManager.setAlarmClock — переживает Doze, показывает системную иконку будущего сигнала (тап по ней открывает наш экран); перепланирование после перезагрузки, обновления приложения, смены времени/часового пояса и выдачи разрешения на точные будильники (SystemRescheduleActions). Сигнал играет foreground-сервис независимо от UI; заглушить можно с полноэкранного экрана «Стоп», кнопкой в уведомлении или смахиванием. Вибрация — запасной сигнал. Проверка готовности (разрешения) и диагностический журнал событий — см. docs/.
  • Обработчик «Показать будильники» (ACTION_SHOW_ALARMS) — приложение можно назначить для показа списка будильников (виджеты часов, Ассистент). Полной замены системных часов на Android нет, это ближайшая штатная «имитация».
  • Несколько будильников, каждый включается/выключается отдельно.
  • Режим «по дням недели» — выбор дней чекбоксами; пустой набор = разовый будильник (с опцией «удалить после срабатывания»).
  • Режим «смены» — графики-ротации (пресеты 2/2, сутки/трое, утро/день/ночь…). Цикл привязан к опорной дате; в рабочие слоты — звонок, в выходные — тишина.
  • Редактор произвольного цикла — пресеты как шаблоны плюс «Свой цикл»: для каждого дня отдельно задаётся тип (Утро/День/Ночь/Выходной — для цвета в календаре) и будильник (вкл/выкл + время). Тип и звонок независимы: ночь можно показать без будильника, а выходной — со звонком. Цикл хранится в alarms.cycleSpec (сериализация — ShiftCycleCodec).
  • Календарь смен — наглядная цветная сетка месяца (утро/день/ночь/выходной/отпуск), точка на днях со звонком, листание по месяцам. Ночная смена через полночь показывается на сутках отработки, а звонок — вечером предыдущего дня.
  • Правки календаря (подмены) — тап по дню в календаре → сделать день Утро/День/Ночь/Выходной или «вернуть по графику». Режим «Диапазон»: тап начала + тап конца → правка на весь блок (сдать рабочий блок пакетом или отработать выходные). Так меняешь отдельные дни, не трогая цикл. Правки хранятся в таблице alarm_overrides (один день → исключение, диапазон → подмена; раскладка по приоритетам движка — ScheduleOverrides). Для ночных смен «Выходной» на одиночной ночи делает умную отмену: снимает звонок, будивший на эту ночь (он на предыдущем дне), сохраняя звонок на следующую (ScheduleOverrides.cancelNight).
  • Периоды без будильника с типом (отпуск / больничный / отгул / за свой счёт) — на эти дни звонок выключается, в календаре период красится по типу (зелёный / болотный / бирюзовый / сиреневый). Тип выбирается чипами; хранится в колонке reason (PeriodKind, без миграции). Период можно завести и из календаря (тап по дню/диапазону → тип периода), и отдельным блоком «+ Период». Больничный внутри отпуска продлевает отпуск на число дней болезни (ТК РФ, VacationSick; правило РФ — в перспективе настраиваемое в региональном модуле).
  • Учёт праздников (производственный календарь) — тумблер «Учитывать праздники» + полярность: по рабочим (глушить звонок в праздники/выходные/переносы) или по выходным (будить в выходные и праздники — чтобы не залёживаться). Движок: ProductionCalendar (статус дня), AlarmPolarity/HolidayAlarms. Данные тянутся с официального источника (isDayOff.ru) в локальный кэш с оффлайн-fallback на встроенный РФ-2026; звонок от сети не зависит (docs/HOLIDAY_CALENDAR_SOURCE.md). Мультистрана и выбор страны — впереди. Ввод периода двумя способами: диапазоном дат или «с даты на N дней».

Отпуск и фаза цикла

Период отпуска глушит звонок. Что происходит с фазой сменного цикла после возвращения — задаётся переключателем «Заморозить цикл на время отпуска»:

  • выключено (по умолчанию) — цикл крутится по календарю: ротация под низом идёт своим чередом, после отпуска выходишь на ту смену, что приходится «по графику»;
  • включено — цикл замораживается: отпускные дни не считаются, после отпуска продолжаешь с той же смены, на которой ушёл (для индивидуального отсчёта / вахты).

Архитектура

Чистая логика отделена от Android — её легко покрывать юнит-тестами.

Слой Где Что
UI ui/, MainActivity Список будильников и редактор (Compose).
Данные data/ Room: AlarmEntity, AlarmPeriod, AlarmOverride (+ DAO, AlarmRepository).
Движок расписания schedule/ Чистый ShiftEngine (резолв смены/звонка на дату, отпуска, режимы цикла) и AlarmTimes (мост для одного будильника). Без Android и I/O.
Планирование alarm/ AlarmScheduler (AlarmManager), AlarmReceiver (срабатывание + перепланирование), BootReceiver, AlarmService + AlarmActivity (экран звонка).

Приоритет резолва смены на дату: исключение > временная подмена > период отпуска > базовая ротация. Юнит-тесты движка — app/src/test/.../schedule/.

Сборка и запуск

Требуется JDK 21 (подойдёт JBR от Android Studio). На этой машине:

JAVA_HOME="C:\Program Files\Android\Android Studio\jbr" \
GRADLE_USER_HOME="H:\gradlecache" \
./gradlew.bat testDebugUnitTest assembleDebug --console=plain

GRADLE_USER_HOME важен: без него тест-форк падает на кириллическом пути пользователя.

Готовый APK: app/build/outputs/apk/debug/app-debug.apk.

Инструментальный тест миграции БД (нужен подключённый телефон/устройство, не эмулятор):

./gradlew.bat :app:connectedDebugAndroidTest \
  -Pandroid.testInstrumentationRunnerArguments.class=ru.titeha.shiftalarm.data.AppDatabaseMigrationTest

Стек и версии

  • compileSdk / targetSdk 36, minSdk 26, JVM 21.
  • Jetpack Compose (Material 3), Room (через KSP), DataStore.
  • Компонент com.github.titeha:AnalogPickerPlayground (версия — в gradle/libs.versions.toml).

Статус

Приложение предрелизное. Известные пред-релизные TODO закрыты; фича «отпуск» (периоды без будильника) доведена до конца, включая превью «след:» в списке.

Миграции БД — настоящие (без пересоздания): схемы версий экспортируются в app/schemas/, переходы покрыты инструментальным тестом миграции (AppDatabaseMigrationTest).

Планы (следующие итерации): производственный календарь праздников как отдельный платный модуль по странам (РФ → Казахстан → …), локализация (en, kk). Подмены по дню и диапазоном в UI — уже есть (см. «Правки календаря»). Идея на потом — «детский»/школьный профиль (учебная неделя + каникулы как периоды без звонка).

About

«Будильник работяги» — будильник для сменных графиков (2/2, сутки/трое, утро-день-ночь) и обычные разовые/повторяющиеся будильники. Android, Jetpack Compose.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages