Примеры Flutter-проектов
KegelFit
Доработка существующего приложения.
Правки внешнего вида приложения: Так как заказчик - дизайнер, то трепетно следит, чтобы в приложении все было pixel perfect. Чтобы дизайн лучше совпадал с макетом, я предложил сделать скейлинг приложения, так оно считает, что у него одна и та же ширина на всех устройствах. Ширина приложения = ширине в макете. Реализовано с помощью подмены MediaQuery.
Рефакторинг старта приложения: В приложении несколько стадий загрузки: onboard, предложение покупки, предложение триал, напоминание о списании триал, разрешение уведомлений, предложение оценки приложения. Все эти этапы могут активировать из разных условий: какой запуск по счету, время первого запуска, состояние подписки и т д. Изначально не было общего механизма переходов и, например, экран разрешения уведомлений мог открывать из onboard или предложения о покупки. Я переписал эту часть - оформил в виде стейт-машин, где каждый роут отчитывается о выполнении перед bloc инициализации, а не решает куда нужно переходить дальше.
Молодая Арктика
Место встречи молодёжи всей Мурманской области. Новости из жизни молодёжи, события, пространства, вакансии волонтеров, магазин и прочий контент.
Личный кабинет, баллы, покупки и большое количество медиа-контента. В приложении 53 экрана.


Invent
Приложение для проведения инвертаризация с помощью чтения qr-кодов.
Небольшое приложение, для которого был развернут сервер (nodejs, express, parse server). В приложении можно зарегистрироваться и авторизоваться с помощью email и пароля. Email валидируется с помощью parse server, для которого был разработан адаптер к unisender. Также в приложении можно пакетно загрузить объекты инвертаризации из типового xls файла. Есть функция экспорта qr-кодов в pdf файл, для последующей отправки на печать.


SemesterRus
Приложение для изучения русского языка, как иностранного.
Для приложения был создан редактор страниц, с помощью которого верстались уроки, экзамены, тесты и другие текстовые материалы (например, 'о приложении' и 'пользовательское соглашение'). В редакторе можно добавлять картинки, видео, таблицы, текст, тест с выбором ответа, тест с сопоставлением вариантов ответа, задания с заполнением пробелов. Также можно создавать задания на тему урока с проверкой ИИ (gpt-4o) - диалоги, эссе.
С помощью редактора было добавлено около 1500 записанных аудио. В какой-то момент выяснилось, что многие из них недостаточно громкие и/или содержат тишину в начале и конце. Для улучшения качества звука было решено обрезать тишину. Для этого написал скрипт, который прошелся по всем файлам. С помощью ffmpeg замерил уровень громкости и увеличил его, где требуется и обрезал тишину.
Для проекта необходимо было добавить свыше 2000 изображений для слов и уроков. Их сгенерировал скриптом с помощью dall-e-3. Так как было довольно много мусора, то дописал раздел в админке для выбора изображений из pexels.com и unsplash.com.


NRK87.
Приложение для работы с трекерами, которые продаются вместе с детской одеждой бренда NRK87.
Главная функция приложения - карта с маркерами трекеров, которые нужно было отрисовать самостоятельно. Для это нужно скачать аватарку, нарисовать маркер в буфере в нужном размере (т к google_maps_flutter рисует маркеры в размер), сохранить полученное на диск (на будущее), массив байт передать в BitmapDescriptor.


Добро.будильник
Приложение будильник, который переводит деньги в пользу благотворительных фондов, если человек проспал.
Функция будильника оказалась не самой простой задачей для Flutter. Объединив ограничения ОС приняли решение использовать flutter_local_notifications, так как библиотека может показывать нотификации по расписанию.
Для android в нативном проекте настроили показ Activity в полноэкранном режиме и дали возможность запускать ее на заблокированном экране. Для iOS сложнее: назначаем серию нотификаций (раз в 3 секунды в течении минуты).
Довольно сложной задачей было настроить рекуррентные платежи с помощью tinkoff_acquiring, т к заведение карты складывается из нескольких запросов + использование WebView для прохождения 3-D Secure.


ProjectV и Coffeecell
Платформа для работы в компаниях, основанных на сети независимых дистрибьюторов. В приложениях множество функций: обучение, новости, чат, события, календарь, отчеты, кошельки и т д.
В тот момент, когда начинали портировать проект с нативных платформ, еще не было готовой библиотеки капчи Geetest. Поэтому реализовали ее самостоятельно, в том числе с поддержкой Web (через вызов js.context.callMethod и установкой метода обратного вызова js.allowInterop) - на текущий момент официальная библиотека gt3_flutter_plugin этого не умеет.
В приложениях есть редактор публикаций, в которые можно поместить фото, видео, товары и делать галереи из всего этого. Для того, чтобы вставить медиа из тела поста, рисуем кнопку со скрепкой рядом с курсором, но только на пустой строке. Во Flutter нет удобного способа вычислить координаты каретки.
Обычно рекомендуют использовать TextPainter с такими же стилями, паддингами и размерами, как у TextField, но не всегда он вычисляет точное положение каретки. Да и создание и расчет TextPainter накладная операция.
Изучив исходники Flutter, нашли способ добраться до RenderEditable через глобальные ключи и поля state-классов. У RenderEditable есть метод getLocalRectForCaret, который вычисляет положение каретки исходя из содержимого TextField - это легче и надежнее способа с TextPainter. Также написали тест, на случай, если однажды доступ к RenderEditable будет утерян во Flutter SDK.

Календарь
Модуль календаря встречает в нескольких наших приложениях, при этом использует разные источники и делает переходы в разный контент. Для этого разработали систему CalendarSource, каждое приложение наследует любое их кол-во и регистрирует для своей версии календаря. Также гибко настраиваются некоторые детали интерфейса и стили, в том числе ночная тема.
Когда делали фичу, нам стало интересно, насколько производительным будет фича с таким кол-вом объектов + плавными анимациями перехода между разделами неделя, месяц и год. Пробовали разные решение, в итоге мы рисуем все объекты через CustomPainter, а также кэшируем все TextPainter, так как их создание и расчет размеров является довольно тяжелой операцией. Анимации переходов работают на основе форка local_hero, отдельные элементы анимируются flutter_animate.
UME
Приложение для отслеживания здоровья питомцев, подборе питания и его покупки, хранения документов, планирования событий и процедур связанных с питомцами.
В приложении есть раздел Магазин - это также переиспользуемая фича. Для UME и NRK87 это один конкретный магазин, для остальных приложений это набор разных магазинов (маркетплейс). Сущность магазина имеет свои настройки: цвета, пункты доставки самовывоза, распространение, возможность оплатить баллами из доступ кошельков. Экран оформления заказа динамически строится на основе настроек магазина и может включать до 6 разных запросов к серверу, эти данные могут зависеть от конкретного приложения. Например, в UME можно выбрать питомца, для которого происходит покупка - это позволит начислить баллы для питомца (внутренние 'очки').
Также для приложения UME мы впервые задействовали Rive. Я самостоятельно делал анимации для иконок в bottombar.

Страница сверстана с помощью Dart Jaspr
