Заряд
Ваш собственный ресурс, а не батарея телефона. Четыре состояния, время между переключениями и картинка на рабочий стол.

Зачем этот экран
Приоритеты отвечают на вопрос «куда ушло время». Этот экран отвечает на другой: в каком состоянии оно уходило. Четыре часа работы на полном заряде и четыре часа на нуле — это разные четыре часа, и без второй величины первая обманывает.
Единица здесь не клик, а переключение. Вы отмечаете состояние, когда оно действительно изменилось; приложение считает время между отметками. Один тап утром описывает всё утро.
Что на экране
- Герой — большая батарея текущего состояния, его название и строка «Сегодня в этом состоянии — …». Сразу после первой отметки вместо времени стоит «Отсчёт пошёл».
- «Как вы сейчас» — четыре состояния подряд: «Полный заряд», «Средний», «На нуле», «Заряжаюсь». У каждого — расшифровка и время, набранное сегодня.
- «Сегодня» — полоса, разбитая по долям состояний за сутки. Появляется, когда за сегодня есть что делить.
- «Отметки за день» — лента из четырнадцати дней и список переключений выбранного дня: время, состояние и сколько оно продержалось.
- «Поставь заставку на рабочий стол» — генератор обоев.

Что означают четыре состояния
| Состояние | Смысл |
|---|---|
| Полный заряд | Есть силы на сложное. Беритесь за то, что требует головы. |
| Средний | Рабочее состояние. Тянете рутину, но не подвиги. |
| На нуле | Ресурс кончился. Всё, что делается, делается через силу. |
| Заряжаюсь | Восстанавливаетесь: сон, тишина, прогулка, ничегонеделание. |
«Заряжаюсь» — не четвёртый уровень шкалы, а другое измерение: это занятие, а не величина. Поэтому в средний заряд дня оно не входит вовсе (подробнее — в статистике).
Как этим пользоваться
Отметить состояние
Нажмите на нужную строку. Повторное нажатие на уже выбранное состояние ничего не делает — это не событие.
То же можно сделать с любой вкладки, нажав батарею в шапке: она стоит и на главном экране, и в статистике, и в навыках, и в настройках. Шторка там та же, и вопрос про расход из неё задаётся тоже.
Ответить, что посадило батарею
При переходе на «на нуле» появляется вопрос.

Одно касание — и ответ уходит в отдельную статистику («Что сажает батарею»). Ответ «Не знаю» — тоже ответ, он считается наравне с остальными.
Если энергию съело то, чего в приоритетах нет — дорога, чужая просьба, недосып, — напишите это в поле под списком и нажмите стрелку (или Enter). Ответ станет отдельной строкой в статистике, а одинаковые тексты сложатся в одну: «недосып», названный трижды, покажет «3 раза». Длина ограничена 40 знаками — это подпись строки, а не дневник.
Кнопка «Пропустить» три секунды заблокирована и показывает отсчёт: она появляется ровно там, где палец уже стоит после выбора «на нуле», и без паузы нажималась бы рефлекторно. Ответить можно сразу — задержка касается только пропуска.

Пока отсчёт идёт, шторку нельзя закрыть ни фоном, ни системной «назад» — иначе задержка на кнопке ничего не значила бы.
Дописать или исправить отметку
Классический случай: легли спать и забыли переключить на «Заряжаюсь» — вся ночь засчиталась как то состояние, в котором вы были вечером.
Выберите день в ленте «Отметки за день» и нажмите «Добавить отметку»: время и состояние. Всё, что было после неё, пересчитается само — отмечается момент переключения, а не отрезок, поэтому одна отметка в 23:00 чинит всю ночь.
Нажатие на существующую отметку открывает её же: можно передвинуть время, поменять состояние или удалить.
У сегодняшнего дня время ограничено текущей минутой: отметка — это «уже случилось», и пока в поле стоит время, которого ещё не было, «Сохранить» заперто. У прошедших дней предела нет — там наступили все минуты.
Над списком стоит строка «С начала суток — …»: она показывает состояние, перенесённое с прошлого дня. Без неё день, в котором ничего не переключали, выглядел бы пустым, хотя всё это время человек в каком-то состоянии был.
Причина «на нуле» переезжает вместе с отметкой, но исчезает, если поменять состояние: у полного заряда причины разряда быть не может.
Отметить ночь утром
Тот же классический случай, но не руками. Если с последней отметки прошло больше пяти часов, она не «Заряжаюсь», а на часах утро — приложение спрашивает про ночь само, при первом за день открытии.
В шторке две вещи: время, когда вы легли (в первый раз 23:00, дальше — ваш прошлый ответ на этом устройстве), и те же четыре состояния. Нажатие на состояние и есть сохранение: в обычное утро это одно касание.
Записываются две отметки: «Заряжаюсь» на время отхода ко сну и выбранное состояние на текущую минуту. Одной мало — без второй весь день до следующего касания считался бы сном.
Время разрешается относительно «сейчас»: больше текущего — это вчерашний вечер, меньше или равно — сегодняшняя ночь (легли в 01:30, встали в 7:00). Раньше последней существующей отметки время не встаёт: такая ничего не чинит, и пока в поле стоит она, состояния заперты.
Нажатие мимо шторки, свайп и системная «назад» закрывают её без единой записи, и до следующего утра она не возвращается. Отметка «сегодня уже спрашивали» локальная, на этом устройстве: настройки едут на все устройства, а «я утром отмахнулся» — событие этого телефона.
Сделать обои

Нажмите «Сделать обои с зарядом», выберите состояние и размер экрана. Подробности, включая три способа сохранения, — на странице «Обои с зарядом».
Пустое состояние

Пока не сделано ни одной отметки, батарея приглушена, а вместо времени стоит объяснение: отсчёт начнётся с первого выбора.
Пределы и предупреждения
- Отмечайте изменение, а не факт. Если вы отметили «полный заряд» утром и больше не трогали приложение, все сутки засчитаются как полный заряд — включая ночь.
- Состояние переходит через полночь: отметка в пятницу вечером без последующих изменений засчитывается и на субботу, и на воскресенье.
- Сегодняшний день считается только до текущего момента, вечер не начисляется авансом.
- Вопрос «что съело энергию» появляется, только если в списке есть хотя бы один приоритет: иначе это пустая модалка.
Чего здесь нельзя
- Отметить заряд глубже четырнадцати дней назад. Столько же, сколько у блоков: дальше уже не вспомнить.
- Отметить будущее. Лента предлагает только прошедшие дни и сегодня, а у сегодняшнего дня время в шторке кончается на текущей минуте.
- Задать длительность напрямую. Отмечается момент переключения; длительность всегда считается между соседними отметками.
- Добавить своё состояние. Их ровно четыре, и они зашиты.
- Посмотреть неделю или месяц. Здесь только сегодня; разборы — в статистике.
Рядом
Статистика · Обои с зарядом · Приоритеты
Как это работает внутри
- Экран —
src/screens/ChargeScreen.tsx. Уровни —BATTERY_LEVELS = [3, 2, 1, 4]вsrc/domain/types.ts; порядок именно такой, потому что это порядок показа, а числа — то, как состояние лежит в хранилище. - Хранится не состояние, а список переключений:
BatteryShift— это[минута_дня, уровень]либо[минута_дня, уровень, чем_посажен]. Третий элемент необязателен по типу, поэтому записи, сделанные до появления вопроса, читаются без миграции. - Правка списка смен — чистые
setShiftиremoveShiftвsrc/domain/battery.ts, покрытыеsrc/domain/battery.test.ts. Редьюсер (battery-set,battery-removeвsrc/store/useStore.tsx) только зовёт их и выкидывает опустевший день из журнала, чтобы он не считался днём «с отметками». - Повтор того же уровня отбрасывается в
setBattery, а не в редьюсере: это правило живого нажатия. Задним числом такая отметка бывает осмысленной — например, когда вечернее состояние надо явно продлить после ночной паузы. - Время между отметками считает
computeBatteryStats(src/domain/stats.ts). Она же переносит состояние через полночь (levelEnteringDay) и обрезает сегодняшний день поminuteOfDay(now). Строку «с начала суток» на экране даёт экспортированнаяlevelBeforeиз того же файла. - Текущий уровень — это
currentBatteryLevel: последняя отметка, которая уже наступила, а не последняя в журнале. Разница нужна для записей, сделанных до запрета будущего времени и приехавших с чужих часов: вечерняя отметка иначе объявлялась бы текущим состоянием с утра. - Запрет будущего стоит в двух местах: шторка не даёт сохранить время позже текущей минуты (
maxMinuteвsrc/components/BatteryShiftSheet.tsx), аsetBatteryAtподрезает минуту сегодняшнего дня по «сейчас». Второе — не дубль: через это действие идут и правка задним числом, и перенос времени, и правило не должно держаться на одном экране. - Часы экрана —
useNow(src/components/useNow.ts), тик на границе минуты и на возврате из фона. От них и «сегодня в этом состоянии», и хвост последней отметки, и предел времени, и сами сутки: до этого длительности считались от журнала и замирали до следующей записи, а открытый с вечера экран показывал утром вчерашние часы. - Утренний вопрос про ночь — чистые
nightAskиnightBedtimeвsrc/domain/battery.ts(правило показа и разбор времени, покрытыbattery.test.ts); шторка —src/components/NightSheet.tsx, отметка устройства —src/components/nightMemory.tsвmetaлокальной базы, рядом с сессией и идентификатором устройства. Сохранение зовётsetBatteryAtна время сна иsetBatteryна сейчас: новых путей записи не появилось. - Лента дней — общий
src/components/DayPicker.tsx. Он принимает предикатhasEntries, а не журнал: лента одна и та же для кликов и для заряда, а «непустой день» у них значит разное. - Ответ «что посадило» прикрепляется к последней отметке дня; если сегодня отметок ещё нет, действие уходит на ближайший предыдущий день с отметками (случай
drainтам же) — это случай «спросили в 23:59, ответили в 00:01». - «Не знаю» хранится как
DRAIN_UNKNOWN = '?', а не пустая строка: пустая была неотличима от «ответа нет» при сериализации и пропадала при перезагрузке. - Ответ своими словами хранится там же, с префиксом
DRAIN_TEXT_PREFIX = '!'(drainCustom/drainTextOfвsrc/domain/types.ts). Префикс, а не отдельное поле: id приоритетов состоят из букв и цифр, поэтому по первому знаку всегда видно, ссылка это или чужая причина. Предел —DRAIN_TEXT_MAX = 40, и разбор месяца режет длину повторно, потому что файл копии мог приехать чужим. - Смена заряда живого времени идёт через один
usePickBattery(src/components/BatteryPrompt.tsx), и вопрос задаётся там же. До этого он жил внутри экрана «Заряд», и та же смена на «на нуле» из батарейки в шапке проходила молча — статистика причин зависела от того, каким путём отметили состояние. - Задержка пропуска —
SKIP_DELAY_SECONDS = 3вsrc/components/DrainSheet.tsx.