Перейти к основному содержанию

Lists: список дел, который хранится у вас

11 October 2026

Пока все мои устройства были от Apple, список дел я вёл в Things . Это красивое и удобное приложение, и менять его я не собирался.

Потом телефон сменился на Android, а приложения для Android у Things нет. Я перепробовал замены: TickTick, 2Do и многие другие. Ни одна не прижилась.

В итоге я сделал свой список дел: с помощью Claude написал Lists . Возможности взяты у 2Do, внешний вид у Things. Данные лежат на устройстве, а синхронизируются через хранилище, которое у вас уже есть: каталог WebDAV или сервер CalDAV.

Представление «Сегодня» в Lists на macOS

Что получилось

Lists состоит из трёх частей: приложение для macOS, приложение для Android и веб-интерфейс, который ставится на свой сервер. Все три работают с одними данными и умеют одно и то же; где платформа отличается, это описано в руководстве1.

Учётной записи нет, и подписываться не на что. Приложение полностью работает без сети и без настроенной синхронизации: правка сразу записывается на устройстве, а до остальных доходит, когда появится связь.

Интерфейс английский и русский, язык берётся из системы. Оформление светлое и тёмное, по умолчанию как в системе.

Задачи

Обязательно у задачи только название. Остальное добавляется по мере надобности:

  • заметка в Markdown;
  • дата начала и срок, день или день со временем;
  • приоритет и теги;
  • повтор и напоминание;
  • вложения и подзадачи.

Даты хранятся без часового пояса: «завтра в 9:00» останется девятью утра и после перелёта. Задача с датой начала в будущем не показывается в «Сегодня», пока этот день не наступит.

Список с открытой карточкой задачи: заметка, срок, приоритет, тег, файл и подзадачи

Заметки. Markdown оформляется прямо при наборе, отдельного режима просмотра нет. Знаки разметки скрыты везде, кроме абзаца, в котором стоит курсор. Чекбоксы - [ ] переключаются щелчком, таблицы рисуются сеткой, ссылки открываются. Хранится заметка так, как набрана, поэтому поиск и CalDAV видят обычный текст.

Вложения. К задаче прикладывается любое число файлов. Скачанный файл открывается без сети. Изображения и PDF показываются внутри приложения, остальное открывается в программе по умолчанию. Файл можно сохранить наружу или передать в другое приложение.

Подзадачи и проекты. Подзадача — это строка с отметкой и названием, своих дат и заметок у неё нет. Когда нужно больше, задачу можно сделать проектом. Проект появляется в боковой панели со счётчиком «сделано/всего», а его задачи полноценные, со всеми полями и своими подзадачами.

Повторы. Готовые варианты: каждый день, по будням, раз в неделю, раз в две недели, раз в месяц, раз в квартал, раз в год. Своё правило повторяет задачу каждые N дней, недель, месяцев или лет, по выбранным дням недели или, например, в последнюю пятницу месяца. Отсчёт идёт от срока или от дня, когда задача выполнена. Правило заканчивается после N повторов, в назначенный день или не заканчивается вовсе.

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

Отмена. Выполненная задача не исчезает сразу: несколько секунд она стоит на месте зачёркнутой, и её можно вернуть. Удаление отменяется, удалённое лежит в корзине, пока её не очистят вручную.

Кроме списков, есть постоянные представления: «Входящие», «Сегодня», «Предстоящие», «Все», «Выполненные», «Не буду делать» и «Корзина». Сохранённые фильтры собирают задачи из разных списков по сроку, спискам, тегам, приоритету, состоянию и словам в тексте. Поиск идёт по названиям и заметкам во всех списках.

Быстрый ввод

Задача должна записываться быстрее, чем забывается. Для этого хватает одной строки:

купить молоко завтра 18:30 !! #дом @Покупки

Получится задача «купить молоко» со сроком на завтра в 18:30, средним приоритетом и тегом «дом» в списке «Покупки». Даты понимаются на русском и английском. То, что приложение распознало, оно показывает плашками до сохранения, а распознавание можно выключить.

Мест, откуда задачу можно добавить, много:

  • macOS: ⌘N в основном окне, окно поверх любой программы по ⌃⌥Пробел, значок в строке меню со списком задач на сегодня, «Поделиться», меню «Службы» и адрес lists://add?text=…;
  • Android: кнопка «+», «Поделиться», меню выделенного текста, ярлык на значке приложения, плитка быстрых настроек и виджеты;
  • веб: поле «Новая задача» в списке.

Окно быстрого ввода на macOS: заметка начата с текста из буфера обмена

Окно быстрого ввода начинает заметку с содержимого буфера обмена. Скопировали ссылку, нажали клавишу, набрали название — ссылка уже в заметке. Каждая копия используется один раз, а то, что менеджер паролей пометил скрытым, приложение не читает.

Android

На телефоне Lists выглядит так же, как на Mac, насколько это позволяет экран: крупное название представления, задача в одну строку, карточка задачи выезжает снизу.

Смахивание вправо выполняет задачу, влево открывает выбор срока. Долгое нажатие открывает меню, а из него включается выбор нескольких задач: их можно разом выполнить, перенести или удалить, и всё действие отменяется одной кнопкой.

На главный экран ставятся два виджета, 2×2 и 4×4. Каждый показывает «Сегодня», «Входящие» или выбранный список, и задачу можно отметить прямо в нём. В шторке можно держать постоянное уведомление с задачами на сегодня и кнопкой «Новая задача».

Напоминания настраиваются на каждом устройстве отдельно: за сколько предупреждать о сроке, в котором часу напоминать о задачах на день, присылать ли сводку дня. И на Android, и на macOS в «Сегодня» можно показать события дня из календарей устройства. Они только читаются и никуда не отправляются.

Синхронизация

Это главная часть приложения. Своего сервера у Lists нет. Устройства обмениваются изменениями через хранилище, от которого нужно только читать, писать, перечислять и удалять файлы. Хранилищ три вида:

ВидЧто лежит в хранилищеКогда выбирать
WebDAVжурнал изменений приложения, передаётся всёлюбой сервер WebDAV, в том числе Nextcloud
Папкато же самоекаталог, который синхронизирует другая программа: Syncthing, iCloud Drive
CalDAVпо одному VTODO на задачу, календарь на списокзадачи должны быть видны и в других клиентах CalDAV

Папку умеют приложение для macOS и веб-сервер, на Android этого вида нет.

Как сливаются правки. Каждое поле каждой задачи хранится отдельно и несёт метку времени. Если на телефоне изменили срок, а на компьютере в это время дописали заметку, сохранятся обе правки. Если на двух устройствах изменили одно и то же поле, побеждает более поздняя правка. Итог не зависит от того, в каком порядке изменения дошли: два устройства с одинаковым набором изменений показывают одно и то же2.

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

CalDAV. Здесь списки становятся календарями, а задачи обычными VTODO, так что их видят Tasks.org, DAVx5 и другие клиенты. Всё, чего в стандарте нет, Lists кладёт в собственное свойство рядом со стандартными. Правки, сделанные в других клиентах, подхватываются, а их свойства сохраняются. Ограничения такие: общие настройки через CalDAV не передаются, вложения ограничены 5 МБ на файл и 20 МБ на задачу. Сервер, который вырезает неизвестные свойства, оставит от задачи только стандартные поля3.

Когда запускается. После правки на устройстве синхронизация идёт через две секунды тишины. Пока приложение открыто, она повторяется раз в минуту и ещё раз при возврате в приложение. На Android запуск после правки отдан системе, поэтому изменение уйдёт, даже если приложение сразу закрыли, а без сети дождётся её появления. Там же синхронизация идёт в фоне раз в 15 минут. Сбой сети ничего не теряет, ошибка синхронизации работе не мешает.

Если подключить к непустому хранилищу устройство, на котором уже есть задачи, приложение спросит, что оставить: слить обе стороны, взять данные хранилища или заменить хранилище данными устройства.

Быстрая доставка

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

Lists сокращает это ожидание уведомлениями. Устройство, которое выгрузило изменения, просит остальные синхронизироваться, и они делают это за несколько секунд. В проекте такой запрос называется толчком.

Данных толчок не несёт. В нём одно слово, sync, а задачи по-прежнему идут через ваше хранилище.

Настраивается это так:

  • macOS и веб-сервер получают толчки через сервер ntfy , общий https://ntfy.sh или свой. Адрес задаётся в настройках синхронизации, у веб-сервера — в переменной LISTS_PUSH_SERVER.
  • Android получает толчки через UnifiedPush . На телефон ставится приложение-распространитель, например ntfy, и в настройках синхронизации Lists включается «Синхронизировать сразу после правки на другом устройстве». Работает это и при закрытом приложении.

Об адресах устройства договариваются сами, через то же хранилище: каждое публикует там, куда ему слать толчок. Mac и веб-сервер, которые пользуются одним сервером ntfy, слушают одну тему со случайным именем из 32 знаков, и один запрос будит всех. Телефон остаётся при адресе, который выдал распространитель.

На сервере без входа имя темы — единственная защита. Сервер ntfy при этом видит, когда вы что-то правили, но не видит, что именно. Для своего сервера ntfy с закрытым доступом Lists принимает токен; он хранится в связке ключей macOS или шифруется ключом из Android Keystore.

Толчок необязателен. Запросы уходят уже после синхронизации и её не задерживают, а потерянный толчок означает только то, что изменение придёт по расписанию. При проверке на эмуляторе задача, добавленная на другом устройстве, дошла до телефона с убитым процессом приложения примерно за три секунды4.

Телефон, который ограничивает фоновую работу, такие запуски откладывает. В настройках синхронизации Lists показывает, ограничено ли приложение, и предлагает снять ограничение батареи; то же стоит сделать для приложения ntfy.

Веб-интерфейс

Приложения для iOS нет, и вместо него сделан веб-интерфейс. Чисто браузерным он быть не может: серверы WebDAV и CalDAV не разрешают запросы с чужих страниц. Поэтому вместе с ним идёт небольшой сервер lists-web. Для остальных это ещё одно устройство: он держит свою копию данных и синхронизируется наравне с приложениями.

Веб-интерфейс Lists: список с открытой карточкой задачи

Сохранённый фильтр в веб-интерфейсе Lists

Запускается он одной командой:

docker run -d --name lists \
  -p 8080:8080 \
  -v lists-data:/data \
  -e LISTS_WEB_PASSWORD='придумайте пароль' \
  ghcr.io/juev/lists:0.2.0

Образ собран для amd64 и arm64. Вход по паролю или через OpenID Connect, синхронизация задаётся переменными окружения. Страница рассчитана и на телефон, её можно добавить на экран «Домой». Сервер сделан для одного человека: все, кто вошёл, видят одни и те же данные5.

Чем Lists отличается

Данные у вас. Они лежат на устройстве и в хранилище, которое вы выбрали сами. Учётной записи нет, чужого сервера с вашими задачами тоже. Если проект завтра остановится, приложение продолжит работать, а с CalDAV задачи останутся ещё и в стандартном формате.

Работает без сети. Сеть нужна только для обмена изменениями. Самолёт, метро и упавший сервер ничего не меняют.

Одна логика на всех платформах. Хранение, слияние правок, синхронизация, повторы и разбор строки быстрого ввода написаны один раз, на Rust, и подключены к приложениям на Swift и Kotlin. Два независимо написанных слияния рано или поздно разошлись бы в мелочи. Интерфейс при этом у каждой платформы свой: SwiftUI на macOS, Jetpack Compose на Android6.

Правки не теряются. Слияние по полям избавляет от файлов вида «конфликтная копия» и от вопросов, какую версию оставить.

Переезд несложный. Lists читает резервную копию 2Do, CSV из Todoist, доску Trello в JSON и списки Microsoft To Do. Повторный импорт того же файла обновляет уже перенесённое.

Резервные копии. Приложения для macOS и Android раз в сутки сохраняют копию данных на устройстве и хранят последние пять. Копию можно восстановить, сохранить в другое место или перенести на другое устройство. Перед обновлением, которое меняет формат хранения, копия делается сама.

Код открыт. Лицензия MIT, спецификации лежат в репозитории рядом с кодом.

Что ещё не сделано

Проекту неделя. Первый коммит сделан 5 октября, с тех пор вышло тринадцать версий, считая предварительные; последняя стабильная 0.2.0, готовится 0.3.0. Работа продолжается, и вот чего пока нет:

  • приложения для iOS; телефон от Apple обслуживает веб-интерфейс;
  • шифрования данных в хранилище: приложение кладёт их туда открыто;
  • перетаскивания задач и списков на Android, и дата окончания повтора там не задаётся;
  • своих правил повтора и уведомлений в веб-интерфейсе;
  • сборок под Intel для macOS и под что-либо, кроме arm64, для Android.

Часть сделанного проверена тестами и на эмуляторе, но не на разных настоящих устройствах и серверах. Что именно и чем проверено, записано в конце спецификации7. Ошибки тоже есть: найденные записаны в задачах репозитория.

Как попробовать

Сборки лежат на странице релизов :

  • macOS 14 или новее на Apple silicon: образ диска .dmg;
  • Android 8.0 или новее на arm64: файл .apk, подписанный одним и тем же ключом от версии к версии;
  • веб-сервер: образ ghcr.io/juev/lists.

Начать можно без синхронизации, она подключается позже. Если уже есть список дел в другом приложении, его можно импортировать.

Попробуйте. Замечания, ошибки и пожелания оставляйте в задачах репозитория : разбираю я их именно там.


  1. docs/usage.md — руководство по приложениям и веб-интерфейсу. ↩︎

  2. docs/specs/sync.md — модель данных, правила слияния и формат хранилища. ↩︎

  3. docs/specs/caldav.md — что передаётся через CalDAV и что нет. ↩︎

  4. Раздел «Толчок между устройствами» в docs/specs/sync.md : проверка от 6 октября на эмуляторе с приложением ntfy 1.25.2. ↩︎

  5. docs/self-hosting.md — Docker, настройки, вход и обратный прокси. ↩︎

  6. docs/architecture.md — принятые решения и отклонённые варианты. ↩︎

  7. Раздел «Что реализовано» в docs/specs/product.md . ↩︎