Демо-проект

Панель диспетчера в телефоне: Графин

Заказы, водители и просрочка в кармане диспетчера; две правки чужого экрана сделаны в двух состояниях, до и после.

разработка мобильного приложения · Flutter · Dart · Android · iOS

7 экрановот сводки смены до карточки водителя
24 заказа5 новых, 9 в пути, из них 3 просрочены
8 водителейстатус, зона, машина, последний пинг
2 правкикаждая собрана в двух состояниях
5 пресетовпереключают состояние одной командой
Первый экран демо: Панель диспетчера в телефоне: Графин

Задача

«Графин» - служба доставки питьевой воды и обслуживания кулеров: бутыли 19 литров, помпы, возвратная тара, окна доставки. Демо-проект: компания, водители и заказы вымышлены, задача типовая. Диспетчер не всегда сидит за монитором - он отходит к складу, к машинам, к телефону в коридоре, и всё это время смена продолжается. Мобильная панель нужна ровно для этих минут: посмотреть, что горит, и передать заказ другому водителю, не возвращаясь к столу.

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

Решение

Flutter, семь экранов: смена, заказы, водители, карточка заказа, карточка водителя, полная лента событий и «О приложении». Тема только тёмная - так в брифе, светлой у этого демо нет.

  • Правка «список не показывает, что горит». В состоянии «до» просроченный заказ ничем не помечен: № 1031 стоит седьмым в плоском списке и подписан «В пути» тем же приглушённым серым, что «Доставлен» у соседних строк, - на первом экране он читается как обычная строка. Два других просроченных стоят 9-м и 12-м и до первого экрана вообще не доходят. В состоянии «после» просроченные подняты в секцию с липким заголовком, у строк заказов, которые ещё в работе, появился обратный отсчёт до конца окна доставки, статус получил цвет, а просроченная строка - красную полосу слева. Под заголовком - лента из пяти чипов-фильтров с количествами (все 24, новые 5, в пути 9, просрочены 3, доставлены 7); в ширину экрана она не помещается и прокручивается вбок.
  • Правка «пустой экран ничего не объясняет». Фильтр «Просрочены», когда просрочек нет, показывал голый фон. Стало: нарисованная галочка в круге, заголовок «Просрочек нет», строка «Все 24 заказа идут в срок» и кнопка «Показать все заказы».
  • Оба состояния живут в одном дереве кода и выбираются переменной сборки: --dart-define=DEMO=k11-before. Веток git и папок «before/after» нет - любой кадр переснимается одной командой, и «до» не устаревает, пока правится «после».
  • Просрочка - не статус, а вычисляемый признак: срок вышел, а заказ ещё в работе - назначен, забран или в пути. Отдельным статусом заказ оказался бы одновременно «в пути» и «просрочен»: все три просроченных в демо как раз «в пути».
  • Действия диспетчера работают, а не нарисованы: заказ передаётся другому водителю через шторку выбора и отмечается доставленным, таймлайн из пяти шагов дописывается временем.

Детали, которые легко не заметить

  • Данные детерминированы: «сейчас» - константа 25 августа 2026, 15:14, ни Random, ни DateTime.now() в данных нет. Поэтому «просрочен на 14 минут» и «-00:14» - результат вычитания, а не записанная строка, и кадр переснимается один в один хоть через полгода.
  • Действия не портят исходные данные: списки неизменяемы, обновление собирает новый заказ. Отдельный тест проверяет, что после отметки доставленным прежний объект остался нетронутым.
  • Русские окончания считаются, а не подставляются: «на 1 минуту», «на 2 минуты», «на 14 минут» - одна функция на три формы.
  • Неизвестный пресет не даёт приложению открыться «как получится»: вместо панели показывается экран ошибки со списком допустимых значений. Сборка при этом проходит - String.fromEnvironment принимает любую строку, проверка живёт в рантайме, и на неё есть тест.
  • В данных нет ни одного телефона и ни одной улицы с домом: у заказа показаны зона, район и этаж. Демонстрационная природа заявлена прямо - строка внизу экрана смены и отдельный экран «О приложении».
  • Шрифты лежат в репозитории, пакет google_fonts не подключён намеренно: он тянет файлы по сети, и в кадр может попасть подменный шрифт.
  • Съёмка автоматизирована скриптом: статус-бар приводится к нейтральному виду (9:41, без оператора), кадр снимается только через simctl и adb. Кадры Android дополнительно проверяются на сигнатуру png, завершающий чанк и минимальный размер - adb exec-out умеет молча обрезать файл.
  • Расхождение внутри брифа оставлено видимым, а не замазано: подпись плитки «из них 12 закрыты» не сходится с числами чипов, из которых следует 10. Обе цифры и их происхождение записаны в README, решать владельцу.

Что осталось

Галерея кадров для этой страницы не собрана: есть только исходники съёмки, двенадцать необработанных кадров с iOS и Android. Пар «до и после» на странице пока нет. Кода это не касается: все пять пресетов сняты на обеих платформах, то есть обе сборки собираются и запускаются.

Соседние проекты